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
33namespace android {
34
35// Global singleton.
36AudioHardwareInput gAudioHardwareInput;
37
38AudioHardwareInput::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
56AudioHardwareInput::~AudioHardwareInput()
57{
58    if (mHotplugThread != NULL) {
59        mHotplugThread->shutdown();
60        mHotplugThread.clear();
61    }
62
63    closeAllInputStreams();
64}
65
66status_t AudioHardwareInput::setMicMute(bool mute)
67{
68    mMicMute = mute;
69    return NO_ERROR;
70}
71
72status_t AudioHardwareInput::getMicMute(bool* mute)
73{
74    *mute = mMicMute;
75    return NO_ERROR;
76}
77
78// milliseconds per ALSA period
79const uint32_t AudioHardwareInput::kPeriodMsec = 20;
80
81size_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
94status_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
102AudioStreamIn* 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
129void 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
143void 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
153void 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
168status_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
200void 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
238void 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
257const AudioHotplugThread::DeviceInfo* AudioHardwareInput::getBestDevice(int inputSource)
258{
259    bool doVoiceRecognition = (inputSource == AUDIO_SOURCE_VOICE_RECOGNITION);
260    const bool favorNoVoiceRecognition = (inputSource == AUDIO_SOURCE_UNPROCESSED);
261    int chosenDeviceIndex = -1;
262    Mutex::Autolock _l(mLock);
263
264    ALOGD("AudioHardwareInput::getBestDevice inputSource = %d, doVoiceRecognition = %d",
265        inputSource, (doVoiceRecognition ? 1 : 0));
266    // RemoteControl is the only input device usable for voice recognition
267    // and no other devices are used for voice recognition.
268    // Currently the RemoteControl is the only device marked with forVoiceRecognition=true.
269    // A connected USB mic could be used for anything but voice recognition.
270    // For UNPROCESSED source, a connected USB microphone will be favored over the remote mic.
271    for (int i=0; i<kMaxDevices; i++) {
272        if (mDeviceInfos[i].valid) {
273            if (favorNoVoiceRecognition) {
274                if (mDeviceInfos[i].forVoiceRecognition) {
275                    chosenDeviceIndex = i;
276                    //continue matching
277                } else {
278                    chosenDeviceIndex = i;
279                    break;
280                }
281            } else if (mDeviceInfos[i].forVoiceRecognition == doVoiceRecognition) {
282                chosenDeviceIndex = i;
283                break;
284            }
285        }
286    }
287
288    if (chosenDeviceIndex < 0) {
289        ALOGE("ERROR AudioHardwareInput::getBestDevice, none for source %d", inputSource);
290    } else {
291        ALOGD("AudioHardwareInput::getBestDevice chose #%d", chosenDeviceIndex);
292    }
293
294    return (chosenDeviceIndex >= 0) ? &mDeviceInfos[chosenDeviceIndex] : NULL;
295}
296
297}; // namespace android
298