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 <cutils/log.h>
20
21#include <audio_hw.h>
22#include <dlfcn.h>
23
24#ifdef __LP64__
25        #define LIB_SPEAKER_BUNDLE "/system/lib64/soundfx/libspeakerbundle.so"
26#else
27        #define LIB_SPEAKER_BUNDLE "/system/lib/soundfx/libspeakerbundle.so"
28#endif
29
30typedef void (*set_mode_t)(int);
31typedef void (*set_speaker_on_t)(bool);
32typedef void (*set_earpiece_on_t)(bool);
33typedef void (*set_voice_vol_t)(float);
34
35struct speaker_data {
36    struct audio_device *adev;
37    void *speaker_bundle;
38    set_mode_t set_mode;
39    set_speaker_on_t set_speaker_on;
40    set_earpiece_on_t set_earpiece_on;
41    set_voice_vol_t set_voice_vol;
42};
43
44static struct speaker_data* open_speaker_bundle()
45{
46    struct speaker_data *sd = calloc(1, sizeof(struct speaker_data));
47
48    sd->speaker_bundle = dlopen(LIB_SPEAKER_BUNDLE, RTLD_NOW);
49    if (sd->speaker_bundle == NULL) {
50        ALOGE("%s: DLOPEN failed for %s", __func__, LIB_SPEAKER_BUNDLE);
51        goto error;
52    } else {
53        ALOGV("%s: DLOPEN successful for %s", __func__, LIB_SPEAKER_BUNDLE);
54
55        sd->set_mode = (set_mode_t)dlsym(sd->speaker_bundle,
56                                             "set_mode");
57        if (sd->set_mode == NULL) {
58            ALOGE("%s: dlsym error %s for set_mode", __func__,
59                  dlerror());
60            goto error;
61        }
62        sd->set_speaker_on = (set_speaker_on_t)dlsym(sd->speaker_bundle,
63                                             "set_speaker_on");
64        if (sd->set_speaker_on == NULL) {
65            ALOGE("%s: dlsym error %s for set_speaker_on", __func__,
66                  dlerror());
67            goto error;
68        }
69        sd->set_earpiece_on = (set_earpiece_on_t)dlsym(sd->speaker_bundle,
70                                             "set_earpiece_on");
71        if (sd->set_earpiece_on == NULL) {
72            ALOGE("%s: dlsym error %s for set_earpiece_on", __func__,
73                  dlerror());
74            goto error;
75        }
76        sd->set_voice_vol = (set_voice_vol_t)dlsym(sd->speaker_bundle,
77                                             "set_voice_volume");
78        if (sd->set_voice_vol == NULL) {
79            ALOGE("%s: dlsym error %s for set_voice_volume",
80                  __func__, dlerror());
81            goto error;
82        }
83    }
84    return sd;
85
86error:
87    free(sd);
88    return 0;
89}
90
91static void close_speaker_bundle(struct speaker_data *sd)
92{
93    if (sd != NULL) {
94        dlclose(sd->speaker_bundle);
95        free(sd);
96        sd = NULL;
97    }
98}
99
100void *audio_extn_extspk_init(struct audio_device *adev)
101{
102    struct speaker_data *data = open_speaker_bundle();
103
104    if (data)
105        data->adev = adev;
106
107    return data;
108}
109
110void audio_extn_extspk_deinit(void *extn)
111{
112    struct speaker_data *data = (struct speaker_data*)extn;
113    close_speaker_bundle(data);
114}
115
116void audio_extn_extspk_update(void* extn)
117{
118    struct speaker_data *data = (struct speaker_data*)extn;
119
120    if (data) {
121        bool speaker_on = false;
122        bool earpiece_on = false;
123        struct listnode *node;
124        struct audio_usecase *usecase;
125        list_for_each(node, &data->adev->usecase_list) {
126            usecase = node_to_item(node, struct audio_usecase, list);
127            if (usecase->devices & AUDIO_DEVICE_OUT_EARPIECE) {
128                if(data->adev->snd_dev_ref_cnt[usecase->out_snd_device] != 0) {
129                    earpiece_on = true;
130                }
131            }
132            if (usecase->devices & AUDIO_DEVICE_OUT_SPEAKER) {
133                if(data->adev->snd_dev_ref_cnt[usecase->out_snd_device] != 0) {
134                    speaker_on = true;
135                }
136            }
137        }
138        data->set_earpiece_on(earpiece_on);
139        data->set_speaker_on(speaker_on);
140    }
141}
142
143void audio_extn_extspk_set_mode(void* extn, audio_mode_t mode)
144{
145    struct speaker_data *data = (struct speaker_data*)extn;
146
147    if (data)
148        data->set_mode(mode);
149}
150
151void audio_extn_extspk_set_voice_vol(void* extn, float vol)
152{
153    struct speaker_data *data = (struct speaker_data*)extn;
154
155    if (data)
156        data->set_voice_vol(vol);
157}
158