• 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 <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