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