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