blob: 6d5e613037d00cabbf19320f913c8b3260335cff [file] [log] [blame]
Christopher N. Hesse41c9f3d2017-02-02 20:48:56 +01001/*
2 * Copyright (C) 2017 Christopher N. Hesse <raymanfx@gmail.com>
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "audio_hw_voice"
Christopher N. Hesse86f7ea82017-02-15 09:41:05 +010018#define LOG_NDEBUG 0
Christopher N. Hesse41c9f3d2017-02-02 20:48:56 +010019/*#define VERY_VERY_VERBOSE_LOGGING*/
20#ifdef VERY_VERY_VERBOSE_LOGGING
21#define ALOGVV ALOGV
22#else
23#define ALOGVV(a...) do { } while(0)
24#endif
25
26#include <stdlib.h>
27#include <pthread.h>
28
Christopher N. Hesse696959d2017-02-02 20:49:55 +010029#include <cutils/log.h>
30#include <cutils/properties.h>
31
32#include <samsung_audio.h>
33
Christopher N. Hesse41c9f3d2017-02-02 20:48:56 +010034#include "audio_hw.h"
35#include "voice.h"
36
Christopher N. Hesse0fdef0c2017-02-25 01:37:56 +010037#ifdef AUDIENCE_EARSMART_IC
38#include "audience.h"
39#endif
40
Christopher N. Hesse696959d2017-02-02 20:49:55 +010041static struct pcm_config pcm_config_voicecall = {
42 .channels = 2,
43 .rate = 8000,
44 .period_size = CAPTURE_PERIOD_SIZE_LOW_LATENCY,
45 .period_count = CAPTURE_PERIOD_COUNT_LOW_LATENCY,
46 .format = PCM_FORMAT_S16_LE,
47};
48
49static struct pcm_config pcm_config_voicecall_wideband = {
50 .channels = 2,
51 .rate = 16000,
52 .period_size = CAPTURE_PERIOD_SIZE_LOW_LATENCY,
53 .period_count = CAPTURE_PERIOD_COUNT_LOW_LATENCY,
54 .format = PCM_FORMAT_S16_LE,
55};
56
Andreas Schneider05bc1882017-02-09 14:03:11 +010057struct pcm_config pcm_config_voice_sco = {
58 .channels = 1,
59 .rate = SCO_DEFAULT_SAMPLING_RATE,
60 .period_size = SCO_PERIOD_SIZE,
61 .period_count = SCO_PERIOD_COUNT,
62 .format = PCM_FORMAT_S16_LE,
63};
64
Fevax51bd12c2017-03-15 10:56:39 -030065struct pcm_config pcm_config_voice_sco_wb = {
66 .channels = 1,
Martin Hoffmannf1a35392017-07-26 12:10:37 +020067 .rate = SCO_WB_SAMPLING_RATE,
Fevax51bd12c2017-03-15 10:56:39 -030068 .period_size = SCO_PERIOD_SIZE,
69 .period_count = SCO_PERIOD_COUNT,
70 .format = PCM_FORMAT_S16_LE,
71};
72
Christopher N. Hesse696959d2017-02-02 20:49:55 +010073/* Prototypes */
74int start_voice_call(struct audio_device *adev);
75int stop_voice_call(struct audio_device *adev);
76
77void set_voice_session_audio_path(struct voice_session *session)
Christopher N. Hesse41c9f3d2017-02-02 20:48:56 +010078{
Christopher N. Hesse696959d2017-02-02 20:49:55 +010079 enum _AudioPath device_type;
Andreas Schneiderd44edaa2017-02-13 16:21:35 +010080 int rc;
Christopher N. Hesse696959d2017-02-02 20:49:55 +010081
82 switch(session->out_device) {
83 case AUDIO_DEVICE_OUT_SPEAKER:
84 device_type = SOUND_AUDIO_PATH_SPEAKER;
85 break;
86 case AUDIO_DEVICE_OUT_EARPIECE:
Andreas Schneidere6286b92017-02-14 17:24:23 +010087 device_type = SOUND_AUDIO_PATH_EARPIECE;
Christopher N. Hesse696959d2017-02-02 20:49:55 +010088 break;
89 case AUDIO_DEVICE_OUT_WIRED_HEADSET:
90 device_type = SOUND_AUDIO_PATH_HEADSET;
91 break;
92 case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
93 device_type = SOUND_AUDIO_PATH_HEADPHONE;
94 break;
95 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
96 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
97 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
98 device_type = SOUND_AUDIO_PATH_BLUETOOTH;
99 break;
100 default:
Andreas Schneidere6286b92017-02-14 17:24:23 +0100101 /* if output device isn't supported, use earpiece by default */
102 device_type = SOUND_AUDIO_PATH_EARPIECE;
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100103 break;
104 }
105
106 ALOGV("%s: ril_set_call_audio_path(%d)", __func__, device_type);
107
Andreas Schneiderd44edaa2017-02-13 16:21:35 +0100108 rc = ril_set_call_audio_path(&session->ril, device_type);
109 ALOGE_IF(rc != 0, "Failed to set audio path: (%d)", rc);
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100110}
111
112/*
113 * This decides based on the output device, if we enable
114 * two mic control
115 */
116void prepare_voice_session(struct voice_session *session,
117 audio_devices_t active_out_devices)
118{
119 ALOGV("%s: active_out_devices: 0x%x", __func__, active_out_devices);
120
121 session->out_device = active_out_devices;
122
123 switch (session->out_device) {
124 case AUDIO_DEVICE_OUT_EARPIECE:
125 case AUDIO_DEVICE_OUT_SPEAKER:
126 session->two_mic_control = true;
127 break;
128 default:
129 session->two_mic_control = false;
130 break;
131 }
132
133 if (session->two_mic_disabled) {
134 session->two_mic_control = false;
135 }
136}
137
138/*
Andreas Schneider05bc1882017-02-09 14:03:11 +0100139 * This must be called with the hw device mutex locked, OK to hold other
140 * mutexes.
141 */
stenkinevgeniy53929f72018-07-09 11:20:36 +0000142void stop_voice_session_bt_sco(struct audio_device *adev) {
Andreas Schneider05bc1882017-02-09 14:03:11 +0100143 ALOGV("%s: Closing SCO PCMs", __func__);
144
stenkinevgeniy53929f72018-07-09 11:20:36 +0000145 if (adev->pcm_sco_rx != NULL) {
146 pcm_stop(adev->pcm_sco_rx);
147 pcm_close(adev->pcm_sco_rx);
148 adev->pcm_sco_rx = NULL;
Andreas Schneider05bc1882017-02-09 14:03:11 +0100149 }
150
stenkinevgeniy53929f72018-07-09 11:20:36 +0000151 if (adev->pcm_sco_tx != NULL) {
152 pcm_stop(adev->pcm_sco_tx);
153 pcm_close(adev->pcm_sco_tx);
154 adev->pcm_sco_tx = NULL;
Andreas Schneider05bc1882017-02-09 14:03:11 +0100155 }
stenkinevgeniy884938a2018-07-09 14:48:19 +0000156
157 /* audio codecs like wm5201 need open modem pcm while using bt sco */
158 if (adev->mode != AUDIO_MODE_IN_CALL)
159 stop_voice_session(adev->voice.session);
Andreas Schneider05bc1882017-02-09 14:03:11 +0100160}
161
162/* must be called with the hw device mutex locked, OK to hold other mutexes */
stenkinevgeniy53929f72018-07-09 11:20:36 +0000163void start_voice_session_bt_sco(struct audio_device *adev)
Andreas Schneider05bc1882017-02-09 14:03:11 +0100164{
Fevax51bd12c2017-03-15 10:56:39 -0300165 struct pcm_config *voice_sco_config;
166
stenkinevgeniy53929f72018-07-09 11:20:36 +0000167 if (adev->pcm_sco_rx != NULL || adev->pcm_sco_tx != NULL) {
Andreas Schneider05bc1882017-02-09 14:03:11 +0100168 ALOGW("%s: SCO PCMs already open!\n", __func__);
169 return;
170 }
171
172 ALOGV("%s: Opening SCO PCMs", __func__);
173
stenkinevgeniy53929f72018-07-09 11:20:36 +0000174 if (adev->voice.bluetooth_wb) {
Fevax51bd12c2017-03-15 10:56:39 -0300175 ALOGV("%s: pcm_config wideband", __func__);
176 voice_sco_config = &pcm_config_voice_sco_wb;
177 } else {
178 ALOGV("%s: pcm_config narrowband", __func__);
179 voice_sco_config = &pcm_config_voice_sco;
180 }
Andreas Schneider05bc1882017-02-09 14:03:11 +0100181
stenkinevgeniy53929f72018-07-09 11:20:36 +0000182 adev->pcm_sco_rx = pcm_open(SOUND_CARD,
Andreas Schneider05bc1882017-02-09 14:03:11 +0100183 SOUND_PLAYBACK_SCO_DEVICE,
184 PCM_OUT|PCM_MONOTONIC,
Fevax51bd12c2017-03-15 10:56:39 -0300185 voice_sco_config);
stenkinevgeniy53929f72018-07-09 11:20:36 +0000186 if (adev->pcm_sco_rx != NULL && !pcm_is_ready(adev->pcm_sco_rx)) {
Andreas Schneider05bc1882017-02-09 14:03:11 +0100187 ALOGE("%s: cannot open PCM SCO RX stream: %s",
stenkinevgeniy53929f72018-07-09 11:20:36 +0000188 __func__, pcm_get_error(adev->pcm_sco_rx));
Andreas Schneider05bc1882017-02-09 14:03:11 +0100189 goto err_sco_rx;
190 }
191
stenkinevgeniy53929f72018-07-09 11:20:36 +0000192 adev->pcm_sco_tx = pcm_open(SOUND_CARD,
Andreas Schneider05bc1882017-02-09 14:03:11 +0100193 SOUND_CAPTURE_SCO_DEVICE,
194 PCM_IN|PCM_MONOTONIC,
Fevax51bd12c2017-03-15 10:56:39 -0300195 voice_sco_config);
stenkinevgeniy53929f72018-07-09 11:20:36 +0000196 if (adev->pcm_sco_tx && !pcm_is_ready(adev->pcm_sco_tx)) {
Andreas Schneider05bc1882017-02-09 14:03:11 +0100197 ALOGE("%s: cannot open PCM SCO TX stream: %s",
stenkinevgeniy53929f72018-07-09 11:20:36 +0000198 __func__, pcm_get_error(adev->pcm_sco_tx));
Andreas Schneider05bc1882017-02-09 14:03:11 +0100199 goto err_sco_tx;
200 }
201
stenkinevgeniy53929f72018-07-09 11:20:36 +0000202 pcm_start(adev->pcm_sco_rx);
203 pcm_start(adev->pcm_sco_tx);
Andreas Schneider05bc1882017-02-09 14:03:11 +0100204
stenkinevgeniy884938a2018-07-09 14:48:19 +0000205 /* audio codecs like wm5201 need open modem pcm while using bt sco */
206 if (adev->mode != AUDIO_MODE_IN_CALL)
207 start_voice_session(adev->voice.session);
208
Andreas Schneider05bc1882017-02-09 14:03:11 +0100209 return;
210
211err_sco_tx:
stenkinevgeniy53929f72018-07-09 11:20:36 +0000212 pcm_close(adev->pcm_sco_tx);
213 adev->pcm_sco_tx = NULL;
Andreas Schneider05bc1882017-02-09 14:03:11 +0100214err_sco_rx:
stenkinevgeniy53929f72018-07-09 11:20:36 +0000215 pcm_close(adev->pcm_sco_rx);
216 adev->pcm_sco_rx = NULL;
Andreas Schneider05bc1882017-02-09 14:03:11 +0100217}
218/*
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100219 * This function must be called with hw device mutex locked, OK to hold other
220 * mutexes
221 */
222int start_voice_session(struct voice_session *session)
223{
224 struct pcm_config *voice_config;
225
226 if (session->pcm_voice_rx != NULL || session->pcm_voice_tx != NULL) {
227 ALOGW("%s: Voice PCMs already open!\n", __func__);
228 return 0;
229 }
230
231 ALOGV("%s: Opening voice PCMs", __func__);
232
Andreas Schneider49b9dcb2017-02-13 17:15:07 +0100233 /* TODO: Handle wb_amr=2 */
234 if (session->wb_amr_type >= 1) {
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100235 ALOGV("%s: pcm_config wideband", __func__);
236 voice_config = &pcm_config_voicecall_wideband;
237 } else {
238 ALOGV("%s: pcm_config narrowband", __func__);
239 voice_config = &pcm_config_voicecall;
240 }
241
242 /* Open modem PCM channels */
243 session->pcm_voice_rx = pcm_open(SOUND_CARD,
244 SOUND_PLAYBACK_VOICE_DEVICE,
245 PCM_OUT|PCM_MONOTONIC,
246 voice_config);
247 if (session->pcm_voice_rx != NULL && !pcm_is_ready(session->pcm_voice_rx)) {
248 ALOGE("%s: cannot open PCM voice RX stream: %s",
249 __func__,
250 pcm_get_error(session->pcm_voice_rx));
251
252 pcm_close(session->pcm_voice_tx);
253 session->pcm_voice_tx = NULL;
254
255 return -ENOMEM;
256 }
257
258 session->pcm_voice_tx = pcm_open(SOUND_CARD,
259 SOUND_CAPTURE_VOICE_DEVICE,
260 PCM_IN|PCM_MONOTONIC,
261 voice_config);
262 if (session->pcm_voice_tx != NULL && !pcm_is_ready(session->pcm_voice_tx)) {
263 ALOGE("%s: cannot open PCM voice TX stream: %s",
264 __func__,
265 pcm_get_error(session->pcm_voice_tx));
266
267 pcm_close(session->pcm_voice_rx);
268 session->pcm_voice_rx = NULL;
269
270 return -ENOMEM;
271 }
272
273 pcm_start(session->pcm_voice_rx);
274 pcm_start(session->pcm_voice_tx);
275
Christopher N. Hesse0fdef0c2017-02-25 01:37:56 +0100276#ifdef AUDIENCE_EARSMART_IC
277 ALOGV("%s: Enabling Audience IC", __func__);
278 es_start_voice_session(session);
279#endif
280
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100281 if (session->two_mic_control) {
282 ALOGV("%s: enabling two mic control", __func__);
283 ril_set_two_mic_control(&session->ril, AUDIENCE, TWO_MIC_SOLUTION_ON);
284 } else {
285 ALOGV("%s: disabling two mic control", __func__);
286 ril_set_two_mic_control(&session->ril, AUDIENCE, TWO_MIC_SOLUTION_OFF);
287 }
288
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100289 return 0;
290}
291
292/*
293 * This function must be called with hw device mutex locked, OK to hold other
294 * mutexes
295 */
296void stop_voice_session(struct voice_session *session)
297{
298 int status = 0;
299
Usaamah Patelb8250d02017-12-19 15:42:38 +0000300 ril_set_call_clock_sync(&session->ril, SOUND_CLOCK_STOP);
301
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100302 ALOGV("%s: Closing active PCMs", __func__);
303
304 if (session->pcm_voice_rx != NULL) {
305 pcm_stop(session->pcm_voice_rx);
306 pcm_close(session->pcm_voice_rx);
307 session->pcm_voice_rx = NULL;
308 status++;
309 }
310
311 if (session->pcm_voice_tx != NULL) {
312 pcm_stop(session->pcm_voice_tx);
313 pcm_close(session->pcm_voice_tx);
314 session->pcm_voice_tx = NULL;
315 status++;
316 }
317
Christopher N. Hesse0fdef0c2017-02-25 01:37:56 +0100318#ifdef AUDIENCE_EARSMART_IC
319 ALOGV("%s: Disabling Audience IC", __func__);
320 es_stop_voice_session();
321#endif
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100322
323 session->out_device = AUDIO_DEVICE_NONE;
324
325 ALOGV("%s: Successfully closed %d active PCMs", __func__, status);
326}
327
328void set_voice_session_volume(struct voice_session *session, float volume)
329{
330 enum _SoundType sound_type;
331
332 switch (session->out_device) {
333 case AUDIO_DEVICE_OUT_EARPIECE:
334 sound_type = SOUND_TYPE_VOICE;
335 break;
336 case AUDIO_DEVICE_OUT_SPEAKER:
337 sound_type = SOUND_TYPE_SPEAKER;
338 break;
339 case AUDIO_DEVICE_OUT_WIRED_HEADSET:
340 case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
341 sound_type = SOUND_TYPE_HEADSET;
342 break;
343 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
344 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
345 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
346 case AUDIO_DEVICE_OUT_ALL_SCO:
347 sound_type = SOUND_TYPE_BTVOICE;
348 break;
349 default:
350 sound_type = SOUND_TYPE_VOICE;
351 }
352
353 ril_set_call_volume(&session->ril, sound_type, volume);
354}
355
Andreas Schneider107a8482017-02-06 12:36:31 +0100356void set_voice_session_mic_mute(struct voice_session *session, bool state)
357{
358 enum _MuteCondition mute_condition = state ? TX_MUTE : TX_UNMUTE;
359
360 ril_set_mute(&session->ril, mute_condition);
361}
362
Andreas Schneider82f32482017-02-06 09:00:48 +0100363bool voice_session_uses_twomic(struct voice_session *session)
364{
365 if (session->two_mic_disabled) {
366 return false;
367 }
368
369 return session->two_mic_control;
370}
371
Andreas Schneider59486fa2017-02-06 09:16:39 +0100372bool voice_session_uses_wideband(struct voice_session *session)
373{
Christopher N. Hessee4a1c592018-01-16 18:33:38 +0100374 if (session->out_device & AUDIO_DEVICE_OUT_ALL_SCO) {
Christopher N. Hesse6a960022018-01-29 03:28:10 +0100375 return session->vdata->bluetooth_wb;
Christopher N. Hessee4a1c592018-01-16 18:33:38 +0100376 }
377
Andreas Schneider49b9dcb2017-02-13 17:15:07 +0100378 return session->wb_amr_type >= 1;
Andreas Schneider59486fa2017-02-06 09:16:39 +0100379}
380
Andreas Schneider49b9dcb2017-02-13 17:15:07 +0100381static void voice_session_wb_amr_callback(void *data, int wb_amr_type)
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100382{
383 struct audio_device *adev = (struct audio_device *)data;
384 struct voice_session *session =
385 (struct voice_session *)adev->voice.session;
386
387 pthread_mutex_lock(&adev->lock);
388
Andreas Schneider49b9dcb2017-02-13 17:15:07 +0100389 if (session->wb_amr_type != wb_amr_type) {
390 session->wb_amr_type = wb_amr_type;
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100391
392 /* reopen the modem PCMs at the new rate */
393 if (adev->voice.in_call) {
Andreas Schneider49b9dcb2017-02-13 17:15:07 +0100394 ALOGV("%s: %s wide band voice call (WB_AMR=%d)",
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100395 __func__,
Andreas Schneider49b9dcb2017-02-13 17:15:07 +0100396 wb_amr_type > 0 ? "Enable" : "Disable",
397 wb_amr_type);
398
399 /* TODO Handle wb_amr_type=2 */
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100400
Andreas Schneidere9a44a22017-02-14 13:00:48 +0100401 /*
402 * We need stop the PCM and start with the
403 * wide band pcm_config.
404 */
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100405 stop_voice_call(adev);
406 start_voice_call(adev);
407 }
408 }
409
410 pthread_mutex_unlock(&adev->lock);
411}
412
413struct voice_session *voice_session_init(struct audio_device *adev)
414{
415 char voice_config[PROPERTY_VALUE_MAX];
Christopher N. Hesse41c9f3d2017-02-02 20:48:56 +0100416 struct voice_session *session;
417 int ret;
418
419 session = calloc(1, sizeof(struct voice_session));
420 if (session == NULL) {
421 return NULL;
422 }
423
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100424 /* Two mic control */
425 ret = property_get_bool("audio_hal.disable_two_mic", false);
426 if (ret > 0) {
427 session->two_mic_disabled = true;
428 }
429
Christopher N. Hesse41c9f3d2017-02-02 20:48:56 +0100430 /* Do this as the last step so we do not have to close it on error */
431 ret = ril_open(&session->ril);
432 if (ret != 0) {
433 free(session);
434 return NULL;
435 }
436
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100437 ret = property_get("audio_hal.force_voice_config", voice_config, "");
438 if (ret > 0) {
439 if ((strncmp(voice_config, "narrow", 6)) == 0)
Andreas Schneider49b9dcb2017-02-13 17:15:07 +0100440 session->wb_amr_type = 0;
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100441 else if ((strncmp(voice_config, "wide", 4)) == 0)
Andreas Schneider49b9dcb2017-02-13 17:15:07 +0100442 session->wb_amr_type = 1;
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100443 ALOGV("%s: Forcing voice config: %s", __func__, voice_config);
444 } else {
Christopher N. Hesse74c317d2017-02-15 09:47:20 +0100445 if (RIL_UNSOL_SNDMGR_WB_AMR_REPORT > 0) {
446 /* register callback for wideband AMR setting */
447 ret = ril_set_wb_amr_callback(&session->ril,
448 voice_session_wb_amr_callback,
449 (void *)adev);
450 if (ret != 0) {
451 ALOGE("%s: Failed to register WB_AMR callback", __func__);
452 free(session);
453 return NULL;
454 }
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100455
Christopher N. Hesse74c317d2017-02-15 09:47:20 +0100456 ALOGV("%s: Registered WB_AMR callback", __func__);
457 } else {
458 ALOGV("%s: WB_AMR callback not supported", __func__);
459 }
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100460 }
461
Christopher N. Hesse6a960022018-01-29 03:28:10 +0100462 session->vdata = &adev->voice;
463
Christopher N. Hesse41c9f3d2017-02-02 20:48:56 +0100464 return session;
465}
466
467void voice_session_deinit(struct voice_session *session)
468{
469 ril_close(&session->ril);
470 free(session);
471}