1ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen/*
2ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen**
3ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen** Copyright 2012, The Android Open Source Project
4ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen**
5ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen** Licensed under the Apache License, Version 2.0 (the "License");
6ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen** you may not use this file except in compliance with the License.
7ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen** You may obtain a copy of the License at
8ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen**
9ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen**     http://www.apache.org/licenses/LICENSE-2.0
10ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen**
11ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen** Unless required by applicable law or agreed to in writing, software
12ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen** distributed under the License is distributed on an "AS IS" BASIS,
13ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen** See the License for the specific language governing permissions and
15ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen** limitations under the License.
16ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen*/
17ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
18ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen#define LOG_TAG "AudioHAL:AudioHotplugThread"
19ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen#include <utils/Log.h>
20ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
21ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen#include <assert.h>
22ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen#include <dirent.h>
23ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen#include <poll.h>
24ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen#include <sys/eventfd.h>
25ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen#include <sys/inotify.h>
26ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen#include <sys/ioctl.h>
27ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
28ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen#include <sound/asound.h>
29ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
30ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen#include <utils/misc.h>
31ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen#include <utils/String8.h>
32ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
33ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen#include "AudioHotplugThread.h"
34ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
35ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen// This name is used to recognize the AndroidTV Remote mic so we can
36ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen// use it for voice recognition.
37ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen#define ANDROID_TV_REMOTE_AUDIO_DEVICE_NAME "ATVRAudio"
38ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
39ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chennamespace android {
40ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
41ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen/*
42ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen * ALSA parameter manipulation routines
43ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen *
44ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen * TODO: replace this when TinyAlsa offers a suitable API
45ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen */
46ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
47ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chenstatic inline int param_is_mask(int p)
48ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen{
49ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
50ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        (p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
51ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen}
52ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
53ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chenstatic inline int param_is_interval(int p)
54ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen{
55ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    return (p >= SNDRV_PCM_HW_PARAM_FIRST_INTERVAL) &&
56ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        (p <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL);
57ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen}
58ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
59ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chenstatic inline struct snd_interval *param_to_interval(
60ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        struct snd_pcm_hw_params *p, int n)
61ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen{
62ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    assert(p->intervals);
63ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    assert(param_is_interval(n));
64ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    return &(p->intervals[n - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]);
65ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen}
66ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
67ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chenstatic inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n)
68ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen{
69ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    assert(p->masks);
70ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    assert(param_is_mask(n));
71ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
72ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen}
73ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
74ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chenstatic inline void snd_mask_any(struct snd_mask *mask)
75ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen{
76ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    memset(mask, 0xff, sizeof(struct snd_mask));
77ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen}
78ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
79ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chenstatic inline void snd_interval_any(struct snd_interval *i)
80ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen{
81ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    i->min = 0;
82ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    i->openmin = 0;
83ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    i->max = UINT_MAX;
84ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    i->openmax = 0;
85ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    i->integer = 0;
86ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    i->empty = 0;
87ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen}
88ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
89ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chenstatic void param_init(struct snd_pcm_hw_params *p)
90ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen{
91ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    int n, k;
92ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
93ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    memset(p, 0, sizeof(*p));
94ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK;
95ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen         n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) {
96ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        struct snd_mask *m = param_to_mask(p, n);
97ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        snd_mask_any(m);
98ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    }
99ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL;
100ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen         n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) {
101ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        struct snd_interval *i = param_to_interval(p, n);
102ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        snd_interval_any(i);
103ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    }
104ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    p->rmask = 0xFFFFFFFF;
105ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen}
106ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
107ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen/*
108ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen * Hotplug thread
109ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen */
110ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
111ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chenconst char* AudioHotplugThread::kThreadName = "ATVRemoteAudioHotplug";
112ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
113ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen// directory where ALSA device nodes appear
114ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chenconst char* AudioHotplugThread::kAlsaDeviceDir = "/dev/snd";
115ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
116ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen// filename suffix for ALSA nodes representing capture devices
117ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chenconst char  AudioHotplugThread::kDeviceTypeCapture = 'c';
118ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
119ae089528c7e3a8107be65657e52276dd068c1039Mike J. ChenAudioHotplugThread::AudioHotplugThread(Callback& callback)
120ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    : mCallback(callback)
121ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    , mShutdownEventFD(-1)
122ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen{
123ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen}
124ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
125ae089528c7e3a8107be65657e52276dd068c1039Mike J. ChenAudioHotplugThread::~AudioHotplugThread()
126ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen{
127ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    if (mShutdownEventFD != -1) {
128ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        ::close(mShutdownEventFD);
129ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    }
130ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen}
131ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
132ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chenbool AudioHotplugThread::start()
133ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen{
134ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    mShutdownEventFD = eventfd(0, EFD_NONBLOCK);
135ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    if (mShutdownEventFD == -1) {
136ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        return false;
137ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    }
138ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
139ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    return (run(kThreadName) == NO_ERROR);
140ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen}
141ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
142ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chenvoid AudioHotplugThread::shutdown()
143ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen{
144ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    requestExit();
145ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    uint64_t tmp = 1;
146ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    ::write(mShutdownEventFD, &tmp, sizeof(tmp));
147ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    join();
148ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen}
149ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
150ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chenbool AudioHotplugThread::parseCaptureDeviceName(const char* name,
151ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                                                unsigned int* card,
152ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                                                unsigned int* device)
153ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen{
154ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    char deviceType;
155ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    int ret = sscanf(name, "pcmC%uD%u%c", card, device, &deviceType);
156ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    return (ret == 3 && deviceType == kDeviceTypeCapture);
157ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen}
158ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
159ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chenstatic inline void getAlsaParamInterval(const struct snd_pcm_hw_params& params,
160ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                                        int n, unsigned int* min,
161ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                                        unsigned int* max)
162ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen{
163ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    struct snd_interval* interval = param_to_interval(
164ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        const_cast<struct snd_pcm_hw_params*>(&params), n);
165ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    *min = interval->min;
166ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    *max = interval->max;
167ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen}
168ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
169ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen// This was hacked out of "alsa_utils.cpp".
170ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chenstatic int s_get_alsa_card_name(char *name, size_t len, int card_id)
171ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen{
172ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        int fd;
173ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        int amt = -1;
174ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        snprintf(name, len, "/proc/asound/card%d/id", card_id);
175ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        fd = open(name, O_RDONLY);
176ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        if (fd >= 0) {
177ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            amt = read(fd, name, len - 1);
178ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            if (amt > 0) {
179ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                // replace the '\n' at the end of the proc file with '\0'
180ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                name[amt - 1] = 0;
181ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            }
182ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            close(fd);
183ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        }
184ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        return amt;
185ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen}
186ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
187ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chenbool AudioHotplugThread::getDeviceInfo(unsigned int pcmCard,
188ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                                       unsigned int pcmDevice,
189ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                                       DeviceInfo* info)
190ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen{
191ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    bool result = false;
192ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    int ret;
193ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    int len;
194ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    char cardName[64] = "";
195ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
196ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    String8 devicePath = String8::format("%s/pcmC%dD%d%c",
197ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            kAlsaDeviceDir, pcmCard, pcmDevice, kDeviceTypeCapture);
198ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
199ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    ALOGD("AudioHotplugThread::getDeviceInfo opening %s", devicePath.string());
200ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    int alsaFD = open(devicePath.string(), O_RDONLY);
201ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    if (alsaFD == -1) {
202ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        ALOGE("AudioHotplugThread::getDeviceInfo open failed for %s", devicePath.string());
203ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        goto done;
204ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    }
205ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
206ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    // query the device's ALSA configuration space
207ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    struct snd_pcm_hw_params params;
208ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    param_init(&params);
209ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    ret = ioctl(alsaFD, SNDRV_PCM_IOCTL_HW_REFINE, &params);
210ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    if (ret == -1) {
211ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        ALOGE("AudioHotplugThread: refine ioctl failed");
212ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        goto done;
213ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    }
214ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
215ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    info->pcmCard = pcmCard;
216ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    info->pcmDevice = pcmDevice;
217ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    getAlsaParamInterval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
218ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                         &info->minSampleBits, &info->maxSampleBits);
219ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    getAlsaParamInterval(params, SNDRV_PCM_HW_PARAM_CHANNELS,
220ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                         &info->minChannelCount, &info->maxChannelCount);
221ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    getAlsaParamInterval(params, SNDRV_PCM_HW_PARAM_RATE,
222ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                         &info->minSampleRate, &info->maxSampleRate);
223ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
224ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    // Ugly hack to recognize Remote mic and mark it for voice recognition
225ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    info->forVoiceRecognition = false;
226ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    len = s_get_alsa_card_name(cardName, sizeof(cardName), pcmCard);
227ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    ALOGD("AudioHotplugThread get_alsa_card_name returned %d, %s", len, cardName);
228ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    if (len > 0) {
229ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        if (strcmp(ANDROID_TV_REMOTE_AUDIO_DEVICE_NAME, cardName) == 0) {
230ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            ALOGD("AudioHotplugThread found Android TV remote mic on Card %d, for VOICE_RECOGNITION", pcmCard);
231ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            info->forVoiceRecognition = true;
232ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        }
233ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    }
234ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
235ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    result = true;
236ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
237ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chendone:
238ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    if (alsaFD != -1) {
239ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        close(alsaFD);
240ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    }
241ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    return result;
242ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen}
243ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
244ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen// scan the ALSA device directory for a usable capture device
245ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chenvoid AudioHotplugThread::scanForDevice()
246ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen{
247ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    DIR* alsaDir;
248ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    DeviceInfo deviceInfo;
249ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
250ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    alsaDir = opendir(kAlsaDeviceDir);
251ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    if (alsaDir == NULL)
252ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        return;
253ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
254ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    while (true) {
255ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        struct dirent entry, *result;
256ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        int ret = readdir_r(alsaDir, &entry, &result);
257ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        if (ret != 0 || result == NULL)
258ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            break;
259ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        unsigned int pcmCard, pcmDevice;
260ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        if (parseCaptureDeviceName(entry.d_name, &pcmCard, &pcmDevice)) {
261ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            if (getDeviceInfo(pcmCard, pcmDevice, &deviceInfo)) {
262ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                mCallback.onDeviceFound(deviceInfo);
263ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            }
264ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        }
265ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    }
266ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
267ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    closedir(alsaDir);
268ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen}
269ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
270ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chenbool AudioHotplugThread::threadLoop()
271ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen{
272ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    int inotifyFD = -1;
273ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    int watchFD = -1;
274ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    int flags;
275ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
276ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    // watch for changes to the ALSA device directory
277ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    inotifyFD = inotify_init();
278ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    if (inotifyFD == -1) {
279ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        ALOGE("AudioHotplugThread: inotify_init failed");
280ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        goto done;
281ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    }
282ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    flags = fcntl(inotifyFD, F_GETFL, 0);
283ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    if (flags == -1) {
284ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        ALOGE("AudioHotplugThread: F_GETFL failed");
285ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        goto done;
286ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    }
287ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    if (fcntl(inotifyFD, F_SETFL, flags | O_NONBLOCK) == -1) {
288ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        ALOGE("AudioHotplugThread: F_SETFL failed");
289ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        goto done;
290ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    }
291ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
292ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    watchFD = inotify_add_watch(inotifyFD, kAlsaDeviceDir,
293ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                                IN_CREATE | IN_DELETE);
294ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    if (watchFD == -1) {
295ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        ALOGE("AudioHotplugThread: inotify_add_watch failed");
296ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        goto done;
297ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    }
298ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
299ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    // check for any existing capture devices
300ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    scanForDevice();
301ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
302ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    while (!exitPending()) {
303ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        // wait for a change to the ALSA directory or a shutdown signal
304ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        struct pollfd fds[2] = {
305ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            { inotifyFD, POLLIN, 0 },
306ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            { mShutdownEventFD, POLLIN, 0 }
307ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        };
308ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        int ret = poll(fds, NELEM(fds), -1);
309ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        if (ret == -1) {
310ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            ALOGE("AudioHotplugThread: poll failed");
311ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            break;
312ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        } else if (fds[1].revents & POLLIN) {
313ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            // shutdown requested
314ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            break;
315ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        }
316ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
317ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        if (!(fds[0].revents & POLLIN)) {
318ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            continue;
319ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        }
320ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
321ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        // parse the filesystem change events
322ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        char eventBuf[256];
323ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        ret = read(inotifyFD, eventBuf, sizeof(eventBuf));
324ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        if (ret == -1) {
325ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            ALOGE("AudioHotplugThread: read failed");
326ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            break;
327ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        }
328ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
329ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        for (int i = 0; i < ret;) {
330ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            if ((ret - i) < (int)sizeof(struct inotify_event)) {
331ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                ALOGE("AudioHotplugThread: read an invalid inotify_event");
332ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                break;
333ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            }
334ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
335ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            struct inotify_event *event =
336ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                    reinterpret_cast<struct inotify_event*>(eventBuf + i);
337ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
338ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            if ((ret - i) < (int)(sizeof(struct inotify_event) + event->len)) {
339ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                ALOGE("AudioHotplugThread: read a bad inotify_event length");
340ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                break;
341ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            }
342ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
343ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            char *name = ((char *) event) +
344ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                    offsetof(struct inotify_event, name);
345ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
346ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            unsigned int pcmCard, pcmDevice;
347ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            if (parseCaptureDeviceName(name, &pcmCard, &pcmDevice)) {
348ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                if (event->mask & IN_CREATE) {
349ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                    // Some devices can not be opened immediately after the
350ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                    // inotify event occurs.  Add a delay to avoid these
351ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                    // races.  (50ms was chosen arbitrarily)
352ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                    const int kOpenTimeoutMs = 50;
353ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                    struct pollfd pfd = {mShutdownEventFD, POLLIN, 0};
354ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                    if (poll(&pfd, 1, kOpenTimeoutMs) == -1) {
355ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                        ALOGE("AudioHotplugThread: poll failed");
356ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                        break;
357ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                    } else if (pfd.revents & POLLIN) {
358ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                        // shutdown requested
359ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                        break;
360ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                    }
361ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
362ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                    DeviceInfo deviceInfo;
363ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                    if (getDeviceInfo(pcmCard, pcmDevice, &deviceInfo)) {
364ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                        mCallback.onDeviceFound(deviceInfo);
365ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                    }
366ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                } else if (event->mask & IN_DELETE) {
367ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                    mCallback.onDeviceRemoved(pcmCard, pcmDevice);
368ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen                }
369ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            }
370ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
371ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen            i += sizeof(struct inotify_event) + event->len;
372ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        }
373ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    }
374ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
375ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chendone:
376ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    if (watchFD != -1) {
377ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        inotify_rm_watch(inotifyFD, watchFD);
378ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    }
379ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    if (inotifyFD != -1) {
380ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen        close(inotifyFD);
381ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    }
382ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
383ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen    return false;
384ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen}
385ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen
386ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen}; // namespace android
387