How to Get, Build, and Extend WebRTC m79 Source for Windows, Android, and iOS
This guide explains how to obtain the WebRTC m79 source, compile it for Windows, Android, and iOS, walk through the basic signaling and peer‑connection workflow, and implement advanced video‑capture and audio‑volume features with custom C++ extensions, while unifying the codebase across platforms.
1. Source acquisition and compilation
All commands refer to the webrtc m79 source unless otherwise noted.
The source and build instructions are documented at webrtc.googlesource.com .
Windows platform
# Set environment variables
GYP_GENERATORS=msvs-ninja,ninja
GYP_MSVS_OVERRIDE_PATH=D:\Program Files (x86)\Microsoft Visual Studio\2017\Community
GYP_MSVS_VERSION=2017
DEPOT_TOOLS_WIN_TOOLCHAIN=0
fetch --nohooks webrtc
gclient sync
gn gen out/Debug --ide=vs2017 --args="is_debug=true target_cpu=\"x86\""
ninja -C out/DebugAndroid platform
fetch --nohooks webrtc_android
gclient sync
cd src/
./build/install-build-deps.sh
./build/install-build-deps-android.sh
# To build for ARM64: use target_cpu="arm64"
# To build for 32‑bit x86: use target_cpu="x86"
# To build for 64‑bit x64: use target_cpu="x64"
gn gen out/Debug --args='target_os="android" target_cpu="arm"'
ninja -C out/DebugiOS platform
fetch --nohooks webrtc_ios
gclient sync
./tools_webrtc/ios/build_ios_libs.shAfter downloading and compiling, the generated libraries can be linked into applications on each platform.
2. WebRTC interaction logic
WebRTC does not provide a complete audio‑video system; it only defines how a session is established and media is transmitted. A typical session involves exchanging SDP (media description) and ICE candidates via a signaling server (HTTP, WebSocket, or any custom protocol).
3. Basic application
The following code implements a LAN‑only P2P call; signaling is omitted.
General development flow:
Initialize
PeerConnectionFactoryInterface rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> peer_connection_factory_;
peer_connection_factory_ = webrtc::CreatePeerConnectionFactory(
nullptr, nullptr, signaling_thread.get(), nullptr,
webrtc::CreateBuiltinAudioEncoderFactory(),
webrtc::CreateBuiltinAudioDecoderFactory(),
webrtc::CreateBuiltinVideoEncoderFactory(),
webrtc::CreateBuiltinVideoDecoderFactory(),
nullptr, nullptr);Create
PeerConnectionInterface rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_;
peer_connection_ = peer_connection_factory_->CreatePeerConnection(config, nullptr, nullptr, this);Add AudioTrack and
VideoTrack rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
peer_connection_factory_->CreateAudioTrack(kAudioLabel,
peer_connection_factory_->CreateAudioSource(cricket::AudioOptions())));
auto result = peer_connection_->AddTrack(audio_track, {kStreamId});
rtc::scoped_refptr<CapturerTrackSource> video_device = CapturerTrackSource::Create();
rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
peer_connection_factory_->CreateVideoTrack(kVideoLabel, video_device));
result = peer_connection_->AddTrack(video_track, {kStreamId});If rendering is needed, attach a VideoSink to the video track
video_track_->AddOrUpdateSink(this, rtc::VideoSinkWants());SDP and ICE candidate exchange (simplified)
// Client A creates offer
peer_connection_->CreateOffer(this, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions());
peer_connection_->SetLocalDescription(DummySetSessionDescriptionObserver::Create(), desc);
// Send SDP to Client B via signaling
// Client B receives SDP, creates PeerConnection, then creates answer
peer_connection_->SetRemoteDescription(DummySetSessionDescriptionObserver::Create(), remote_desc);
peer_connection_->CreateAnswer(this, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions());
peer_connection_->SetLocalDescription(DummySetSessionDescriptionObserver::Create(), desc);
// Exchange ICE candidates (may arrive before SDP, cache if needed)
peer_connection_->AddIceCandidate(candidate);When no errors occur, media data starts flowing to the VideoSink and the audio device module for playback.
4. Advanced applications
Two practical use‑cases on the client side are presented.
4.1 Video self‑capture
Live‑stream SDKs often provide beauty filters, but the vanilla WebRTC source lacks such features. To feed processed RGBA/NV12 textures into WebRTC, you need to understand the video‑capture pipeline.
4.1.1 Understanding the video pipeline
VideoSourceInterface: provides add / remove methods for video frames. VideoSinkInterface: unified output interface. VideoTrack holds a VideoSourceInterface; the encoder is attached to the track.
The data flow is: VideoTrack → VideoRtpSender → WebRtcVideoVChannel → WebRtcVideoSendStream → VideoSendStream →
VideoStreamEncoder VideoBroadcasterimplements both VideoSourceInterface and VideoSinkInterface, managing a std::vector<VideoSinkInterface*> of sinks. CapturerTrackSource implements VideoSourceInterface and forwards frames to the broadcaster, which then distributes them to all registered sinks.
4.1.2 Solution
/* VideoSourceImpl.h */
class VideoSourceImpl : public VideoSourceInterface<VideoFrame> {
public:
virtual ~VideoSourceImpl();
static VideoSourceImpl* Create(size_t width, size_t height, size_t target_fps, size_t capture_device_index);
void AddOrUpdateSink(VideoSinkInterface<VideoFrame>* sink, const VideoSinkWants& wants) override;
void RemoveSink(VideoSinkInterface<VideoFrame>* sink) override;
void OnFrame(VideoFrame& frame) override;
private:
VideoSourceImpl();
VideoBroadcaster broadcaster_;
};
/* VideoSourceImpl.cc */
VideoSourceImpl* VideoSourceImpl::Create(size_t width, size_t height, size_t fps, size_t idx) {
auto v = std::make_unique<VideoSourceImpl>();
return v.release();
}
VideoSourceImpl::VideoSourceImpl() {}
VideoSourceImpl::~VideoSourceImpl() {}
void VideoSourceImpl::AddOrUpdateSink(VideoSinkInterface<VideoFrame>* sink, const VideoSinkWants& wants) {
broadcaster_.AddOrUpdateSink(sink, wants);
}
void VideoSourceImpl::RemoveSink(VideoSinkInterface<VideoFrame>* sink) { broadcaster_.RemoveSink(sink); }
void VideoSourceImpl::OnFrame(VideoFrame& frame) { broadcaster_.OnFrame(frame); }Pass a VideoSourceImpl instance to VideoTrack; external texture/RGBA/NV12 data can be injected via VideoSourceImpl::OnFrame.
4.2 Audio local‑volume callback
In multi‑person voice chat, displaying real‑time volume levels is useful, but vanilla WebRTC lacks this feature.
4.2.1 Audio pipeline and ADM
AudioDeviceModule: abstracts platform‑specific audio capture/playback; owns an AudioDeviceBuffer. AudioDeviceBuffer: holds an AudioTransport for data flow. AudioTransport: interface for feeding captured audio ( RecordedDataIsAvailable) and requesting playback data ( NeedMorePlayData). AudioProcessing: performs 3A (AEC, AGC, NS) on captured audio. AudioMixer: mixes remote audio streams. AudioState: orchestrates the above components.
class AudioDeviceModule : public rtc::RefCountInterface {
public:
static rtc::scoped_refptr<AudioDeviceModule> Create(AudioLayer audio_layer, TaskQueueFactory* task_queue_factory);
virtual int32_t RegisterAudioCallback(AudioTransport* audioCallback) = 0;
virtual int32_t StartPlayout() = 0;
virtual int32_t StopPlayout() = 0;
virtual bool Playing() const = 0;
virtual int32_t StartRecording() = 0;
virtual int32_t StopRecording() = 0;
virtual bool Recording() const = 0;
protected:
~AudioDeviceModule() override {}
}; class AudioDeviceBuffer {
AudioTransport* audio_transport_cb_;
// ... other members ...
};
int32_t AudioDeviceBuffer::RegisterAudioCallback(AudioTransport* audio_callback) {
if (playing_ || recording_) return -1;
audio_transport_cb_ = audio_callback;
return 0;
} class AudioTransport {
public:
virtual int32_t RecordedDataIsAvailable(const void* audioSamples, size_t nSamples,
size_t nBytesPerSample, size_t nChannels, uint32_t samplesPerSec,
uint32_t total_delay_ms, int32_t clockDrift, uint32_t currentMicLevel,
bool keyPressed, uint32_t& newMicLevel) = 0;
virtual int32_t NeedMorePlayData(size_t nSamples, size_t nBytesPerSample,
size_t nChannels, uint32_t samplesPerSec, void* audioSamples,
size_t& nSamplesOut, int64_t* elapsed_time_ms, int64_t* ntp_time_ms) = 0;
protected:
virtual ~AudioTransport() {}
};Platform‑specific AudioDeviceModule implementations (Windows, Android, iOS) each contain a concrete AudioDeviceBuffer which holds a platform‑specific AudioTransport. The link is established via AudioDeviceModule::RegisterAudioCallback.
4.2.2 Custom solution
// CustomADMWrapper.h
class CustomADMWrapper : public webrtc::AudioDeviceModule, public webrtc::AudioTransport {
public:
// AudioTransport overrides
int32_t RecordedDataIsAvailable(const void* audioSamples, size_t nSamples,
size_t nBytesPerSample, size_t nChannels, uint32_t samples_per_sec,
uint32_t total_delay_ms, int32_t clockDrift, uint32_t currentMicLevel,
bool keyPressed, uint32_t& newMicLevel) override;
};
// CustomADMWrapper.cc
int32_t CustomADMWrapper::RecordedDataIsAvailable(const void* audioSamples, size_t nSamples,
size_t nBytesPerSample, size_t nChannels, uint32_t samples_per_sec,
uint32_t total_delay_ms, int32_t clockDrift, uint32_t currentMicLevel,
bool keyPressed, uint32_t& newMicLevel) {
// Compute volume level and report it upstream.
return res;
}5. Unified source management
WebRTC maintains separate branches for each platform. By extracting the common core into a single repository and keeping platform‑specific third‑party libraries in separate repos, developers can modify the core in one place and build for Windows, Android, or iOS without branch switching.
6. System architecture
Core layer: exposes public APIs, integrates WebRTC and signaling SDKs, manages business logic and logging.
Adapter layer: JNI on Android, Objective‑C on iOS, direct calls on Windows.
API layer: provides platform‑specific interfaces, integrates ADM, codec, and other platform features.
Core library wraps platform‑specific builds. DYRtcClient module integrates signaling SDK, WebRTC, and logging. DYRTCEngineKit_Windows/Android/iOS modules implement platform‑specific capture, encoding, and ADM logic.
By unifying the source and business logic, maintenance costs for WebRTC‑based products are greatly reduced.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Douyu Streaming
Official account of Douyu Streaming Development Department, sharing audio and video technology best practices.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
