1 /* 2 ** 3 ** Copyright 2012, The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 18 #define LOG_TAG "AudioHAL:AudioHardwareInput" 19 #include <utils/Log.h> 20 21 #include <fcntl.h> 22 #include <sys/eventfd.h> 23 #include <sys/stat.h> 24 #include <sys/types.h> 25 #include <unistd.h> 26 27 #include <utils/String8.h> 28 29 #include "AudioHardwareInput.h" 30 #include "AudioHotplugThread.h" 31 #include "AudioStreamIn.h" 32 33 namespace android { 34 35 // Global singleton. 36 AudioHardwareInput gAudioHardwareInput; 37 38 AudioHardwareInput::AudioHardwareInput() 39 : mMicMute(false) 40 { 41 mHotplugThread = new AudioHotplugThread(*this); 42 if (mHotplugThread == NULL) { 43 ALOGE("Unable to create ATV Remote audio hotplug thread. " 44 "Pluggable audio input devices will not function."); 45 } else if (!mHotplugThread->start()) { 46 ALOGE("Unable to start ATV Remote audio hotplug thread. " 47 "Pluggable audio input devices will not function."); 48 mHotplugThread.clear(); 49 } 50 51 for (int i=0; i<kMaxDevices; i++) { 52 mDeviceInfos[i].valid = false; 53 } 54 } 55 56 AudioHardwareInput::~AudioHardwareInput() 57 { 58 if (mHotplugThread != NULL) { 59 mHotplugThread->shutdown(); 60 mHotplugThread.clear(); 61 } 62 63 closeAllInputStreams(); 64 } 65 66 status_t AudioHardwareInput::setMicMute(bool mute) 67 { 68 mMicMute = mute; 69 return NO_ERROR; 70 } 71 72 status_t AudioHardwareInput::getMicMute(bool* mute) 73 { 74 *mute = mMicMute; 75 return NO_ERROR; 76 } 77 78 // milliseconds per ALSA period 79 const uint32_t AudioHardwareInput::kPeriodMsec = 10; 80 81 size_t AudioHardwareInput::calculateInputBufferSize(uint32_t outputSampleRate, 82 audio_format_t format, 83 uint32_t channelCount) 84 { 85 size_t size; 86 87 // AudioFlinger expects audio buffers to be a multiple of 16 frames 88 size = (kPeriodMsec * outputSampleRate) / 1000; 89 size = ((size + 15) / 16) * 16; 90 91 return size * channelCount * audio_bytes_per_sample(format); 92 } 93 94 status_t AudioHardwareInput::getInputBufferSize(const audio_config* config) 95 { 96 size_t size = calculateInputBufferSize(config->sample_rate, 97 config->format, 98 audio_channel_count_from_in_mask(config->channel_mask)); 99 return size; 100 } 101 102 AudioStreamIn* AudioHardwareInput::openInputStream(uint32_t devices, 103 audio_format_t* format, uint32_t* channelMask, uint32_t* sampleRate, 104 status_t* status) 105 { 106 (void) devices; 107 Mutex::Autolock _l(mLock); 108 109 AudioStreamIn* in; 110 111 in = new AudioStreamIn(*this); 112 if (in == NULL) { 113 *status = NO_MEMORY; 114 return NULL; 115 } 116 117 *status = in->set(format, channelMask, sampleRate); 118 119 if (*status != NO_ERROR) { 120 delete in; 121 return NULL; 122 } 123 124 mInputStreams.add(in); 125 126 return in; 127 } 128 129 void AudioHardwareInput::closeInputStream(AudioStreamIn* in) 130 { 131 Mutex::Autolock _l(mLock); 132 133 for (size_t i = 0; i < mInputStreams.size(); i++) { 134 if (in == mInputStreams[i]) { 135 mInputStreams.removeAt(i); 136 in->standby(); 137 delete in; 138 break; 139 } 140 } 141 } 142 143 void AudioHardwareInput::closeAllInputStreams() 144 { 145 while (mInputStreams.size() != 0) { 146 AudioStreamIn* in = mInputStreams[0]; 147 mInputStreams.removeAt(0); 148 in->standby(); 149 delete in; 150 } 151 } 152 153 void AudioHardwareInput::standbyAllInputStreams(const AudioHotplugThread::DeviceInfo* deviceInfo) 154 { 155 for (size_t i = 0; i < mInputStreams.size(); i++) { 156 if (deviceInfo == NULL || deviceInfo == mInputStreams[i]->getDeviceInfo()) { 157 mInputStreams[i]->standby(); 158 } 159 } 160 } 161 162 #define DUMP(a...) \ 163 snprintf(buffer, SIZE, a); \ 164 buffer[SIZE - 1] = 0; \ 165 result.append(buffer); 166 #define B2STR(b) b ? "true" : "false" 167 168 status_t AudioHardwareInput::dump(int fd) 169 { 170 const size_t SIZE = 256; 171 char buffer[SIZE]; 172 String8 result; 173 174 DUMP("\nAudioHardwareInput::dump\n"); 175 176 for (int i=0; i<kMaxDevices; i++) { 177 if (mDeviceInfos[i].valid) { 178 DUMP("device[%d] is valid\n", i); 179 DUMP("\tcapture card: %d\n", mDeviceInfos[i].pcmCard); 180 DUMP("\tcapture device: %d\n", mDeviceInfos[i].pcmDevice); 181 } 182 } 183 184 ::write(fd, result.string(), result.size()); 185 186 { 187 Mutex::Autolock _l(mLock); 188 for (size_t i = 0; i < mInputStreams.size(); i++) { 189 mInputStreams[i]->dump(fd); 190 } 191 } 192 193 return NO_ERROR; 194 } 195 196 #undef DUMP 197 #undef B2STR 198 199 // called on the audio hotplug thread 200 void AudioHardwareInput::onDeviceFound( 201 const AudioHotplugThread::DeviceInfo& devInfo) 202 { 203 bool foundSlot = false; 204 Mutex::Autolock _l(mLock); 205 206 ALOGD("AudioHardwareInput::onDeviceFound pcmCard = %d", devInfo.pcmCard); 207 208 for (int i=0; i<kMaxDevices; i++) { 209 if (mDeviceInfos[i].valid) { 210 if ((mDeviceInfos[i].pcmCard == devInfo.pcmCard) 211 && (mDeviceInfos[i].pcmDevice == devInfo.pcmDevice)) { 212 ALOGW("AudioHardwareInput::onDeviceFound already has %d:%d", 213 devInfo.pcmCard, devInfo.pcmDevice); 214 return; // Got it already so no action needed. 215 } 216 } 217 } 218 219 // New device so find an empty slot and save it. 220 for (int i=0; i<kMaxDevices; i++) { 221 if (!mDeviceInfos[i].valid) { 222 ALOGD("AudioHardwareInput::onDeviceFound saving as device #%d", i); 223 mDeviceInfos[i] = devInfo; 224 mDeviceInfos[i].valid = true; 225 foundSlot = true; 226 /* Restart any currently running streams. */ 227 standbyAllInputStreams(NULL); 228 break; 229 } 230 } 231 232 if (!foundSlot) { 233 ALOGW("AudioHardwareInput::onDeviceFound found more devices than expected! Dropped"); 234 } 235 } 236 237 // called on the audio hotplug thread 238 void AudioHardwareInput::onDeviceRemoved(unsigned int pcmCard, unsigned int pcmDevice) 239 { 240 Mutex::Autolock _l(mLock); 241 242 ALOGD("AudioHardwareInput::onDeviceRemoved pcmCard = %d", pcmCard); 243 // Find matching DeviceInfo. 244 for (int i=0; i<kMaxDevices; i++) { 245 if (mDeviceInfos[i].valid) { 246 if ((mDeviceInfos[i].pcmCard == pcmCard) && (mDeviceInfos[i].pcmDevice == pcmDevice)) { 247 ALOGD("AudioHardwareInput::onDeviceRemoved matches #%d", i); 248 mDeviceInfos[i].valid = false; 249 /* If currently active stream is using this device then restart. */ 250 standbyAllInputStreams(&mDeviceInfos[i]); 251 break; 252 } 253 } 254 } 255 } 256 257 const AudioHotplugThread::DeviceInfo* AudioHardwareInput::getBestDevice(int inputSource) 258 { 259 bool doVoiceRecognition = (inputSource == AUDIO_SOURCE_VOICE_RECOGNITION); 260 int chosenDeviceIndex = -1; 261 Mutex::Autolock _l(mLock); 262 263 ALOGD("AudioHardwareInput::getBestDevice inputSource = %d, doVoiceRecognition = %d", 264 inputSource, (doVoiceRecognition ? 1 : 0)); 265 // RemoteControl is the only input device usable for voice recognition 266 // and no other devices are used for voice recognition. 267 // Currently the RemoteControl is the only device marked with forVoiceRecognition=true. 268 // A connected USB mic could be used for anything but voice recognition. 269 for (int i=0; i<kMaxDevices; i++) { 270 if (mDeviceInfos[i].valid) { 271 if (mDeviceInfos[i].forVoiceRecognition == doVoiceRecognition) { 272 chosenDeviceIndex = i; 273 break; 274 } 275 } 276 } 277 278 if (chosenDeviceIndex < 0) { 279 ALOGE("ERROR AudioHardwareInput::getBestDevice, none for source %d", inputSource); 280 } else { 281 ALOGD("AudioHardwareInput::getBestDevice chose #%d", chosenDeviceIndex); 282 } 283 284 return (chosenDeviceIndex >= 0) ? &mDeviceInfos[chosenDeviceIndex] : NULL; 285 } 286 287 }; // namespace android 288