/*
* Copyright (C) 2014 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.
*/
#define LOG_TAG "ext_speaker"
/*#define LOG_NDEBUG 0*/
#include <cutils/log.h>
#include <stdlib.h>
#include <audio_hw.h>
#include <dlfcn.h>
#ifdef __LP64__
#define LIB_SPEAKER_BUNDLE "/system/lib64/soundfx/libspeakerbundle.so"
#else
#define LIB_SPEAKER_BUNDLE "/system/lib/soundfx/libspeakerbundle.so"
#endif
typedef void (*set_mode_t)(int);
typedef void (*set_speaker_on_t)(bool);
typedef void (*set_earpiece_on_t)(bool);
typedef void (*set_voice_vol_t)(float);
struct speaker_data {
struct audio_device *adev;
void *speaker_bundle;
set_mode_t set_mode;
set_speaker_on_t set_speaker_on;
set_earpiece_on_t set_earpiece_on;
set_voice_vol_t set_voice_vol;
};
static struct speaker_data* open_speaker_bundle()
{
struct speaker_data *sd = calloc(1, sizeof(struct speaker_data));
sd->speaker_bundle = dlopen(LIB_SPEAKER_BUNDLE, RTLD_NOW);
if (sd->speaker_bundle == NULL) {
ALOGE("%s: DLOPEN failed for %s", __func__, LIB_SPEAKER_BUNDLE);
goto error;
} else {
ALOGV("%s: DLOPEN successful for %s", __func__, LIB_SPEAKER_BUNDLE);
sd->set_mode = (set_mode_t)dlsym(sd->speaker_bundle,
"set_mode");
if (sd->set_mode == NULL) {
ALOGE("%s: dlsym error %s for set_mode", __func__,
dlerror());
goto error;
}
sd->set_speaker_on = (set_speaker_on_t)dlsym(sd->speaker_bundle,
"set_speaker_on");
if (sd->set_speaker_on == NULL) {
ALOGE("%s: dlsym error %s for set_speaker_on", __func__,
dlerror());
goto error;
}
sd->set_earpiece_on = (set_earpiece_on_t)dlsym(sd->speaker_bundle,
"set_earpiece_on");
if (sd->set_earpiece_on == NULL) {
ALOGE("%s: dlsym error %s for set_earpiece_on", __func__,
dlerror());
goto error;
}
sd->set_voice_vol = (set_voice_vol_t)dlsym(sd->speaker_bundle,
"set_voice_volume");
if (sd->set_voice_vol == NULL) {
ALOGE("%s: dlsym error %s for set_voice_volume",
__func__, dlerror());
goto error;
}
}
return sd;
error:
free(sd);
return 0;
}
static void close_speaker_bundle(struct speaker_data *sd)
{
if (sd != NULL) {
dlclose(sd->speaker_bundle);
free(sd);
sd = NULL;
}
}
void *audio_extn_extspk_init(struct audio_device *adev)
{
struct speaker_data *data = open_speaker_bundle();
if (data)
data->adev = adev;
return data;
}
void audio_extn_extspk_deinit(void *extn)
{
struct speaker_data *data = (struct speaker_data*)extn;
close_speaker_bundle(data);
}
void audio_extn_extspk_update(void* extn)
{
struct speaker_data *data = (struct speaker_data*)extn;
if (data) {
bool speaker_on = false;
bool earpiece_on = false;
struct listnode *node;
struct audio_usecase *usecase;
list_for_each(node, &data->adev->usecase_list) {
usecase = node_to_item(node, struct audio_usecase, list);
if (usecase->devices & AUDIO_DEVICE_OUT_EARPIECE) {
if(data->adev->snd_dev_ref_cnt[usecase->out_snd_device] != 0) {
earpiece_on = true;
}
}
if (usecase->devices & AUDIO_DEVICE_OUT_SPEAKER) {
if(data->adev->snd_dev_ref_cnt[usecase->out_snd_device] != 0) {
speaker_on = true;
}
}
}
data->set_earpiece_on(earpiece_on);
data->set_speaker_on(speaker_on);
}
}
void audio_extn_extspk_set_mode(void* extn, audio_mode_t mode)
{
struct speaker_data *data = (struct speaker_data*)extn;
if (data)
data->set_mode(mode);
}
void audio_extn_extspk_set_voice_vol(void* extn, float vol)
{
struct speaker_data *data = (struct speaker_data*)extn;
if (data)
data->set_voice_vol(vol);
}