Home | History | Annotate | Download | only in libaudio
      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 = 20;
     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     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