1c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George/* 2c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George * Copyright (C) 2016 The Android Open Source Project 3c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George * 4c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George * Licensed under the Apache License, Version 2.0 (the "License"); 5c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George * you may not use this file except in compliance with the License. 6c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George * You may obtain a copy of the License at 7c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George * 8c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George * http://www.apache.org/licenses/LICENSE-2.0 9c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George * 10c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George * Unless required by applicable law or agreed to in writing, software 11c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George * distributed under the License is distributed on an "AS IS" BASIS, 12c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George * See the License for the specific language governing permissions and 14c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George * limitations under the License. 15c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George */ 16c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 17c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#define LOG_TAG "audio_hw_sndmonitor" 18c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George/*#define LOG_NDEBUG 0*/ 19c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#define LOG_NDDEBUG 0 20c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 21c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George/* monitor sound card, cpe state 22c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 23c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George audio_dev registers for a callback from this module in adev_open 24c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George Each stream in audio_hal registers for a callback in 25c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George adev_open_*_stream. 26c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 27c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George A thread is spawned to poll() on sound card state files in /proc. 28c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George On observing a sound card state change, this thread invokes the 29c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George callbacks registered. 30c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 31c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George Callbacks are deregistered in adev_close_*_stream and adev_close 32c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George*/ 33c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#include <stdlib.h> 34c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#include <dirent.h> 35c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#include <unistd.h> 36c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#include <fcntl.h> 37c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#include <sys/stat.h> 38c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#include <sys/poll.h> 396431fe63703982df8e83644a168c7432e3fd855cJiyong Park#include <pthread.h> 40c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#include <cutils/list.h> 41c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#include <cutils/hashmap.h> 42e6e2d441c567d5da185b787d6c10ca2c8b36a694Haynes Mathew George#include <log/log.h> 43c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#include <cutils/str_parms.h> 44c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#include <ctype.h> 45c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 46c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#include "audio_hw.h" 47c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#include "audio_extn.h" 48c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 49c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George//#define MONITOR_DEVICE_EVENTS 50c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#define CPE_MAGIC_NUM 0x2000 51c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#define MAX_CPE_SLEEP_RETRY 2 52c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#define CPE_SLEEP_WAIT 100 53c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 54c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#define MAX_SLEEP_RETRY 100 55c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#define AUDIO_INIT_SLEEP_WAIT 100 /* 100 ms */ 56c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 57c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#define AUDIO_PARAMETER_KEY_EXT_AUDIO_DEVICE "ext_audio_device" 58c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 59c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgetypedef enum { 60c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George audio_event_on, 61c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George audio_event_off 62c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} audio_event_status; 63c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 64c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgetypedef struct { 65c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George int card; 66c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George int fd; 67c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George struct listnode node; // membership in sndcards list 68c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George card_status_t status; 69c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} sndcard_t; 70c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 71c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgetypedef struct { 72c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George char * dev; 73c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George int fd; 74c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George int status; 75c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George struct listnode node; // membership in deviceevents list; 76c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} dev_event_t; 77c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 78c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgetypedef void (* notifyfn)(const void * target, const char * msg); 79c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 80c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgetypedef struct { 81c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George const void * target; 82c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George notifyfn notify; 83c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George struct listnode cards; 84c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George unsigned int num_cards; 85c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George struct listnode dev_events; 86c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George unsigned int num_dev_events; 87c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George pthread_t monitor_thread; 88c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George int intpipe[2]; 89c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George Hashmap * listeners; // from stream * -> callback func 90c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George bool initcheck; 91c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} sndmonitor_state_t; 92c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 93c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgestatic sndmonitor_state_t sndmonitor; 94c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 95c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgestatic char * read_state(int fd) 96c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 97c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George struct stat buf; 98c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (fstat(fd, &buf) < 0) 99c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return NULL; 100c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 101c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George off_t pos = lseek(fd, 0, SEEK_CUR); 102c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George off_t avail = buf.st_size - pos; 103c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (avail <= 0) { 104c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ALOGD("avail %ld", avail); 105c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return NULL; 106c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 107c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 108c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George char * state = (char *)calloc(avail+1, sizeof(char)); 109c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (!state) 110c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return NULL; 111c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 112c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ssize_t bytes=read(fd, state, avail); 113c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (bytes <= 0) 114c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return NULL; 115c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 116c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George // trim trailing whitespace 117c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George while (bytes && isspace(*(state+bytes-1))) { 118c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George *(state + bytes - 1) = '\0'; 119c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George --bytes; 120c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 121c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George lseek(fd, 0, SEEK_SET); 122c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return state; 123c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 124c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 125c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgestatic int add_new_sndcard(int card, int fd) 126c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 127c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George sndcard_t * s = (sndcard_t *)calloc(sizeof(sndcard_t), 1); 128c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 129c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (!s) 130c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return -1; 131c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 132c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George s->card = card; 133c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George s->fd = fd; // dup? 134c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 135c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George char * state = read_state(fd); 136c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George bool online = state && !strcmp(state, "ONLINE"); 137c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 138c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ALOGV("card %d initial state %s %d", card, state, online); 139c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 140c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (state) 141c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George free(state); 142c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 143c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George s->status = online ? CARD_STATUS_ONLINE : CARD_STATUS_OFFLINE; 144c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George list_add_tail(&sndmonitor.cards, &s->node); 145c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return 0; 146c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 147c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 148c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgestatic int enum_sndcards() 149c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 150c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George const char* cards = "/proc/asound/cards"; 151c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George int tries = 10; 152c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George char *line = NULL; 153c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George size_t len = 0; 154c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ssize_t bytes_read; 155c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George char path[128] = {0}; 15666ff30c81a8c561db01217297f849614a9599533Haynes Mathew George char *ptr, *saveptr, *card_id; 157c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George int line_no=0; 158c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George unsigned int num_cards=0, num_cpe=0; 159c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George FILE *fp; 160c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George int fd, ret; 161c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 162c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George while (--tries) { 163c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if ((fp = fopen(cards, "r")) == NULL) { 164c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ALOGE("Cannot open %s file to get list of sound cards", cards); 165c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George usleep(100000); 166c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George continue; 167c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 168c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George break; 169c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 170c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 171c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (!tries) 172c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return -ENODEV; 173c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 174c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George while ((bytes_read = getline(&line, &len, fp) != -1)) { 175c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George // skip every other line to to match 176c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George // the output format of /proc/asound/cards 177c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (line_no++ % 2) 178c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George continue; 179c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 180c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ptr = strtok_r(line, " [", &saveptr); 181c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (!ptr) 182c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George continue; 183c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 18466ff30c81a8c561db01217297f849614a9599533Haynes Mathew George card_id = strtok_r(saveptr+1, "]", &saveptr); 18566ff30c81a8c561db01217297f849614a9599533Haynes Mathew George if (!card_id) 18666ff30c81a8c561db01217297f849614a9599533Haynes Mathew George continue; 18766ff30c81a8c561db01217297f849614a9599533Haynes Mathew George 18866ff30c81a8c561db01217297f849614a9599533Haynes Mathew George // Limit to sound cards associated with ADSP 18966ff30c81a8c561db01217297f849614a9599533Haynes Mathew George if ((strncasecmp(card_id, "msm", 3) != 0) && 19066ff30c81a8c561db01217297f849614a9599533Haynes Mathew George (strncasecmp(card_id, "sdm", 3) != 0) && 19166ff30c81a8c561db01217297f849614a9599533Haynes Mathew George (strncasecmp(card_id, "sdc", 3) != 0) && 19266ff30c81a8c561db01217297f849614a9599533Haynes Mathew George (strncasecmp(card_id, "apq", 3) != 0)) { 19366ff30c81a8c561db01217297f849614a9599533Haynes Mathew George ALOGW("Skip over non-ADSP snd card %s", card_id); 19466ff30c81a8c561db01217297f849614a9599533Haynes Mathew George continue; 19566ff30c81a8c561db01217297f849614a9599533Haynes Mathew George } 19666ff30c81a8c561db01217297f849614a9599533Haynes Mathew George 197c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George snprintf(path, sizeof(path), "/proc/asound/card%s/state", ptr); 198c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ALOGV("Opening sound card state : %s", path); 199c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 200c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George fd = open(path, O_RDONLY); 201c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (fd == -1) { 202c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ALOGE("Open %s failed : %s", path, strerror(errno)); 203c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George continue; 204c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 205c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 206c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ret = add_new_sndcard(atoi(ptr), fd); 207b500b90b12d84dbb6f500a1f2dd247992a5e5daeKevin Rocard if (ret != 0) { 208b500b90b12d84dbb6f500a1f2dd247992a5e5daeKevin Rocard close(fd); // card state fd ownership is taken by sndcard on success 209c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George continue; 210b500b90b12d84dbb6f500a1f2dd247992a5e5daeKevin Rocard } 211c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 212c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George num_cards++; 213c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 214c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George // query cpe state for this card as well 215c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George tries=MAX_CPE_SLEEP_RETRY; 216c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George snprintf(path, sizeof(path), "/proc/asound/card%s/cpe0_state", ptr); 217c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 218c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (access(path, R_OK) < 0) { 219c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ALOGW("access %s failed w/ err %s", path, strerror(errno)); 220c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George continue; 221c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 222c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 223c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ALOGV("Open cpe state card state %s", path); 224c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George while (--tries) { 225c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if ((fd = open(path, O_RDONLY)) < 0) { 226c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ALOGW("Open cpe state card state failed, retry : %s", path); 227c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George usleep(CPE_SLEEP_WAIT*1000); 228c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George continue; 229c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 230c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George break; 231c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 232c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 233c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (!tries) 234c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George continue; 235c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 236c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ret = add_new_sndcard(CPE_MAGIC_NUM+num_cpe, fd); 237b500b90b12d84dbb6f500a1f2dd247992a5e5daeKevin Rocard if (ret != 0) { 238b500b90b12d84dbb6f500a1f2dd247992a5e5daeKevin Rocard close(fd); // card state fd ownership is taken by sndcard on success 239c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George continue; 240b500b90b12d84dbb6f500a1f2dd247992a5e5daeKevin Rocard } 241c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 242c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George num_cpe++; 243c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George num_cards++; 244c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 245c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (line) 246c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George free(line); 247c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George fclose(fp); 248c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ALOGV("sndmonitor registerer num_cards %d", num_cards); 249c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George sndmonitor.num_cards = num_cards; 250c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return num_cards ? 0 : -1; 251c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 252c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 253c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgestatic void free_sndcards() 254c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 255c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George while (!list_empty(&sndmonitor.cards)) { 256c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George struct listnode * n = list_head(&sndmonitor.cards); 257c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George sndcard_t * s = node_to_item(n, sndcard_t, node); 258c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George list_remove(n); 259c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George close(s->fd); 260c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George free(s); 261c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 262c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 263c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 264c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgestatic int add_new_dev_event(char * d_name, int fd) 265c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 266c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George dev_event_t * d = (dev_event_t *)calloc(sizeof(dev_event_t), 1); 267c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 268c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (!d) 269c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return -1; 270c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 271c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George d->dev = strdup(d_name); 272c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George d->fd = fd; 273c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George list_add_tail(&sndmonitor.dev_events, &d->node); 274c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return 0; 275c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 276c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 277c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgestatic int enum_dev_events() 278c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 279c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George const char* events_dir = "/sys/class/switch/"; 280c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George DIR *dp; 281c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George struct dirent* in_file; 282c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George int fd; 283c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George char path[128] = {0}; 284c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George unsigned int num_dev_events = 0; 285c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 286c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if ((dp = opendir(events_dir)) == NULL) { 287c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ALOGE("Cannot open switch directory %s err %s", 288c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George events_dir, strerror(errno)); 289c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return -1; 290c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 291c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 292c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George while ((in_file = readdir(dp)) != NULL) { 293c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (!strstr(in_file->d_name, "qc_")) 294c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George continue; 295c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 296c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George snprintf(path, sizeof(path), "%s/%s/state", 297c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George events_dir, in_file->d_name); 298c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 299c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ALOGV("Opening audio dev event state : %s ", path); 300c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George fd = open(path, O_RDONLY); 301c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (fd == -1) { 302c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ALOGE("Open %s failed : %s", path, strerror(errno)); 303c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } else { 304c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (!add_new_dev_event(in_file->d_name, fd)) 305c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George num_dev_events++; 306c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 307c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 308c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George closedir(dp); 309c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George sndmonitor.num_dev_events = num_dev_events; 310c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return num_dev_events ? 0 : -1; 311c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 312c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 313c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgestatic void free_dev_events() 314c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 315c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George while (!list_empty(&sndmonitor.dev_events)) { 316c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George struct listnode * n = list_head(&sndmonitor.dev_events); 317c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George dev_event_t * d = node_to_item(n, dev_event_t, node); 318c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George list_remove(n); 319c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George close(d->fd); 320c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George free(d->dev); 321c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George free(d); 322c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 323c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 324c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 325c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgestatic int notify(const struct str_parms * params) 326c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 327c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (!params) 328c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return -1; 329c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 330c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George char * str = str_parms_to_str((struct str_parms *)params); 331c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 332c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (!str) 333c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return -1; 334c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 335c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (sndmonitor.notify) 336c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George sndmonitor.notify(sndmonitor.target, str); 337c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 338c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ALOGV("%s", str); 339c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George free(str); 340c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return 0; 341c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 342c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 343c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgeint on_dev_event(dev_event_t * dev_event) 344c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 345c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George char state_buf[2]; 346c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (read(dev_event->fd, state_buf, 1) <= 0) 347c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return -1; 348c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 349c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George lseek(dev_event->fd, 0, SEEK_SET); 350c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George state_buf[1]='\0'; 351c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (atoi(state_buf) == dev_event->status) 352c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return 0; 353c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 354c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George dev_event->status = atoi(state_buf); 355c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 356c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George struct str_parms * params = str_parms_create(); 357c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 358c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (!params) 359c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return -1; 360c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 361c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George char val[32] = {0}; 362c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George snprintf(val, sizeof(val), "%s,%s", dev_event->dev, 363c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George dev_event->status ? "ON" : "OFF"); 364c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 365c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (str_parms_add_str(params, AUDIO_PARAMETER_KEY_EXT_AUDIO_DEVICE, val) < 0) 366c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return -1; 367c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 368c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George int ret = notify(params); 369c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George str_parms_destroy(params); 370c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return ret; 371c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 372c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 373c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgebool on_sndcard_state_update(sndcard_t * s) 374c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 375c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George char rd_buf[9]={0}; 376c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George card_status_t status; 377c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 378c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (read(s->fd, rd_buf, 8) <= 0) 379c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return -1; 380c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 381c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George rd_buf[8] = '\0'; 382c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George lseek(s->fd, 0, SEEK_SET); 383c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 384c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ALOGV("card num %d, new state %s", s->card, rd_buf); 385c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 386c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George bool is_cpe = (s->card >= CPE_MAGIC_NUM); 387c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (strstr(rd_buf, "OFFLINE")) 388c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George status = CARD_STATUS_OFFLINE; 389c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George else if (strstr(rd_buf, "ONLINE")) 390c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George status = CARD_STATUS_ONLINE; 391c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George else { 392c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ALOGE("unknown state"); 393c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return 0; 394c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 395c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 396c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (status == s->status) // no change 397c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return 0; 398c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 399c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George s->status = status; 400c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 401c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George struct str_parms * params = str_parms_create(); 402c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 403c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (!params) 404c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return -1; 405c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 406c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George char val[32] = {0}; 407c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George // cpe actual card num is (card - MAGIC_NUM). so subtract accordingly 408c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George snprintf(val, sizeof(val), "%d,%s", s->card - (is_cpe ? CPE_MAGIC_NUM : 0), 409c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George status == CARD_STATUS_ONLINE ? "ONLINE" : "OFFLINE"); 410c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 411c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (str_parms_add_str(params, is_cpe ? "CPE_STATUS" : "SND_CARD_STATUS", 412c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George val) < 0) 413c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return -1; 414c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 415c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George int ret = notify(params); 416c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George str_parms_destroy(params); 417c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return ret; 418c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 419c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 420c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgevoid * monitor_thread_loop(void * args __unused) 421c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 422c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ALOGV("Start threadLoop()"); 423c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George unsigned int num_poll_fds = sndmonitor.num_cards + 424c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George sndmonitor.num_dev_events + 1/*pipe*/; 425c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George struct pollfd * pfd = (struct pollfd *)calloc(sizeof(struct pollfd), 426c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George num_poll_fds); 427c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (!pfd) 428c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return NULL; 429c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 430c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George pfd[0].fd = sndmonitor.intpipe[0]; 431c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George pfd[0].events = POLLPRI|POLLIN; 432c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 433c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George int i=1; 434c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George struct listnode *node; 435c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George list_for_each(node, &sndmonitor.cards) { 436c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George sndcard_t * s = node_to_item(node, sndcard_t, node); 437c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George pfd[i].fd = s->fd; 438c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George pfd[i].events = POLLPRI; 439c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ++i; 440c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 441c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 442c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George list_for_each(node, &sndmonitor.dev_events) { 443c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George dev_event_t * d = node_to_item(node, dev_event_t, node); 444c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George pfd[i].fd = d->fd; 445c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George pfd[i].events = POLLPRI; 446c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ++i; 447c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 448c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 449c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George while (1) { 450c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (poll(pfd, num_poll_fds, -1) < 0) { 451641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George int errno_ = errno; 452c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ALOGE("poll() failed w/ err %s", strerror(errno)); 453641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George switch (errno_) { 454641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George case EINTR: 455641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George case ENOMEM: 456641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George sleep(2); 457641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George continue; 458641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George default: 459641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George /* above errors can be caused due to current system 460641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George state .. any other error is not expected */ 461641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George LOG_ALWAYS_FATAL("unxpected poll() system call failure"); 462641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George break; 463641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George } 464c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 465c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ALOGV("out of poll()"); 466c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 467c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#define READY_TO_READ(p) ((p)->revents & (POLLIN|POLLPRI)) 468c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#define ERROR_IN_FD(p) ((p)->revents & (POLLERR|POLLHUP|POLLNVAL)) 469c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 470c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George // check if requested to exit 471c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (READY_TO_READ(&pfd[0])) { 472c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George char buf[2]={0}; 473c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George read(pfd[0].fd, buf, 1); 474c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (!strcmp(buf, "Q")) 475c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George break; 476c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } else if (ERROR_IN_FD(&pfd[0])) { 477c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George // do not consider for poll again 478641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George // POLLERR - can this happen? 479641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George // POLLHUP - adev must not close pipe 480641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George // POLLNVAL - fd is valid 481641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George LOG_ALWAYS_FATAL("unxpected error in pipe poll fd 0x%x", 482641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George pfd[0].revents); 483c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George pfd[0].fd *= -1; 484c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 485c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 486c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George i=1; 487c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George list_for_each(node, &sndmonitor.cards) { 488c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George sndcard_t * s = node_to_item(node, sndcard_t, node); 489c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (READY_TO_READ(&pfd[i])) 490c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George on_sndcard_state_update(s); 491c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George else if (ERROR_IN_FD(&pfd[i])) { 492c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George // do not consider for poll again 493641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George // POLLERR - can this happen as we are reading from a fs? 494641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George // POLLHUP - not valid for cardN/state 495641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George // POLLNVAL - fd is valid 496641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George LOG_ALWAYS_FATAL("unxpected error in card poll fd 0x%x", 497641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George pfd[i].revents); 498c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George pfd[i].fd *= -1; 499c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 500c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ++i; 501c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 502c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 503c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George list_for_each(node, &sndmonitor.dev_events) { 504c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George dev_event_t * d = node_to_item(node, dev_event_t, node); 505c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (READY_TO_READ(&pfd[i])) 506c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George on_dev_event(d); 507c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George else if (ERROR_IN_FD(&pfd[i])) { 508c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George // do not consider for poll again 509641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George // POLLERR - can this happen as we are reading from a fs? 510641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George // POLLHUP - not valid for switch/state 511641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George // POLLNVAL - fd is valid 512641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George LOG_ALWAYS_FATAL("unxpected error in dev poll fd 0x%x", 513641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George pfd[i].revents); 514c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George pfd[i].fd *= -1; 515c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 516c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ++i; 517c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 518c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 519641275e1bdbb0fb863911aa93eba40f1e4358b70Haynes Mathew George 520c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return NULL; 521c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 522c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 523c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George// ---- listener static APIs ---- // 524c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgestatic int hashfn(void * key) 525c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 526c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return (int)key; 527c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 528c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 529c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgestatic bool hasheq(void * key1, void *key2) 530c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 531c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return key1 == key2; 532c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 533c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 534c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgestatic bool snd_cb(void* key, void* value, void* context) 535c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 536c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George snd_mon_cb cb = (snd_mon_cb)value; 537c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George cb(key, context); 538c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return true; 539c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 540c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 541c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgestatic void snd_mon_update(const void * target __unused, const char * msg) 542c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 543c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George // target can be used to check if this message is intended for the 544c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George // recipient or not. (using some statically saved state) 545c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 546c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George struct str_parms *parms = str_parms_create_str(msg); 547c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 548c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (!parms) 549c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return; 550c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 551c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George hashmapLock(sndmonitor.listeners); 552c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George hashmapForEach(sndmonitor.listeners, snd_cb, parms); 553c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George hashmapUnlock(sndmonitor.listeners); 554c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 555c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George str_parms_destroy(parms); 556c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 557c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 558c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgestatic int listeners_init() 559c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 560c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George sndmonitor.listeners = hashmapCreate(5, hashfn, hasheq); 561c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (!sndmonitor.listeners) 562c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return -1; 563c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return 0; 564c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 565c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 566c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgestatic int listeners_deinit() 567c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 568c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George // XXX TBD 569c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return -1; 570c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 571c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 572c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgestatic int add_listener(void *stream, snd_mon_cb cb) 573c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 574c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George Hashmap * map = sndmonitor.listeners; 575c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George hashmapLock(map); 576c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George hashmapPut(map, stream, cb); 577c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George hashmapUnlock(map); 578c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return 0; 579c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 580c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 581c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgestatic int del_listener(void * stream) 582c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 583c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George Hashmap * map = sndmonitor.listeners; 584c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George hashmapLock(map); 585c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George hashmapRemove(map, stream); 586c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George hashmapUnlock(map); 587c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return 0; 588c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 589c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 590c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George// --- public APIs --- // 591c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 592c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgeint audio_extn_snd_mon_deinit() 593c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 594c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (!sndmonitor.initcheck) 595c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return -1; 596c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 597c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George write(sndmonitor.intpipe[1], "Q", 1); 598c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George pthread_join(sndmonitor.monitor_thread, (void **) NULL); 599c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George free_dev_events(); 600a54534423a8201eb2954675ceba470dac3a1fc75Kevin Rocard listeners_deinit(); 601a54534423a8201eb2954675ceba470dac3a1fc75Kevin Rocard free_sndcards(); 602a54534423a8201eb2954675ceba470dac3a1fc75Kevin Rocard close(sndmonitor.intpipe[0]); 603a54534423a8201eb2954675ceba470dac3a1fc75Kevin Rocard close(sndmonitor.intpipe[1]); 604a54534423a8201eb2954675ceba470dac3a1fc75Kevin Rocard 605c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George sndmonitor.initcheck = 0; 606c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return 0; 607c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 608c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 609c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgeint audio_extn_snd_mon_init() 610c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 611c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George sndmonitor.notify = snd_mon_update; 612c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George sndmonitor.target = NULL; // unused for now 613c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George list_init(&sndmonitor.cards); 614c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George list_init(&sndmonitor.dev_events); 615c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George sndmonitor.initcheck = false; 616c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 617c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (pipe(sndmonitor.intpipe) < 0) 618a54534423a8201eb2954675ceba470dac3a1fc75Kevin Rocard goto pipe_error; 619c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 620c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (enum_sndcards() < 0) 621a54534423a8201eb2954675ceba470dac3a1fc75Kevin Rocard goto enum_sncards_error; 622c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 623c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (listeners_init() < 0) 624a54534423a8201eb2954675ceba470dac3a1fc75Kevin Rocard goto listeners_error; 625c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 626c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#ifdef MONITOR_DEVICE_EVENTS 627c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George enum_dev_events(); // failure here isn't fatal 628c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George#endif 629c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 630c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George int ret = pthread_create(&sndmonitor.monitor_thread, 631c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George (const pthread_attr_t *) NULL, 632c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George monitor_thread_loop, NULL); 633c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 634c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (ret) { 635a54534423a8201eb2954675ceba470dac3a1fc75Kevin Rocard goto monitor_thread_create_error; 636c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 637c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George sndmonitor.initcheck = true; 638c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return 0; 639a54534423a8201eb2954675ceba470dac3a1fc75Kevin Rocard 640a54534423a8201eb2954675ceba470dac3a1fc75Kevin Rocardmonitor_thread_create_error: 641a54534423a8201eb2954675ceba470dac3a1fc75Kevin Rocard listeners_deinit(); 642a54534423a8201eb2954675ceba470dac3a1fc75Kevin Rocardlisteners_error: 643a54534423a8201eb2954675ceba470dac3a1fc75Kevin Rocard free_sndcards(); 644a54534423a8201eb2954675ceba470dac3a1fc75Kevin Rocardenum_sncards_error: 645a54534423a8201eb2954675ceba470dac3a1fc75Kevin Rocard close(sndmonitor.intpipe[0]); 646a54534423a8201eb2954675ceba470dac3a1fc75Kevin Rocard close(sndmonitor.intpipe[1]); 647a54534423a8201eb2954675ceba470dac3a1fc75Kevin Rocardpipe_error: 648a54534423a8201eb2954675ceba470dac3a1fc75Kevin Rocard return -ENODEV; 649c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 650c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 651c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgeint audio_extn_snd_mon_register_listener(void *stream, snd_mon_cb cb) 652c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 653c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (!sndmonitor.initcheck) { 654c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ALOGW("sndmonitor initcheck failed, cannot register"); 655c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return -1; 656c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 657c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 658c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return add_listener(stream, cb); 659c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 660c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 661c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew Georgeint audio_extn_snd_mon_unregister_listener(void * stream) 662c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George{ 663c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George if (!sndmonitor.initcheck) { 664c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ALOGW("sndmonitor initcheck failed, cannot deregister"); 665c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return -1; 666c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George } 667c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George 668c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George ALOGV("deregister listener for stream %p ", stream); 669c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George return del_listener(stream); 670c735fb07458a06b7f4dc702607b3cb722a78c9f7Haynes Mathew George} 671