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