blob: a4b654256ac9a9a5c090918fb082860ed04c0542 [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. Hessee4a1c592018-01-16 18:33:38 +010041/**
42 * container_of - cast a member of a structure out to the containing structure
43 * @ptr: the pointer to the member.
44 * @type: the type of the container struct this is embedded in.
45 * @member: the name of the member within the struct.
46 *
47 */
48#define container_of(ptr, type, member) ({ \
49 void *__mptr = (void *)(ptr); \
50 ((type *)((uintptr_t)__mptr - offsetof(type, member))); })
51
Christopher N. Hesse696959d2017-02-02 20:49:55 +010052static struct pcm_config pcm_config_voicecall = {
53 .channels = 2,
54 .rate = 8000,
55 .period_size = CAPTURE_PERIOD_SIZE_LOW_LATENCY,
56 .period_count = CAPTURE_PERIOD_COUNT_LOW_LATENCY,
57 .format = PCM_FORMAT_S16_LE,
58};
59
60static struct pcm_config pcm_config_voicecall_wideband = {
61 .channels = 2,
62 .rate = 16000,
63 .period_size = CAPTURE_PERIOD_SIZE_LOW_LATENCY,
64 .period_count = CAPTURE_PERIOD_COUNT_LOW_LATENCY,
65 .format = PCM_FORMAT_S16_LE,
66};
67
Andreas Schneider05bc1882017-02-09 14:03:11 +010068struct pcm_config pcm_config_voice_sco = {
69 .channels = 1,
70 .rate = SCO_DEFAULT_SAMPLING_RATE,
71 .period_size = SCO_PERIOD_SIZE,
72 .period_count = SCO_PERIOD_COUNT,
73 .format = PCM_FORMAT_S16_LE,
74};
75
Fevax51bd12c2017-03-15 10:56:39 -030076/* SCO WB and NB uses 8kHz for now, 16kHz it's on TO DO*/
77struct pcm_config pcm_config_voice_sco_wb = {
78 .channels = 1,
79 .rate = SCO_DEFAULT_SAMPLING_RATE,
80 .period_size = SCO_PERIOD_SIZE,
81 .period_count = SCO_PERIOD_COUNT,
82 .format = PCM_FORMAT_S16_LE,
83};
84
Christopher N. Hesse696959d2017-02-02 20:49:55 +010085/* Prototypes */
86int start_voice_call(struct audio_device *adev);
87int stop_voice_call(struct audio_device *adev);
88
89void set_voice_session_audio_path(struct voice_session *session)
Christopher N. Hesse41c9f3d2017-02-02 20:48:56 +010090{
Christopher N. Hesse696959d2017-02-02 20:49:55 +010091 enum _AudioPath device_type;
Andreas Schneiderd44edaa2017-02-13 16:21:35 +010092 int rc;
Christopher N. Hesse696959d2017-02-02 20:49:55 +010093
94 switch(session->out_device) {
95 case AUDIO_DEVICE_OUT_SPEAKER:
96 device_type = SOUND_AUDIO_PATH_SPEAKER;
97 break;
98 case AUDIO_DEVICE_OUT_EARPIECE:
Andreas Schneidere6286b92017-02-14 17:24:23 +010099 device_type = SOUND_AUDIO_PATH_EARPIECE;
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100100 break;
101 case AUDIO_DEVICE_OUT_WIRED_HEADSET:
102 device_type = SOUND_AUDIO_PATH_HEADSET;
103 break;
104 case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
105 device_type = SOUND_AUDIO_PATH_HEADPHONE;
106 break;
107 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
108 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
109 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
110 device_type = SOUND_AUDIO_PATH_BLUETOOTH;
111 break;
112 default:
Andreas Schneidere6286b92017-02-14 17:24:23 +0100113 /* if output device isn't supported, use earpiece by default */
114 device_type = SOUND_AUDIO_PATH_EARPIECE;
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100115 break;
116 }
117
118 ALOGV("%s: ril_set_call_audio_path(%d)", __func__, device_type);
119
Andreas Schneiderd44edaa2017-02-13 16:21:35 +0100120 rc = ril_set_call_audio_path(&session->ril, device_type);
121 ALOGE_IF(rc != 0, "Failed to set audio path: (%d)", rc);
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100122}
123
124/*
125 * This decides based on the output device, if we enable
126 * two mic control
127 */
128void prepare_voice_session(struct voice_session *session,
129 audio_devices_t active_out_devices)
130{
131 ALOGV("%s: active_out_devices: 0x%x", __func__, active_out_devices);
132
133 session->out_device = active_out_devices;
134
135 switch (session->out_device) {
136 case AUDIO_DEVICE_OUT_EARPIECE:
137 case AUDIO_DEVICE_OUT_SPEAKER:
138 session->two_mic_control = true;
139 break;
140 default:
141 session->two_mic_control = false;
142 break;
143 }
144
145 if (session->two_mic_disabled) {
146 session->two_mic_control = false;
147 }
148}
149
150/*
Andreas Schneider05bc1882017-02-09 14:03:11 +0100151 * This must be called with the hw device mutex locked, OK to hold other
152 * mutexes.
153 */
154static void stop_voice_session_bt_sco(struct voice_session *session) {
155 ALOGV("%s: Closing SCO PCMs", __func__);
156
157 if (session->pcm_sco_rx != NULL) {
158 pcm_stop(session->pcm_sco_rx);
159 pcm_close(session->pcm_sco_rx);
160 session->pcm_sco_rx = NULL;
161 }
162
163 if (session->pcm_sco_tx != NULL) {
164 pcm_stop(session->pcm_sco_tx);
165 pcm_close(session->pcm_sco_tx);
166 session->pcm_sco_tx = NULL;
167 }
168}
169
170/* must be called with the hw device mutex locked, OK to hold other mutexes */
171void start_voice_session_bt_sco(struct voice_session *session)
172{
Fevax51bd12c2017-03-15 10:56:39 -0300173 struct pcm_config *voice_sco_config;
Christopher N. Hessee4a1c592018-01-16 18:33:38 +0100174 struct voice_data *vdata = container_of(session, struct voice_data, session);
Fevax51bd12c2017-03-15 10:56:39 -0300175
Andreas Schneider05bc1882017-02-09 14:03:11 +0100176 if (session->pcm_sco_rx != NULL || session->pcm_sco_tx != NULL) {
177 ALOGW("%s: SCO PCMs already open!\n", __func__);
178 return;
179 }
180
181 ALOGV("%s: Opening SCO PCMs", __func__);
182
Christopher N. Hessee4a1c592018-01-16 18:33:38 +0100183 if (vdata->bluetooth_wb) {
Fevax51bd12c2017-03-15 10:56:39 -0300184 ALOGV("%s: pcm_config wideband", __func__);
185 voice_sco_config = &pcm_config_voice_sco_wb;
186 } else {
187 ALOGV("%s: pcm_config narrowband", __func__);
188 voice_sco_config = &pcm_config_voice_sco;
189 }
Andreas Schneider05bc1882017-02-09 14:03:11 +0100190
191 session->pcm_sco_rx = pcm_open(SOUND_CARD,
192 SOUND_PLAYBACK_SCO_DEVICE,
193 PCM_OUT|PCM_MONOTONIC,
Fevax51bd12c2017-03-15 10:56:39 -0300194 voice_sco_config);
Andreas Schneider05bc1882017-02-09 14:03:11 +0100195 if (session->pcm_sco_rx != NULL && !pcm_is_ready(session->pcm_sco_rx)) {
196 ALOGE("%s: cannot open PCM SCO RX stream: %s",
197 __func__, pcm_get_error(session->pcm_sco_rx));
198 goto err_sco_rx;
199 }
200
201 session->pcm_sco_tx = pcm_open(SOUND_CARD,
202 SOUND_CAPTURE_SCO_DEVICE,
203 PCM_IN|PCM_MONOTONIC,
Fevax51bd12c2017-03-15 10:56:39 -0300204 voice_sco_config);
Andreas Schneider05bc1882017-02-09 14:03:11 +0100205 if (session->pcm_sco_tx && !pcm_is_ready(session->pcm_sco_tx)) {
206 ALOGE("%s: cannot open PCM SCO TX stream: %s",
207 __func__, pcm_get_error(session->pcm_sco_tx));
208 goto err_sco_tx;
209 }
210
211 pcm_start(session->pcm_sco_rx);
212 pcm_start(session->pcm_sco_tx);
213
214 return;
215
216err_sco_tx:
217 pcm_close(session->pcm_sco_tx);
218 session->pcm_sco_tx = NULL;
219err_sco_rx:
220 pcm_close(session->pcm_sco_rx);
221 session->pcm_sco_rx = NULL;
222}
223/*
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100224 * This function must be called with hw device mutex locked, OK to hold other
225 * mutexes
226 */
227int start_voice_session(struct voice_session *session)
228{
229 struct pcm_config *voice_config;
230
231 if (session->pcm_voice_rx != NULL || session->pcm_voice_tx != NULL) {
232 ALOGW("%s: Voice PCMs already open!\n", __func__);
233 return 0;
234 }
235
236 ALOGV("%s: Opening voice PCMs", __func__);
237
Andreas Schneider49b9dcb2017-02-13 17:15:07 +0100238 /* TODO: Handle wb_amr=2 */
239 if (session->wb_amr_type >= 1) {
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100240 ALOGV("%s: pcm_config wideband", __func__);
241 voice_config = &pcm_config_voicecall_wideband;
242 } else {
243 ALOGV("%s: pcm_config narrowband", __func__);
244 voice_config = &pcm_config_voicecall;
245 }
246
247 /* Open modem PCM channels */
248 session->pcm_voice_rx = pcm_open(SOUND_CARD,
249 SOUND_PLAYBACK_VOICE_DEVICE,
250 PCM_OUT|PCM_MONOTONIC,
251 voice_config);
252 if (session->pcm_voice_rx != NULL && !pcm_is_ready(session->pcm_voice_rx)) {
253 ALOGE("%s: cannot open PCM voice RX stream: %s",
254 __func__,
255 pcm_get_error(session->pcm_voice_rx));
256
257 pcm_close(session->pcm_voice_tx);
258 session->pcm_voice_tx = NULL;
259
260 return -ENOMEM;
261 }
262
263 session->pcm_voice_tx = pcm_open(SOUND_CARD,
264 SOUND_CAPTURE_VOICE_DEVICE,
265 PCM_IN|PCM_MONOTONIC,
266 voice_config);
267 if (session->pcm_voice_tx != NULL && !pcm_is_ready(session->pcm_voice_tx)) {
268 ALOGE("%s: cannot open PCM voice TX stream: %s",
269 __func__,
270 pcm_get_error(session->pcm_voice_tx));
271
272 pcm_close(session->pcm_voice_rx);
273 session->pcm_voice_rx = NULL;
274
275 return -ENOMEM;
276 }
277
278 pcm_start(session->pcm_voice_rx);
279 pcm_start(session->pcm_voice_tx);
280
Andreas Schneider05bc1882017-02-09 14:03:11 +0100281 if (session->out_device & AUDIO_DEVICE_OUT_ALL_SCO) {
282 start_voice_session_bt_sco(session);
283 }
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100284
Christopher N. Hesse0fdef0c2017-02-25 01:37:56 +0100285#ifdef AUDIENCE_EARSMART_IC
286 ALOGV("%s: Enabling Audience IC", __func__);
287 es_start_voice_session(session);
288#endif
289
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100290 if (session->two_mic_control) {
291 ALOGV("%s: enabling two mic control", __func__);
292 ril_set_two_mic_control(&session->ril, AUDIENCE, TWO_MIC_SOLUTION_ON);
293 } else {
294 ALOGV("%s: disabling two mic control", __func__);
295 ril_set_two_mic_control(&session->ril, AUDIENCE, TWO_MIC_SOLUTION_OFF);
296 }
297
298 ril_set_call_clock_sync(&session->ril, SOUND_CLOCK_START);
299
300 return 0;
301}
302
303/*
304 * This function must be called with hw device mutex locked, OK to hold other
305 * mutexes
306 */
307void stop_voice_session(struct voice_session *session)
308{
309 int status = 0;
310
311 ALOGV("%s: Closing active PCMs", __func__);
312
313 if (session->pcm_voice_rx != NULL) {
314 pcm_stop(session->pcm_voice_rx);
315 pcm_close(session->pcm_voice_rx);
316 session->pcm_voice_rx = NULL;
317 status++;
318 }
319
320 if (session->pcm_voice_tx != NULL) {
321 pcm_stop(session->pcm_voice_tx);
322 pcm_close(session->pcm_voice_tx);
323 session->pcm_voice_tx = NULL;
324 status++;
325 }
326
Andreas Schneider05bc1882017-02-09 14:03:11 +0100327 if (session->out_device & AUDIO_DEVICE_OUT_ALL_SCO) {
328 stop_voice_session_bt_sco(session);
329 }
330
Christopher N. Hesse0fdef0c2017-02-25 01:37:56 +0100331#ifdef AUDIENCE_EARSMART_IC
332 ALOGV("%s: Disabling Audience IC", __func__);
333 es_stop_voice_session();
334#endif
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100335
336 session->out_device = AUDIO_DEVICE_NONE;
337
338 ALOGV("%s: Successfully closed %d active PCMs", __func__, status);
339}
340
341void set_voice_session_volume(struct voice_session *session, float volume)
342{
343 enum _SoundType sound_type;
344
345 switch (session->out_device) {
346 case AUDIO_DEVICE_OUT_EARPIECE:
347 sound_type = SOUND_TYPE_VOICE;
348 break;
349 case AUDIO_DEVICE_OUT_SPEAKER:
350 sound_type = SOUND_TYPE_SPEAKER;
351 break;
352 case AUDIO_DEVICE_OUT_WIRED_HEADSET:
353 case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
354 sound_type = SOUND_TYPE_HEADSET;
355 break;
356 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
357 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
358 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
359 case AUDIO_DEVICE_OUT_ALL_SCO:
360 sound_type = SOUND_TYPE_BTVOICE;
361 break;
362 default:
363 sound_type = SOUND_TYPE_VOICE;
364 }
365
366 ril_set_call_volume(&session->ril, sound_type, volume);
367}
368
Andreas Schneider107a8482017-02-06 12:36:31 +0100369void set_voice_session_mic_mute(struct voice_session *session, bool state)
370{
371 enum _MuteCondition mute_condition = state ? TX_MUTE : TX_UNMUTE;
372
373 ril_set_mute(&session->ril, mute_condition);
374}
375
Andreas Schneider82f32482017-02-06 09:00:48 +0100376bool voice_session_uses_twomic(struct voice_session *session)
377{
378 if (session->two_mic_disabled) {
379 return false;
380 }
381
382 return session->two_mic_control;
383}
384
Andreas Schneider59486fa2017-02-06 09:16:39 +0100385bool voice_session_uses_wideband(struct voice_session *session)
386{
Christopher N. Hessee4a1c592018-01-16 18:33:38 +0100387 struct voice_data *vdata = container_of(session, struct voice_data, session);
388
389 if (session->out_device & AUDIO_DEVICE_OUT_ALL_SCO) {
390 return vdata->bluetooth_wb;
391 }
392
Andreas Schneider49b9dcb2017-02-13 17:15:07 +0100393 return session->wb_amr_type >= 1;
Andreas Schneider59486fa2017-02-06 09:16:39 +0100394}
395
Andreas Schneider49b9dcb2017-02-13 17:15:07 +0100396static void voice_session_wb_amr_callback(void *data, int wb_amr_type)
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100397{
398 struct audio_device *adev = (struct audio_device *)data;
399 struct voice_session *session =
400 (struct voice_session *)adev->voice.session;
401
402 pthread_mutex_lock(&adev->lock);
403
Andreas Schneider49b9dcb2017-02-13 17:15:07 +0100404 if (session->wb_amr_type != wb_amr_type) {
405 session->wb_amr_type = wb_amr_type;
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100406
407 /* reopen the modem PCMs at the new rate */
408 if (adev->voice.in_call) {
Andreas Schneider49b9dcb2017-02-13 17:15:07 +0100409 ALOGV("%s: %s wide band voice call (WB_AMR=%d)",
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100410 __func__,
Andreas Schneider49b9dcb2017-02-13 17:15:07 +0100411 wb_amr_type > 0 ? "Enable" : "Disable",
412 wb_amr_type);
413
414 /* TODO Handle wb_amr_type=2 */
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100415
Andreas Schneidere9a44a22017-02-14 13:00:48 +0100416 /*
417 * We need stop the PCM and start with the
418 * wide band pcm_config.
419 */
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100420 stop_voice_call(adev);
421 start_voice_call(adev);
422 }
423 }
424
425 pthread_mutex_unlock(&adev->lock);
426}
427
428struct voice_session *voice_session_init(struct audio_device *adev)
429{
430 char voice_config[PROPERTY_VALUE_MAX];
Christopher N. Hesse41c9f3d2017-02-02 20:48:56 +0100431 struct voice_session *session;
432 int ret;
433
434 session = calloc(1, sizeof(struct voice_session));
435 if (session == NULL) {
436 return NULL;
437 }
438
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100439 /* Two mic control */
440 ret = property_get_bool("audio_hal.disable_two_mic", false);
441 if (ret > 0) {
442 session->two_mic_disabled = true;
443 }
444
Christopher N. Hesse41c9f3d2017-02-02 20:48:56 +0100445 /* Do this as the last step so we do not have to close it on error */
446 ret = ril_open(&session->ril);
447 if (ret != 0) {
448 free(session);
449 return NULL;
450 }
451
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100452 ret = property_get("audio_hal.force_voice_config", voice_config, "");
453 if (ret > 0) {
454 if ((strncmp(voice_config, "narrow", 6)) == 0)
Andreas Schneider49b9dcb2017-02-13 17:15:07 +0100455 session->wb_amr_type = 0;
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100456 else if ((strncmp(voice_config, "wide", 4)) == 0)
Andreas Schneider49b9dcb2017-02-13 17:15:07 +0100457 session->wb_amr_type = 1;
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100458 ALOGV("%s: Forcing voice config: %s", __func__, voice_config);
459 } else {
Christopher N. Hesse74c317d2017-02-15 09:47:20 +0100460 if (RIL_UNSOL_SNDMGR_WB_AMR_REPORT > 0) {
461 /* register callback for wideband AMR setting */
462 ret = ril_set_wb_amr_callback(&session->ril,
463 voice_session_wb_amr_callback,
464 (void *)adev);
465 if (ret != 0) {
466 ALOGE("%s: Failed to register WB_AMR callback", __func__);
467 free(session);
468 return NULL;
469 }
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100470
Christopher N. Hesse74c317d2017-02-15 09:47:20 +0100471 ALOGV("%s: Registered WB_AMR callback", __func__);
472 } else {
473 ALOGV("%s: WB_AMR callback not supported", __func__);
474 }
Christopher N. Hesse696959d2017-02-02 20:49:55 +0100475 }
476
Christopher N. Hesse41c9f3d2017-02-02 20:48:56 +0100477 return session;
478}
479
480void voice_session_deinit(struct voice_session *session)
481{
482 ril_close(&session->ril);
483 free(session);
484}