diff options
author | Andrew Dodd <atd7@cornell.edu> | 2012-11-10 14:23:08 -0500 |
---|---|---|
committer | codeworkx <codeworkx@cyanogenmod.org> | 2012-12-02 15:33:50 +0100 |
commit | cdc1a96ac05f2eb3e2fea69aa90a18ae3d5696cd (patch) | |
tree | 45b05501c3321d44b4a6e48c39f06d000911e41f /tinyalsa_audio/audio_ril_interface.c | |
parent | fd9472ca4bff6c415a1bdfc95a56e64efee5ccf7 (diff) | |
download | device_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.c | 374 |
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; +} |