ecc3d13410
Change-Id: Ia356da8437917be3355eba59c1df3943bb33f905
376 lines
10 KiB
C
376 lines
10 KiB
C
/*
|
|
* 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;
|
|
}
|