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*>(¶ms), 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(¶ms); 209ae089528c7e3a8107be65657e52276dd068c1039Mike J. Chen ret = ioctl(alsaFD, SNDRV_PCM_IOCTL_HW_REFINE, ¶ms); 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