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
AudioHardwareInput()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
~AudioHardwareInput()56 AudioHardwareInput::~AudioHardwareInput()
57 {
58 if (mHotplugThread != NULL) {
59 mHotplugThread->shutdown();
60 mHotplugThread.clear();
61 }
62
63 closeAllInputStreams();
64 }
65
setMicMute(bool mute)66 status_t AudioHardwareInput::setMicMute(bool mute)
67 {
68 mMicMute = mute;
69 return NO_ERROR;
70 }
71
getMicMute(bool * mute)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
calculateInputBufferSize(uint32_t outputSampleRate,audio_format_t format,uint32_t channelCount)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
getInputBufferSize(const audio_config * config)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
openInputStream(uint32_t devices,audio_format_t * format,uint32_t * channelMask,uint32_t * sampleRate,status_t * status)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
closeInputStream(AudioStreamIn * in)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
closeAllInputStreams()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
standbyAllInputStreams(const AudioHotplugThread::DeviceInfo * deviceInfo)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
dump(int fd)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
onDeviceFound(const AudioHotplugThread::DeviceInfo & devInfo)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
onDeviceRemoved(unsigned int pcmCard,unsigned int pcmDevice)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
getBestDevice(int inputSource)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