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