• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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