使用音频设备播放 WebRTC C++ 应用程序的 AudioStream
Play AudioStream of WebRTC C++ Application with Audio Device
我用 C++ 编写了两个使用 WebRTC 的命令行应用程序:
- 客户端创建一个 PeerConnection 并打开一个 AudioStream
- 服务器接收并播放音频流
基本实现工作:他们交换 SDP-Offer 和 -Answer,使用 ICE 找到他们的外部 IP,创建具有相应约束的 PeerConnection 和 PeerConnectionFactory 等。我在服务器端添加了一个钩子到 RtpReceiverImpl::IncomingRtpPacket
将接收到的有效负载写入文件。该文件包含有效的 PCM 音频。因此,我假设客户端通过网络成功地将数据流式传输到服务器应用程序。
在服务器端,我的回调 PeerConnectionObserver::OnAddStream
被调用并收到 MediaStreamInterface
。此外,我可以通过我的音频设备迭代 DeviceManagerInterface::GetAudioOutputDevices
。所以基本上,一切都很好。
缺少什么:我需要某种胶水来告诉 WebRTC 在相应的设备上播放我的 AudioStream。我已经看到我可以获得 AudioSink、AudioRenderer 和 AudioTrack 对象。再一次:不幸的是,我没有看到将它们传递给音频设备的接口。有人可以帮我吗?
一个重要提示:我想避免调试真正的硬件。因此,我在构建 WebRTC 模块时添加了 -DWEBRTC_DUMMY_FILE_DEVICES。它应该将音频写入输出文件,但该文件仅包含 0x00。输入文件读取成功,因为正如我前面提到的,音频是通过 RTP 发送的。
最后,我找到了解决方案:首先,我不得不说我的代码使用的是 2017 年的 WebRTC。因此,以下内容可能已更改 and/or 已修复:
在调试我的代码和我看到的 WebRTC 库之后:添加远程流时,播放应该自动开始。开发人员无需在 VoiceEngine
中调用 playout()
或类似的东西。当库识别出远程音频流时,播放暂停,新源添加到混音器,然后恢复播放。唯一控制播放的 API 由 webrtc::MediaStreamInterface
提供,它通过 PeerConnectionObserver::OnAddStream
传递。例如 SetVolume()
或 set_enabled()
.
那么,我的情况出了什么问题?我使用了 FileAudioDevice
class 应该将原始音频数据写入输出文件而不是扬声器。我的实现包含两个错误:
FileAudioDevice::Playing()
在任何情况下都返回 true。因此,库添加了远程流,想要恢复播放,调用 FileAudioDevice::Playing()
返回 true 并中止,因为它认为 AudioDevice 已经处于播放模式。
- FileWrapper class 中似乎存在错误。最终输出通过
_outputFile.Write(_playoutBuffer, kPlayoutBufferSize)
以 FileAudioDevice::PlayThreadProcess()
写入磁盘。但是,这不起作用。幸运的是,一个普通的 C fwrite() 作为 hacky bugfix 确实有效。
我用 C++ 编写了两个使用 WebRTC 的命令行应用程序:
- 客户端创建一个 PeerConnection 并打开一个 AudioStream
- 服务器接收并播放音频流
基本实现工作:他们交换 SDP-Offer 和 -Answer,使用 ICE 找到他们的外部 IP,创建具有相应约束的 PeerConnection 和 PeerConnectionFactory 等。我在服务器端添加了一个钩子到 RtpReceiverImpl::IncomingRtpPacket
将接收到的有效负载写入文件。该文件包含有效的 PCM 音频。因此,我假设客户端通过网络成功地将数据流式传输到服务器应用程序。
在服务器端,我的回调 PeerConnectionObserver::OnAddStream
被调用并收到 MediaStreamInterface
。此外,我可以通过我的音频设备迭代 DeviceManagerInterface::GetAudioOutputDevices
。所以基本上,一切都很好。
缺少什么:我需要某种胶水来告诉 WebRTC 在相应的设备上播放我的 AudioStream。我已经看到我可以获得 AudioSink、AudioRenderer 和 AudioTrack 对象。再一次:不幸的是,我没有看到将它们传递给音频设备的接口。有人可以帮我吗?
一个重要提示:我想避免调试真正的硬件。因此,我在构建 WebRTC 模块时添加了 -DWEBRTC_DUMMY_FILE_DEVICES。它应该将音频写入输出文件,但该文件仅包含 0x00。输入文件读取成功,因为正如我前面提到的,音频是通过 RTP 发送的。
最后,我找到了解决方案:首先,我不得不说我的代码使用的是 2017 年的 WebRTC。因此,以下内容可能已更改 and/or 已修复:
在调试我的代码和我看到的 WebRTC 库之后:添加远程流时,播放应该自动开始。开发人员无需在 VoiceEngine
中调用 playout()
或类似的东西。当库识别出远程音频流时,播放暂停,新源添加到混音器,然后恢复播放。唯一控制播放的 API 由 webrtc::MediaStreamInterface
提供,它通过 PeerConnectionObserver::OnAddStream
传递。例如 SetVolume()
或 set_enabled()
.
那么,我的情况出了什么问题?我使用了 FileAudioDevice
class 应该将原始音频数据写入输出文件而不是扬声器。我的实现包含两个错误:
FileAudioDevice::Playing()
在任何情况下都返回 true。因此,库添加了远程流,想要恢复播放,调用FileAudioDevice::Playing()
返回 true 并中止,因为它认为 AudioDevice 已经处于播放模式。- FileWrapper class 中似乎存在错误。最终输出通过
_outputFile.Write(_playoutBuffer, kPlayoutBufferSize)
以FileAudioDevice::PlayThreadProcess()
写入磁盘。但是,这不起作用。幸运的是,一个普通的 C fwrite() 作为 hacky bugfix 确实有效。