1 /*
2 * Copyright (C) 2016 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 "audio_hw_sndmonitor"
18 /*#define LOG_NDEBUG 0*/
19 #define LOG_NDDEBUG 0
20
21 /* monitor sound card, cpe state
22
23 audio_dev registers for a callback from this module in adev_open
24 Each stream in audio_hal registers for a callback in
25 adev_open_*_stream.
26
27 A thread is spawned to poll() on sound card state files in /proc.
28 On observing a sound card state change, this thread invokes the
29 callbacks registered.
30
31 Callbacks are deregistered in adev_close_*_stream and adev_close
32 */
33 #include <stdlib.h>
34 #include <dirent.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <sys/stat.h>
38 #include <sys/poll.h>
39 #include <cutils/list.h>
40 #include <cutils/hashmap.h>
41 #include <cutils/log.h>
42 #include <cutils/str_parms.h>
43 #include <ctype.h>
44
45 #include "audio_hw.h"
46 #include "audio_extn.h"
47
48 //#define MONITOR_DEVICE_EVENTS
49 #define CPE_MAGIC_NUM 0x2000
50 #define MAX_CPE_SLEEP_RETRY 2
51 #define CPE_SLEEP_WAIT 100
52
53 #define MAX_SLEEP_RETRY 100
54 #define AUDIO_INIT_SLEEP_WAIT 100 /* 100 ms */
55
56 #define AUDIO_PARAMETER_KEY_EXT_AUDIO_DEVICE "ext_audio_device"
57
58 typedef enum {
59 audio_event_on,
60 audio_event_off
61 } audio_event_status;
62
63 typedef struct {
64 int card;
65 int fd;
66 struct listnode node; // membership in sndcards list
67 card_status_t status;
68 } sndcard_t;
69
70 typedef struct {
71 char * dev;
72 int fd;
73 int status;
74 struct listnode node; // membership in deviceevents list;
75 } dev_event_t;
76
77 typedef void (* notifyfn)(const void * target, const char * msg);
78
79 typedef struct {
80 const void * target;
81 notifyfn notify;
82 struct listnode cards;
83 unsigned int num_cards;
84 struct listnode dev_events;
85 unsigned int num_dev_events;
86 pthread_t monitor_thread;
87 int intpipe[2];
88 Hashmap * listeners; // from stream * -> callback func
89 bool initcheck;
90 } sndmonitor_state_t;
91
92 static sndmonitor_state_t sndmonitor;
93
read_state(int fd)94 static char * read_state(int fd)
95 {
96 struct stat buf;
97 if (fstat(fd, &buf) < 0)
98 return NULL;
99
100 off_t pos = lseek(fd, 0, SEEK_CUR);
101 off_t avail = buf.st_size - pos;
102 if (avail <= 0) {
103 ALOGD("avail %ld", avail);
104 return NULL;
105 }
106
107 char * state = (char *)calloc(avail+1, sizeof(char));
108 if (!state)
109 return NULL;
110
111 ssize_t bytes=read(fd, state, avail);
112 if (bytes <= 0)
113 return NULL;
114
115 // trim trailing whitespace
116 while (bytes && isspace(*(state+bytes-1))) {
117 *(state + bytes - 1) = '\0';
118 --bytes;
119 }
120 lseek(fd, 0, SEEK_SET);
121 return state;
122 }
123
add_new_sndcard(int card,int fd)124 static int add_new_sndcard(int card, int fd)
125 {
126 sndcard_t * s = (sndcard_t *)calloc(sizeof(sndcard_t), 1);
127
128 if (!s)
129 return -1;
130
131 s->card = card;
132 s->fd = fd; // dup?
133
134 char * state = read_state(fd);
135 bool online = state && !strcmp(state, "ONLINE");
136
137 ALOGV("card %d initial state %s %d", card, state, online);
138
139 if (state)
140 free(state);
141
142 s->status = online ? CARD_STATUS_ONLINE : CARD_STATUS_OFFLINE;
143 list_add_tail(&sndmonitor.cards, &s->node);
144 return 0;
145 }
146
enum_sndcards()147 static int enum_sndcards()
148 {
149 const char* cards = "/proc/asound/cards";
150 int tries = 10;
151 char *line = NULL;
152 size_t len = 0;
153 ssize_t bytes_read;
154 char path[128] = {0};
155 char *ptr, *saveptr;
156 int line_no=0;
157 unsigned int num_cards=0, num_cpe=0;
158 FILE *fp;
159 int fd, ret;
160
161 while (--tries) {
162 if ((fp = fopen(cards, "r")) == NULL) {
163 ALOGE("Cannot open %s file to get list of sound cards", cards);
164 usleep(100000);
165 continue;
166 }
167 break;
168 }
169
170 if (!tries)
171 return -ENODEV;
172
173 while ((bytes_read = getline(&line, &len, fp) != -1)) {
174 // skip every other line to to match
175 // the output format of /proc/asound/cards
176 if (line_no++ % 2)
177 continue;
178
179 ptr = strtok_r(line, " [", &saveptr);
180 if (!ptr)
181 continue;
182
183 snprintf(path, sizeof(path), "/proc/asound/card%s/state", ptr);
184 ALOGV("Opening sound card state : %s", path);
185
186 fd = open(path, O_RDONLY);
187 if (fd == -1) {
188 ALOGE("Open %s failed : %s", path, strerror(errno));
189 continue;
190 }
191
192 ret = add_new_sndcard(atoi(ptr), fd);
193 if (ret != 0)
194 continue;
195
196 num_cards++;
197
198 // query cpe state for this card as well
199 tries=MAX_CPE_SLEEP_RETRY;
200 snprintf(path, sizeof(path), "/proc/asound/card%s/cpe0_state", ptr);
201
202 if (access(path, R_OK) < 0) {
203 ALOGW("access %s failed w/ err %s", path, strerror(errno));
204 continue;
205 }
206
207 ALOGV("Open cpe state card state %s", path);
208 while (--tries) {
209 if ((fd = open(path, O_RDONLY)) < 0) {
210 ALOGW("Open cpe state card state failed, retry : %s", path);
211 usleep(CPE_SLEEP_WAIT*1000);
212 continue;
213 }
214 break;
215 }
216
217 if (!tries)
218 continue;
219
220 ret = add_new_sndcard(CPE_MAGIC_NUM+num_cpe, fd);
221 if (ret != 0)
222 continue;
223
224 num_cpe++;
225 num_cards++;
226 }
227 if (line)
228 free(line);
229 fclose(fp);
230 ALOGV("sndmonitor registerer num_cards %d", num_cards);
231 sndmonitor.num_cards = num_cards;
232 return num_cards ? 0 : -1;
233 }
234
free_sndcards()235 static void free_sndcards()
236 {
237 while (!list_empty(&sndmonitor.cards)) {
238 struct listnode * n = list_head(&sndmonitor.cards);
239 sndcard_t * s = node_to_item(n, sndcard_t, node);
240 list_remove(n);
241 close(s->fd);
242 free(s);
243 }
244 }
245
add_new_dev_event(char * d_name,int fd)246 static int add_new_dev_event(char * d_name, int fd)
247 {
248 dev_event_t * d = (dev_event_t *)calloc(sizeof(dev_event_t), 1);
249
250 if (!d)
251 return -1;
252
253 d->dev = strdup(d_name);
254 d->fd = fd;
255 list_add_tail(&sndmonitor.dev_events, &d->node);
256 return 0;
257 }
258
enum_dev_events()259 static int enum_dev_events()
260 {
261 const char* events_dir = "/sys/class/switch/";
262 DIR *dp;
263 struct dirent* in_file;
264 int fd;
265 char path[128] = {0};
266 unsigned int num_dev_events = 0;
267
268 if ((dp = opendir(events_dir)) == NULL) {
269 ALOGE("Cannot open switch directory %s err %s",
270 events_dir, strerror(errno));
271 return -1;
272 }
273
274 while ((in_file = readdir(dp)) != NULL) {
275 if (!strstr(in_file->d_name, "qc_"))
276 continue;
277
278 snprintf(path, sizeof(path), "%s/%s/state",
279 events_dir, in_file->d_name);
280
281 ALOGV("Opening audio dev event state : %s ", path);
282 fd = open(path, O_RDONLY);
283 if (fd == -1) {
284 ALOGE("Open %s failed : %s", path, strerror(errno));
285 } else {
286 if (!add_new_dev_event(in_file->d_name, fd))
287 num_dev_events++;
288 }
289 }
290 closedir(dp);
291 sndmonitor.num_dev_events = num_dev_events;
292 return num_dev_events ? 0 : -1;
293 }
294
free_dev_events()295 static void free_dev_events()
296 {
297 while (!list_empty(&sndmonitor.dev_events)) {
298 struct listnode * n = list_head(&sndmonitor.dev_events);
299 dev_event_t * d = node_to_item(n, dev_event_t, node);
300 list_remove(n);
301 close(d->fd);
302 free(d->dev);
303 free(d);
304 }
305 }
306
notify(const struct str_parms * params)307 static int notify(const struct str_parms * params)
308 {
309 if (!params)
310 return -1;
311
312 char * str = str_parms_to_str((struct str_parms *)params);
313
314 if (!str)
315 return -1;
316
317 if (sndmonitor.notify)
318 sndmonitor.notify(sndmonitor.target, str);
319
320 ALOGV("%s", str);
321 free(str);
322 return 0;
323 }
324
on_dev_event(dev_event_t * dev_event)325 int on_dev_event(dev_event_t * dev_event)
326 {
327 char state_buf[2];
328 if (read(dev_event->fd, state_buf, 1) <= 0)
329 return -1;
330
331 lseek(dev_event->fd, 0, SEEK_SET);
332 state_buf[1]='\0';
333 if (atoi(state_buf) == dev_event->status)
334 return 0;
335
336 dev_event->status = atoi(state_buf);
337
338 struct str_parms * params = str_parms_create();
339
340 if (!params)
341 return -1;
342
343 char val[32] = {0};
344 snprintf(val, sizeof(val), "%s,%s", dev_event->dev,
345 dev_event->status ? "ON" : "OFF");
346
347 if (str_parms_add_str(params, AUDIO_PARAMETER_KEY_EXT_AUDIO_DEVICE, val) < 0)
348 return -1;
349
350 int ret = notify(params);
351 str_parms_destroy(params);
352 return ret;
353 }
354
on_sndcard_state_update(sndcard_t * s)355 bool on_sndcard_state_update(sndcard_t * s)
356 {
357 char rd_buf[9]={0};
358 card_status_t status;
359
360 if (read(s->fd, rd_buf, 8) <= 0)
361 return -1;
362
363 rd_buf[8] = '\0';
364 lseek(s->fd, 0, SEEK_SET);
365
366 ALOGV("card num %d, new state %s", s->card, rd_buf);
367
368 bool is_cpe = (s->card >= CPE_MAGIC_NUM);
369 if (strstr(rd_buf, "OFFLINE"))
370 status = CARD_STATUS_OFFLINE;
371 else if (strstr(rd_buf, "ONLINE"))
372 status = CARD_STATUS_ONLINE;
373 else {
374 ALOGE("unknown state");
375 return 0;
376 }
377
378 if (status == s->status) // no change
379 return 0;
380
381 s->status = status;
382
383 struct str_parms * params = str_parms_create();
384
385 if (!params)
386 return -1;
387
388 char val[32] = {0};
389 // cpe actual card num is (card - MAGIC_NUM). so subtract accordingly
390 snprintf(val, sizeof(val), "%d,%s", s->card - (is_cpe ? CPE_MAGIC_NUM : 0),
391 status == CARD_STATUS_ONLINE ? "ONLINE" : "OFFLINE");
392
393 if (str_parms_add_str(params, is_cpe ? "CPE_STATUS" : "SND_CARD_STATUS",
394 val) < 0)
395 return -1;
396
397 int ret = notify(params);
398 str_parms_destroy(params);
399 return ret;
400 }
401
monitor_thread_loop(void * args __unused)402 void * monitor_thread_loop(void * args __unused)
403 {
404 ALOGV("Start threadLoop()");
405 unsigned int num_poll_fds = sndmonitor.num_cards +
406 sndmonitor.num_dev_events + 1/*pipe*/;
407 struct pollfd * pfd = (struct pollfd *)calloc(sizeof(struct pollfd),
408 num_poll_fds);
409 if (!pfd)
410 return NULL;
411
412 pfd[0].fd = sndmonitor.intpipe[0];
413 pfd[0].events = POLLPRI|POLLIN;
414
415 int i=1;
416 struct listnode *node;
417 list_for_each(node, &sndmonitor.cards) {
418 sndcard_t * s = node_to_item(node, sndcard_t, node);
419 pfd[i].fd = s->fd;
420 pfd[i].events = POLLPRI;
421 ++i;
422 }
423
424 list_for_each(node, &sndmonitor.dev_events) {
425 dev_event_t * d = node_to_item(node, dev_event_t, node);
426 pfd[i].fd = d->fd;
427 pfd[i].events = POLLPRI;
428 ++i;
429 }
430
431 while (1) {
432 if (poll(pfd, num_poll_fds, -1) < 0) {
433 int errno_ = errno;
434 ALOGE("poll() failed w/ err %s", strerror(errno));
435 switch (errno_) {
436 case EINTR:
437 case ENOMEM:
438 sleep(2);
439 continue;
440 default:
441 /* above errors can be caused due to current system
442 state .. any other error is not expected */
443 LOG_ALWAYS_FATAL("unxpected poll() system call failure");
444 break;
445 }
446 }
447 ALOGV("out of poll()");
448
449 #define READY_TO_READ(p) ((p)->revents & (POLLIN|POLLPRI))
450 #define ERROR_IN_FD(p) ((p)->revents & (POLLERR|POLLHUP|POLLNVAL))
451
452 // check if requested to exit
453 if (READY_TO_READ(&pfd[0])) {
454 char buf[2]={0};
455 read(pfd[0].fd, buf, 1);
456 if (!strcmp(buf, "Q"))
457 break;
458 } else if (ERROR_IN_FD(&pfd[0])) {
459 // do not consider for poll again
460 // POLLERR - can this happen?
461 // POLLHUP - adev must not close pipe
462 // POLLNVAL - fd is valid
463 LOG_ALWAYS_FATAL("unxpected error in pipe poll fd 0x%x",
464 pfd[0].revents);
465 pfd[0].fd *= -1;
466 }
467
468 i=1;
469 list_for_each(node, &sndmonitor.cards) {
470 sndcard_t * s = node_to_item(node, sndcard_t, node);
471 if (READY_TO_READ(&pfd[i]))
472 on_sndcard_state_update(s);
473 else if (ERROR_IN_FD(&pfd[i])) {
474 // do not consider for poll again
475 // POLLERR - can this happen as we are reading from a fs?
476 // POLLHUP - not valid for cardN/state
477 // POLLNVAL - fd is valid
478 LOG_ALWAYS_FATAL("unxpected error in card poll fd 0x%x",
479 pfd[i].revents);
480 pfd[i].fd *= -1;
481 }
482 ++i;
483 }
484
485 list_for_each(node, &sndmonitor.dev_events) {
486 dev_event_t * d = node_to_item(node, dev_event_t, node);
487 if (READY_TO_READ(&pfd[i]))
488 on_dev_event(d);
489 else if (ERROR_IN_FD(&pfd[i])) {
490 // do not consider for poll again
491 // POLLERR - can this happen as we are reading from a fs?
492 // POLLHUP - not valid for switch/state
493 // POLLNVAL - fd is valid
494 LOG_ALWAYS_FATAL("unxpected error in dev poll fd 0x%x",
495 pfd[i].revents);
496 pfd[i].fd *= -1;
497 }
498 ++i;
499 }
500 }
501
502 return NULL;
503 }
504
505 // ---- listener static APIs ---- //
hashfn(void * key)506 static int hashfn(void * key)
507 {
508 return (int)key;
509 }
510
hasheq(void * key1,void * key2)511 static bool hasheq(void * key1, void *key2)
512 {
513 return key1 == key2;
514 }
515
snd_cb(void * key,void * value,void * context)516 static bool snd_cb(void* key, void* value, void* context)
517 {
518 snd_mon_cb cb = (snd_mon_cb)value;
519 cb(key, context);
520 return true;
521 }
522
snd_mon_update(const void * target __unused,const char * msg)523 static void snd_mon_update(const void * target __unused, const char * msg)
524 {
525 // target can be used to check if this message is intended for the
526 // recipient or not. (using some statically saved state)
527
528 struct str_parms *parms = str_parms_create_str(msg);
529
530 if (!parms)
531 return;
532
533 hashmapLock(sndmonitor.listeners);
534 hashmapForEach(sndmonitor.listeners, snd_cb, parms);
535 hashmapUnlock(sndmonitor.listeners);
536
537 str_parms_destroy(parms);
538 }
539
listeners_init()540 static int listeners_init()
541 {
542 sndmonitor.listeners = hashmapCreate(5, hashfn, hasheq);
543 if (!sndmonitor.listeners)
544 return -1;
545 return 0;
546 }
547
listeners_deinit()548 static int listeners_deinit()
549 {
550 // XXX TBD
551 return -1;
552 }
553
add_listener(void * stream,snd_mon_cb cb)554 static int add_listener(void *stream, snd_mon_cb cb)
555 {
556 Hashmap * map = sndmonitor.listeners;
557 hashmapLock(map);
558 hashmapPut(map, stream, cb);
559 hashmapUnlock(map);
560 return 0;
561 }
562
del_listener(void * stream)563 static int del_listener(void * stream)
564 {
565 Hashmap * map = sndmonitor.listeners;
566 hashmapLock(map);
567 hashmapRemove(map, stream);
568 hashmapUnlock(map);
569 return 0;
570 }
571
572 // --- public APIs --- //
573
audio_extn_snd_mon_deinit()574 int audio_extn_snd_mon_deinit()
575 {
576 if (!sndmonitor.initcheck)
577 return -1;
578
579 write(sndmonitor.intpipe[1], "Q", 1);
580 pthread_join(sndmonitor.monitor_thread, (void **) NULL);
581 free_sndcards();
582 free_dev_events();
583 sndmonitor.initcheck = 0;
584 return 0;
585 }
586
audio_extn_snd_mon_init()587 int audio_extn_snd_mon_init()
588 {
589 sndmonitor.notify = snd_mon_update;
590 sndmonitor.target = NULL; // unused for now
591 list_init(&sndmonitor.cards);
592 list_init(&sndmonitor.dev_events);
593 sndmonitor.initcheck = false;
594
595 if (pipe(sndmonitor.intpipe) < 0)
596 return -ENODEV;
597
598 if (enum_sndcards() < 0)
599 return -ENODEV;
600
601 if (listeners_init() < 0)
602 return -ENODEV;
603
604 #ifdef MONITOR_DEVICE_EVENTS
605 enum_dev_events(); // failure here isn't fatal
606 #endif
607
608 int ret = pthread_create(&sndmonitor.monitor_thread,
609 (const pthread_attr_t *) NULL,
610 monitor_thread_loop, NULL);
611
612 if (ret) {
613 free_sndcards();
614 free_dev_events();
615 close(sndmonitor.intpipe[0]);
616 close(sndmonitor.intpipe[1]);
617 return -ENODEV;
618 }
619 sndmonitor.initcheck = true;
620 return 0;
621 }
622
audio_extn_snd_mon_register_listener(void * stream,snd_mon_cb cb)623 int audio_extn_snd_mon_register_listener(void *stream, snd_mon_cb cb)
624 {
625 if (!sndmonitor.initcheck) {
626 ALOGW("sndmonitor initcheck failed, cannot register");
627 return -1;
628 }
629
630 return add_listener(stream, cb);
631 }
632
audio_extn_snd_mon_unregister_listener(void * stream)633 int audio_extn_snd_mon_unregister_listener(void * stream)
634 {
635 if (!sndmonitor.initcheck) {
636 ALOGW("sndmonitor initcheck failed, cannot deregister");
637 return -1;
638 }
639
640 ALOGV("deregister listener for stream %p ", stream);
641 return del_listener(stream);
642 }
643