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 <stdlib.h>
22 #include <audio_hw.h>
23 #include <dlfcn.h>
24 
25 #ifdef __LP64__
26 #define LIB_SPEAKER_BUNDLE "/system/lib64/soundfx/libspeakerbundle.so"
27 #else
28 #define LIB_SPEAKER_BUNDLE "/system/lib/soundfx/libspeakerbundle.so"
29 #endif
30 
31 typedef void (*set_mode_t)(int);
32 typedef void (*set_speaker_on_t)(bool);
33 typedef void (*set_earpiece_on_t)(bool);
34 typedef void (*set_voice_vol_t)(float);
35 
36 struct 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 
open_speaker_bundle()45 static 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 
87 error:
88     free(sd);
89     return 0;
90 }
91 
close_speaker_bundle(struct speaker_data * sd)92 static 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 
audio_extn_extspk_init(struct audio_device * adev)101 void *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 
audio_extn_extspk_deinit(void * extn)111 void audio_extn_extspk_deinit(void *extn)
112 {
113     struct speaker_data *data = (struct speaker_data*)extn;
114     close_speaker_bundle(data);
115 }
116 
audio_extn_extspk_update(void * extn)117 void 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 
audio_extn_extspk_set_mode(void * extn,audio_mode_t mode)144 void 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 
audio_extn_extspk_set_voice_vol(void * extn,float vol)152 void 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