高通輸入輸出裝置選擇
阿新 • • 發佈:2019-01-10
static int adev_open_input_stream(struct audio_hw_device *dev,
audio_io_handle_t handle __unused,
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)
{
struct audio_device *adev = (struct audio_device *)dev;
struct stream_in *in;
int ret = 0, buffer_size, frame_size;
int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
bool is_low_latency = false;
*stream_in = NULL;
if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0)
return -EINVAL;
in = (struct stream_in * )calloc(1, sizeof(struct stream_in));
pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL);
pthread_mutex_init(&in->pre_lock, (const pthread_mutexattr_t *) NULL);
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;
in->device = devices;
in->source = AUDIO_SOURCE_DEFAULT;
in->dev = adev;
in->standby = 1;
in->channel_mask = config->channel_mask;
in->capture_handle = handle;
/* Update config params with the requested sample rate and channels */
in->usecase = USECASE_AUDIO_RECORD;
if (config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE &&
(flags & AUDIO_INPUT_FLAG_FAST) != 0) {
is_low_latency = true;
in->usecase = USECASE_AUDIO_RECORD_LOW_LATENCY;
}
in->config = pcm_config_audio_capture;
in->config.rate = config->sample_rate;
in->format = config->format;
if (in->device == AUDIO_DEVICE_IN_TELEPHONY_RX) {
if (config->sample_rate == 0)
config->sample_rate = AFE_PROXY_SAMPLING_RATE;
if (config->sample_rate != 48000 && config->sample_rate != 16000 &&
config->sample_rate != 8000) {
config->sample_rate = AFE_PROXY_SAMPLING_RATE;
ret = -EINVAL;
goto err_open;
}
if (config->format == AUDIO_FORMAT_DEFAULT)
config->format = AUDIO_FORMAT_PCM_16_BIT;
if (config->format != AUDIO_FORMAT_PCM_16_BIT) {
config->format = AUDIO_FORMAT_PCM_16_BIT;
ret = -EINVAL;
goto err_open;
}
in->usecase = USECASE_AUDIO_RECORD_AFE_PROXY;
in->config = pcm_config_afe_proxy_record;
in->config.channels = channel_count;
in->config.rate = config->sample_rate;
} else if (channel_count == 6) {
if(audio_extn_ssr_get_enabled()) {
if(audio_extn_ssr_init(in)) {
ret = -EINVAL;
goto err_open;
}
} else {
ALOGW("%s: surround sound recording is not supported", __func__);
}
} else if (audio_extn_compr_cap_enabled() &&
audio_extn_compr_cap_format_supported(config->format) &&
(in->dev->mode != AUDIO_MODE_IN_COMMUNICATION)) {
audio_extn_compr_cap_init(in);
} else {
in->config.channels = channel_count;
frame_size = audio_stream_in_frame_size(&in->stream);
buffer_size = get_input_buffer_size(config->sample_rate,
config->format,
channel_count,
is_low_latency);
in->config.period_size = buffer_size / frame_size;
}
/* This stream could be for sound trigger lab,
get sound trigger pcm if present */
audio_extn_sound_trigger_check_and_get_session(in);
audio_extn_perf_lock_init();
*stream_in = &in->stream;
return ret;
err_open:
free(in);
*stream_in = NULL;
return ret;
}
static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
size_t bytes)
{
struct stream_in *in = (struct stream_in *)stream;
struct audio_device *adev = in->dev;
int ret = -1;
int snd_scard_state = get_snd_card_state(adev);
lock_input_stream(in);
if (in->standby) {
if (!in->is_st_session) {
pthread_mutex_lock(&adev->lock);
if (in->usecase == USECASE_COMPRESS_VOIP_CALL){
ret = voice_extn_compress_voip_start_input_stream(in);
}
else{
ret = start_input_stream(in);
}
pthread_mutex_unlock(&adev->lock);
if (ret != 0) {
goto exit;
}
}
in->standby = 0;
}
if (in->pcm) {
if (audio_extn_ssr_get_enabled() &&
audio_channel_count_from_in_mask(in->channel_mask) == 6)
ret = audio_extn_ssr_read(stream, buffer, bytes);
else if (audio_extn_compr_cap_usecase_supported(in->usecase))
ret = audio_extn_compr_cap_read(in, buffer, bytes);
else if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY)
ret = pcm_mmap_read(in->pcm, buffer, bytes);
else
ret = pcm_read(in->pcm, buffer, bytes);
if (ret < 0)
ret = -errno;
}
/*
* Instead of writing zeroes here, we could trust the hardware
* to always provide zeroes when muted.
*/
if (ret == 0 && voice_get_mic_mute(adev) && !voice_is_in_call_rec_stream(in))
memset(buffer, 0, bytes);
exit:
/* ToDo: There may be a corner case when SSR happens back to back during
start/stop. Need to post different error to handle that. */
if (-ENETRESET == ret) {
set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
}
pthread_mutex_unlock(&in->lock);
if (ret != 0) {
if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
pthread_mutex_lock(&adev->lock);
voice_extn_compress_voip_close_input_stream(&in->stream.common);
pthread_mutex_unlock(&adev->lock);
in->standby = true;
}
memset(buffer, 0, bytes);
in_standby(&in->stream.common);
usleep(bytes * 1000000 / audio_stream_in_frame_size(stream) /
in_get_sample_rate(&in->stream.common));
}
return bytes;
}
int voice_extn_compress_voip_start_input_stream(struct stream_in *in)
{
int ret = 0;
struct audio_device *adev = in->dev;
int snd_card_status = get_snd_card_state(adev);
if (SND_CARD_STATE_OFFLINE == snd_card_status) {
ret = -ENETRESET;
goto error;
}
if (!voip_data.in_stream_count)
ret = voice_extn_compress_voip_open_input_stream(in);
adev->active_input = in;
ret = voip_start_call(adev, &in->config);
in->pcm = voip_data.pcm_tx;
error:
return ret;
}
int start_input_stream(struct stream_in *in)
{
/* 1. Enable output device and stream routing controls */
int ret = 0;
struct audio_usecase *uc_info;
struct audio_device *adev = in->dev;
int snd_card_status = get_snd_card_state(adev);
int usecase = platform_update_usecase_from_source(in->source,in->usecase);
if (get_usecase_from_list(adev, usecase) == NULL)
in->usecase = usecase;
if (SND_CARD_STATE_OFFLINE == snd_card_status) {
ret = -EIO;
goto error_config;
}
/* Check if source matches incall recording usecase criteria */
ret = voice_check_and_set_incall_rec_usecase(adev, in);
if (get_usecase_from_list(adev, in->usecase) != NULL) {
goto error_config;
}
in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
adev->active_input = in;
uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
uc_info->id = in->usecase;
uc_info->type = PCM_CAPTURE;
uc_info->stream.in = in;
uc_info->devices = in->device;
uc_info->in_snd_device = SND_DEVICE_NONE;
uc_info->out_snd_device = SND_DEVICE_NONE;
list_add_tail(&adev->usecase_list, &uc_info->list);
audio_extn_perf_lock_acquire();
select_devices(adev, in->usecase);
unsigned int flags = PCM_IN;
unsigned int pcm_open_retry_count = 0;
if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) {
flags |= PCM_MMAP | PCM_NOIRQ;
pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
}
while (1) {
in->pcm = pcm_open(adev->snd_card, in->pcm_device_id, flags, &in->config);
if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
if (in->pcm != NULL) {
pcm_close(in->pcm);
in->pcm = NULL;
}
if (pcm_open_retry_count-- == 0) {
ret = -EIO;
goto error_open;
}
usleep(PROXY_OPEN_WAIT_TIME * 1000);
continue;
}
break;
}
ret = pcm_prepare(in->pcm);
if (ret < 0) {
pcm_close(in->pcm);
in->pcm = NULL;
goto error_open;
}
return ret;
}
int select_devices(struct audio_device *adev, audio_usecase_t uc_id)
{
snd_device_t out_snd_device = SND_DEVICE_NONE;
snd_device_t in_snd_device = SND_DEVICE_NONE;
struct audio_usecase *usecase = NULL;
struct audio_usecase *vc_usecase = NULL;
struct audio_usecase *voip_usecase = NULL;
struct audio_usecase *hfp_usecase = NULL;
audio_usecase_t hfp_ucid;
int status = 0;
usecase = get_usecase_from_list(adev, uc_id);
if (usecase == NULL) {
return -EINVAL;
}
ALOGD("++%s: start usecase->type %d",__func__, usecase->type);
if ((usecase->type == VOICE_CALL) ||
(usecase->type == VOIP_CALL) ||
(usecase->type == PCM_HFP_CALL)) {
out_snd_device = platform_get_output_snd_device(adev->platform,
usecase->stream.out->devices);
in_snd_device = platform_get_input_snd_device(adev->platform, usecase->stream.out->devices);
usecase->devices = usecase->stream.out->devices;
} else {
/*
* If the voice call is active, use the sound devices of voice call usecase
* so that it would not result any device switch. All the usecases will
* be switched to new device when select_devices() is called for voice call
* usecase. This is to avoid switching devices for voice call when
* check_usecases_codec_backend() is called below.
*/
if (voice_is_in_call(adev) && adev->mode == AUDIO_MODE_IN_CALL) {
vc_usecase = get_usecase_from_list(adev,
get_usecase_id_from_usecase_type(adev, VOICE_CALL));
if ((vc_usecase) && ((vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) ||
(usecase->devices == AUDIO_DEVICE_IN_VOICE_CALL))) {
in_snd_device = vc_usecase->in_snd_device;
out_snd_device = vc_usecase->out_snd_device;
}
} else if (voice_extn_compress_voip_is_active(adev)) {
voip_usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
if ((voip_usecase) && ((voip_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) &&
(usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) &&
(voip_usecase->stream.out != adev->primary_output))) {
in_snd_device = voip_usecase->in_snd_device;
out_snd_device = voip_usecase->out_snd_device;
}
} else if (audio_extn_hfp_is_active(adev)) {
hfp_ucid = audio_extn_hfp_get_usecase();
hfp_usecase = get_usecase_from_list(adev, hfp_ucid);
if ((hfp_usecase) && (hfp_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND)) {
in_snd_device = hfp_usecase->in_snd_device;
out_snd_device = hfp_usecase->out_snd_device;
}
}
if (usecase->type == PCM_PLAYBACK) {
usecase->devices = usecase->stream.out->devices;
in_snd_device = SND_DEVICE_NONE;
if (out_snd_device == SND_DEVICE_NONE) {
out_snd_device = platform_get_output_snd_device(adev->platform,
usecase->stream.out->devices);
if (usecase->stream.out == adev->primary_output &&
adev->active_input &&
out_snd_device != usecase->out_snd_device) {
select_devices(adev, adev->active_input->usecase);
}
}
} else if (usecase->type == PCM_CAPTURE) {
usecase->devices = usecase->stream.in->device;
out_snd_device = SND_DEVICE_NONE;
if (in_snd_device == SND_DEVICE_NONE) {
audio_devices_t out_device = AUDIO_DEVICE_NONE;
if ((adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
(adev->mode == AUDIO_MODE_IN_COMMUNICATION &&
adev->active_input->source == AUDIO_SOURCE_MIC)) &&
adev->primary_output && !adev->primary_output->standby) {
out_device = adev->primary_output->devices;
platform_set_echo_reference(adev->platform, false);
} else if (usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY) {
out_device = AUDIO_DEVICE_OUT_TELEPHONY_TX;
}
in_snd_device = platform_get_input_snd_device(adev->platform, out_device);
}
}
}
if (out_snd_device == usecase->out_snd_device &&
in_snd_device == usecase->in_snd_device) {
return 0;
}
/*
* Limitation: While in call, to do a device switch we need to disable
* and enable both RX and TX devices though one of them is same as current
* device.
*/
if ((usecase->type == VOICE_CALL) &&
(usecase->in_snd_device != SND_DEVICE_NONE) &&
(usecase->out_snd_device != SND_DEVICE_NONE)) {
status = platform_switch_voice_call_device_pre(adev->platform);
}
/* Disable current sound devices */
if (usecase->out_snd_device != SND_DEVICE_NONE) {
disable_audio_route(adev, usecase);
disable_snd_device(adev, usecase->out_snd_device);
}
if (usecase->in_snd_device != SND_DEVICE_NONE) {
disable_audio_route(adev, usecase);
disable_snd_device(adev, usecase->in_snd_device);
}
/* Applicable only on the targets that has external modem.
* New device information should be sent to modem before enabling
* the devices to reduce in-call device switch time.
*/
if ((usecase->type == VOICE_CALL) &&
(usecase->in_snd_device != SND_DEVICE_NONE) &&
(usecase->out_snd_device != SND_DEVICE_NONE)) {
status = platform_switch_voice_call_enable_device_config(adev->platform,
out_snd_device,
in_snd_device);
}
/* Enable new sound devices */
if (out_snd_device != SND_DEVICE_NONE) {
if (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND)
check_usecases_codec_backend(adev, usecase, out_snd_device);
enable_snd_device(adev, out_snd_device);
}
if (in_snd_device != SND_DEVICE_NONE) {
check_and_route_capture_usecases(adev, usecase, in_snd_device);
enable_snd_device(adev, in_snd_device);
}
if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) {
status = platform_switch_voice_call_device_post(adev->platform,
out_snd_device,
in_snd_device);
enable_audio_route_for_voice_usecases(adev, usecase);
}
usecase->in_snd_device = in_snd_device;
usecase->out_snd_device = out_snd_device;
if (usecase->type == PCM_PLAYBACK) {
audio_extn_utils_update_stream_app_type_cfg(adev->platform,
&adev->streams_output_cfg_list,
usecase->stream.out->devices,
usecase->stream.out->flags,
usecase->stream.out->format,
usecase->stream.out->sample_rate,
usecase->stream.out->bit_width,
&usecase->stream.out->app_type_cfg);
}
enable_audio_route(adev, usecase);
/* Applicable only on the targets that has external modem.
* Enable device command should be sent to modem only after
* enabling voice call mixer controls
*/
if (usecase->type == VOICE_CALL)
status = platform_switch_voice_call_usecase_route_post(adev->platform,
out_snd_device,
in_snd_device);
return status;
}
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)
{
struct audio_device *adev = (struct audio_device *)dev;
struct stream_out *out;
int ret = 0;
audio_format_t format;
*stream_out = NULL;
if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
(SND_CARD_STATE_OFFLINE == get_snd_card_state(adev))) {
ALOGE(" sound card is not active rejecting compress output open request");
return -EINVAL;
}
out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
if (devices == AUDIO_DEVICE_NONE)
devices = AUDIO_DEVICE_OUT_SPEAKER;
out->flags = flags;
out->devices = devices;
out->dev = adev;
format = out->format = config->format;
out->sample_rate = config->sample_rate;
out->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO;
out->handle = handle;
out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
/* Init use case and pcm_config */
if ((out->flags == AUDIO_OUTPUT_FLAG_DIRECT) &&
(out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL ||
out->devices & AUDIO_DEVICE_OUT_PROXY)) {
pthread_mutex_lock(&adev->lock);
if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
ret = read_hdmi_channel_masks(out);
if (out->devices & AUDIO_DEVICE_OUT_PROXY)
ret = audio_extn_read_afe_proxy_channel_masks(out);
if (config->sample_rate == 0)
config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
if (config->channel_mask == 0)
config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
out->channel_mask = config->channel_mask;
out->sample_rate = config->sample_rate;
out->usecase = USECASE_AUDIO_PLAYBACK_MULTI_CH;
out->config = pcm_config_hdmi_multi;
out->config.rate = config->sample_rate;
out->config.channels = audio_channel_count_from_out_mask(out->channel_mask);
out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2);
} else if ((out->dev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
(out->flags == (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_VOIP_RX)) &&
(voice_extn_compress_voip_is_config_supported(config))) {
ret = voice_extn_compress_voip_open_output_stream(out);
} else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
if (config->offload_info.version != AUDIO_INFO_INITIALIZER.version ||
config->offload_info.size != AUDIO_INFO_INITIALIZER.size) {
ALOGE("%s: Unsupported Offload information", __func__);
ret = -EINVAL;
goto error_open;
}
if (!is_supported_format(config->offload_info.format) &&
!audio_extn_is_dolby_format(config->offload_info.format)) {
ALOGE("%s: Unsupported audio format", __func__);
ret = -EINVAL;
goto error_open;
}
out->compr_config.codec = (struct snd_codec *)
calloc(1, sizeof(struct snd_codec));
if (!out->compr_config.codec) {
ret = -ENOMEM;
goto error_open;
}
out->usecase = get_offload_usecase(adev);
if (config->offload_info.channel_mask)
out->channel_mask = config->offload_info.channel_mask;
else if (config->channel_mask) {
out->channel_mask = config->channel_mask;
config->offload_info.channel_mask = config->channel_mask;
}
format = out->format = config->offload_info.format;
out->sample_rate = config->offload_info.sample_rate;
out->stream.set_callback = out_set_callback;
out->stream.pause = out_pause;
out->stream.resume = out_resume;
out->stream.drain = out_drain;
out->stream.flush = out_flush;
out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
if (audio_extn_is_dolby_format(config->offload_info.format))
out->compr_config.codec->id =
audio_extn_dolby_get_snd_codec_id(adev, out,
config->offload_info.format);
else
out->compr_config.codec->id =
get_snd_codec_id(config->offload_info.format);
if (audio_is_offload_pcm(config->offload_info.format)) {
out->compr_config.fragment_size =
platform_get_pcm_offload_buffer_size(&config->offload_info);
} else {
out->compr_config.fragment_size =
platform_get_compress_offload_buffer_size(&config->offload_info);
}
out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
out->compr_config.codec->sample_rate =
config->offload_info.sample_rate;
out->compr_config.codec->bit_rate =
config->offload_info.bit_rate;
out->compr_config.codec->ch_in =
audio_channel_count_from_out_mask(config->channel_mask);
out->compr_config.codec->ch_out = out->compr_config.codec->ch_in;
out->bit_width = PCM_OUTPUT_BIT_WIDTH;
if (config->offload_info.format == AUDIO_FORMAT_AAC)
out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
if (config->offload_info.format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD)
out->compr_config.codec->format = SNDRV_PCM_FORMAT_S16_LE;
if(config->offload_info.format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD)
out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE;
if (out->bit_width == 24) {
out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE;
}
if (config->offload_info.format == AUDIO_FORMAT_FLAC)
out->compr_config.codec->options.flac_dec.sample_size = PCM_OUTPUT_BIT_WIDTH;
if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING)
out->non_blocking = 1;
out->send_new_metadata = 1;
out->offload_state = OFFLOAD_STATE_IDLE;
out->playback_started = 0;
create_offload_callback_thread(out);
//Decide if we need to use gapless mode by default
check_and_set_gapless_mode(adev);
} else if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) {
ret = voice_check_and_set_incall_music_usecase(adev, out);
if (ret != 0) {
ALOGE("%s: Incall music delivery usecase cannot be set error:%d",
__func__, ret);
goto error_open;
}
} else if (out->devices == AUDIO_DEVICE_OUT_TELEPHONY_TX) {
if (config->sample_rate == 0)
config->sample_rate = AFE_PROXY_SAMPLING_RATE;
if (config->sample_rate != 48000 && config->sample_rate != 16000 &&
config->sample_rate != 8000) {
config->sample_rate = AFE_PROXY_SAMPLING_RATE;
ret = -EINVAL;
goto error_open;
}
out->sample_rate = config->sample_rate;
out->config.rate = config->sample_rate;
if (config->format == AUDIO_FORMAT_DEFAULT)
config->format = AUDIO_FORMAT_PCM_16_BIT;
if (config->format != AUDIO_FORMAT_PCM_16_BIT) {
config->format = AUDIO_FORMAT_PCM_16_BIT;
ret = -EINVAL;
goto error_open;
}
out->format = config->format;
out->usecase = USECASE_AUDIO_PLAYBACK_AFE_PROXY;
out->config = pcm_config_afe_proxy_playback;
adev->voice_tx_output = out;
} else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
format = AUDIO_FORMAT_PCM_16_BIT;
out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
out->config = pcm_config_low_latency;
out->sample_rate = out->config.rate;
} else {
/* primary path is the default path selected if no other outputs are available/suitable */
format = AUDIO_FORMAT_PCM_16_BIT;
out->usecase = USECASE_AUDIO_PLAYBACK_PRIMARY;
out->config = pcm_config_deep_buffer;
out->sample_rate = out->config.rate;
}
audio_extn_utils_update_stream_app_type_cfg(adev->platform,
&adev->streams_output_cfg_list,
devices, flags, format, out->sample_rate,
out->bit_width, &out->app_type_cfg);
if ((out->usecase == USECASE_AUDIO_PLAYBACK_PRIMARY) ||
(flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
/* Ensure the default output is not selected twice */
if(adev->primary_output == NULL)
adev->primary_output = out;
else {
ALOGE("%s: Primary output is already opened", __func__);
ret = -EEXIST;
goto error_open;
}
}
/* Check if this usecase is already existing */
pthread_mutex_lock(&adev->lock);
if ((get_usecase_from_list(adev, out->usecase) != NULL) &&
(out->usecase != USECASE_COMPRESS_VOIP_CALL)) {
ALOGE("%s: Usecase (%d) is already present", __func__, out->usecase);
pthread_mutex_unlock(&adev->lock);
ret = -EEXIST;
goto error_open;
}
pthread_mutex_unlock(&adev->lock);
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_next_write_timestamp = out_get_next_write_timestamp;
out->stream.get_presentation_position = out_get_presentation_position;
out->standby = 1;
/* out->muted = false; by calloc() */
/* out->written = 0; by calloc() */
pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL);
pthread_mutex_init(&out->pre_lock, (const pthread_mutexattr_t *) NULL);
pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL);
config->format = out->stream.common.get_format(&out->stream.common);
config->channel_mask = out->stream.common.get_channels(&out->stream.common);
config->sample_rate = out->stream.common.get_sample_rate(&out->stream.common);
*stream_out = &out->stream;
ALOGV("%s: exit", __func__);
return 0;
error_open:
free(out);
*stream_out = NULL;
return ret;
}
static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
size_t bytes)
{
struct stream_out *out = (struct stream_out *)stream;
struct audio_device *adev = out->dev;
int snd_scard_state = get_snd_card_state(adev);
ssize_t ret = 0;
lock_output_stream(out);
if (SND_CARD_STATE_OFFLINE == snd_scard_state) {
// increase written size during SSR to avoid mismatch
// with the written frames count in AF
if (!is_offload_usecase(out->usecase))
out->written += bytes / (out->config.channels * sizeof(short));
if (out->pcm) {
ALOGD(" %s: sound card is not active/SSR state", __func__);
ret= -EIO;
goto exit;
} else if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
//during SSR for compress usecase we should return er