| /* |
| * Copyright (C) 2021 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "host/frontend/webrtc/lib/audio_device.h" |
| |
| #include <string.h> |
| |
| #include <android-base/logging.h> |
| |
| #include <chrono> |
| #include <thread> |
| |
| namespace cuttlefish { |
| namespace webrtc_streaming { |
| |
| CfAudioDeviceModule::CfAudioDeviceModule() {} |
| |
| int CfAudioDeviceModule::GetMoreAudioData(void* data, int bytes_per_sample, |
| int samples_per_channel, |
| int num_channels, int sample_rate, |
| bool& muted) { |
| muted = !playing_ || !audio_callback_; |
| if (muted) { |
| return 0; |
| } |
| |
| size_t read_samples; |
| int64_t elapsed_time; |
| int64_t ntp_time_ms; |
| auto res = audio_callback_->NeedMorePlayData( |
| samples_per_channel, bytes_per_sample, num_channels, sample_rate, data, |
| read_samples, &elapsed_time, &ntp_time_ms); |
| if (res != 0) { |
| return res; |
| } |
| return read_samples / num_channels; |
| } |
| |
| // Retrieve the currently utilized audio layer |
| int32_t CfAudioDeviceModule::ActiveAudioLayer(AudioLayer* audioLayer) const { |
| return -1; |
| } |
| |
| // Full-duplex transportation of PCM audio |
| int32_t CfAudioDeviceModule::RegisterAudioCallback( |
| webrtc::AudioTransport* audio_callback) { |
| audio_callback_ = audio_callback; |
| return 0; |
| } |
| |
| // Main initialization and termination |
| int32_t CfAudioDeviceModule::Init() { return 0; } |
| int32_t CfAudioDeviceModule::Terminate() { return 0; } |
| bool CfAudioDeviceModule::Initialized() const { return true; } |
| |
| // Device enumeration |
| int16_t CfAudioDeviceModule::PlayoutDevices() { return 1; } |
| int16_t CfAudioDeviceModule::RecordingDevices() { return 1; } |
| int32_t CfAudioDeviceModule::PlayoutDeviceName( |
| uint16_t index, char name[webrtc::kAdmMaxDeviceNameSize], |
| char guid[webrtc::kAdmMaxGuidSize]) { |
| if (index != 0) { |
| return -1; |
| } |
| constexpr auto device_name = "Cuttlefish Webrtc Audio"; |
| constexpr auto device_guid = "Cuttlefish Webrtc Audio Device Id"; |
| strncpy(name, device_name, webrtc::kAdmMaxDeviceNameSize); |
| name[webrtc::kAdmMaxDeviceNameSize - 1] = '\0'; |
| strncpy(guid, device_guid, webrtc::kAdmMaxGuidSize); |
| guid[webrtc::kAdmMaxGuidSize - 1] = '\0'; |
| return 0; |
| } |
| int32_t CfAudioDeviceModule::RecordingDeviceName( |
| uint16_t index, char name[webrtc::kAdmMaxDeviceNameSize], |
| char guid[webrtc::kAdmMaxGuidSize]) { |
| if (index != 0) { |
| return -1; |
| } |
| constexpr auto device_name = "Cuttlefish Webrtc Audio"; |
| constexpr auto device_guid = "Cuttlefish Webrtc Audio Device Id"; |
| strncpy(name, device_name, webrtc::kAdmMaxDeviceNameSize); |
| name[webrtc::kAdmMaxDeviceNameSize - 1] = '\0'; |
| strncpy(guid, device_guid, webrtc::kAdmMaxGuidSize); |
| guid[webrtc::kAdmMaxGuidSize - 1] = '\0'; |
| return 0; |
| } |
| |
| // Device selection |
| int32_t CfAudioDeviceModule::SetPlayoutDevice(uint16_t index) { return 0; } |
| int32_t CfAudioDeviceModule::SetPlayoutDevice(WindowsDeviceType device) { |
| return -1; |
| } |
| int32_t CfAudioDeviceModule::SetRecordingDevice(uint16_t index) { return 0; } |
| int32_t CfAudioDeviceModule::SetRecordingDevice(WindowsDeviceType device) { |
| return -1; |
| } |
| |
| // Audio transport initialization |
| int32_t CfAudioDeviceModule::PlayoutIsAvailable(bool* available) { |
| *available = true; |
| return 0; |
| } |
| int32_t CfAudioDeviceModule::InitPlayout() { return 0; } |
| bool CfAudioDeviceModule::PlayoutIsInitialized() const { return true; } |
| int32_t CfAudioDeviceModule::RecordingIsAvailable(bool* available) { |
| *available = 0; |
| return 0; |
| } |
| int32_t CfAudioDeviceModule::InitRecording() { return 0; } |
| bool CfAudioDeviceModule::RecordingIsInitialized() const { return true; } |
| |
| // Audio transport control |
| int32_t CfAudioDeviceModule::StartPlayout() { |
| playing_ = true; |
| return 0; |
| } |
| int32_t CfAudioDeviceModule::StopPlayout() { |
| playing_ = false; |
| return 0; |
| } |
| bool CfAudioDeviceModule::Playing() const { return playing_; } |
| int32_t CfAudioDeviceModule::StartRecording() { |
| recording_ = true; |
| return 0; |
| } |
| int32_t CfAudioDeviceModule::StopRecording() { |
| recording_ = false; |
| return 0; |
| } |
| bool CfAudioDeviceModule::Recording() const { return recording_; } |
| |
| // Audio mixer initialization |
| int32_t CfAudioDeviceModule::InitSpeaker() { return -1; } |
| bool CfAudioDeviceModule::SpeakerIsInitialized() const { return false; } |
| int32_t CfAudioDeviceModule::InitMicrophone() { return 0; } |
| bool CfAudioDeviceModule::MicrophoneIsInitialized() const { return true; } |
| |
| // Speaker volume controls |
| int32_t CfAudioDeviceModule::SpeakerVolumeIsAvailable(bool* available) { |
| *available = false; |
| return 0; |
| } |
| int32_t CfAudioDeviceModule::SetSpeakerVolume(uint32_t volume) { return -1; } |
| int32_t CfAudioDeviceModule::SpeakerVolume(uint32_t* volume) const { |
| return -1; |
| } |
| int32_t CfAudioDeviceModule::MaxSpeakerVolume(uint32_t* maxVolume) const { |
| return -1; |
| } |
| int32_t CfAudioDeviceModule::MinSpeakerVolume(uint32_t* minVolume) const { |
| return -1; |
| } |
| |
| // Microphone volume controls |
| int32_t CfAudioDeviceModule::MicrophoneVolumeIsAvailable(bool* available) { |
| *available = false; |
| return 0; |
| } |
| int32_t CfAudioDeviceModule::SetMicrophoneVolume(uint32_t volume) { return -1; } |
| int32_t CfAudioDeviceModule::MicrophoneVolume(uint32_t* volume) const { |
| return -1; |
| } |
| int32_t CfAudioDeviceModule::MaxMicrophoneVolume(uint32_t* maxVolume) const { |
| return -1; |
| } |
| int32_t CfAudioDeviceModule::MinMicrophoneVolume(uint32_t* minVolume) const { |
| return -1; |
| } |
| |
| // Speaker mute control |
| int32_t CfAudioDeviceModule::SpeakerMuteIsAvailable(bool* available) { |
| *available = false; |
| return 0; |
| } |
| int32_t CfAudioDeviceModule::SetSpeakerMute(bool enable) { return -1; } |
| int32_t CfAudioDeviceModule::SpeakerMute(bool* enabled) const { return -1; } |
| |
| // Microphone mute control |
| int32_t CfAudioDeviceModule::MicrophoneMuteIsAvailable(bool* available) { |
| *available = false; |
| return 0; |
| } |
| int32_t CfAudioDeviceModule::SetMicrophoneMute(bool enable) { return -1; } |
| int32_t CfAudioDeviceModule::MicrophoneMute(bool* enabled) const { return -1; } |
| |
| // Stereo support |
| int32_t CfAudioDeviceModule::StereoPlayoutIsAvailable(bool* available) const { |
| *available = true; |
| return 0; |
| } |
| int32_t CfAudioDeviceModule::SetStereoPlayout(bool enable) { |
| stereo_playout_enabled_ = enable; |
| return 0; |
| } |
| int32_t CfAudioDeviceModule::StereoPlayout(bool* enabled) const { |
| *enabled = stereo_playout_enabled_; |
| return 0; |
| } |
| int32_t CfAudioDeviceModule::StereoRecordingIsAvailable(bool* available) const { |
| *available = true; |
| return 0; |
| } |
| int32_t CfAudioDeviceModule::SetStereoRecording(bool enable) { |
| stereo_recording_enabled_ = enable; |
| return 0; |
| } |
| int32_t CfAudioDeviceModule::StereoRecording(bool* enabled) const { |
| *enabled = stereo_recording_enabled_; |
| return 0; |
| } |
| |
| // Playout delay |
| int32_t CfAudioDeviceModule::PlayoutDelay(uint16_t* delayMS) const { |
| // There is currently no way to estimate the real delay for thiese streams. |
| // Given that 10ms buffers are used almost everywhere in the pipeline we know |
| // the delay is at least 10ms, so that's the best guess here. |
| *delayMS = 10; |
| return 0; |
| } |
| |
| // Only supported on Android. |
| bool CfAudioDeviceModule::BuiltInAECIsAvailable() const { return false; } |
| bool CfAudioDeviceModule::BuiltInAGCIsAvailable() const { return false; } |
| bool CfAudioDeviceModule::BuiltInNSIsAvailable() const { return false; } |
| |
| // Enables the built-in audio effects. Only supported on Android. |
| int32_t CfAudioDeviceModule::EnableBuiltInAEC(bool enable) { return -1; } |
| int32_t CfAudioDeviceModule::EnableBuiltInAGC(bool enable) { return -1; } |
| int32_t CfAudioDeviceModule::EnableBuiltInNS(bool enable) { return -1; } |
| |
| int32_t CfAudioDeviceModule::GetPlayoutUnderrunCount() const { return -1; } |
| |
| } // namespace webrtc_streaming |
| } // namespace cuttlefish |