1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "ext_speaker"
18/*#define LOG_NDEBUG 0*/
19#include <log/log.h>
20
21#include <stdlib.h>
22#include <audio_hw.h>
23#include <dlfcn.h>
24
25#ifdef __LP64__
26#define LIB_SPEAKER_BUNDLE "/vendor/lib64/soundfx/libspeakerbundle.so"
27#else
28#define LIB_SPEAKER_BUNDLE "/vendor/lib/soundfx/libspeakerbundle.so"
29#endif
30
31typedef void (*set_mode_t)(int);
32typedef void (*set_speaker_on_t)(bool);
33typedef void (*set_earpiece_on_t)(bool);
34typedef void (*set_voice_vol_t)(float);
35
36struct speaker_data {
37    struct audio_device *adev;
38    void *speaker_bundle;
39    set_mode_t set_mode;
40    set_speaker_on_t set_speaker_on;
41    set_earpiece_on_t set_earpiece_on;
42    set_voice_vol_t set_voice_vol;
43};
44
45static struct speaker_data* open_speaker_bundle()
46{
47    struct speaker_data *sd = calloc(1, sizeof(struct speaker_data));
48
49    sd->speaker_bundle = dlopen(LIB_SPEAKER_BUNDLE, RTLD_NOW);
50    if (sd->speaker_bundle == NULL) {
51        ALOGE("%s: DLOPEN failed for %s", __func__, LIB_SPEAKER_BUNDLE);
52        goto error;
53    } else {
54        ALOGV("%s: DLOPEN successful for %s", __func__, LIB_SPEAKER_BUNDLE);
55
56        sd->set_mode = (set_mode_t)dlsym(sd->speaker_bundle,
57                                             "set_mode");
58        if (sd->set_mode == NULL) {
59            ALOGE("%s: dlsym error %s for set_mode", __func__,
60                  dlerror());
61            goto error;
62        }
63        sd->set_speaker_on = (set_speaker_on_t)dlsym(sd->speaker_bundle,
64                                             "set_speaker_on");
65        if (sd->set_speaker_on == NULL) {
66            ALOGE("%s: dlsym error %s for set_speaker_on", __func__,
67                  dlerror());
68            goto error;
69        }
70        sd->set_earpiece_on = (set_earpiece_on_t)dlsym(sd->speaker_bundle,
71                                             "set_earpiece_on");
72        if (sd->set_earpiece_on == NULL) {
73            ALOGE("%s: dlsym error %s for set_earpiece_on", __func__,
74                  dlerror());
75            goto error;
76        }
77        sd->set_voice_vol = (set_voice_vol_t)dlsym(sd->speaker_bundle,
78                                             "set_voice_volume");
79        if (sd->set_voice_vol == NULL) {
80            ALOGE("%s: dlsym error %s for set_voice_volume",
81                  __func__, dlerror());
82            goto error;
83        }
84    }
85    return sd;
86
87error:
88    free(sd);
89    return 0;
90}
91
92static void close_speaker_bundle(struct speaker_data *sd)
93{
94    if (sd != NULL) {
95        dlclose(sd->speaker_bundle);
96        free(sd);
97        sd = NULL;
98    }
99}
100
101void *audio_extn_extspk_init(struct audio_device *adev)
102{
103    struct speaker_data *data = open_speaker_bundle();
104
105    if (data)
106        data->adev = adev;
107
108    return data;
109}
110
111void audio_extn_extspk_deinit(void *extn)
112{
113    struct speaker_data *data = (struct speaker_data*)extn;
114    close_speaker_bundle(data);
115}
116
117void audio_extn_extspk_update(void* extn)
118{
119    struct speaker_data *data = (struct speaker_data*)extn;
120
121    if (data) {
122        bool speaker_on = false;
123        bool earpiece_on = false;
124        struct listnode *node;
125        struct audio_usecase *usecase;
126        list_for_each(node, &data->adev->usecase_list) {
127            usecase = node_to_item(node, struct audio_usecase, list);
128            if (usecase->devices & AUDIO_DEVICE_OUT_EARPIECE) {
129                if(data->adev->snd_dev_ref_cnt[usecase->out_snd_device] != 0) {
130                    earpiece_on = true;
131                }
132            }
133            if (usecase->devices & AUDIO_DEVICE_OUT_SPEAKER) {
134                if(data->adev->snd_dev_ref_cnt[usecase->out_snd_device] != 0) {
135                    speaker_on = true;
136                }
137            }
138        }
139        data->set_earpiece_on(earpiece_on);
140        data->set_speaker_on(speaker_on);
141    }
142}
143
144void audio_extn_extspk_set_mode(void* extn, audio_mode_t mode)
145{
146    struct speaker_data *data = (struct speaker_data*)extn;
147
148    if (data)
149        data->set_mode(mode);
150}
151
152void audio_extn_extspk_set_voice_vol(void* extn, float vol)
153{
154    struct speaker_data *data = (struct speaker_data*)extn;
155
156    if (data)
157        data->set_voice_vol(vol);
158}
159