1 /* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29 #define LOG_TAG "listen_hal_loader"
30 /* #define LOG_NDEBUG 0 */
31 /* #define LOG_NDDEBUG 0 */
32 #include <stdbool.h>
33 #include <stdlib.h>
34 #include <dlfcn.h>
35 #include <cutils/log.h>
36 #ifdef AUDIO_LISTEN_ENABLED
37 #include <listen_types.h>
38 #endif
39 #include "audio_hw.h"
40 #include "audio_extn.h"
41 #include "platform.h"
42 #include "platform_api.h"
43
44
45 #ifdef AUDIO_LISTEN_ENABLED
46
47 #define LIB_LISTEN_LOADER "/vendor/lib/liblistenhardware.so"
48
49 #define LISTEN_LOAD_SYMBOLS(dev, func_p, func_type, symbol) \
50 {\
51 dev->func_p = (func_type)dlsym(dev->lib_handle,#symbol);\
52 if (dev->func_p == NULL) {\
53 ALOGE("%s: dlsym error %s for %s",\
54 __func__, dlerror(), #symbol);\
55 free(dev);\
56 dev = NULL;\
57 return -EINVAL;\
58 }\
59 }
60
61
62 typedef int (*create_listen_hw_t)(unsigned int snd_card,
63 struct audio_route *audio_route);
64 typedef void (*destroy_listen_hw_t)();
65
66 typedef int (*open_listen_session_t)(struct audio_hw_device *,
67 struct listen_open_params*,
68 struct listen_session**);
69
70 typedef int (*close_listen_session_t)(struct audio_hw_device *dev,
71 struct listen_session* handle);
72
73 typedef int (*set_mad_observer_t)(struct audio_hw_device *dev,
74 listen_callback_t cb_func);
75
76 typedef int (*listen_set_parameters_t)(struct audio_hw_device *dev,
77 const char *kv_pairs);
78 typedef char* (*get_parameters_t)(const struct audio_hw_device *dev,
79 const char *keys);
80 typedef void (*listen_notify_event_t)(event_type_t event_type);
81
82 struct listen_audio_device {
83 void *lib_handle;
84 struct audio_device *adev;
85
86 create_listen_hw_t create_listen_hw;
87 destroy_listen_hw_t destroy_listen_hw;
88 open_listen_session_t open_listen_session;
89 close_listen_session_t close_listen_session;
90 set_mad_observer_t set_mad_observer;
91 listen_set_parameters_t listen_set_parameters;
92 get_parameters_t get_parameters;
93 listen_notify_event_t notify_event;
94 };
95
96 static struct listen_audio_device *listen_dev;
97
audio_extn_listen_update_device_status(snd_device_t snd_device,listen_event_type_t event)98 void audio_extn_listen_update_device_status(snd_device_t snd_device,
99 listen_event_type_t event)
100 {
101 bool raise_event = false;
102 int device_type = -1;
103
104 if (snd_device >= SND_DEVICE_OUT_BEGIN &&
105 snd_device < SND_DEVICE_OUT_END)
106 device_type = PCM_PLAYBACK;
107 else if (snd_device >= SND_DEVICE_IN_BEGIN &&
108 snd_device < SND_DEVICE_IN_END)
109 device_type = PCM_CAPTURE;
110 else {
111 ALOGE("%s: invalid device 0x%x, for event %d",
112 __func__, snd_device, event);
113 return;
114 }
115
116 if (listen_dev) {
117 raise_event = platform_listen_device_needs_event(snd_device);
118 ALOGI("%s(): device 0x%x of type %d for Event %d, with Raise=%d",
119 __func__, snd_device, device_type, event, raise_event);
120 if (raise_event && (device_type == PCM_CAPTURE)) {
121 switch(event) {
122 case LISTEN_EVENT_SND_DEVICE_FREE:
123 listen_dev->notify_event(AUDIO_DEVICE_IN_INACTIVE);
124 break;
125 case LISTEN_EVENT_SND_DEVICE_BUSY:
126 listen_dev->notify_event(AUDIO_DEVICE_IN_ACTIVE);
127 break;
128 default:
129 ALOGW("%s:invalid event %d for device 0x%x",
130 __func__, event, snd_device);
131 }
132 }/*Events for output device, if required can be placed here in else*/
133 }
134 }
135
audio_extn_listen_update_stream_status(struct audio_usecase * uc_info,listen_event_type_t event)136 void audio_extn_listen_update_stream_status(struct audio_usecase *uc_info,
137 listen_event_type_t event)
138 {
139 bool raise_event = false;
140 audio_usecase_t uc_id;
141 int usecase_type = -1;
142
143 if (uc_info == NULL) {
144 ALOGE("%s: usecase is NULL!!!", __func__);
145 return;
146 }
147 uc_id = uc_info->id;
148 usecase_type = uc_info->type;
149
150 if (listen_dev) {
151 raise_event = platform_listen_usecase_needs_event(uc_id);
152 ALOGI("%s(): uc_id %d of type %d for Event %d, with Raise=%d",
153 __func__, uc_id, usecase_type, event, raise_event);
154 if (raise_event && (usecase_type == PCM_PLAYBACK)) {
155 switch(event) {
156 case LISTEN_EVENT_STREAM_FREE:
157 listen_dev->notify_event(AUDIO_STREAM_OUT_INACTIVE);
158 break;
159 case LISTEN_EVENT_STREAM_BUSY:
160 listen_dev->notify_event(AUDIO_STREAM_OUT_ACTIVE);
161 break;
162 default:
163 ALOGW("%s:invalid event %d, for usecase %d",
164 __func__, event, uc_id);
165 }
166 }/*Events for capture usecase, if required can be placed here in else*/
167 }
168 }
169
audio_extn_listen_set_parameters(struct audio_device * adev,struct str_parms * parms)170 void audio_extn_listen_set_parameters(struct audio_device *adev,
171 struct str_parms *parms)
172 {
173 ALOGV("%s: enter", __func__);
174 if (listen_dev) {
175 char *kv_pairs = str_parms_to_str(parms);
176 ALOGV_IF(kv_pairs != NULL, "%s: %s", __func__, kv_pairs);
177 listen_dev->listen_set_parameters(&adev->device, kv_pairs);
178 free(kv_pairs);
179 }
180
181 return;
182 }
183
audio_extn_listen_init(struct audio_device * adev,unsigned int snd_card)184 int audio_extn_listen_init(struct audio_device *adev, unsigned int snd_card)
185 {
186 int ret;
187 void *lib_handle;
188
189 ALOGI("%s: Enter", __func__);
190
191 lib_handle = dlopen(LIB_LISTEN_LOADER, RTLD_NOW);
192
193 if (lib_handle == NULL) {
194 ALOGE("%s: DLOPEN failed for %s. error = %s", __func__, LIB_LISTEN_LOADER,
195 dlerror());
196 return -EINVAL;
197 } else {
198 ALOGI("%s: DLOPEN successful for %s", __func__, LIB_LISTEN_LOADER);
199
200 listen_dev = (struct listen_audio_device*)
201 calloc(1, sizeof(struct listen_audio_device));
202
203 if (!listen_dev) {
204 ALOGE("failed to allocate listen_dev mem");
205 return -ENOMEM;
206 }
207
208 listen_dev->lib_handle = lib_handle;
209 listen_dev->adev = adev;
210
211 LISTEN_LOAD_SYMBOLS(listen_dev, create_listen_hw,
212 create_listen_hw_t, create_listen_hw);
213
214 LISTEN_LOAD_SYMBOLS(listen_dev, destroy_listen_hw,
215 destroy_listen_hw_t, destroy_listen_hw);
216
217 LISTEN_LOAD_SYMBOLS(listen_dev, open_listen_session,
218 open_listen_session_t, open_listen_session);
219
220 adev->device.open_listen_session = listen_dev->open_listen_session;
221
222 LISTEN_LOAD_SYMBOLS(listen_dev, close_listen_session,
223 close_listen_session_t, close_listen_session);
224
225 adev->device.close_listen_session = listen_dev->close_listen_session;
226
227 LISTEN_LOAD_SYMBOLS(listen_dev, set_mad_observer,
228 set_mad_observer_t, set_mad_observer);
229
230 adev->device.set_mad_observer = listen_dev->set_mad_observer;
231
232 LISTEN_LOAD_SYMBOLS(listen_dev, listen_set_parameters,
233 listen_set_parameters_t, listen_hw_set_parameters);
234
235 adev->device.listen_set_parameters = listen_dev->listen_set_parameters;
236
237 LISTEN_LOAD_SYMBOLS(listen_dev, get_parameters,
238 get_parameters_t, listen_hw_get_parameters);
239
240 LISTEN_LOAD_SYMBOLS(listen_dev, notify_event,
241 listen_notify_event_t, listen_hw_notify_event);
242
243 listen_dev->create_listen_hw(snd_card, adev->audio_route);
244 }
245 return 0;
246 }
247
audio_extn_listen_deinit(struct audio_device * adev)248 void audio_extn_listen_deinit(struct audio_device *adev)
249 {
250 ALOGI("%s: Enter", __func__);
251
252 if (listen_dev && (listen_dev->adev == adev) && listen_dev->lib_handle) {
253 listen_dev->destroy_listen_hw();
254 dlclose(listen_dev->lib_handle);
255 free(listen_dev);
256 listen_dev = NULL;
257 }
258 }
259
260 #endif /* AUDIO_LISTEN_ENABLED */
261