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