summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
authorSimon Wilson <simonwilson@google.com>2011-06-21 14:09:10 -0700
committerSimon Wilson <simonwilson@google.com>2011-06-24 13:36:54 -0700
commit1ff6591ccffac61e070243b30c9862e5e756fb22 (patch)
treeb3de4756190cfe39252bab35576670982f14989a /audio
parentbe939764f20a889cb0172d9d2f5d93e1424a00a1 (diff)
downloaddevice_samsung_tuna-1ff6591ccffac61e070243b30c9862e5e756fb22.zip
device_samsung_tuna-1ff6591ccffac61e070243b30c9862e5e756fb22.tar.gz
device_samsung_tuna-1ff6591ccffac61e070243b30c9862e5e756fb22.tar.bz2
audio: voice call support
- Also ensured that PRODUCT_PACKAGES is set so that the HAL is copied into the filesystem. Change-Id: I89790e5aec1d6beb7d4650316ec070503a35c436
Diffstat (limited to 'audio')
-rw-r--r--audio/Android.mk4
-rw-r--r--audio/audio_hw.c143
-rw-r--r--audio/ril_interface.c86
-rw-r--r--audio/ril_interface.h67
4 files changed, 269 insertions, 31 deletions
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 <tinyalsa/asoundlib.h>
#include <speex/speex_resampler.h>
+#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 <dlfcn.h>
+
+#include <utils/Log.h>
+
+#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
+