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