Home | History | Annotate | Download | only in audio_extn
      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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 ---- //
    524 static int hashfn(void * key)
    525 {
    526     return (int)key;
    527 }
    528 
    529 static bool hasheq(void * key1, void *key2)
    530 {
    531     return key1 == key2;
    532 }
    533 
    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 
    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 
    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 
    566 static int listeners_deinit()
    567 {
    568     // XXX TBD
    569     return -1;
    570 }
    571 
    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 
    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 
    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 
    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 
    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 
    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