Home | History | Annotate | Download | only in voice_engine
      1 /*
      2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include "webrtc/voice_engine/voe_hardware_impl.h"
     12 
     13 #include <assert.h>
     14 
     15 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
     16 #include "webrtc/system_wrappers/interface/trace.h"
     17 #include "webrtc/voice_engine/include/voe_errors.h"
     18 #include "webrtc/voice_engine/voice_engine_impl.h"
     19 
     20 namespace webrtc
     21 {
     22 
     23 VoEHardware* VoEHardware::GetInterface(VoiceEngine* voiceEngine)
     24 {
     25 #ifndef WEBRTC_VOICE_ENGINE_HARDWARE_API
     26     return NULL;
     27 #else
     28     if (NULL == voiceEngine)
     29     {
     30         return NULL;
     31     }
     32     VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
     33     s->AddRef();
     34     return s;
     35 #endif
     36 }
     37 
     38 #ifdef WEBRTC_VOICE_ENGINE_HARDWARE_API
     39 
     40 VoEHardwareImpl::VoEHardwareImpl(voe::SharedData* shared) : _shared(shared)
     41 {
     42     WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
     43                  "VoEHardwareImpl() - ctor");
     44 }
     45 
     46 VoEHardwareImpl::~VoEHardwareImpl()
     47 {
     48     WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
     49                  "~VoEHardwareImpl() - dtor");
     50 }
     51 
     52 int VoEHardwareImpl::SetAudioDeviceLayer(AudioLayers audioLayer)
     53 {
     54     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
     55                  "SetAudioDeviceLayer(audioLayer=%d)", audioLayer);
     56 
     57     // Don't allow a change if VoE is initialized
     58     if (_shared->statistics().Initialized())
     59     {
     60         _shared->SetLastError(VE_ALREADY_INITED, kTraceError);
     61         return -1;
     62     }
     63 
     64     // Map to AudioDeviceModule::AudioLayer
     65     AudioDeviceModule::AudioLayer
     66         wantedLayer(AudioDeviceModule::kPlatformDefaultAudio);
     67     switch (audioLayer)
     68     {
     69         case kAudioPlatformDefault:
     70             // already set above
     71             break;
     72         case kAudioWindowsCore:
     73             wantedLayer = AudioDeviceModule::kWindowsCoreAudio;
     74             break;
     75         case kAudioWindowsWave:
     76             wantedLayer = AudioDeviceModule::kWindowsWaveAudio;
     77             break;
     78         case kAudioLinuxAlsa:
     79             wantedLayer = AudioDeviceModule::kLinuxAlsaAudio;
     80             break;
     81         case kAudioLinuxPulse:
     82             wantedLayer = AudioDeviceModule::kLinuxPulseAudio;
     83             break;
     84     }
     85 
     86     // Save the audio device layer for Init()
     87     _shared->set_audio_device_layer(wantedLayer);
     88 
     89     return 0;
     90 }
     91 
     92 int VoEHardwareImpl::GetAudioDeviceLayer(AudioLayers& audioLayer)
     93 {
     94     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
     95                "GetAudioDeviceLayer(devices=?)");
     96 
     97     // Can always be called regardless of VoE state
     98 
     99     AudioDeviceModule::AudioLayer
    100         activeLayer(AudioDeviceModule::kPlatformDefaultAudio);
    101 
    102     if (_shared->audio_device())
    103     {
    104         // Get active audio layer from ADM
    105         if (_shared->audio_device()->ActiveAudioLayer(&activeLayer) != 0)
    106         {
    107             _shared->SetLastError(VE_UNDEFINED_SC_ERR, kTraceError,
    108                 "  Audio Device error");
    109             return -1;
    110         }
    111     }
    112     else
    113     {
    114         // Return VoE's internal layer setting
    115         activeLayer = _shared->audio_device_layer();
    116     }
    117 
    118     // Map to AudioLayers
    119     switch (activeLayer)
    120     {
    121         case AudioDeviceModule::kPlatformDefaultAudio:
    122             audioLayer = kAudioPlatformDefault;
    123             break;
    124         case AudioDeviceModule::kWindowsCoreAudio:
    125             audioLayer = kAudioWindowsCore;
    126             break;
    127         case AudioDeviceModule::kWindowsWaveAudio:
    128             audioLayer = kAudioWindowsWave;
    129             break;
    130         case AudioDeviceModule::kLinuxAlsaAudio:
    131             audioLayer = kAudioLinuxAlsa;
    132             break;
    133         case AudioDeviceModule::kLinuxPulseAudio:
    134             audioLayer = kAudioLinuxPulse;
    135             break;
    136         default:
    137             _shared->SetLastError(VE_UNDEFINED_SC_ERR, kTraceError,
    138                 "  unknown audio layer");
    139     }
    140 
    141     WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
    142         VoEId(_shared->instance_id(), -1),
    143         "  Output: audioLayer=%d", audioLayer);
    144 
    145     return 0;
    146 }
    147 int VoEHardwareImpl::GetNumOfRecordingDevices(int& devices)
    148 {
    149     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    150                  "GetNumOfRecordingDevices(devices=?)");
    151 
    152     if (!_shared->statistics().Initialized())
    153     {
    154         _shared->SetLastError(VE_NOT_INITED, kTraceError);
    155         return -1;
    156     }
    157 
    158     devices = static_cast<int> (_shared->audio_device()->RecordingDevices());
    159 
    160     WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
    161         VoEId(_shared->instance_id(), -1), "  Output: devices=%d", devices);
    162 
    163     return 0;
    164 }
    165 
    166 int VoEHardwareImpl::GetNumOfPlayoutDevices(int& devices)
    167 {
    168     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    169                  "GetNumOfPlayoutDevices(devices=?)");
    170 
    171     if (!_shared->statistics().Initialized())
    172     {
    173         _shared->SetLastError(VE_NOT_INITED, kTraceError);
    174         return -1;
    175     }
    176 
    177     devices = static_cast<int> (_shared->audio_device()->PlayoutDevices());
    178 
    179     WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
    180         VoEId(_shared->instance_id(), -1),
    181         "  Output: devices=%d", devices);
    182 
    183     return 0;
    184 }
    185 
    186 int VoEHardwareImpl::GetRecordingDeviceName(int index,
    187                                             char strNameUTF8[128],
    188                                             char strGuidUTF8[128])
    189 {
    190     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    191                  "GetRecordingDeviceName(index=%d)", index);
    192 
    193     if (!_shared->statistics().Initialized())
    194     {
    195         _shared->SetLastError(VE_NOT_INITED, kTraceError);
    196         return -1;
    197     }
    198     if (strNameUTF8 == NULL)
    199     {
    200         _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
    201             "GetRecordingDeviceName() invalid argument");
    202         return -1;
    203     }
    204 
    205     // Note that strGuidUTF8 is allowed to be NULL
    206 
    207     // Init len variable to length of supplied vectors
    208     const uint16_t strLen = 128;
    209 
    210     // Check if length has been changed in module
    211     assert(strLen == kAdmMaxDeviceNameSize);
    212     assert(strLen == kAdmMaxGuidSize);
    213 
    214     char name[strLen];
    215     char guid[strLen];
    216 
    217     // Get names from module
    218     if (_shared->audio_device()->RecordingDeviceName(index, name, guid) != 0)
    219     {
    220         _shared->SetLastError(VE_CANNOT_RETRIEVE_DEVICE_NAME, kTraceError,
    221             "GetRecordingDeviceName() failed to get device name");
    222         return -1;
    223     }
    224 
    225     // Copy to vectors supplied by user
    226     strncpy(strNameUTF8, name, strLen);
    227     WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
    228         VoEId(_shared->instance_id(), -1),
    229         "  Output: strNameUTF8=%s", strNameUTF8);
    230 
    231     if (strGuidUTF8 != NULL)
    232     {
    233         strncpy(strGuidUTF8, guid, strLen);
    234         WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
    235             VoEId(_shared->instance_id(), -1),
    236             "  Output: strGuidUTF8=%s", strGuidUTF8);
    237     }
    238 
    239     return 0;
    240 }
    241 
    242 int VoEHardwareImpl::GetPlayoutDeviceName(int index,
    243                                           char strNameUTF8[128],
    244                                           char strGuidUTF8[128])
    245 {
    246     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    247                  "GetPlayoutDeviceName(index=%d)", index);
    248 
    249     if (!_shared->statistics().Initialized())
    250     {
    251         _shared->SetLastError(VE_NOT_INITED, kTraceError);
    252         return -1;
    253     }
    254     if (strNameUTF8 == NULL)
    255     {
    256         _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
    257             "GetPlayoutDeviceName() invalid argument");
    258         return -1;
    259     }
    260 
    261     // Note that strGuidUTF8 is allowed to be NULL
    262 
    263     // Init len variable to length of supplied vectors
    264     const uint16_t strLen = 128;
    265 
    266     // Check if length has been changed in module
    267     assert(strLen == kAdmMaxDeviceNameSize);
    268     assert(strLen == kAdmMaxGuidSize);
    269 
    270     char name[strLen];
    271     char guid[strLen];
    272 
    273     // Get names from module
    274     if (_shared->audio_device()->PlayoutDeviceName(index, name, guid) != 0)
    275     {
    276         _shared->SetLastError(VE_CANNOT_RETRIEVE_DEVICE_NAME, kTraceError,
    277             "GetPlayoutDeviceName() failed to get device name");
    278         return -1;
    279     }
    280 
    281     // Copy to vectors supplied by user
    282     strncpy(strNameUTF8, name, strLen);
    283     WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
    284         VoEId(_shared->instance_id(), -1),
    285         "  Output: strNameUTF8=%s", strNameUTF8);
    286 
    287     if (strGuidUTF8 != NULL)
    288     {
    289         strncpy(strGuidUTF8, guid, strLen);
    290         WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
    291             VoEId(_shared->instance_id(), -1),
    292             "  Output: strGuidUTF8=%s", strGuidUTF8);
    293     }
    294 
    295     return 0;
    296 }
    297 
    298 int VoEHardwareImpl::SetRecordingDevice(int index,
    299                                         StereoChannel recordingChannel)
    300 {
    301     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    302                  "SetRecordingDevice(index=%d, recordingChannel=%d)",
    303                  index, (int) recordingChannel);
    304     CriticalSectionScoped cs(_shared->crit_sec());
    305 
    306     if (!_shared->statistics().Initialized())
    307     {
    308         _shared->SetLastError(VE_NOT_INITED, kTraceError);
    309         return -1;
    310     }
    311 
    312     bool isRecording(false);
    313 
    314     // Store state about activated recording to be able to restore it after the
    315     // recording device has been modified.
    316     if (_shared->audio_device()->Recording())
    317     {
    318         WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
    319                      "SetRecordingDevice() device is modified while recording"
    320                      " is active...");
    321         isRecording = true;
    322         if (_shared->audio_device()->StopRecording() == -1)
    323         {
    324             _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
    325                 "SetRecordingDevice() unable to stop recording");
    326             return -1;
    327         }
    328     }
    329 
    330     // We let the module do the index sanity
    331 
    332     // Set recording channel
    333     AudioDeviceModule::ChannelType recCh =
    334         AudioDeviceModule::kChannelBoth;
    335     switch (recordingChannel)
    336     {
    337         case kStereoLeft:
    338             recCh = AudioDeviceModule::kChannelLeft;
    339             break;
    340         case kStereoRight:
    341             recCh = AudioDeviceModule::kChannelRight;
    342             break;
    343         case kStereoBoth:
    344             // default setting kChannelBoth (<=> mono)
    345             break;
    346     }
    347 
    348     if (_shared->audio_device()->SetRecordingChannel(recCh) != 0) {
    349       _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
    350           "SetRecordingChannel() unable to set the recording channel");
    351     }
    352 
    353     // Map indices to unsigned since underlying functions need that
    354     uint16_t indexU = static_cast<uint16_t> (index);
    355 
    356     int32_t res(0);
    357 
    358     if (index == -1)
    359     {
    360         res = _shared->audio_device()->SetRecordingDevice(
    361             AudioDeviceModule::kDefaultCommunicationDevice);
    362     }
    363     else if (index == -2)
    364     {
    365         res = _shared->audio_device()->SetRecordingDevice(
    366             AudioDeviceModule::kDefaultDevice);
    367     }
    368     else
    369     {
    370         res = _shared->audio_device()->SetRecordingDevice(indexU);
    371     }
    372 
    373     if (res != 0)
    374     {
    375         _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
    376             "SetRecordingDevice() unable to set the recording device");
    377         return -1;
    378     }
    379 
    380     // Init microphone, so user can do volume settings etc
    381     if (_shared->audio_device()->InitMicrophone() == -1)
    382     {
    383         _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceWarning,
    384             "SetRecordingDevice() cannot access microphone");
    385     }
    386 
    387     // Set number of channels
    388     bool available = false;
    389     if (_shared->audio_device()->StereoRecordingIsAvailable(&available) != 0) {
    390       _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
    391           "StereoRecordingIsAvailable() failed to query stereo recording");
    392     }
    393 
    394     if (_shared->audio_device()->SetStereoRecording(available) != 0)
    395     {
    396         _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
    397             "SetRecordingDevice() failed to set mono recording mode");
    398     }
    399 
    400     // Restore recording if it was enabled already when calling this function.
    401     if (isRecording)
    402     {
    403         if (!_shared->ext_recording())
    404         {
    405             WEBRTC_TRACE(kTraceInfo, kTraceVoice,
    406                 VoEId(_shared->instance_id(), -1),
    407                 "SetRecordingDevice() recording is now being restored...");
    408             if (_shared->audio_device()->InitRecording() != 0)
    409             {
    410                 WEBRTC_TRACE(kTraceError, kTraceVoice,
    411                     VoEId(_shared->instance_id(), -1),
    412                     "SetRecordingDevice() failed to initialize recording");
    413                 return -1;
    414             }
    415             if (_shared->audio_device()->StartRecording() != 0)
    416             {
    417                 WEBRTC_TRACE(kTraceError, kTraceVoice,
    418                              VoEId(_shared->instance_id(), -1),
    419                              "SetRecordingDevice() failed to start recording");
    420                 return -1;
    421             }
    422         }
    423     }
    424 
    425     return 0;
    426 }
    427 
    428 int VoEHardwareImpl::SetPlayoutDevice(int index)
    429 {
    430     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    431                  "SetPlayoutDevice(index=%d)", index);
    432     CriticalSectionScoped cs(_shared->crit_sec());
    433 
    434     if (!_shared->statistics().Initialized())
    435     {
    436         _shared->SetLastError(VE_NOT_INITED, kTraceError);
    437         return -1;
    438     }
    439 
    440     bool isPlaying(false);
    441 
    442     // Store state about activated playout to be able to restore it after the
    443     // playout device has been modified.
    444     if (_shared->audio_device()->Playing())
    445     {
    446         WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
    447                      "SetPlayoutDevice() device is modified while playout is "
    448                      "active...");
    449         isPlaying = true;
    450         if (_shared->audio_device()->StopPlayout() == -1)
    451         {
    452             _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
    453                 "SetPlayoutDevice() unable to stop playout");
    454             return -1;
    455         }
    456     }
    457 
    458     // We let the module do the index sanity
    459 
    460     // Map indices to unsigned since underlying functions need that
    461     uint16_t indexU = static_cast<uint16_t> (index);
    462 
    463     int32_t res(0);
    464 
    465     if (index == -1)
    466     {
    467         res = _shared->audio_device()->SetPlayoutDevice(
    468             AudioDeviceModule::kDefaultCommunicationDevice);
    469     }
    470     else if (index == -2)
    471     {
    472         res = _shared->audio_device()->SetPlayoutDevice(
    473             AudioDeviceModule::kDefaultDevice);
    474     }
    475     else
    476     {
    477         res = _shared->audio_device()->SetPlayoutDevice(indexU);
    478     }
    479 
    480     if (res != 0)
    481     {
    482         _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceError,
    483             "SetPlayoutDevice() unable to set the playout device");
    484         return -1;
    485     }
    486 
    487     // Init speaker, so user can do volume settings etc
    488     if (_shared->audio_device()->InitSpeaker() == -1)
    489     {
    490         _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceWarning,
    491             "SetPlayoutDevice() cannot access speaker");
    492     }
    493 
    494     // Set number of channels
    495     bool available = false;
    496     _shared->audio_device()->StereoPlayoutIsAvailable(&available);
    497     if (_shared->audio_device()->SetStereoPlayout(available) != 0)
    498     {
    499         _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
    500             "SetPlayoutDevice() failed to set stereo playout mode");
    501     }
    502 
    503     // Restore playout if it was enabled already when calling this function.
    504     if (isPlaying)
    505     {
    506         if (!_shared->ext_playout())
    507         {
    508             WEBRTC_TRACE(kTraceInfo, kTraceVoice,
    509                 VoEId(_shared->instance_id(), -1),
    510                 "SetPlayoutDevice() playout is now being restored...");
    511             if (_shared->audio_device()->InitPlayout() != 0)
    512             {
    513                 WEBRTC_TRACE(kTraceError, kTraceVoice,
    514                   VoEId(_shared->instance_id(), -1),
    515                   "SetPlayoutDevice() failed to initialize playout");
    516                 return -1;
    517             }
    518             if (_shared->audio_device()->StartPlayout() != 0)
    519             {
    520                 WEBRTC_TRACE(kTraceError, kTraceVoice,
    521                              VoEId(_shared->instance_id(), -1),
    522                              "SetPlayoutDevice() failed to start playout");
    523                 return -1;
    524             }
    525         }
    526     }
    527 
    528     return 0;
    529 }
    530 
    531 int VoEHardwareImpl::SetRecordingSampleRate(unsigned int samples_per_sec) {
    532   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    533                "%s", __FUNCTION__);
    534   if (!_shared->statistics().Initialized()) {
    535     _shared->SetLastError(VE_NOT_INITED, kTraceError);
    536     return false;
    537   }
    538   return _shared->audio_device()->SetRecordingSampleRate(samples_per_sec);
    539 }
    540 
    541 int VoEHardwareImpl::RecordingSampleRate(unsigned int* samples_per_sec) const {
    542   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    543                "%s", __FUNCTION__);
    544   if (!_shared->statistics().Initialized()) {
    545     _shared->SetLastError(VE_NOT_INITED, kTraceError);
    546     return false;
    547   }
    548   return _shared->audio_device()->RecordingSampleRate(samples_per_sec);
    549 }
    550 
    551 int VoEHardwareImpl::SetPlayoutSampleRate(unsigned int samples_per_sec) {
    552   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    553                "%s", __FUNCTION__);
    554   if (!_shared->statistics().Initialized()) {
    555     _shared->SetLastError(VE_NOT_INITED, kTraceError);
    556     return false;
    557   }
    558   return _shared->audio_device()->SetPlayoutSampleRate(samples_per_sec);
    559 }
    560 
    561 int VoEHardwareImpl::PlayoutSampleRate(unsigned int* samples_per_sec) const {
    562   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    563                "%s", __FUNCTION__);
    564   if (!_shared->statistics().Initialized()) {
    565     _shared->SetLastError(VE_NOT_INITED, kTraceError);
    566     return false;
    567   }
    568   return _shared->audio_device()->PlayoutSampleRate(samples_per_sec);
    569 }
    570 
    571 #endif  // WEBRTC_VOICE_ENGINE_HARDWARE_API
    572 
    573 }  // namespace webrtc
    574