void proxy_prepare(alsa_device_proxy * proxy, alsa_device_profile* profile, struct pcm_config * config) { ALOGV("proxy_prepare()"); proxy->profile = profile; #ifdef LOG_PCM_PARAMS log_pcm_config(config, "proxy_setup()"); #endif proxy->alsa_config.format = config->format != PCM_FORMAT_INVALID && profile_is_format_valid(profile, config->format) ? config->format : profile->default_config.format; proxy->alsa_config.rate = config->rate != 0 && profile_is_sample_rate_valid(profile, config->rate) ? config->rate : profile->default_config.rate; proxy->alsa_config.channels = config->channels != 0 && profile_is_channel_count_valid(profile, config->channels) ? config->channels : profile->default_config.channels; proxy->alsa_config.period_count = profile->default_config.period_count; proxy->alsa_config.period_size = profile_get_period_size(proxy->profile, proxy->alsa_config.rate); // Hack for USB accessory audio. // Here we set the correct value for period_count if tinyalsa fails to get it from the // f_audio_source driver. if (proxy->alsa_config.period_count == 0) { proxy->alsa_config.period_count = 4; } proxy->pcm = NULL; }
void proxy_prepare(alsa_device_proxy * proxy, alsa_device_profile* profile, struct pcm_config * config) { ALOGV("proxy_prepare(c:%d, d:%d)", profile->card, profile->device); proxy->profile = profile; #ifdef LOG_PCM_PARAMS log_pcm_config(config, "proxy_setup()"); #endif proxy->alsa_config.format = config->format != PCM_FORMAT_INVALID && profile_is_format_valid(profile, config->format) ? config->format : profile->default_config.format; proxy->alsa_config.rate = config->rate != 0 && profile_is_sample_rate_valid(profile, config->rate) ? config->rate : profile->default_config.rate; proxy->alsa_config.channels = config->channels != 0 && profile_is_channel_count_valid(profile, config->channels) ? config->channels : profile->default_config.channels; proxy->alsa_config.period_count = profile->default_config.period_count; proxy->alsa_config.period_size = profile_get_period_size(proxy->profile, proxy->alsa_config.rate); // Hack for USB accessory audio. // Here we set the correct value for period_count if tinyalsa fails to get it from the // f_audio_source driver. if (proxy->alsa_config.period_count == 0) { proxy->alsa_config.period_count = 4; } proxy->pcm = NULL; // config format should be checked earlier against profile. if (config->format >= 0 && (size_t)config->format < ARRAY_SIZE(format_byte_size_map)) { proxy->frame_size = format_byte_size_map[config->format] * proxy->alsa_config.channels; } else { proxy->frame_size = 1; } }
static int adev_open_input_stream(struct audio_hw_device *dev, audio_io_handle_t handle, audio_devices_t devices, struct audio_config *config, struct audio_stream_in **stream_in, audio_input_flags_t flags __unused, const char *address /*__unused*/, audio_source_t source __unused) { ALOGV("in adev_open_input_stream() rate:%" PRIu32 ", chanMask:0x%" PRIX32 ", fmt:%" PRIu8, config->sample_rate, config->channel_mask, config->format); struct stream_in *in = (struct stream_in *)calloc(1, sizeof(struct stream_in)); int ret = 0; if (in == NULL) return -ENOMEM; /* setup function pointers */ in->stream.common.get_sample_rate = in_get_sample_rate; in->stream.common.set_sample_rate = in_set_sample_rate; in->stream.common.get_buffer_size = in_get_buffer_size; in->stream.common.get_channels = in_get_channels; in->stream.common.get_format = in_get_format; in->stream.common.set_format = in_set_format; in->stream.common.standby = in_standby; in->stream.common.dump = in_dump; in->stream.common.set_parameters = in_set_parameters; in->stream.common.get_parameters = in_get_parameters; in->stream.common.add_audio_effect = in_add_audio_effect; in->stream.common.remove_audio_effect = in_remove_audio_effect; in->stream.set_gain = in_set_gain; in->stream.read = in_read; in->stream.get_input_frames_lost = in_get_input_frames_lost; pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL); pthread_mutex_init(&in->pre_lock, (const pthread_mutexattr_t *) NULL); in->dev = (struct audio_device *)dev; pthread_mutex_lock(&in->dev->lock); in->profile = &in->dev->in_profile; struct pcm_config proxy_config; memset(&proxy_config, 0, sizeof(proxy_config)); /* Pull out the card/device pair */ parse_card_device_params(false, &(in->profile->card), &(in->profile->device)); profile_read_device_info(in->profile); pthread_mutex_unlock(&in->dev->lock); /* Rate */ if (config->sample_rate == 0) { proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(in->profile); } else if (profile_is_sample_rate_valid(in->profile, config->sample_rate)) { proxy_config.rate = config->sample_rate; } else { ALOGE("%s: The requested sample rate (%d) is not valid", __func__, config->sample_rate); proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(in->profile); ret = -EINVAL; } /* Format */ if (config->format == AUDIO_FORMAT_DEFAULT) { proxy_config.format = profile_get_default_format(in->profile); config->format = audio_format_from_pcm_format(proxy_config.format); } else { enum pcm_format fmt = pcm_format_from_audio_format(config->format); if (profile_is_format_valid(in->profile, fmt)) { proxy_config.format = fmt; } else { ALOGE("%s: The requested format (0x%x) is not valid", __func__, config->format); proxy_config.format = profile_get_default_format(in->profile); config->format = audio_format_from_pcm_format(proxy_config.format); ret = -EINVAL; } } /* Channels */ unsigned proposed_channel_count = 0; if (k_force_channels) { proposed_channel_count = k_force_channels; } else if (config->channel_mask == AUDIO_CHANNEL_NONE) { proposed_channel_count = profile_get_default_channel_count(in->profile); } if (proposed_channel_count != 0) { config->channel_mask = audio_channel_in_mask_from_count(proposed_channel_count); if (config->channel_mask == AUDIO_CHANNEL_INVALID) config->channel_mask = audio_channel_mask_for_index_assignment_from_count(proposed_channel_count); in->hal_channel_count = proposed_channel_count; } else { in->hal_channel_count = audio_channel_count_from_in_mask(config->channel_mask); } /* we can expose any channel mask, and emulate internally based on channel count. */ in->hal_channel_mask = config->channel_mask; proxy_config.channels = profile_get_default_channel_count(in->profile); proxy_prepare(&in->proxy, in->profile, &proxy_config); in->standby = true; in->conversion_buffer = NULL; in->conversion_buffer_size = 0; *stream_in = &in->stream; return ret; }
static int adev_open_output_stream(struct audio_hw_device *dev, audio_io_handle_t handle, audio_devices_t devices, audio_output_flags_t flags, struct audio_config *config, struct audio_stream_out **stream_out, const char *address /*__unused*/) { ALOGV("adev_open_output_stream() handle:0x%X, device:0x%X, flags:0x%X, addr:%s", handle, devices, flags, address); struct audio_device *adev = (struct audio_device *)dev; struct stream_out *out; out = (struct stream_out *)calloc(1, sizeof(struct stream_out)); if (!out) return -ENOMEM; /* setup function pointers */ out->stream.common.get_sample_rate = out_get_sample_rate; out->stream.common.set_sample_rate = out_set_sample_rate; out->stream.common.get_buffer_size = out_get_buffer_size; out->stream.common.get_channels = out_get_channels; out->stream.common.get_format = out_get_format; out->stream.common.set_format = out_set_format; out->stream.common.standby = out_standby; out->stream.common.dump = out_dump; out->stream.common.set_parameters = out_set_parameters; out->stream.common.get_parameters = out_get_parameters; out->stream.common.add_audio_effect = out_add_audio_effect; out->stream.common.remove_audio_effect = out_remove_audio_effect; out->stream.get_latency = out_get_latency; out->stream.set_volume = out_set_volume; out->stream.write = out_write; out->stream.get_render_position = out_get_render_position; out->stream.get_presentation_position = out_get_presentation_position; out->stream.get_next_write_timestamp = out_get_next_write_timestamp; pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL); pthread_mutex_init(&out->pre_lock, (const pthread_mutexattr_t *) NULL); out->dev = adev; pthread_mutex_lock(&adev->lock); out->profile = &adev->out_profile; // build this to hand to the alsa_device_proxy struct pcm_config proxy_config; memset(&proxy_config, 0, sizeof(proxy_config)); /* Pull out the card/device pair */ parse_card_device_params(true, &(out->profile->card), &(out->profile->device)); profile_read_device_info(out->profile); pthread_mutex_unlock(&adev->lock); int ret = 0; /* Rate */ if (config->sample_rate == 0) { proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile); } else if (profile_is_sample_rate_valid(out->profile, config->sample_rate)) { proxy_config.rate = config->sample_rate; } else { ALOGE("%s: The requested sample rate (%d) is not valid", __func__, config->sample_rate); proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile); ret = -EINVAL; } /* Format */ if (config->format == AUDIO_FORMAT_DEFAULT) { proxy_config.format = profile_get_default_format(out->profile); config->format = audio_format_from_pcm_format(proxy_config.format); } else { enum pcm_format fmt = pcm_format_from_audio_format(config->format); if (profile_is_format_valid(out->profile, fmt)) { proxy_config.format = fmt; } else { ALOGE("%s: The requested format (0x%x) is not valid", __func__, config->format); proxy_config.format = profile_get_default_format(out->profile); config->format = audio_format_from_pcm_format(proxy_config.format); ret = -EINVAL; } } /* Channels */ unsigned proposed_channel_count = 0; if (k_force_channels) { proposed_channel_count = k_force_channels; } else if (config->channel_mask == AUDIO_CHANNEL_NONE) { proposed_channel_count = profile_get_default_channel_count(out->profile); } if (proposed_channel_count != 0) { if (proposed_channel_count <= FCC_2) { // use channel position mask for mono and stereo config->channel_mask = audio_channel_out_mask_from_count(proposed_channel_count); } else { // use channel index mask for multichannel config->channel_mask = audio_channel_mask_for_index_assignment_from_count(proposed_channel_count); } out->hal_channel_count = proposed_channel_count; } else { out->hal_channel_count = audio_channel_count_from_out_mask(config->channel_mask); } /* we can expose any channel mask, and emulate internally based on channel count. */ out->hal_channel_mask = config->channel_mask; /* no validity checks are needed as proxy_prepare() forces channel_count to be valid. * and we emulate any channel count discrepancies in out_write(). */ proxy_config.channels = proposed_channel_count; #if TARGET_AUDIO_PRIMARY out->profile->default_config.period_count = 4; #endif proxy_prepare(&out->proxy, out->profile, &proxy_config); /* TODO The retry mechanism isn't implemented in AudioPolicyManager/AudioFlinger. */ ret = 0; out->conversion_buffer = NULL; out->conversion_buffer_size = 0; out->standby = true; *stream_out = &out->stream; return ret; err_open: free(out); *stream_out = NULL; return -ENOSYS; }