3
0
replicant-device_samsung_ga.../tinyalsa_audio/audio_ril_interface.c

376 lines
10 KiB
C
Raw Normal View History

/*
* 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_set_mic_mute)(void *, enum ril_mic_mute);
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_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_mic_mute(struct tinyalsa_audio_ril_interface *ril_interface, enum ril_mic_mute state)
{
if (audio_ril_interface_connect_if_required(ril_interface))
return 0;
return _ril_set_mic_mute(ril_interface->interface, state);
}
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_set_mic_mute = dlsym(dl_handle, "SetMute");
_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_mic_mute ||
!_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;
}