diff --git a/audio/audio_hw.c b/audio/audio_hw.c index 3aa24b0..9786a8a 100644 --- a/audio/audio_hw.c +++ b/audio/audio_hw.c @@ -126,7 +126,7 @@ struct stream_out_common { out_close_fn close; struct audio_device *dev; - const struct hw_stream *hw; + struct hw_stream *hw; pthread_mutex_t lock; @@ -203,7 +203,7 @@ struct stream_in_common { in_close_fn close; struct audio_device *dev; - const struct hw_stream *hw; + struct hw_stream *hw; pthread_mutex_t lock; @@ -379,6 +379,9 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) struct stream_out_common *out = (struct stream_out_common *)stream; struct audio_device *adev = out->dev; + static uint32_t cardold, devold; + static bool saved = false; + uint32_t cardnum, devnum; uint32_t v; int ret; @@ -388,6 +391,23 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) if (ret >= 0) { apply_route(out->hw, v); + if (get_device_alsadev(adev->cm, v, &cardnum, &devnum) < 0) { + if (saved) { + ALOGI("restoring params with card=%u dev=%u", cardold, devold); + out->hw->card_number = cardold; + out->hw->device_number = devold; + } + } else { + ALOGI("updating params with card=%u dev=%u", cardnum, devnum); + if (!saved) { + cardold = out->hw->card_number; + devold = out->hw->device_number; + ALOGI("saved params with card=%u dev=%u", cardold, devold); + saved = true; + } + out->hw->card_number = cardnum; + out->hw->device_number = devnum; + } } stream_invoke_usecases(out->hw, kvpairs); @@ -735,6 +755,8 @@ static void out_pcm_fill_params(struct stream_out_pcm *out, /* Must be called with hw device and output stream mutexes locked */ static int start_output_pcm(struct stream_out_pcm *out) { + struct config_mgr *cm = out->common.dev->cm; + uint32_t device, cardnum, devnum; int ret; struct pcm_config config = { @@ -750,10 +772,21 @@ static int start_output_pcm(struct stream_out_pcm *out) ALOGV("+start_output_stream(%p)", out); - out->pcm = pcm_open(out->common.hw->card_number, - out->common.hw->device_number, - PCM_OUT | PCM_MONOTONIC, - &config); + device = get_current_routes(out->common.hw); + ret = get_device_alsadev(cm, device, &cardnum, &devnum); + if (ret < 0) { + ALOGI("device = %u (not alsadev, ret=%d)", device, ret); + out->pcm = pcm_open(out->common.hw->card_number, + out->common.hw->device_number, + PCM_OUT | PCM_MONOTONIC, + &config); + } else { + ALOGI("device = %u (alsadev)", device); + out->pcm = pcm_open(cardnum, + devnum, + PCM_OUT | PCM_MONOTONIC, + &config); + } if (out->pcm && !pcm_is_ready(out->pcm)) { ALOGE("pcm_open(out) failed: %s", pcm_get_error(out->pcm)); @@ -1799,6 +1832,8 @@ static void in_pcm_fill_params(struct stream_in_pcm *in, /* Must be called with hw device and input stream mutexes locked */ static int do_open_pcm_input(struct stream_in_pcm *in) { + struct config_mgr *cm = in->common.dev->cm; + uint32_t device, cardnum, devnum; struct pcm_config config; int ret; @@ -1818,10 +1853,21 @@ static int do_open_pcm_input(struct stream_in_pcm *in) config.format = pcm_format_from_android_format(in->common.format), config.start_threshold = 0; - in->pcm = pcm_open(in->common.hw->card_number, - in->common.hw->device_number, - PCM_IN | PCM_MONOTONIC, - &config); + device = get_current_routes(in->common.hw); + ret = get_device_alsadev(cm, device, &cardnum, &devnum); + if (ret < 0) { + ALOGV("device = %u (not alsadev, ret=%d)", device, ret); + in->pcm = pcm_open(in->common.hw->card_number, + in->common.hw->device_number, + PCM_IN | PCM_MONOTONIC, + &config); + } else { + ALOGV("device = %u (alsadev)", device); + in->pcm = pcm_open(cardnum, + devnum, + PCM_IN | PCM_MONOTONIC, + &config); + } if (!in->pcm || !pcm_is_ready(in->pcm)) { ALOGE_IF(in->pcm,"pcm_open(in) failed: %s", pcm_get_error(in->pcm)); @@ -1876,7 +1922,7 @@ static int change_input_source_locked(struct stream_in_pcm *in, const char *valu { struct audio_config config; const char *stream_name; - const struct hw_stream *hw = NULL; + struct hw_stream *hw = NULL; const int new_source = atoi(value); *was_changed = false; @@ -2047,12 +2093,16 @@ static ssize_t in_pcm_read(struct audio_stream_in *stream, void *buffer, static int in_pcm_set_parameters(struct audio_stream *stream, const char *kvpairs) { struct stream_in_pcm *in = (struct stream_in_pcm *)stream; + struct config_mgr *cm = in->common.dev->cm; struct str_parms *parms; char value[32]; uint32_t new_routing = 0; bool routing_changed; uint32_t devices; bool input_was_changed; + static uint32_t cardold, devold; + static bool saved = false; + uint32_t cardnum, devnum; int ret; ALOGV("+in_pcm_set_parameters(%p) '%s'", stream, kvpairs); @@ -2091,6 +2141,23 @@ static int in_pcm_set_parameters(struct audio_stream *stream, const char *kvpair if (in->common.hw) { ALOGV("Apply routing=0x%x to input stream", new_routing); apply_route(in->common.hw, new_routing); + if (get_device_alsadev(cm, new_routing, &cardnum, &devnum) < 0) { + if (saved) { + ALOGV("restoring params with card=%u dev=%u", cardold, devold); + in->common.hw->card_number = cardold; + in->common.hw->device_number = devold; + } + } else { + ALOGV("updating params with card=%u dev=%u", cardnum, devnum); + if (!saved) { + cardold = in->common.hw->card_number; + devold = in->common.hw->device_number; + ALOGV("saved params with card=%u dev=%u", cardold, devold); + saved = true; + } + in->common.hw->card_number = cardnum; + in->common.hw->device_number = devnum; + } } } @@ -2159,7 +2226,7 @@ static int adev_open_output_stream_v3(struct audio_hw_device *dev, config->format, config->channel_mask, config->sample_rate, flags); devices &= AUDIO_DEVICE_OUT_ALL; - const struct hw_stream *hw = get_stream(adev->cm, devices, flags, config); + struct hw_stream *hw = get_stream(adev->cm, devices, flags, config); if (!hw) { ALOGE("No suitable output stream for devices=0x%x flags=0x%x format=0x%x", devices, flags, config->format); @@ -2257,7 +2324,7 @@ static int adev_open_input_stream_v3(struct audio_hw_device *dev, *stream_in = NULL; devices &= AUDIO_DEVICE_IN_ALL; - const struct hw_stream *hw = get_stream(adev->cm, devices, 0, config); + struct hw_stream *hw = get_stream(adev->cm, devices, 0, config); if (!hw) { ALOGE("No suitable input stream for devices=0x%x flags=0x%x format=0x%x", devices, flags, config->format); diff --git a/configmgr/audio_config.c b/configmgr/audio_config.c index b936472..ace18f9 100644 --- a/configmgr/audio_config.c +++ b/configmgr/audio_config.c @@ -163,6 +163,8 @@ struct codec_probe { struct device { uint32_t type; /* 0 is reserved for the global device */ int use_count; /* counts total streams using this device */ + uint32_t card_number; + uint32_t device_number; struct dyn_array path_array; }; @@ -863,7 +865,7 @@ static bool open_stream_l(struct config_mgr *cm, struct stream *s) } } -const struct hw_stream *get_stream(struct config_mgr *cm, +struct hw_stream *get_stream(struct config_mgr *cm, const audio_devices_t devices, const audio_output_flags_t flags, const struct audio_config *config ) @@ -907,7 +909,7 @@ const struct hw_stream *get_stream(struct config_mgr *cm, } } -const struct hw_stream *get_named_stream(struct config_mgr *cm, +struct hw_stream *get_named_stream(struct config_mgr *cm, const char *name) { struct stream *s; @@ -1078,6 +1080,31 @@ int get_stream_constant_int32(const struct hw_stream *stream, return ret; } +/********************************************************************* + * Device + *********************************************************************/ + +int get_device_alsadev(struct config_mgr *cm, uint32_t type, uint32_t *cardnum, uint32_t *devnum) +{ + struct device *pdev = cm->device_array.devices; + int dev_count = cm->device_array.count; + + while (dev_count > 0) { + if (pdev->type == type) { + cardnum = &pdev->card_number; + devnum = &pdev->device_number; + if (*cardnum < UINT_MAX && *devnum < UINT_MAX) { + return 0; + } + return -ENODEV; + } + --dev_count; + ++pdev; + } + + return -ENOENT; +} + /********************************************************************* * Config file parsing * @@ -1133,7 +1160,8 @@ static const struct parse_element elem_table[e_elem_count] = { [e_elem_device] = { .name = "device", - .valid_attribs = BIT(e_attrib_name), + .valid_attribs = BIT(e_attrib_name) | BIT(e_attrib_card) + | BIT(e_attrib_cardname) | BIT(e_attrib_device), .required_attribs = BIT(e_attrib_name), .valid_subelem = BIT(e_elem_path), .start_fn = parse_device_start, @@ -2505,8 +2533,11 @@ static int parse_device_start(struct parse_state *state) struct dyn_array *array = &state->cm->device_array; uint32_t device_flag; uint32_t *existing_devices; + uint32_t card = UINT_MAX; + uint32_t device_number = UINT_MAX; const struct parse_device *p; struct device* d; + int ret; p = parse_match_device(dev_name); @@ -2536,7 +2567,32 @@ static int parse_device_start(struct parse_state *state) *existing_devices |= device_flag; } - ALOGV("Add device '%s'", dev_name); + if (state->attribs.value[e_attrib_cardname] != NULL && + state->attribs.value[e_attrib_card] != NULL) { + ALOGE("device must be configured by only one of 'card' OR 'cardname'. Both provided."); + return -EINVAL; + } + + ret = attrib_to_uint(&card, state, e_attrib_card); + if (ret == -EINVAL) { + return ret; + } + + if (state->attribs.value[e_attrib_cardname] != NULL && + get_card_id_for_name(state->attribs.value[e_attrib_cardname], &card) != 0) { + return -EINVAL; + } + + ret = attrib_to_uint(&device_number, state, e_attrib_device); + if (ret == -EINVAL) { + return ret; + } + + if (card < UINT_MAX && device_number < UINT_MAX) { + ALOGV("Add device '%s' (card=%u device=%u)", dev_name, card, device_number); + } else { + ALOGV("Add device '%s'", dev_name); + } d = new_device(array, device_flag); if (d == NULL) { @@ -2544,6 +2600,9 @@ static int parse_device_start(struct parse_state *state) } state->current.device = d; + d->card_number = card; + d->device_number = device_number; + return 0; } diff --git a/include/tinyhal/audio_config.h b/include/tinyhal/audio_config.h index bf81033..84397dc 100644 --- a/include/tinyhal/audio_config.h +++ b/include/tinyhal/audio_config.h @@ -32,6 +32,7 @@ struct mixer; struct mixer_ctl; struct config_mgr; struct audio_config; +struct device; /** Stream type */ enum stream_type { @@ -129,13 +130,13 @@ uint32_t get_supported_output_devices( struct config_mgr *cm ); * Note that this only considers unnamed streams (those without a 'name' * attribute). For named streams use get_named_stream(). */ -const struct hw_stream *get_stream( struct config_mgr *cm, +struct hw_stream *get_stream( struct config_mgr *cm, const audio_devices_t devices, const audio_output_flags_t flags, const struct audio_config *config ); /** Find a named custom stream and return a pointer to it */ -const struct hw_stream *get_named_stream(struct config_mgr *cm, +struct hw_stream *get_named_stream(struct config_mgr *cm, const char *name); /** Return the value of a constant defined by a element as a string @@ -187,6 +188,13 @@ int apply_use_case( const struct hw_stream* stream, const char *setting, const char *case_name); +/** Get the ALSA card and device number associated to this device + * @return 0 if the device type has card and device numbers defined + * @return -ENODEV if the device type has no card and device number defined + * @return -ENOENT if the device type was not found + */ +int get_device_alsadev(struct config_mgr *cm, uint32_t type, uint32_t *cardnum, uint32_t *devnum); + #if defined(__cplusplus) } /* extern "C" */ #endif