For posterity, and since I have faced this multiple times and later forgot/lost the information here, the entire RTP receive, decode, pipeline in WebRTC eventually delivers decoded PCM packets to webrtc/modules/audio_coding/neteq/neteq_impl.cc, into a PacketBuffer.
They then just sit in the packet_buffer and wait for something to come along and request/pull packets out.
This only happens in webrtc/voice_engine/channel.cc in 'MixerParticipant::AudioFrameInfo Channel::GetAudioFrameWithMuted' and 'AudioMixer::Source::AudioFrameInfo Channel::GetAudioFrameWithInfo'
You will notice that in GetAudioFrameWithMuted, this is where the audio_sink_->OnData(data) callback is made, that will eventually propagate to delivering frames to our registered AudioSinkInterface.
So, what is responsible for calling GetAudioFrameWIthMuted, or GetAudioFrameWithInfo?
Basically the mixer module:
webrtc/modules/audio_mixer/audio_mixer_impl.cc: AudioFrameList AudioMixerImpl::GetAudioFromSources
And what configures the mixer, and animates its requests for more frames?
webrtc/audio/audio_receive_stream.cc:
void AudioReceiveStream::Start() {
RTC_DCHECK_RUN_ON(&thread_checker_);
if (playing_) {
return;
}
int error = SetVoiceEnginePlayout(true);
cout << "AudioReceiveStream::Start SetVoiceEnginePlayout(true) error: " << error << endl;
if (error != 0) {
LOG(LS_ERROR) << "AudioReceiveStream::Start failed with error: " << error;
return;
}
cout << "AudioReceiveStream::Start mixer()->AddSource(this)" << endl;
if (!audio_state()->mixer()->AddSource(this)) {
LOG(LS_ERROR) << "Failed to add source to mixer.";
SetVoiceEnginePlayout(false);
return;
}
playing_ = true;
}
So, basically the way this code reads is, it attempts to start voice playout via the voice engine, and if it fails, it never attaches the mixer, which then never is around
to deliver audio samples to our OnData callback.
The remedy is as Ricky B. says, to provide your own AudioDeviceModule.
Override PeerConnectionFactory's default constructor, and replace the call to CreatePeerConnectionFactory with one that attaches a FakeAudioCaptureModule:
rtc::scoped_refptr<webrtc::AudioDeviceModule> adm = FakeAudioCaptureModule::Create();
The source for FakeAudioCaptureModule can be found here:
./webrtc/api/test/fakeaudiocapturemodule.cc
This will ultimately break normal playout, but probably a proxy could be made to wrap the default AudioDeviceModule, and basically if it fails to initialize, still allow the rest of the audio processing pipeline to continue so samples can be captured, and libwebrtc can continue to be used just as a library independent of its rendering features.
- Jason Thomas.