/audio/audio_hw.c
C | 3078 lines | 2405 code | 461 blank | 212 comment | 472 complexity | 70f0ce432fdbda3eb3c8317ab9c347f5 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- /*
- * Copyright (C) 2011 The Android Open Source Project
- * Copyright (C) 2012 Wolfson Microelectronics plc
- * Copyright (C) 2012 The CyanogenMod Project
- * Daniel Hillenbrand <codeworkx@cyanogenmod.com>
- * Guillaume "XpLoDWilD" Lesniak <xplodgui@gmail.com>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #define LOG_TAG "audio_hw_primary"
- #define LOG_NDEBUG 0
- #include <errno.h>
- #include <pthread.h>
- #include <stdint.h>
- #include <sys/time.h>
- #include <stdlib.h>
- #include <expat.h>
- #include <cutils/log.h>
- #include <cutils/str_parms.h>
- #include <cutils/properties.h>
- #include <hardware/hardware.h>
- #include <system/audio.h>
- #include <hardware/audio.h>
- #include <tinyalsa/asoundlib.h>
- #include <audio_utils/resampler.h>
- #include <audio_utils/echo_reference.h>
- #include <hardware/audio_effect.h>
- #include <audio_effects/effect_aec.h>
- #include "audio_hw.h"
- #include "ril_interface.h"
- struct pcm_config pcm_config_mm = {
- .channels = 2,
- .rate = MM_FULL_POWER_SAMPLING_RATE,
- .period_size = DEEP_BUFFER_LONG_PERIOD_SIZE,
- .period_count = PLAYBACK_DEEP_BUFFER_LONG_PERIOD_COUNT,
- .format = PCM_FORMAT_S16_LE,
- };
- struct pcm_config pcm_config_tones = {
- .channels = 2,
- .rate = MM_FULL_POWER_SAMPLING_RATE,
- .period_size = SHORT_PERIOD_SIZE,
- .period_count = PLAYBACK_SHORT_PERIOD_COUNT,
- .format = PCM_FORMAT_S16_LE,
- .start_threshold = 0,
- .avail_min = 0,
- };
- struct pcm_config pcm_config_capture = {
- .channels = 2,
- .rate = DEFAULT_IN_SAMPLING_RATE,
- .period_size = CAPTURE_PERIOD_SIZE,
- .period_count = CAPTURE_PERIOD_COUNT,
- .format = PCM_FORMAT_S16_LE,
- };
- struct pcm_config pcm_config_vx = {
- .channels = 2,
- .rate = VX_WB_SAMPLING_RATE,
- .period_size = 160,
- .period_count = 2,
- .format = PCM_FORMAT_S16_LE,
- };
- #define MIN(x, y) ((x) > (y) ? (y) : (x))
- struct m0_audio_device {
- struct audio_hw_device hw_device;
- pthread_mutex_t lock; /* see note below on mutex acquisition order */
- struct m0_dev_cfg *dev_cfgs;
- int num_dev_cfgs;
- struct mixer *mixer;
- audio_mode_t mode;
- int active_out_device;
- int out_device;
- int active_in_device;
- int in_device;
- struct pcm *pcm_modem_dl;
- struct pcm *pcm_modem_ul;
- struct pcm *pcm_bt_dl;
- struct pcm *pcm_bt_ul;
- int in_call;
- float voice_volume;
- struct m0_stream_in *active_input;
- struct m0_stream_out *outputs[OUTPUT_TOTAL];
- bool mic_mute;
- struct echo_reference_itfe *echo_reference;
- bool bluetooth_nrec;
- int wb_amr;
- bool screen_off;
- /* RIL */
- struct ril_handle ril;
- };
- struct m0_stream_out {
- struct audio_stream_out stream;
- pthread_mutex_t lock; /* see note below on mutex acquisition order */
- struct pcm_config config[PCM_TOTAL];
- struct pcm *pcm[PCM_TOTAL];
- struct resampler_itfe *resampler;
- char *buffer;
- size_t buffer_frames;
- int standby;
- struct echo_reference_itfe *echo_reference;
- int write_threshold;
- bool use_long_periods;
- audio_channel_mask_t channel_mask;
- audio_channel_mask_t sup_channel_masks[3];
- struct m0_audio_device *dev;
- };
- #define MAX_PREPROCESSORS 3 /* maximum one AGC + one NS + one AEC per input stream */
- struct effect_info_s {
- effect_handle_t effect_itfe;
- size_t num_channel_configs;
- channel_config_t* channel_configs;
- };
- #define NUM_IN_AUX_CNL_CONFIGS 2
- channel_config_t in_aux_cnl_configs[NUM_IN_AUX_CNL_CONFIGS] = {
- { AUDIO_CHANNEL_IN_FRONT , AUDIO_CHANNEL_IN_BACK},
- { AUDIO_CHANNEL_IN_STEREO , AUDIO_CHANNEL_IN_RIGHT}
- };
- struct m0_stream_in {
- struct audio_stream_in stream;
- pthread_mutex_t lock; /* see note below on mutex acquisition order */
- struct pcm_config config;
- struct pcm *pcm;
- int device;
- struct resampler_itfe *resampler;
- struct resampler_buffer_provider buf_provider;
- unsigned int requested_rate;
- int standby;
- int source;
- struct echo_reference_itfe *echo_reference;
- bool need_echo_reference;
- int16_t *read_buf;
- size_t read_buf_size;
- size_t read_buf_frames;
- int16_t *proc_buf_in;
- int16_t *proc_buf_out;
- size_t proc_buf_size;
- size_t proc_buf_frames;
- int16_t *ref_buf;
- size_t ref_buf_size;
- size_t ref_buf_frames;
- int read_status;
- int num_preprocessors;
- struct effect_info_s preprocessors[MAX_PREPROCESSORS];
- bool aux_channels_changed;
- uint32_t main_channels;
- uint32_t aux_channels;
- struct m0_audio_device *dev;
- };
- struct m0_dev_cfg {
- int mask;
- struct route_setting *on;
- unsigned int on_len;
- struct route_setting *off;
- unsigned int off_len;
- };
- /**
- * NOTE: when multiple mutexes have to be acquired, always respect the following order:
- * hw device > in stream > out stream
- */
- static void select_output_device(struct m0_audio_device *adev);
- static void select_input_device(struct m0_audio_device *adev);
- static int adev_set_voice_volume(struct audio_hw_device *dev, float volume);
- static int do_input_standby(struct m0_stream_in *in);
- static int do_output_standby(struct m0_stream_out *out);
- static void in_update_aux_channels(struct m0_stream_in *in, effect_handle_t effect);
- /* The enable flag when 0 makes the assumption that enums are disabled by
- * "Off" and integers/booleans by 0 */
- static int set_bigroute_by_array(struct mixer *mixer, struct route_setting *route,
- int enable)
- {
- struct mixer_ctl *ctl;
- unsigned int i, j, ret;
- /* Go through the route array and set each value */
- i = 0;
- while (route[i].ctl_name) {
- ctl = mixer_get_ctl_by_name(mixer, route[i].ctl_name);
- if (!ctl) {
- ALOGE("Unknown control '%s'\n", route[i].ctl_name);
- return -EINVAL;
- }
- if (route[i].strval) {
- if (enable) {
- ret = mixer_ctl_set_enum_by_string(ctl, route[i].strval);
- if (ret != 0) {
- ALOGE("Failed to set '%s' to '%s'\n", route[i].ctl_name, route[i].strval);
- } else {
- ALOGV("Set '%s' to '%s'\n", route[i].ctl_name, route[i].strval);
- }
- } else {
- ret = mixer_ctl_set_enum_by_string(ctl, "Off");
- if (ret != 0) {
- ALOGE("Failed to set '%s' to '%s'\n", route[i].ctl_name, route[i].strval);
- } else {
- ALOGV("Set '%s' to '%s'\n", route[i].ctl_name, "Off");
- }
- }
- } else {
- /* This ensures multiple (i.e. stereo) values are set jointly */
- for (j = 0; j < mixer_ctl_get_num_values(ctl); j++) {
- if (enable) {
- ret = mixer_ctl_set_value(ctl, j, route[i].intval);
- if (ret != 0) {
- ALOGE("Failed to set '%s' to '%d'\n", route[i].ctl_name, route[i].intval);
- } else {
- ALOGV("Set '%s' to '%d'\n", route[i].ctl_name, route[i].intval);
- }
- } else {
- ret = mixer_ctl_set_value(ctl, j, 0);
- if (ret != 0) {
- ALOGE("Failed to set '%s' to '%d'\n", route[i].ctl_name, route[i].intval);
- } else {
- ALOGV("Set '%s' to '%d'\n", route[i].ctl_name, 0);
- }
- }
- }
- }
- i++;
- }
- return 0;
- }
- /* The enable flag when 0 makes the assumption that enums are disabled by
- * "Off" and integers/booleans by 0 */
- static int set_route_by_array(struct mixer *mixer, struct route_setting *route,
- unsigned int len)
- {
- struct mixer_ctl *ctl;
- unsigned int i, j, ret;
- /* Go through the route array and set each value */
- for (i = 0; i < len; i++) {
- ctl = mixer_get_ctl_by_name(mixer, route[i].ctl_name);
- if (!ctl) {
- ALOGE("Unknown control '%s'\n", route[i].ctl_name);
- return -EINVAL;
- }
- if (route[i].strval) {
- ret = mixer_ctl_set_enum_by_string(ctl, route[i].strval);
- if (ret != 0) {
- ALOGE("Failed to set '%s' to '%s'\n",
- route[i].ctl_name, route[i].strval);
- } else {
- ALOGV("Set '%s' to '%s'\n",
- route[i].ctl_name, route[i].strval);
- }
- } else {
- /* This ensures multiple (i.e. stereo) values are set jointly */
- for (j = 0; j < mixer_ctl_get_num_values(ctl); j++) {
- ret = mixer_ctl_set_value(ctl, j, route[i].intval);
- if (ret != 0) {
- ALOGE("Failed to set '%s'.%d to %d\n",
- route[i].ctl_name, j, route[i].intval);
- } else {
- ALOGV("Set '%s'.%d to %d\n",
- route[i].ctl_name, j, route[i].intval);
- }
- }
- }
- }
- return 0;
- }
- /* Must be called with lock */
- void select_devices(struct m0_audio_device *adev)
- {
- int i;
- if (adev->active_out_device == adev->out_device && adev->active_in_device == adev->in_device)
- return;
- ALOGV("Changing output device %x => %x\n", adev->active_out_device, adev->out_device);
- ALOGV("Changing input device %x => %x\n", adev->active_in_device, adev->in_device);
- /* Turn on new devices first so we don't glitch due to powerdown... */
- for (i = 0; i < adev->num_dev_cfgs; i++)
- if ((adev->out_device & adev->dev_cfgs[i].mask) &&
- !(adev->active_out_device & adev->dev_cfgs[i].mask) &&
- !(adev->dev_cfgs[i].mask & AUDIO_DEVICE_BIT_IN))
- set_route_by_array(adev->mixer, adev->dev_cfgs[i].on,
- adev->dev_cfgs[i].on_len);
- for (i = 0; i < adev->num_dev_cfgs; i++)
- if ((adev->in_device & adev->dev_cfgs[i].mask) &&
- !(adev->active_in_device & adev->dev_cfgs[i].mask) &&
- (adev->dev_cfgs[i].mask & AUDIO_DEVICE_BIT_IN))
- set_route_by_array(adev->mixer, adev->dev_cfgs[i].on,
- adev->dev_cfgs[i].on_len);
- /* ...then disable old ones. */
- for (i = 0; i < adev->num_dev_cfgs; i++)
- if (!(adev->out_device & adev->dev_cfgs[i].mask) &&
- (adev->active_out_device & adev->dev_cfgs[i].mask) &&
- !(adev->dev_cfgs[i].mask & AUDIO_DEVICE_BIT_IN))
- set_route_by_array(adev->mixer, adev->dev_cfgs[i].off,
- adev->dev_cfgs[i].off_len);
- for (i = 0; i < adev->num_dev_cfgs; i++)
- if (!(adev->in_device & adev->dev_cfgs[i].mask) &&
- (adev->active_in_device & adev->dev_cfgs[i].mask) &&
- (adev->dev_cfgs[i].mask & AUDIO_DEVICE_BIT_IN))
- set_route_by_array(adev->mixer, adev->dev_cfgs[i].off,
- adev->dev_cfgs[i].off_len);
- adev->active_out_device = adev->out_device;
- adev->active_in_device = adev->in_device;
- }
- static int start_call(struct m0_audio_device *adev)
- {
- ALOGV("Opening modem PCMs");
- int bt_on;
- bt_on = adev->out_device & AUDIO_DEVICE_OUT_ALL_SCO;
- if (bt_on) {
- /* use amr-nb for bluetooth */
- pcm_config_vx.rate = VX_NB_SAMPLING_RATE;
- } else {
- pcm_config_vx.rate = adev->wb_amr ? VX_WB_SAMPLING_RATE : VX_NB_SAMPLING_RATE;
- }
- /* Open modem PCM channels */
- if (adev->pcm_modem_dl == NULL) {
- ALOGD("Opening PCM modem DL stream");
- adev->pcm_modem_dl = pcm_open(CARD_DEFAULT, PORT_MODEM, PCM_OUT, &pcm_config_vx);
- if (!pcm_is_ready(adev->pcm_modem_dl)) {
- ALOGE("cannot open PCM modem DL stream: %s", pcm_get_error(adev->pcm_modem_dl));
- goto err_open_dl;
- }
- }
- if (adev->pcm_modem_ul == NULL) {
- ALOGD("Opening PCM modem UL stream");
- adev->pcm_modem_ul = pcm_open(CARD_DEFAULT, PORT_MODEM, PCM_IN, &pcm_config_vx);
- if (!pcm_is_ready(adev->pcm_modem_ul)) {
- ALOGE("cannot open PCM modem UL stream: %s", pcm_get_error(adev->pcm_modem_ul));
- goto err_open_ul;
- }
- }
- ALOGD("Starting PCM modem streams");
- pcm_start(adev->pcm_modem_dl);
- pcm_start(adev->pcm_modem_ul);
- /* Open bluetooth PCM channels */
- if (bt_on) {
- ALOGV("Opening bluetooth PCMs");
- if (adev->pcm_bt_dl == NULL) {
- ALOGD("Opening PCM bluetooth DL stream");
- adev->pcm_bt_dl = pcm_open(CARD_DEFAULT, PORT_BT, PCM_OUT, &pcm_config_vx);
- if (!pcm_is_ready(adev->pcm_bt_dl)) {
- ALOGE("cannot open PCM bluetooth DL stream: %s", pcm_get_error(adev->pcm_bt_dl));
- goto err_open_dl;
- }
- }
- if (adev->pcm_bt_ul == NULL) {
- ALOGD("Opening PCM bluetooth UL stream");
- adev->pcm_bt_ul = pcm_open(CARD_DEFAULT, PORT_BT, PCM_IN, &pcm_config_vx);
- if (!pcm_is_ready(adev->pcm_bt_ul)) {
- ALOGE("cannot open PCM bluetooth UL stream: %s", pcm_get_error(adev->pcm_bt_ul));
- goto err_open_ul;
- }
- }
- ALOGD("Starting PCM bluetooth streams");
- pcm_start(adev->pcm_bt_dl);
- pcm_start(adev->pcm_bt_ul);
- }
- return 0;
- err_open_ul:
- pcm_close(adev->pcm_modem_ul);
- adev->pcm_modem_ul = NULL;
- pcm_close(adev->pcm_bt_ul);
- adev->pcm_bt_ul = NULL;
- err_open_dl:
- pcm_close(adev->pcm_modem_dl);
- adev->pcm_modem_dl = NULL;
- pcm_close(adev->pcm_bt_dl);
- adev->pcm_bt_dl = NULL;
- return -ENOMEM;
- }
- static void end_call(struct m0_audio_device *adev)
- {
- int bt_on;
- bt_on = adev->out_device & AUDIO_DEVICE_OUT_ALL_SCO;
- if (adev->pcm_modem_dl != NULL) {
- ALOGD("Stopping modem DL PCM");
- pcm_stop(adev->pcm_modem_dl);
- ALOGV("Closing modem DL PCM");
- pcm_close(adev->pcm_modem_dl);
- }
- if (adev->pcm_modem_ul != NULL) {
- ALOGD("Stopping modem UL PCM");
- pcm_stop(adev->pcm_modem_ul);
- ALOGV("Closing modem UL PCM");
- pcm_close(adev->pcm_modem_ul);
- }
- adev->pcm_modem_dl = NULL;
- adev->pcm_modem_ul = NULL;
- if (bt_on) {
- if (adev->pcm_bt_dl != NULL) {
- ALOGD("Stopping bluetooth DL PCM");
- pcm_stop(adev->pcm_bt_dl);
- ALOGV("Closing bluetooth DL PCM");
- pcm_close(adev->pcm_bt_dl);
- }
- if (adev->pcm_bt_ul != NULL) {
- ALOGD("Stopping bluetooth UL PCM");
- pcm_stop(adev->pcm_bt_ul);
- ALOGV("Closing bluetooth UL PCM");
- pcm_close(adev->pcm_bt_ul);
- }
- }
- adev->pcm_bt_dl = NULL;
- adev->pcm_bt_ul = NULL;
- }
- static void set_eq_filter(struct m0_audio_device *adev)
- {
- }
- void audio_set_wb_amr_callback(void *data, int enable)
- {
- struct m0_audio_device *adev = (struct m0_audio_device *)data;
- pthread_mutex_lock(&adev->lock);
- if (adev->wb_amr != enable) {
- adev->wb_amr = enable;
- /* reopen the modem PCMs at the new rate */
- if (adev->in_call) {
- end_call(adev);
- select_output_device(adev);
- start_call(adev);
- }
- }
- pthread_mutex_unlock(&adev->lock);
- }
- static void set_incall_device(struct m0_audio_device *adev)
- {
- int device_type;
- switch(adev->out_device) {
- case AUDIO_DEVICE_OUT_EARPIECE:
- device_type = SOUND_AUDIO_PATH_HANDSET;
- break;
- case AUDIO_DEVICE_OUT_SPEAKER:
- case AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET:
- case AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET:
- case AUDIO_DEVICE_OUT_AUX_DIGITAL:
- device_type = SOUND_AUDIO_PATH_SPEAKER;
- break;
- case AUDIO_DEVICE_OUT_WIRED_HEADSET:
- device_type = SOUND_AUDIO_PATH_HEADSET;
- break;
- case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
- device_type = SOUND_AUDIO_PATH_HEADPHONE;
- break;
- case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
- case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
- case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
- if (adev->bluetooth_nrec) {
- device_type = SOUND_AUDIO_PATH_BLUETOOTH;
- } else {
- device_type = SOUND_AUDIO_PATH_BLUETOOTH_NO_NR;
- }
- break;
- default:
- device_type = SOUND_AUDIO_PATH_HANDSET;
- break;
- }
- /* if output device isn't supported, open modem side to handset by default */
- ALOGE("%s: ril_set_call_audio_path(%d)", __func__, device_type);
- ril_set_call_audio_path(&adev->ril, device_type);
- }
- static void force_all_standby(struct m0_audio_device *adev)
- {
- struct m0_stream_in *in;
- struct m0_stream_out *out;
- /* only needed for low latency output streams as other streams are not used
- * for voice use cases */
- if (adev->outputs[OUTPUT_LOW_LATENCY] != NULL &&
- !adev->outputs[OUTPUT_LOW_LATENCY]->standby) {
- out = adev->outputs[OUTPUT_LOW_LATENCY];
- pthread_mutex_lock(&out->lock);
- do_output_standby(out);
- pthread_mutex_unlock(&out->lock);
- }
- if (adev->active_input) {
- in = adev->active_input;
- pthread_mutex_lock(&in->lock);
- do_input_standby(in);
- pthread_mutex_unlock(&in->lock);
- }
- }
- static void select_mode(struct m0_audio_device *adev)
- {
- if (adev->mode == AUDIO_MODE_IN_CALL) {
- ALOGE("Entering IN_CALL state, in_call=%d", adev->in_call);
- if (!adev->in_call) {
- force_all_standby(adev);
- /* force earpiece route for in call state if speaker is the
- only currently selected route. This prevents having to tear
- down the modem PCMs to change route from speaker to earpiece
- after the ringtone is played, but doesn't cause a route
- change if a headset or bt device is already connected. If
- speaker is not the only thing active, just remove it from
- the route. We'll assume it'll never be used initally during
- a call. This works because we're sure that the audio policy
- manager will update the output device after the audio mode
- change, even if the device selection did not change. */
- if (adev->out_device == AUDIO_DEVICE_OUT_SPEAKER) {
- adev->out_device = AUDIO_DEVICE_OUT_EARPIECE;
- adev->in_device = AUDIO_DEVICE_IN_BUILTIN_MIC & ~AUDIO_DEVICE_BIT_IN;
- } else
- adev->out_device &= ~AUDIO_DEVICE_OUT_SPEAKER;
- select_output_device(adev);
- start_call(adev);
- ril_set_call_clock_sync(&adev->ril, SOUND_CLOCK_START);
- adev_set_voice_volume(&adev->hw_device, adev->voice_volume);
- adev->in_call = 1;
- }
- } else {
- ALOGE("Leaving IN_CALL state, in_call=%d, mode=%d",
- adev->in_call, adev->mode);
- if (adev->in_call) {
- adev->in_call = 0;
- ril_set_call_clock_sync(&adev->ril, SOUND_CLOCK_STOP);
- end_call(adev);
- force_all_standby(adev);
- ALOGD("%s: set voicecall route: voicecall_default_disable", __func__);
- set_bigroute_by_array(adev->mixer, voicecall_default_disable, 1);
- ALOGD("%s: set voicecall route: default_input_disable", __func__);
- set_bigroute_by_array(adev->mixer, default_input_disable, 1);
- ALOGD("%s: set voicecall route: headset_input_disable", __func__);
- set_bigroute_by_array(adev->mixer, headset_input_disable, 1);
- ALOGD("%s: set voicecall route: bt_disable", __func__);
- set_bigroute_by_array(adev->mixer, bt_disable, 1);
- select_output_device(adev);
- //Force Input Standby
- adev->in_device = AUDIO_DEVICE_NONE;
- select_input_device(adev);
- }
- }
- }
- static void select_output_device(struct m0_audio_device *adev)
- {
- int headset_on;
- int headphone_on;
- int speaker_on;
- int earpiece_on;
- int bt_on;
- unsigned int channel;
- headset_on = adev->out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET;
- headphone_on = adev->out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
- speaker_on = adev->out_device & AUDIO_DEVICE_OUT_SPEAKER;
- earpiece_on = adev->out_device & AUDIO_DEVICE_OUT_EARPIECE;
- bt_on = adev->out_device & AUDIO_DEVICE_OUT_ALL_SCO;
- switch(adev->out_device) {
- case AUDIO_DEVICE_OUT_SPEAKER:
- ALOGD("%s: AUDIO_DEVICE_OUT_SPEAKER", __func__);
- break;
- case AUDIO_DEVICE_OUT_WIRED_HEADSET:
- ALOGD("%s: AUDIO_DEVICE_OUT_WIRED_HEADSET", __func__);
- break;
- case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
- ALOGD("%s: AUDIO_DEVICE_OUT_WIRED_HEADPHONE", __func__);
- break;
- case AUDIO_DEVICE_OUT_EARPIECE:
- ALOGD("%s: AUDIO_DEVICE_OUT_EARPIECE", __func__);
- break;
- case AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET:
- ALOGD("%s: AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET", __func__);
- break;
- case AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET:
- ALOGD("%s: AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET", __func__);
- break;
- case AUDIO_DEVICE_OUT_ALL_SCO:
- ALOGD("%s: AUDIO_DEVICE_OUT_ALL_SCO", __func__);
- break;
- case AUDIO_DEVICE_OUT_USB_ACCESSORY:
- ALOGD("%s: AUDIO_DEVICE_OUT_USB_ACCESSORY", __func__);
- break;
- case AUDIO_DEVICE_OUT_USB_DEVICE:
- ALOGD("%s: AUDIO_DEVICE_OUT_USB_DEVICE", __func__);
- break;
- default:
- ALOGD("%s: AUDIO_DEVICE_OUT_ALL", __func__);
- break;
- }
- select_devices(adev);
- set_eq_filter(adev);
- if (adev->mode == AUDIO_MODE_IN_CALL) {
- if (headset_on || headphone_on || speaker_on || earpiece_on) {
- ALOGD("%s: set voicecall route: voicecall_default", __func__);
- set_bigroute_by_array(adev->mixer, voicecall_default, 1);
- } else {
- ALOGD("%s: set voicecall route: voicecall_default_disable", __func__);
- set_bigroute_by_array(adev->mixer, voicecall_default_disable, 1);
- }
- if (speaker_on || earpiece_on || headphone_on) {
- ALOGD("%s: set voicecall route: default_input", __func__);
- set_bigroute_by_array(adev->mixer, default_input, 1);
- } else {
- ALOGD("%s: set voicecall route: default_input_disable", __func__);
- set_bigroute_by_array(adev->mixer, default_input_disable, 1);
- }
- if (headset_on) {
- ALOGD("%s: set voicecall route: headset_input", __func__);
- set_bigroute_by_array(adev->mixer, headset_input, 1);
- } else {
- ALOGD("%s: set voicecall route: headset_input_disable", __func__);
- set_bigroute_by_array(adev->mixer, headset_input_disable, 1);
- }
- if (bt_on) {
- ALOGD("%s: set voicecall route: bt_input", __func__);
- set_bigroute_by_array(adev->mixer, bt_input, 1);
- ALOGD("%s: set voicecall route: bt_output", __func__);
- set_bigroute_by_array(adev->mixer, bt_output, 1);
- } else {
- ALOGD("%s: set voicecall route: bt_disable", __func__);
- set_bigroute_by_array(adev->mixer, bt_disable, 1);
- }
- set_incall_device(adev);
- }
- }
- static void select_input_device(struct m0_audio_device *adev)
- {
- int input_device = AUDIO_DEVICE_BIT_IN | adev->in_device;
- switch(input_device) {
- case AUDIO_DEVICE_IN_BUILTIN_MIC:
- ALOGD("%s: AUDIO_DEVICE_IN_BUILTIN_MIC", __func__);
- break;
- case AUDIO_DEVICE_IN_BACK_MIC:
- // Force use both mics for video recording
- adev->in_device = (AUDIO_DEVICE_IN_BACK_MIC | AUDIO_DEVICE_IN_BUILTIN_MIC) & ~AUDIO_DEVICE_BIT_IN;
- ALOGD("%s: AUDIO_DEVICE_IN_BACK_MIC and AUDIO_DEVICE_IN_BUILTIN_MIC", __func__);
- break;
- case AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET:
- ALOGD("%s: AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET", __func__);
- break;
- case AUDIO_DEVICE_IN_WIRED_HEADSET:
- ALOGD("%s: AUDIO_DEVICE_IN_WIRED_HEADSET", __func__);
- break;
- default:
- break;
- }
- select_devices(adev);
- }
- /* must be called with hw device and output stream mutexes locked */
- static int start_output_stream_low_latency(struct m0_stream_out *out)
- {
- struct m0_audio_device *adev = out->dev;
- unsigned int flags = PCM_OUT;
- int i;
- bool success = true;
- if (adev->mode != AUDIO_MODE_IN_CALL) {
- select_output_device(adev);
- }
- /* default to low power: will be corrected in out_write if necessary before first write to
- * tinyalsa.
- */
- if (adev->out_device & ~(AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET | AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
- /* Something not a dock in use */
- out->config[PCM_NORMAL] = pcm_config_tones;
- out->config[PCM_NORMAL].rate = MM_FULL_POWER_SAMPLING_RATE;
- out->pcm[PCM_NORMAL] = pcm_open(CARD_DEFAULT, PORT_PLAYBACK,
- flags, &out->config[PCM_NORMAL]);
- }
- if (adev->out_device & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
- /* SPDIF output in use */
- out->config[PCM_SPDIF] = pcm_config_tones;
- out->config[PCM_SPDIF].rate = MM_FULL_POWER_SAMPLING_RATE;
- out->pcm[PCM_SPDIF] = pcm_open(CARD_DEFAULT, PORT_PLAYBACK,
- flags, &out->config[PCM_SPDIF]);
- }
- /* Close any PCMs that could not be opened properly and return an error */
- for (i = 0; i < PCM_TOTAL; i++) {
- if (out->pcm[i] && !pcm_is_ready(out->pcm[i])) {
- ALOGE("%s: cannot open pcm_out driver %d: %s", __func__ , i, pcm_get_error(out->pcm[i]));
- pcm_close(out->pcm[i]);
- out->pcm[i] = NULL;
- success = false;
- }
- }
- if (success) {
- out->buffer_frames = pcm_config_tones.period_size * 2;
- if (out->buffer == NULL)
- out->buffer = malloc(out->buffer_frames * audio_stream_frame_size(&out->stream.common));
- if (adev->echo_reference != NULL)
- out->echo_reference = adev->echo_reference;
- out->resampler->reset(out->resampler);
- return 0;
- }
- return -ENOMEM;
- }
- /* must be called with hw device and output stream mutexes locked */
- static int start_output_stream_deep_buffer(struct m0_stream_out *out)
- {
- struct m0_audio_device *adev = out->dev;
- if (adev->mode != AUDIO_MODE_IN_CALL) {
- select_output_device(adev);
- }
- out->write_threshold = PLAYBACK_DEEP_BUFFER_LONG_PERIOD_COUNT * DEEP_BUFFER_LONG_PERIOD_SIZE;
- out->use_long_periods = true;
- out->config[PCM_NORMAL] = pcm_config_mm;
- out->config[PCM_NORMAL].rate = MM_FULL_POWER_SAMPLING_RATE;
- out->pcm[PCM_NORMAL] = pcm_open(CARD_DEFAULT, PORT_PLAYBACK,
- PCM_OUT | PCM_MMAP | PCM_NOIRQ, &out->config[PCM_NORMAL]);
- if (out->pcm[PCM_NORMAL] && !pcm_is_ready(out->pcm[PCM_NORMAL])) {
- ALOGE("%s: cannot open pcm_out driver: %s", __func__, pcm_get_error(out->pcm[PCM_NORMAL]));
- pcm_close(out->pcm[PCM_NORMAL]);
- out->pcm[PCM_NORMAL] = NULL;
- return -ENOMEM;
- }
- out->buffer_frames = DEEP_BUFFER_SHORT_PERIOD_SIZE * 2;
- if (out->buffer == NULL)
- out->buffer = malloc(PLAYBACK_DEEP_BUFFER_LONG_PERIOD_COUNT * DEEP_BUFFER_LONG_PERIOD_SIZE);
- return 0;
- }
- static int check_input_parameters(uint32_t sample_rate, audio_format_t format, int channel_count)
- {
- if (format != AUDIO_FORMAT_PCM_16_BIT)
- return -EINVAL;
- if ((channel_count < 1) || (channel_count > 2))
- return -EINVAL;
- switch(sample_rate) {
- case 8000:
- case 11025:
- case 16000:
- case 22050:
- case 24000:
- case 32000:
- case 44100:
- case 48000:
- break;
- default:
- return -EINVAL;
- }
- return 0;
- }
- static size_t get_input_buffer_size(uint32_t sample_rate, audio_format_t format, int channel_count)
- {
- size_t size;
- size_t device_rate;
- if (check_input_parameters(sample_rate, format, channel_count) != 0)
- return 0;
- /* take resampling into account and return the closest majoring
- multiple of 16 frames, as audioflinger expects audio buffers to
- be a multiple of 16 frames */
- size = (pcm_config_capture.period_size * sample_rate) / pcm_config_capture.rate;
- size = ((size + 15) / 16) * 16;
- return size * channel_count * sizeof(short);
- }
- static void add_echo_reference(struct m0_stream_out *out,
- struct echo_reference_itfe *reference)
- {
- pthread_mutex_lock(&out->lock);
- out->echo_reference = reference;
- pthread_mutex_unlock(&out->lock);
- }
- static void remove_echo_reference(struct m0_stream_out *out,
- struct echo_reference_itfe *reference)
- {
- pthread_mutex_lock(&out->lock);
- if (out->echo_reference == reference) {
- /* stop writing to echo reference */
- reference->write(reference, NULL);
- out->echo_reference = NULL;
- }
- pthread_mutex_unlock(&out->lock);
- }
- static void put_echo_reference(struct m0_audio_device *adev,
- struct echo_reference_itfe *reference)
- {
- if (adev->echo_reference != NULL &&
- reference == adev->echo_reference) {
- /* echo reference is taken from the low latency output stream used
- * for voice use cases */
- if (adev->outputs[OUTPUT_LOW_LATENCY] != NULL &&
- !adev->outputs[OUTPUT_LOW_LATENCY]->standby)
- remove_echo_reference(adev->outputs[OUTPUT_LOW_LATENCY], reference);
- release_echo_reference(reference);
- adev->echo_reference = NULL;
- }
- }
- static struct echo_reference_itfe *get_echo_reference(struct m0_audio_device *adev,
- audio_format_t format,
- uint32_t channel_count,
- uint32_t sampling_rate)
- {
- put_echo_reference(adev, adev->echo_reference);
- /* echo reference is taken from the low latency output stream used
- * for voice use cases */
- if (adev->outputs[OUTPUT_LOW_LATENCY] != NULL &&
- !adev->outputs[OUTPUT_LOW_LATENCY]->standby) {
- struct audio_stream *stream =
- &adev->outputs[OUTPUT_LOW_LATENCY]->stream.common;
- uint32_t wr_channel_count = popcount(stream->get_channels(stream));
- uint32_t wr_sampling_rate = stream->get_sample_rate(stream);
- int status = create_echo_reference(AUDIO_FORMAT_PCM_16_BIT,
- channel_count,
- sampling_rate,
- AUDIO_FORMAT_PCM_16_BIT,
- wr_channel_count,
- wr_sampling_rate,
- &adev->echo_reference);
- if (status == 0)
- add_echo_reference(adev->outputs[OUTPUT_LOW_LATENCY],
- adev->echo_reference);
- }
- return adev->echo_reference;
- }
- static int get_playback_delay(struct m0_stream_out *out,
- size_t frames,
- struct echo_reference_buffer *buffer)
- {
- size_t kernel_frames;
- int status;
- int primary_pcm = 0;
- /* Find the first active PCM to act as primary */
- while ((primary_pcm < PCM_TOTAL) && !out->pcm[primary_pcm])
- primary_pcm++;
- status = pcm_get_htimestamp(out->pcm[primary_pcm], &kernel_frames, &buffer->time_stamp);
- if (status < 0) {
- buffer->time_stamp.tv_sec = 0;
- buffer->time_stamp.tv_nsec = 0;
- buffer->delay_ns = 0;
- ALOGV("%s: pcm_get_htimestamp error,"
- "setting playbackTimestamp to 0", __func__);
- return status;
- }
- kernel_frames = pcm_get_buffer_size(out->pcm[primary_pcm]) - kernel_frames;
- /* adjust render time stamp with delay added by current driver buffer.
- * Add the duration of current frame as we want the render time of the last
- * sample being written. */
- buffer->delay_ns = (long)(((int64_t)(kernel_frames + frames)* 1000000000)/
- MM_FULL_POWER_SAMPLING_RATE);
- return 0;
- }
- static uint32_t out_get_sample_rate(const struct audio_stream *stream)
- {
- return DEFAULT_OUT_SAMPLING_RATE;
- }
- static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
- {
- return 0;
- }
- static size_t out_get_buffer_size_low_latency(const struct audio_stream *stream)
- {
- struct m0_stream_out *out = (struct m0_stream_out *)stream;
- /* take resampling into account and return the closest majoring
- multiple of 16 frames, as audioflinger expects audio buffers to
- be a multiple of 16 frames. Note: we use the default rate here
- from pcm_config_tones.rate. */
- size_t size = (SHORT_PERIOD_SIZE * DEFAULT_OUT_SAMPLING_RATE) / pcm_config_tones.rate;
- size = ((size + 15) / 16) * 16;
- return size * audio_stream_frame_size((struct audio_stream *)stream);
- }
- static size_t out_get_buffer_size_deep_buffer(const struct audio_stream *stream)
- {
- struct m0_stream_out *out = (struct m0_stream_out *)stream;
- /* take resampling into account and return the closest majoring
- multiple of 16 frames, as audioflinger expects audio buffers to
- be a multiple of 16 frames. Note: we use the default rate here
- from pcm_config_mm.rate. */
- size_t size = (DEEP_BUFFER_SHORT_PERIOD_SIZE * DEFAULT_OUT_SAMPLING_RATE) /
- pcm_config_mm.rate;
- size = ((size + 15) / 16) * 16;
- return size * audio_stream_frame_size((struct audio_stream *)stream);
- }
- static audio_channel_mask_t out_get_channels(const struct audio_stream *stream)
- {
- struct m0_stream_out *out = (struct m0_stream_out *)stream;
- return out->channel_mask;
- }
- static audio_format_t out_get_format(const struct audio_stream *stream)
- {
- return AUDIO_FORMAT_PCM_16_BIT;
- }
- static int out_set_format(struct audio_stream *stream, audio_format_t format)
- {
- return 0;
- }
- /* must be called with hw device and output stream mutexes locked */
- static int do_output_standby(struct m0_stream_out *out)
- {
- struct m0_audio_device *adev = out->dev;
- int i;
- bool all_outputs_in_standby = true;
- if (!out->standby) {
- out->standby = 1;
- for (i = 0; i < PCM_TOTAL; i++) {
- if (out->pcm[i]) {
- pcm_close(out->pcm[i]);
- out->pcm[i] = NULL;
- }
- }
- for (i = 0; i < OUTPUT_TOTAL; i++) {
- if (adev->outputs[i] != NULL && !adev->outputs[i]->standby) {
- all_outputs_in_standby = false;
- break;
- }
- }
- /* force standby on low latency output stream so that it can reuse HDMI driver if
- * necessary when restarted */
- if (out == adev->outputs[OUTPUT_HDMI]) {
- if (adev->outputs[OUTPUT_LOW_LATENCY] != NULL &&
- !adev->outputs[OUTPUT_LOW_LATENCY]->standby) {
- struct m0_stream_out *ll_out = adev->outputs[OUTPUT_LOW_LATENCY];
- pthread_mutex_lock(&ll_out->lock);
- do_output_standby(ll_out);
- pthread_mutex_unlock(&ll_out->lock);
- }
- }
- /* stop writing to echo reference */
- if (out->echo_reference != NULL) {
- out->echo_reference->write(out->echo_reference, NULL);
- out->echo_reference = NULL;
- }
- }
- return 0;
- }
- static int out_standby(struct audio_stream *stream)
- {
- struct m0_stream_out *out = (struct m0_stream_out *)stream;
- int status;
- pthread_mutex_lock(&out->dev->lock);
- pthread_mutex_lock(&out->lock);
- status = do_output_standby(out);
- pthread_mutex_unlock(&out->lock);
- pthread_mutex_unlock(&out->dev->lock);
- return status;
- }
- static int out_dump(const struct audio_stream *stream, int fd)
- {
- return 0;
- }
- static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
- {
- struct m0_stream_out *out = (struct m0_stream_out *)stream;
- struct m0_audio_device *adev = out->dev;
- struct m0_stream_in *in;
- struct str_parms *parms;
- char *str;
- char value[32];
- int ret, val = 0;
- bool force_input_standby = false;
- parms = str_parms_create_str(kvpairs);
- ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
- if (ret >= 0) {
- val = atoi(value);
- pthread_mutex_lock(&adev->lock);
- pthread_mutex_lock(&out->lock);
- if (((adev->out_device) != val) && (val != 0)) {
- /* this is needed only when changing device on low latency output
- * as other output streams are not used for voice use cases nor
- * handle duplication to HDMI or SPDIF */
- if (out == adev->outputs[OUTPUT_LOW_LATENCY] && !out->standby) {
- /* a change in output device may change the microphone selection */
- if (adev->active_input &&
- adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
- force_input_standby = true;
- }
- /* force standby if moving to/from HDMI/SPDIF or if the output
- * device changes when in HDMI/SPDIF mode */
- /* FIXME also force standby when in call as some audio path switches do not work
- * while in call and an output stream is active (e.g BT SCO => earpiece) */
- /* FIXME workaround for audio being dropped when switching path without forcing standby
- * (several hundred ms of audio can be lost: e.g beginning of a ringtone. We must understand
- * the root cause in audio HAL, driver or ABE.
- if (((val & AUDIO_DEVICE_OUT_AUX_DIGITAL) ^
- (adev->out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL)) ||
- ((val & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) ^
- (adev->out_device & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET)) ||
- (adev->out_device & (AUDIO_DEVICE_OUT_AUX_DIGITAL |
- AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET)))
- */
- if (((val & AUDIO_DEVICE_OUT_AUX_DIGITAL) ^
- (adev->out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL)) ||
- ((val & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) ^
- (adev->out_device & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET)) ||
- (adev->out_device & (AUDIO_DEVICE_OUT_AUX_DIGITAL |
- AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET)) ||
- ((val & AUDIO_DEVICE_OUT_SPEAKER) ^
- (adev->out_device & AUDIO_DEVICE_OUT_SPEAKER)) ||
- (adev->mode == AUDIO_MODE_IN_CALL))
- do_output_standby(out);
- }
- if (out != adev->outputs[OUTPUT_HDMI]) {
- adev->out_device = val;
- select_output_device(adev);
- }
- }
- pthread_mutex_unlock(&out->lock);
- if (force_input_standby) {
- in = adev->active_input;
- pthread_mutex_lock(&in->lock);
- do_input_standby(in);
- pthread_mutex_unlock(&in->lock);
- }
- pthread_mutex_unlock(&adev->lock);
- }
- str_parms_destroy(parms);
- return ret;
- }
- static char * out_get_parameters(const struct audio_stream *stream, const char *keys)
- {
- struct m0_stream_out *out = (struct m0_stream_out *)stream;
- struct str_parms *query = str_parms_create_str(keys);
- char *str;
- char value[256];
- struct str_parms *reply = str_parms_create();
- size_t i, j;
- int ret;
- bool first = true;
- ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value, sizeof(value));
- if (ret >= 0) {
- value[0] = '\0';
- i = 0;
- while (out->sup_channel_masks[i] != 0) {
- for (j = 0; j < ARRAY_SIZE(out_channels_name_to_enum_table); j++) {
- if (out_channels_name_to_enum_table[j].value == out->sup_channel_masks[i]) {
- if (!first) {
- strcat(value, "|");
- }
- strcat(value, out_channels_name_to_enum_table[j].name);
- first = false;
- break;
- }
- }
- i++;
- }
- str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value);
- str = strdup(str_parms_to_str(reply));
- } else {
- str = strdup(keys);
- }
- str_parms_destroy(query);
- str_parms_destroy(reply);
- return str;
- }
- static uint32_t out_get_latency_low_latency(const struct audio_stream_out *stream)
- {
- struct m0_stream_out *out = (struct m0_stream_out *)stream;
- /* Note: we use the default rate here from pcm_config_mm.rate */
- return (SHORT_PERIOD_SIZE * PLAYBACK_SHORT_PERIOD_COUNT * 1000) / pcm_config_tones.rate;
- }
- static uint32_t out_get_latency_deep_buffer(const struct audio_stream_out *stream)
- {
- struct m0_stream_out *out = (struct m0_stream_out *)stream;
- /* Note: we use the default rate here from pcm_config_mm.rate */
- return (DEEP_BUFFER_LONG_PERIOD_SIZE * PLAYBACK_DEEP_BUFFER_LONG_PERIOD_COUNT * 1000) /
- pcm_config_mm.rate;
- }
- static int out_set_volume(struct audio_stream_out *stream, float left,
- float right)
- {
- return -ENOSYS;
- }
- static ssize_t out_write_low_latency(struct audio_stream_out *stream, const void* buffer,
- size_t bytes)
- {
- int ret;
- struct m0_stream_out *out = (struct m0_stream_out *)stream;
- struct m0_audio_device *adev = out->dev;
- size_t frame_size = audio_stream_frame_size(&out->stream.common);
- size_t in_frames = bytes / frame_size;
- size_t out_frames = in_frames;
- bool force_input_standby = false;
- struct m0_stream_in *in;
- int i;
- /* acquiring hw device mutex systematically is useful if a low priority thread is waiting
- * on the output stream mutex - e.g. executing select_mode() while holding the hw device
- * mutex
- */
- pthread_mutex_lock(&adev->lock);
- pthread_mutex_lock(&out->lock);
- if (out->standby) {
- ret = start_output_stream_low_latency(out);
- if (ret != 0) {
- pthread_mutex_unlock(&adev->lock);
- goto exit;
- }
- out->standby = 0;
- /* a change in output device may change the microphone selection */
- if (adev->active_input &&
- adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION)
- force_input_standby = true;
- }
- pthread_mutex_unlock(&adev->lock);
- for (i = 0; i < PCM_TOTAL; i++) {
- /* only use resampler if required */
- if (out->pcm[i] && (out->config[i].rate != DEFAULT_OUT_SAMPLING_RATE)) {
- out_frames = out->buffer_frames;
- out->resampler->resample_from_input(out->resampler,
- (int16_t *)buffer,
- &in_frames,
- (int16_t *)out->buffer,
- &out_frames);
- break;
- }
- }
- if (out->echo_reference != NULL) {
- struct echo_reference_buffer b;
- b.raw = (void *)buffer;
- b.frame_count = in_frames;
- get_playback_delay(out, out_frames, &b);
- out->echo_reference->write(out->echo_reference, &b);
- }
- /* Write to all active PCMs */
- for (i = 0; i < PCM_TOTAL; i++) {
- if (out->pcm[i]) {
- if (out->config[i].rate == DEFAULT_OUT_SAMPLING_RATE) {
- /* PCM uses native sample rate */
- ret = PCM_WRITE(out->pcm[i], (void *)buffer, bytes);
- } else {
- /* PCM needs resampler */
- ret = PCM_WRITE(out->pcm[i], (void *)out->buffer, out_frames * frame_size);
- }
- if (ret)
- break;
- }
- }
- exit:
- pthread_mutex_unlock(&out->lock);
- if (ret != 0) {
- usleep(bytes * 1000000 / audio_stream_frame_size(&stream->common) /
- out_get_sample_rate(&stream->common));
- }
- if (force_input_standby) {
- pthread_mutex_lock(&adev->lock);
- if (adev->active_input) {
- in = adev->active_input;
- pthread_mutex_lock(&in->lock);
- do_input_standby(in);
- pthread_mutex_unlock(&in->lock);
- }
- pthread_mutex_unlock(&adev->lock);
- }
- return bytes;
- }
- static ssize_t out_write_deep_buffer(struct audio_stream_out *stream, const void* buffer,
- size_t bytes)
- {
- int ret;
- struct m0_stream_out *out = (struct m0_stream_out *)stream;
- struct m0_audio_device *adev = out->dev;
- size_t frame_size = audio_stream_frame_size(&out->stream.common);
- size_t in_frames = bytes / frame_size;
- size_t out_frames;
- bool use_long_periods;
- int kernel_frames;
- void *buf;
- /* acquiring hw device mutex systematically is useful if a low priority thread is waiting
- * on the output stream mutex - e.g. executing select_mode() while holding the hw device
- * mutex
- */
- pthread_mutex_lock(&adev->lock);
- pthread_mutex_lock(&out->lock);
- if (out->standby) {
- ret = start_output_stream_deep_buffer(out);
- if (ret != 0) {
- pthread_mutex_unlock(&adev->lock);
- goto exit;
- }
- out->standby = 0;
- }
- use_long_periods = adev->screen_off && !adev->active_input;
- pthread_mutex_unlock(&adev->lock);
- if (use_long_periods != out->use_long_periods) {
- size_t period_size;
- size_t period_count;
- if (use_long_periods) {
- period_size = DEEP_BUFFER_LONG_PERIOD_SIZE;
- period_count = PLAYBACK_DEEP_BUFFER_LONG_PERIOD_COUNT;
- } else {
- period_size = DEEP_BUFFER_SHORT_PERIOD_SIZE;
- period_count = PLAYBACK_DEEP_BUFFER_SHORT_PERIOD_COUNT;
- }
- out->write_threshold = period_size * period_count;
- pcm_set_avail_min(out->pcm[PCM_NORMAL], period_size);
- out->use_long_periods = use_long_periods;
- }
- /* only use resampler if required */
- if (out->config[PCM_NORMAL].rate != DEFAULT_OUT_SAMPLING_RATE) {
- out_frames = out->buffer_frames;
- out->resampler->resample_from_input(out->resampler,
- (int16_t *)buffer,
- &in_frames,
- (int16_t *)out->buffer,
- &out_frames);
- buf = (void *)out->buffer;
- } else {
- out_frames = in_frames;
- buf = (void *)buffer;
- }
- /* do not allow more than out->write_threshold frames in kernel pcm driver buffer */
- do {
- struct timespec time_stamp;
- if (pcm_get_htimestamp(out->pcm[PCM_NORMAL],
- (unsigned int *)&kernel_frames, &time_stamp) < 0)
- break;
- kernel_frames = pcm_get_buffer_size(out->pcm[PCM_NORMAL]) - kernel_frames;
- if (kernel_frames > out->write_threshold) {
- unsigned long time = (unsigned long)
- (((int64_t)(kernel_frames - out->write_threshold) * 1000000) /
- MM_FULL_POWER_SAMPLING_RATE);
- if (time < MIN_WRITE_SLEEP_US)
- time = MIN_WRITE_SLEEP_US;
- usleep(time);
- }
- } while (kernel_frames > out->write_threshold);
- ret = pcm_mmap_write(out->pcm[PCM_NORMAL], buf, out_frames * frame_size);
- exit:
- pthread_mutex_unlock(&out->lock);
- if (ret != 0) {
- usleep(bytes * 1000000 / audio_stream_frame_size(&stream->common) /
- out_get_sample_rate(&stream->common));
- }
- return bytes;
- }
- static int out_get_render_position(const struct audio_stream_out *stream,
- uint32_t *dsp_frames)
- {
- return -EINVAL;
- }
- static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
- {
- return 0;
- }
- static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
- {
- return 0;
- }
- /** audio_stream_in implementation **/
- /* must be called with hw device and input stream mutexes locked */
- static int start_input_stream(struct m0_stream_in *in)
- {
- int ret = 0;
- struct m0_audio_device *adev = in->dev;
- adev->active_input = in;
- if (adev->mode != AUDIO_MODE_IN_CALL) {
- adev->in_device = in->device;
- select_input_device(adev);
- }
- if (in->aux_channels_changed)
- {
- in->aux_channels_changed = false;
- in->config.channels = popcount(in->main_channels | in->aux_channels);
- if (in->resampler) {
- /* release and recreate the resampler with the new number of channel of the input */
- release_resampler(in->resampler);
- in->resampler = NULL;
- ret = create_resampler(in->config.rate,
- in->requested_rate,
- in->config.channels,
- RESAMPLER_QUALITY_DEFAULT,
- &in->buf_provider,
- &in->resampler);
- }
- ALOGV("%s: New channel configuration, "
- "main_channels = [%04x…
Large files files are truncated, but you can click here to view the full file