diff --git a/audio/audio_hw.c b/audio/audio_hw.c index 3659277d..ff855d57 100644 --- a/audio/audio_hw.c +++ b/audio/audio_hw.c @@ -634,8 +634,6 @@ static snd_device_t get_input_snd_device(struct audio_device *adev, audio_device snd_device = SND_DEVICE_IN_VOICE_MIC; if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) { snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC; - } else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) { - snd_device = SND_DEVICE_IN_BT_SCO_MIC; } if (voice_session_uses_twomic(adev->voice.session)) { @@ -661,6 +659,17 @@ static snd_device_t get_input_snd_device(struct audio_device *adev, audio_device } } } + + /* BT SCO */ + if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) { + snd_device = SND_DEVICE_IN_VOICE_MIC; + + if (out_device & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) { + snd_device = SND_DEVICE_IN_BT_SCO_MIC; + } else if (voice_session_uses_twomic(adev->voice.session)) { + snd_device = SND_DEVICE_IN_VOICE_EARPIECE_MIC; + } + } } else if (source == AUDIO_SOURCE_CAMCORDER) { if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC || in_device & AUDIO_DEVICE_IN_BACK_MIC) { @@ -2726,6 +2735,11 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) } #endif if (val != 0) { + bool bt_sco_active = false; + + if (out->devices & AUDIO_DEVICE_OUT_ALL_SCO) { + bt_sco_active = true; + } out->devices = val; if (!out->standby) { @@ -2758,6 +2772,10 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) } else if ((adev->mode == AUDIO_MODE_IN_CALL) && adev->voice.in_call && (out == adev->primary_output)) { + /* Turn on bluetooth if needed */ + if ((out->devices & AUDIO_DEVICE_OUT_ALL_SCO) && !bt_sco_active) { + start_voice_session_bt_sco(adev->voice.session); + } select_devices(adev, USECASE_VOICE_CALL); } } @@ -3933,6 +3951,9 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) parms = str_parms_create_str(kvpairs); + /****************************************************** + *** BT SCO + ******************************************************/ ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_NREC, value, sizeof(value)); if (ret >= 0) { /* When set to false, HAL should disable EC and NS @@ -3944,6 +3965,21 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) adev->voice.bluetooth_nrec = false; } + ret = str_parms_get_str(parms, + AUDIO_PARAMETER_KEY_BT_SCO_WB, + value, + sizeof(value)); + if (ret >= 0) { + /* TODO: Add support in voice calls */ + if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0) { + adev->voice.bluetooth_wb = true; + ALOGI("%s: Implement support for BT SCO wideband calls!!!", + __func__); + } else { + adev->voice.bluetooth_wb = false; + } + } + ret = str_parms_get_str(parms, "screen_state", value, sizeof(value)); if (ret >= 0) { if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0) diff --git a/audio/audio_hw.h b/audio/audio_hw.h index 45c34075..ca90fef3 100644 --- a/audio/audio_hw.h +++ b/audio/audio_hw.h @@ -381,6 +381,7 @@ struct voice_data { bool in_call; float volume; bool bluetooth_nrec; + bool bluetooth_wb; void *session; }; diff --git a/audio/voice.c b/audio/voice.c index 01a7b96e..08d8baf3 100644 --- a/audio/voice.c +++ b/audio/voice.c @@ -50,6 +50,14 @@ static struct pcm_config pcm_config_voicecall_wideband = { .format = PCM_FORMAT_S16_LE, }; +struct pcm_config pcm_config_voice_sco = { + .channels = 1, + .rate = SCO_DEFAULT_SAMPLING_RATE, + .period_size = SCO_PERIOD_SIZE, + .period_count = SCO_PERIOD_COUNT, + .format = PCM_FORMAT_S16_LE, +}; + /* Prototypes */ int start_voice_call(struct audio_device *adev); int stop_voice_call(struct audio_device *adev); @@ -113,6 +121,70 @@ void prepare_voice_session(struct voice_session *session, } } +/* + * This must be called with the hw device mutex locked, OK to hold other + * mutexes. + */ +static void stop_voice_session_bt_sco(struct voice_session *session) { + ALOGV("%s: Closing SCO PCMs", __func__); + + if (session->pcm_sco_rx != NULL) { + pcm_stop(session->pcm_sco_rx); + pcm_close(session->pcm_sco_rx); + session->pcm_sco_rx = NULL; + } + + if (session->pcm_sco_tx != NULL) { + pcm_stop(session->pcm_sco_tx); + pcm_close(session->pcm_sco_tx); + session->pcm_sco_tx = NULL; + } +} + +/* must be called with the hw device mutex locked, OK to hold other mutexes */ +void start_voice_session_bt_sco(struct voice_session *session) +{ + if (session->pcm_sco_rx != NULL || session->pcm_sco_tx != NULL) { + ALOGW("%s: SCO PCMs already open!\n", __func__); + return; + } + + ALOGV("%s: Opening SCO PCMs", __func__); + + /* TODO: Add wideband support */ + + session->pcm_sco_rx = pcm_open(SOUND_CARD, + SOUND_PLAYBACK_SCO_DEVICE, + PCM_OUT|PCM_MONOTONIC, + &pcm_config_voice_sco); + if (session->pcm_sco_rx != NULL && !pcm_is_ready(session->pcm_sco_rx)) { + ALOGE("%s: cannot open PCM SCO RX stream: %s", + __func__, pcm_get_error(session->pcm_sco_rx)); + goto err_sco_rx; + } + + session->pcm_sco_tx = pcm_open(SOUND_CARD, + SOUND_CAPTURE_SCO_DEVICE, + PCM_IN|PCM_MONOTONIC, + &pcm_config_voice_sco); + if (session->pcm_sco_tx && !pcm_is_ready(session->pcm_sco_tx)) { + ALOGE("%s: cannot open PCM SCO TX stream: %s", + __func__, pcm_get_error(session->pcm_sco_tx)); + goto err_sco_tx; + } + + pcm_start(session->pcm_sco_rx); + pcm_start(session->pcm_sco_tx); + + return; + +err_sco_tx: + pcm_close(session->pcm_sco_tx); + session->pcm_sco_tx = NULL; +err_sco_rx: + pcm_close(session->pcm_sco_rx); + session->pcm_sco_rx = NULL; +} /* * This function must be called with hw device mutex locked, OK to hold other * mutexes @@ -170,7 +242,9 @@ int start_voice_session(struct voice_session *session) pcm_start(session->pcm_voice_rx); pcm_start(session->pcm_voice_tx); - /* TODO: handle SCO */ + if (session->out_device & AUDIO_DEVICE_OUT_ALL_SCO) { + start_voice_session_bt_sco(session); + } if (session->two_mic_control) { ALOGV("%s: enabling two mic control", __func__); @@ -209,7 +283,10 @@ void stop_voice_session(struct voice_session *session) status++; } - /* TODO: handle SCO */ + if (session->out_device & AUDIO_DEVICE_OUT_ALL_SCO) { + stop_voice_session_bt_sco(session); + } + session->out_device = AUDIO_DEVICE_NONE; diff --git a/audio/voice.h b/audio/voice.h index 10f0fef8..c89a3727 100644 --- a/audio/voice.h +++ b/audio/voice.h @@ -25,6 +25,9 @@ struct voice_session { struct pcm *pcm_voice_rx; struct pcm *pcm_voice_tx; + struct pcm *pcm_sco_rx; + struct pcm *pcm_sco_tx; + bool wb_amr; bool two_mic_control; bool two_mic_disabled; @@ -41,6 +44,8 @@ void set_voice_session_volume(struct voice_session *session, float volume); void set_voice_session_audio_path(struct voice_session *session); void set_voice_session_mic_mute(struct voice_session *session, bool state); +void start_voice_session_bt_sco(struct voice_session *session); + bool voice_session_uses_twomic(struct voice_session *session); bool voice_session_uses_wideband(struct voice_session *session);