summaryrefslogtreecommitdiffstats
path: root/tinyalsa_audio/audio_ril_interface.c
diff options
context:
space:
mode:
authorAndrew Dodd <atd7@cornell.edu>2012-11-10 14:23:08 -0500
committercodeworkx <codeworkx@cyanogenmod.org>2012-12-02 15:33:50 +0100
commitcdc1a96ac05f2eb3e2fea69aa90a18ae3d5696cd (patch)
tree45b05501c3321d44b4a6e48c39f06d000911e41f /tinyalsa_audio/audio_ril_interface.c
parentfd9472ca4bff6c415a1bdfc95a56e64efee5ccf7 (diff)
downloaddevice_samsung_galaxys2-common-cdc1a96ac05f2eb3e2fea69aa90a18ae3d5696cd.zip
device_samsung_galaxys2-common-cdc1a96ac05f2eb3e2fea69aa90a18ae3d5696cd.tar.gz
device_samsung_galaxys2-common-cdc1a96ac05f2eb3e2fea69aa90a18ae3d5696cd.tar.bz2
mc1n2: Opensource audio HAL from Replicant
Thanks to Paul Kocialkowski of the Replicant project for this work. Original sources: https://gitorious.org/replicant/hardware_tinyalsa-audio http://git.paulk.fr/gitweb/?p=yamaha-mc1n2-audio.git;a=summary Change-Id: Ia3d89c67d64decb56e3d6518c5f382d38e5a1fa9
Diffstat (limited to 'tinyalsa_audio/audio_ril_interface.c')
-rw-r--r--tinyalsa_audio/audio_ril_interface.c374
1 files changed, 374 insertions, 0 deletions
diff --git a/tinyalsa_audio/audio_ril_interface.c b/tinyalsa_audio/audio_ril_interface.c
new file mode 100644
index 0000000..2fc14c5
--- /dev/null
+++ b/tinyalsa_audio/audio_ril_interface.c
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2012 Paul Kocialkowski <contact@paulk.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define LOG_TAG "TinyALSA-Audio RIL Interface"
+
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <dlfcn.h>
+#include <sys/time.h>
+
+#include <cutils/log.h>
+
+#include <cutils/properties.h>
+
+#define EFFECT_UUID_NULL EFFECT_UUID_NULL_RIL
+#define EFFECT_UUID_NULL_STR EFFECT_UUID_NULL_STR_RIL
+#include "audio_hw.h"
+
+#include "audio_ril_interface.h"
+
+/* 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);
+int (*_ril_set_call_twomic)(void *, enum ril_twomic_device, enum ril_twomic_enable);
+int (*_ril_register_unsolicited_handler)(void *, int, void *);
+int (*_ril_get_wb_amr)(void *, void *);
+
+#define VOLUME_STEPS_DEFAULT "5"
+#define VOLUME_STEPS_PROPERTY "ro.config.vc_call_vol_steps"
+
+static int audio_ril_interface_connect_if_required(struct tinyalsa_audio_ril_interface *ril_interface)
+{
+ if (_ril_is_connected(ril_interface->interface))
+ return 0;
+
+ if (_ril_connect(ril_interface->interface) != RIL_CLIENT_ERR_SUCCESS) {
+ ALOGE("ril_connect() failed");
+ return -1;
+ }
+
+ /* get wb amr status to set pcm samplerate depending on
+ wb amr status when ril is connected. */
+ /* FIXME: AMR */
+#if 0
+ if(_ril_get_wb_amr)
+ _ril_get_wb_amr(ril_interface->client, ril_set_wb_amr_callback);
+#endif
+
+ return 0;
+}
+
+int audio_ril_interface_set_mic_mute(struct tinyalsa_audio_ril_interface *ril_interface, bool state)
+{
+ /*
+ * If you look at the Replicant libaudio-ril-interface
+ * this function is just stubbed out there. So let's not
+ * bother with it
+ */
+ return 0;
+
+}
+
+int audio_ril_interface_set_voice_volume(struct tinyalsa_audio_ril_interface *ril_interface,
+ audio_devices_t device, float volume)
+{
+ int rc;
+
+ enum ril_sound_type sound_type;
+
+ if(ril_interface == NULL)
+ return -1;
+
+ ALOGD("%s(%d, %f)", __func__, device, volume);
+
+ pthread_mutex_lock(&ril_interface->lock);
+
+ /* Should this be returning -1 when a failure occurs? */
+ if (audio_ril_interface_connect_if_required(ril_interface))
+ return 0;
+
+ if(_ril_set_call_volume == NULL)
+ goto error;
+
+ switch((int) device) {
+ case AUDIO_DEVICE_OUT_EARPIECE:
+ sound_type = SOUND_TYPE_VOICE;
+ break;
+ case AUDIO_DEVICE_OUT_SPEAKER:
+ sound_type = SOUND_TYPE_SPEAKER;
+ break;
+ case AUDIO_DEVICE_OUT_WIRED_HEADSET:
+ case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+ sound_type = SOUND_TYPE_HEADSET;
+ break;
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
+ sound_type = SOUND_TYPE_BTVOICE;
+ break;
+ default:
+ sound_type = SOUND_TYPE_VOICE;
+ break;
+ }
+
+ rc = _ril_set_call_volume(ril_interface->interface, sound_type,
+ (int)(volume * ril_interface->volume_steps_max));
+
+ if(rc < 0) {
+ ALOGE("Failed to set RIL interface voice volume");
+ goto error;
+ }
+
+ pthread_mutex_unlock(&ril_interface->lock);
+
+ return 0;
+
+error:
+ pthread_mutex_unlock(&ril_interface->lock);
+
+ return -1;
+}
+
+int audio_ril_interface_set_route(struct tinyalsa_audio_ril_interface *ril_interface, audio_devices_t device)
+{
+ int rc;
+
+ enum ril_audio_path path;
+
+ ALOGD("%s(%d)", __func__, device);
+
+ if(ril_interface == NULL)
+ return -1;
+
+ pthread_mutex_lock(&ril_interface->lock);
+
+ /* Should this be returning -1 when a failure occurs? */
+ if (audio_ril_interface_connect_if_required(ril_interface))
+ return 0;
+
+ ril_interface->device_current = device;
+
+ if(_ril_set_call_audio_path == NULL)
+ goto error;
+
+ switch((int) device) {
+ case AUDIO_DEVICE_OUT_EARPIECE:
+ path = SOUND_AUDIO_PATH_HANDSET;
+ break;
+ case AUDIO_DEVICE_OUT_SPEAKER:
+ path = SOUND_AUDIO_PATH_SPEAKER;
+ break;
+ case AUDIO_DEVICE_OUT_WIRED_HEADSET:
+ path = SOUND_AUDIO_PATH_HEADSET;
+ break;
+ case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+ path = SOUND_AUDIO_PATH_HEADPHONE;
+ break;
+ // FIXME: Bluetooth values/path relation
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+ path = SOUND_AUDIO_PATH_BLUETOOTH;
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
+ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
+ path = SOUND_AUDIO_PATH_BLUETOOTH_NO_NR;
+ break;
+ default:
+ path = SOUND_AUDIO_PATH_HANDSET;
+ break;
+ }
+
+ rc = _ril_set_call_audio_path(ril_interface->interface,path);
+
+ if(rc < 0) {
+ ALOGE("Failed to set RIL interface route");
+ goto error;
+ }
+
+ pthread_mutex_unlock(&ril_interface->lock);
+
+ return 0;
+
+error:
+ pthread_mutex_unlock(&ril_interface->lock);
+
+ return -1;
+}
+
+int audio_ril_interface_set_twomic(struct tinyalsa_audio_ril_interface *ril_interface, enum ril_twomic_enable twomic)
+{
+ int rc;
+
+ ALOGD("%s(%d)", __func__, twomic);
+
+ if(ril_interface == NULL)
+ return -1;
+
+ pthread_mutex_lock(&ril_interface->lock);
+
+ /* Should this be returning -1 when a failure occurs? */
+ if (audio_ril_interface_connect_if_required(ril_interface))
+ return 0;
+
+ if(_ril_set_call_twomic == NULL)
+ goto error;
+
+ rc = _ril_set_call_twomic(ril_interface->interface,AUDIENCE,twomic);
+
+ if(rc < 0) {
+ ALOGE("Failed to set RIL interface route");
+ goto error;
+ }
+
+ pthread_mutex_unlock(&ril_interface->lock);
+
+ return 0;
+
+error:
+ pthread_mutex_unlock(&ril_interface->lock);
+
+ return -1;
+}
+
+/*
+ * Interface
+ */
+
+void audio_ril_interface_close(struct audio_hw_device *dev,
+ struct tinyalsa_audio_ril_interface *ril_interface)
+{
+ struct tinyalsa_audio_device *tinyalsa_audio_device;
+
+ ALOGD("%s(%p)", __func__, ril_interface);
+
+ if(ril_interface->dl_handle != NULL) {
+ if ((_ril_disconnect(ril_interface->interface) != RIL_CLIENT_ERR_SUCCESS) ||
+ (_ril_close_client(ril_interface->interface) != RIL_CLIENT_ERR_SUCCESS)) {
+ ALOGE("ril_disconnect() or ril_close_client() failed");
+ return;
+ }
+
+ dlclose(ril_interface->dl_handle);
+ ril_interface->dl_handle = NULL;
+ }
+
+ if(ril_interface != NULL)
+ free(ril_interface);
+
+ if(dev == NULL)
+ return;
+
+ tinyalsa_audio_device = (struct tinyalsa_audio_device *) dev;
+
+ tinyalsa_audio_device->ril_interface = NULL;
+}
+
+int audio_ril_interface_open(struct audio_hw_device *dev, audio_devices_t device,
+ struct tinyalsa_audio_ril_interface **ril_interface)
+{
+ struct audio_ril_interface *(*audio_ril_interface_open)(void);
+
+ struct tinyalsa_audio_device *tinyalsa_audio_device;
+ struct tinyalsa_audio_ril_interface *tinyalsa_audio_ril_interface;
+ struct audio_ril_interface *interface;
+ void *dl_handle;
+ int rc;
+
+ char property[PROPERTY_VALUE_MAX];
+
+ ALOGD("%s(%p, %d, %p)", __func__, dev, device, ril_interface);
+
+ if(dev == NULL || ril_interface == NULL)
+ return -EINVAL;
+
+ tinyalsa_audio_device = (struct tinyalsa_audio_device *) dev;
+ tinyalsa_audio_ril_interface = calloc(1, sizeof(struct tinyalsa_audio_ril_interface));
+
+ if(tinyalsa_audio_ril_interface == NULL)
+ return -ENOMEM;
+
+ tinyalsa_audio_ril_interface->device = tinyalsa_audio_device;
+ tinyalsa_audio_device->ril_interface = tinyalsa_audio_ril_interface;
+
+ dl_handle = dlopen(RIL_CLIENT_LIBPATH, RTLD_NOW);
+ if(dl_handle == NULL) {
+ ALOGE("Unable to dlopen lib: %s", RIL_CLIENT_LIBPATH);
+ goto error_interface;
+ }
+
+ _ril_open_client = dlsym(dl_handle, "OpenClient_RILD");
+ _ril_close_client = dlsym(dl_handle, "CloseClient_RILD");
+ _ril_connect = dlsym(dl_handle, "Connect_RILD");
+ _ril_is_connected = dlsym(dl_handle, "isConnected_RILD");
+ _ril_disconnect = dlsym(dl_handle, "Disconnect_RILD");
+ _ril_set_call_volume = dlsym(dl_handle, "SetCallVolume");
+ _ril_set_call_audio_path = dlsym(dl_handle, "SetCallAudioPath");
+ _ril_set_call_clock_sync = dlsym(dl_handle, "SetCallClockSync");
+ _ril_set_call_twomic = dlsym(dl_handle, "SetTwoMicControl");
+
+ _ril_register_unsolicited_handler = dlsym(dl_handle,
+ "RegisterUnsolicitedHandler");
+ /* since this function is not supported in all RILs, don't require it */
+ _ril_get_wb_amr = dlsym(dl_handle, "GetWB_AMR");
+
+ 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 ||
+ !_ril_register_unsolicited_handler || !_ril_set_call_twomic) {
+ ALOGE("Cannot get symbols from '%s'", RIL_CLIENT_LIBPATH);
+ dlclose(dl_handle);
+ goto error_interface;
+ }
+
+ interface = _ril_open_client();
+ if(interface == NULL) {
+ ALOGE("Unable to open audio ril interface");
+ goto error_interface;
+ }
+
+ tinyalsa_audio_ril_interface->interface = interface;
+ tinyalsa_audio_ril_interface->dl_handle = dl_handle;
+
+ property_get(VOLUME_STEPS_PROPERTY, property, VOLUME_STEPS_DEFAULT);
+ tinyalsa_audio_ril_interface->volume_steps_max = atoi(property);
+ /* this catches the case where VOLUME_STEPS_PROPERTY does not contain
+ an integer */
+ if (tinyalsa_audio_ril_interface->volume_steps_max == 0)
+ tinyalsa_audio_ril_interface->volume_steps_max = atoi(VOLUME_STEPS_DEFAULT);
+
+ if(device) {
+ tinyalsa_audio_ril_interface->device_current = device;
+ audio_ril_interface_set_route(tinyalsa_audio_ril_interface, device);
+ }
+
+ *ril_interface = tinyalsa_audio_ril_interface;
+
+ return 0;
+
+error_interface:
+ *ril_interface = NULL;
+ free(tinyalsa_audio_ril_interface);
+ tinyalsa_audio_device->ril_interface = NULL;
+
+ if(dl_handle != NULL)
+ dlclose(dl_handle);
+
+ return -1;
+}