From 1ff6591ccffac61e070243b30c9862e5e756fb22 Mon Sep 17 00:00:00 2001 From: Simon Wilson Date: Tue, 21 Jun 2011 14:09:10 -0700 Subject: audio: voice call support - Also ensured that PRODUCT_PACKAGES is set so that the HAL is copied into the filesystem. Change-Id: I89790e5aec1d6beb7d4650316ec070503a35c436 --- audio/Android.mk | 4 +- audio/audio_hw.c | 143 ++++++++++++++++++++++++++++++++++++++++---------- audio/ril_interface.c | 86 ++++++++++++++++++++++++++++++ audio/ril_interface.h | 67 +++++++++++++++++++++++ device.mk | 3 ++ 5 files changed, 272 insertions(+), 31 deletions(-) create mode 100644 audio/ril_interface.c create mode 100644 audio/ril_interface.h diff --git a/audio/Android.mk b/audio/Android.mk index fe4d1bd..1b6e1ac 100644 --- a/audio/Android.mk +++ b/audio/Android.mk @@ -18,11 +18,11 @@ include $(CLEAR_VARS) LOCAL_MODULE := audio.primary.tuna LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw -LOCAL_SRC_FILES := audio_hw.c +LOCAL_SRC_FILES := audio_hw.c ril_interface.c LOCAL_C_INCLUDES += \ external/tinyalsa/include \ external/speex/include -LOCAL_SHARED_LIBRARIES := liblog libcutils libtinyalsa libspeexresampler +LOCAL_SHARED_LIBRARIES := liblog libcutils libtinyalsa libspeexresampler libdl LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) diff --git a/audio/audio_hw.c b/audio/audio_hw.c index 86590db..f001cb0 100644 --- a/audio/audio_hw.c +++ b/audio/audio_hw.c @@ -33,6 +33,8 @@ #include #include +#include "ril_interface.h" + /* Mixer control names */ #define MIXER_DL1_MEDIA_PLAYBACK_VOLUME "DL1 Media Playback Volume" #define MIXER_DL1_VOICE_PLAYBACK_VOLUME "DL1 Voice Playback Volume" @@ -48,6 +50,7 @@ #define MIXER_DL2_MIXER_MULTIMEDIA "DL2 Mixer Multimedia" #define MIXER_SIDETONE_MIXER_PLAYBACK "Sidetone Mixer Playback" #define MIXER_DL1_PDM_SWITCH "DL1 PDM Switch" +#define MIXER_VOICE_CAPTURE_MIXER_CAPTURE "Voice Capture Mixer Capture" #define MIXER_HS_LEFT_PLAYBACK "HS Left Playback" #define MIXER_HS_RIGHT_PLAYBACK "HS Right Playback" @@ -56,10 +59,13 @@ #define MIXER_EARPHONE_DRIVER_SWITCH "Earphone Driver Switch" #define MIXER_ANALOG_LEFT_CAPTURE_ROUTE "Analog Left Capture Route" +#define MIXER_ANALOG_RIGHT_CAPTURE_ROUTE "Analog Right Capture Route" #define MIXER_CAPTURE_PREAMPLIFIER_VOLUME "Capture Preamplifier Volume" #define MIXER_CAPTURE_VOLUME "Capture Volume" #define MIXER_AMIC_UL_VOLUME "AMIC UL Volume" #define MIXER_AUDUL_VOICE_UL_VOLUME "AUDUL Voice UL Volume" +#define MIXER_MUX_VX0 "MUX_VX0" +#define MIXER_MUX_VX1 "MUX_VX1" /* Mixer control gain and route values */ #define MIXER_ABE_GAIN_0DB 120 @@ -68,6 +74,9 @@ #define MIXER_PLAYBACK_HS_DAC "HS DAC" #define MIXER_PLAYBACK_HF_DAC "HF DAC" #define MIXER_MAIN_MIC "Main Mic" +#define MIXER_SUB_MIC "Sub Mic" +#define MIXER_AMIC0 "AMic0" +#define MIXER_AMIC1 "AMic1" /* ALSA ports for OMAP4 */ #define PORT_MM 0 @@ -171,24 +180,20 @@ struct route_setting mm_headset[] = { struct route_setting modem[] = { { - .ctl_name = MIXER_DL1_MEDIA_PLAYBACK_VOLUME, - .intval = MIXER_ABE_GAIN_MINUS1DB, - }, - { - .ctl_name = MIXER_SDT_DL_VOLUME, - .intval = MIXER_ABE_GAIN_0DB, + .ctl_name = MIXER_DL1_MIXER_VOICE, + .intval = 1, }, { - .ctl_name = MIXER_HEADSET_PLAYBACK_VOLUME, - .intval = 8, /* reasonable maximum */ + .ctl_name = MIXER_DL1_VOICE_PLAYBACK_VOLUME, + .intval = 110, }, { - .ctl_name = MIXER_DL1_MIXER_MULTIMEDIA, + .ctl_name = MIXER_SIDETONE_MIXER_PLAYBACK, .intval = 1, }, { - .ctl_name = MIXER_SIDETONE_MIXER_PLAYBACK, - .intval = 1, + .ctl_name = MIXER_SDT_DL_VOLUME, + .intval = MIXER_ABE_GAIN_0DB, }, { .ctl_name = MIXER_DL1_PDM_SWITCH, @@ -203,32 +208,41 @@ struct route_setting modem[] = { .strval = MIXER_PLAYBACK_HS_DAC, }, { - .ctl_name = MIXER_DL1_VOICE_PLAYBACK_VOLUME, - .intval = MIXER_ABE_GAIN_MINUS1DB, + .ctl_name = MIXER_HEADSET_PLAYBACK_VOLUME, + .intval = 13, /* reasonable maximum */ }, + { - .ctl_name = MIXER_DL1_MIXER_VOICE, + .ctl_name = MIXER_MUX_VX0, + .strval = MIXER_AMIC0, + }, + { + .ctl_name = MIXER_MUX_VX1, + .strval = MIXER_AMIC1, + }, + { + .ctl_name = MIXER_VOICE_CAPTURE_MIXER_CAPTURE, .intval = 1, }, { + .ctl_name = MIXER_AUDUL_VOICE_UL_VOLUME, + .intval = 110, + }, + { .ctl_name = MIXER_ANALOG_LEFT_CAPTURE_ROUTE, .strval = MIXER_MAIN_MIC, }, { + .ctl_name = MIXER_ANALOG_RIGHT_CAPTURE_ROUTE, + .strval = MIXER_SUB_MIC, + }, + { .ctl_name = MIXER_CAPTURE_PREAMPLIFIER_VOLUME, .intval = 1, }, { .ctl_name = MIXER_CAPTURE_VOLUME, - .intval = 2, - }, - { - .ctl_name = MIXER_AMIC_UL_VOLUME, - .intval = MIXER_ABE_GAIN_0DB, - }, - { - .ctl_name = MIXER_AUDUL_VOICE_UL_VOLUME, - .intval = MIXER_ABE_GAIN_0DB, + .intval = 4, }, { .ctl_name = NULL, @@ -242,7 +256,7 @@ struct route_setting earphone_switch[] = { }, { .ctl_name = MIXER_EARPHONE_PLAYBACK_VOLUME, - .intval = 10, /* reasonable maximum */ + .intval = 13, /* reasonable maximum */ }, { .ctl_name = NULL, @@ -256,6 +270,13 @@ struct tuna_audio_device { struct mixer *mixer; int mode; int out_device; + struct pcm *pcm_modem_dl; + struct pcm *pcm_modem_ul; + int in_call; + + /* RIL */ + void *ril_handle; + void *ril_client; }; struct tuna_stream_out { @@ -314,11 +335,46 @@ static int set_route_by_array(struct mixer *mixer, struct route_setting *route, static int select_route(struct tuna_audio_device *adev) { if (adev->mode == AUDIO_MODE_IN_CALL) { - /* todo: modem routing is untested */ + LOGE("AUDIO_MODE_IN_CALL"); set_route_by_array(adev->mixer, modem, 1); set_route_by_array(adev->mixer, earphone_switch, 1); + + /* Open modem PCM channels */ + if (adev->pcm_modem_dl == NULL) { + adev->pcm_modem_dl = pcm_open(0, PORT_MODEM, PCM_OUT, &pcm_config_vx); + if (!pcm_is_ready(adev->pcm_modem_dl)) { + LOGE("cannot open PCM modem DL stream: %s", pcm_get_error(adev->pcm_modem_dl)); + goto err_open_dl; + } + } + + if (adev->pcm_modem_ul == NULL) { + adev->pcm_modem_ul = pcm_open(0, PORT_MODEM, PCM_IN, &pcm_config_vx); + if (!pcm_is_ready(adev->pcm_modem_ul)) { + LOGE("cannot open PCM modem UL stream: %s", pcm_get_error(adev->pcm_modem_ul)); + goto err_open_ul; + } + } + + ril_set_call_clock_sync(adev->ril_client, SOUND_CLOCK_START); + ril_set_call_audio_path(adev->ril_client, SOUND_AUDIO_PATH_HANDSET); + + pcm_start(adev->pcm_modem_dl); + pcm_start(adev->pcm_modem_ul); + + adev->in_call = 1; } else if (adev->mode == AUDIO_MODE_NORMAL) { - set_route_by_array(adev->mixer, modem, 0); + LOGE("AUDIO_MODE_NORMAL"); + if (adev->in_call) { + set_route_by_array(adev->mixer, modem, 0); + pcm_stop(adev->pcm_modem_dl); + pcm_stop(adev->pcm_modem_ul); + pcm_close(adev->pcm_modem_dl); + pcm_close(adev->pcm_modem_ul); + adev->pcm_modem_dl = NULL; + adev->pcm_modem_ul = NULL; + adev->in_call = 0; + } switch (adev->out_device) { case AUDIO_DEVICE_OUT_SPEAKER: @@ -343,6 +399,15 @@ static int select_route(struct tuna_audio_device *adev) } return 0; + +err_open_dl: + pcm_close(adev->pcm_modem_dl); + adev->pcm_modem_dl = NULL; +err_open_ul: + pcm_close(adev->pcm_modem_ul); + adev->pcm_modem_ul = NULL; + + return -ENOMEM; } static uint32_t out_get_sample_rate(const struct audio_stream *stream) @@ -637,7 +702,15 @@ static int adev_init_check(const struct audio_hw_device *dev) static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) { - return -ENOSYS; + struct tuna_audio_device *adev = (struct tuna_audio_device *)dev; + + /* todo: this calculation comes from the Nexus S */ + int int_volume = (int)(volume * 5); + + if (adev->in_call) + ril_set_call_volume(adev->ril_client, SOUND_TYPE_VOICE, int_volume); + + return 0; } static int adev_set_master_volume(struct audio_hw_device *dev, float volume) @@ -652,6 +725,7 @@ static int adev_set_mode(struct audio_hw_device *dev, int mode) pthread_mutex_lock(&adev->lock); if (adev->mode != mode) { adev->mode = mode; + LOGE("calling select_route from %s", __func__); select_route(adev); } pthread_mutex_unlock(&adev->lock); @@ -728,6 +802,9 @@ static int adev_close(hw_device_t *device) { struct tuna_audio_device *adev = (struct tuna_audio_device *)device; + /* RIL */ + ril_close(adev->ril_handle, adev->ril_client); + mixer_close(adev->mixer); free(device); return 0; @@ -796,8 +873,16 @@ static int adev_open(const hw_module_t* module, const char* name, return -ENOMEM; } - adev->mode = AUDIO_MODE_INVALID; - adev->out_device = 0; + /* Set the default route before the PCM stream is opened */ + set_route_by_array(adev->mixer, mm_speaker, 1); + adev->mode = AUDIO_MODE_NORMAL; + adev->out_device = AUDIO_DEVICE_OUT_SPEAKER; + + adev->pcm_modem_dl = NULL; + adev->pcm_modem_ul = NULL; + + /* RIL */ + ril_open(&adev->ril_handle, &adev->ril_client); *device = &adev->device.common; diff --git a/audio/ril_interface.c b/audio/ril_interface.c new file mode 100644 index 0000000..b20d42b --- /dev/null +++ b/audio/ril_interface.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * 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. + */ + +#include + +#include + +#include "ril_interface.h" + +int ril_open(void **ril_handle, void **ril_client) +{ + void *handle; + void *client; + + handle = dlopen(RIL_CLIENT_LIBPATH, RTLD_NOW); + + if (!handle) { + LOGE("Cannot open '%s'", RIL_CLIENT_LIBPATH); + return -1; + } + + ril_open_client = dlsym(handle, "OpenClient_RILD"); + ril_close_client = dlsym(handle, "CloseClient_RILD"); + ril_connect = dlsym(handle, "Connect_RILD"); + ril_is_connected = dlsym(handle, "isConnected_RILD"); + ril_disconnect = dlsym(handle, "Disconnect_RILD"); + ril_set_call_volume = dlsym(handle, "SetCallVolume"); + ril_set_call_audio_path = dlsym(handle, "SetCallAudioPath"); + ril_set_call_clock_sync = dlsym(handle, "SetCallClockSync"); + + if (!ril_open_client || !ril_close_client || !ril_connect || + !ril_is_connected || !ril_disconnect || !ril_set_call_volume || + !ril_set_call_audio_path || !ril_set_call_clock_sync) { + LOGE("Cannot get symbols from '%s'", RIL_CLIENT_LIBPATH); + dlclose(handle); + return -1; + } + + client = ril_open_client(); + if (!client) { + LOGE("ril_open_client() failed"); + dlclose(handle); + return -1; + } + + if (ril_connect(client) != RIL_CLIENT_ERR_SUCCESS || + !ril_is_connected(client)) { + LOGE("ril_connect() failed"); + ril_close_client(client); + dlclose(handle); + return -1; + } + + *ril_handle = handle; + *ril_client = client; + return 0; +} + +int ril_close(void *ril_handle, void *ril_client) +{ + if (!ril_handle) + return -1; + + if ((ril_disconnect(ril_client) != RIL_CLIENT_ERR_SUCCESS) || + (ril_close_client(ril_client) != RIL_CLIENT_ERR_SUCCESS)) { + LOGE("ril_disconnect() or ril_close_client() failed"); + return -1; + } + + dlclose(ril_handle); + return 0; +} + diff --git a/audio/ril_interface.h b/audio/ril_interface.h new file mode 100644 index 0000000..95da631 --- /dev/null +++ b/audio/ril_interface.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * 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. + */ + +#ifndef RIL_INTERFACE_H +#define RIL_INTERFACE_H + +#define RIL_CLIENT_LIBPATH "libsecril-client.so" + +#define RIL_CLIENT_ERR_SUCCESS 0 +#define RIL_CLIENT_ERR_AGAIN 1 +#define RIL_CLIENT_ERR_INIT 2 // Client is not initialized +#define RIL_CLIENT_ERR_INVAL 3 // Invalid value +#define RIL_CLIENT_ERR_CONNECT 4 // Connection error +#define RIL_CLIENT_ERR_IO 5 // IO error +#define RIL_CLIENT_ERR_RESOURCE 6 // Resource not available +#define RIL_CLIENT_ERR_UNKNOWN 7 + +enum ril_sound_type { + SOUND_TYPE_VOICE, + SOUND_TYPE_SPEAKER, + SOUND_TYPE_HEADSET, + SOUND_TYPE_BTVOICE +}; + +enum ril_audio_path { + SOUND_AUDIO_PATH_HANDSET, + SOUND_AUDIO_PATH_HEADSET, + SOUND_AUDIO_PATH_SPEAKER, + SOUND_AUDIO_PATH_BLUETOOTH, + SOUND_AUDIO_PATH_BLUETOOTH_NO_NR, + SOUND_AUDIO_PATH_HEADPHONE +}; + +enum ril_clock_state { + SOUND_CLOCK_STOP, + SOUND_CLOCK_START +}; + +/* Function pointers */ +void *(*ril_open_client)(void); +int (*ril_close_client)(void *); +int (*ril_connect)(void *); +int (*ril_is_connected)(void *); +int (*ril_disconnect)(void *); +int (*ril_set_call_volume)(void *, enum ril_sound_type, int); +int (*ril_set_call_audio_path)(void *, enum ril_audio_path); +int (*ril_set_call_clock_sync)(void *, enum ril_clock_state); + +/* Function prototypes */ +int ril_open(void **ril_handle, void **ril_client); +int ril_close(void *ril_handle, void *ril_client); + +#endif + diff --git a/device.mk b/device.mk index 41eea45..f07f73d 100644 --- a/device.mk +++ b/device.mk @@ -35,6 +35,9 @@ PRODUCT_AAPT_CONFIG := normal hdpi xhdpi PRODUCT_PACKAGES := \ sensors.tuna +PRODUCT_PACKAGES += \ + audio.primary.tuna + PRODUCT_COPY_FILES := \ $(LOCAL_KERNEL):kernel \ device/samsung/tuna/init.tuna.rc:root/init.tuna.rc \ -- cgit v1.1