PeerConnection Source Code
Creation and Initialization of RTCPeerConnection
RTCPeerConnection Creation Process:
// 1. Create PeerConnectionFactory
rtc::scoped_refptr<PeerConnectionFactory> factory(
PeerConnectionFactory::Create());
// 2. Create PeerConnection
rtc::scoped_refptr<RTCPeerConnection> pc(
factory->CreatePeerConnection(
configuration, // RTCConfiguration
constraints, // MediaConstraints
nullptr, // PeerConnectionObserver
nullptr, // std::unique_ptr<CertificateVerifier>
&error)); // Error information
// 3. Add media stream
rtc::scoped_refptr<MediaStreamInterface> stream = ...;
pc->AddStream(stream);
// 4. Create Offer/Answer
pc->CreateOffer(offer_observer, offer_answer_options);Key Source Code Implementation:
// peer_connection.cc
rtc::scoped_refptr<RTCPeerConnection> RTCPeerConnection::Create(
PeerConnectionFactory* factory,
const PeerConnectionInterface::RTCConfiguration& configuration,
const MediaConstraintsInterface* constraints,
PeerConnectionObserver* observer,
std::unique_ptr<CertificateVerifier> certificate_verifier,
std::string* error) {
// Validate input parameters
if (!factory) {
*error = "PeerConnectionFactory is null";
return nullptr;
}
// Create PeerConnectionImpl instance
rtc::scoped_refptr<RTCPeerConnection> pc(
new rtc::RefCountedObject<RTCPeerConnectionImpl>(
factory, configuration, constraints, observer,
std::move(certificate_verifier)));
// Initialize PeerConnection
if (!pc->Initialize()) {
*error = "Failed to initialize PeerConnection";
return nullptr;
}
return pc;
}
bool RTCPeerConnectionImpl::Initialize() {
// Create ICE transport
ice_transport_ = CreateIceTransport();
// Create DTLS transport
dtls_transport_ = CreateDtlsTransport(ice_transport_.get());
// Create media engine
media_engine_ = factory_->media_engine();
// Initialize state
signaling_state_ = kStable;
ice_connection_state_ = kIceConnectionNew;
return true;
}SDP Exchange and Negotiation Process
Complete SDP Negotiation Process:
- Create Offer
- Set Local Description
- Send Offer via Signaling Server
- Receive Answer
- Set Remote Description
Key Source Code Implementation:
// sdp_offer_answer.cc
rtc::scoped_refptr<SessionDescriptionInterface> RTCPeerConnectionImpl::CreateOffer(
const CreateSessionDescriptionObserver* observer,
const PeerConnectionInterface::RTCOfferAnswerOptions& options) {
// Create Offer generator
std::unique_ptr<SessionDescriptionInterface> offer(
CreateSessionDescription(SdpType::kOffer, nullptr));
// Add media descriptions
for (const auto& track : local_streams_) {
AddTrackToOffer(track, offer.get(), options);
}
// Set SDP attributes
SetSdpAttributes(offer.get(), options);
// Return generated Offer
return offer;
}
void RTCPeerConnectionImpl::SetLocalDescription(
SetSessionDescriptionObserver* observer,
SessionDescriptionInterface* desc) {
// Validate SDP
if (!ValidateSessionDescription(desc, kLocal)) {
observer->OnFailure("Invalid session description");
return;
}
// Apply SDP to internal state
ApplySessionDescription(desc, kLocal);
// Notify observer
observer->OnSuccess();
// Trigger ICE restart (if needed)
MaybeRestartIce();
}ICE Candidate Collection and Exchange
ICE Candidate Collection Process:
- Collect Host Candidates
- Collect STUN Candidates
- Collect TURN Candidates
- Exchange Candidates via Signaling Server
Key Source Code Implementation:
// ice_transport.cc
void IceTransport::StartGathering() {
// Start collecting host candidates
port_allocator_->StartGettingPorts();
// Send STUN requests to obtain server reflexive candidates
stun_port_->Start();
// Create TURN port if TURN server is configured
if (config_.has_turn_server()) {
turn_port_ = CreateTurnPort(config_.turn_server());
turn_port_->Start();
}
}
void IceTransport::OnCandidateGathered(const IceCandidateInterface* candidate) {
// Add candidate to list
local_candidates_.push_back(candidate);
// Notify observer
if (observer_) {
observer_->OnIceCandidate(candidate);
}
}ICE Candidate Exchange:
// peer_connection.cc
void RTCPeerConnectionImpl::AddIceCandidate(
const IceCandidateInterface* candidate) {
// Validate candidate
if (!candidate) {
LOG(LS_ERROR) << "Null candidate";
return;
}
// Add to ICE transport
if (!ice_transport_->AddRemoteCandidate(candidate)) {
LOG(LS_ERROR) << "Failed to add remote candidate";
return;
}
// Trigger connection check
ice_transport_->MaybeStartGathering();
}Connection State Monitoring and Event Handling
Connection State Types:
enum SignalingState {
kStable,
kHaveLocalOffer,
kHaveRemoteOffer,
kHaveLocalPrAnswer,
kHaveRemotePrAnswer,
kClosed
};
enum IceConnectionState {
kIceConnectionNew,
kIceConnectionChecking,
kIceConnectionConnected,
kIceConnectionCompleted,
kIceConnectionFailed,
kIceConnectionDisconnected,
kIceConnectionClosed,
kIceConnectionMax
};State Monitoring Implementation:
// peer_connection.cc
void RTCPeerConnectionImpl::UpdateConnectionState() {
IceConnectionState new_state = CalculateIceConnectionState();
if (new_state != ice_connection_state_) {
ice_connection_state_ = new_state;
observer_->OnIceConnectionChange(ice_connection_state_);
}
SignalingState new_signaling_state = CalculateSignalingState();
if (new_signaling_state != signaling_state_) {
signaling_state_ = new_signaling_state;
observer_->OnSignalingChange(signaling_state_);
}
}
void RTCPeerConnectionImpl::OnIceConnectionStateChange(
PeerConnectionInterface::IceConnectionState new_state) {
// Handle ICE connection state change
switch (new_state) {
case kIceConnectionFailed:
// Attempt reconnection
MaybeRestartIce();
break;
case kIceConnectionClosed:
// Clean up resources
Cleanup();
break;
default:
break;
}
// Notify observer
observer_->OnIceConnectionChange(new_state);
}Error Handling and Recovery Mechanisms
Error Handling Strategies:
- Automatically restart ICE on connection failure
- Retry on SDP negotiation failure
- Switch candidates on network errors
Key Source Code Implementation:
// peer_connection.cc
void RTCPeerConnectionImpl::MaybeRestartIce() {
if (ice_restart_pending_) {
return;
}
ice_restart_pending_ = true;
// Create new Offer
CreateOffer(
new rtc::RefCountedObject<CreateSessionDescriptionObserverImpl>(
this, [this]() {
// Set local Description
SetLocalDescription(
new rtc::RefCountedObject<SetSessionDescriptionObserverImpl>(
this),
current_local_description_.get());
ice_restart_pending_ = false;
}),
PeerConnectionInterface::RTCOfferAnswerOptions());
}
void RTCPeerConnectionImpl::OnFailure(const std::string& error) {
LOG(LS_ERROR) << "PeerConnection error: " << error;
// Notify observer
if (observer_) {
observer_->OnSignalingChange(kClosed);
}
// Clean up resources
Cleanup();
}MediaStream Source Code
MediaStream Creation and Track Management
MediaStream Creation Process:
// 1. Create media stream
rtc::scoped_refptr<MediaStreamInterface> stream(
peer_connection_factory->CreateLocalMediaStream("stream_label"));
// 2. Add audio track
rtc::scoped_refptr<AudioTrackInterface> audio_track(
peer_connection_factory->CreateAudioTrack("audio_label", audio_source));
stream->AddTrack(audio_track);
// 3. Add video track
rtc::scoped_refptr<VideoTrackInterface> video_track(
peer_connection_factory->CreateVideoTrack("video_label", video_source));
stream->AddTrack(video_track);Key Source Code Implementation:
// media_stream.cc
rtc::scoped_refptr<MediaStreamInterface> PeerConnectionFactory::CreateLocalMediaStream(
const std::string& label) {
// Create MediaStream implementation
rtc::scoped_refptr<MediaStream> stream(new rtc::RefCountedObject<MediaStream>(label));
return stream;
}
void MediaStream::AddTrack(AudioTrackInterface* track) {
// Check for existing track with same ID
if (FindAudioTrack(track->id())) {
LOG(LS_ERROR) << "Audio track with id " << track->id() << " already exists";
return;
}
// Add track
audio_tracks_.push_back(track);
// Notify observers
for (auto& observer : observers_) {
observer->OnTrackAdded(track);
}
}Media Track Constraints and Configuration
Track Constraints Example:
// Create audio constraints
MediaConstraints audio_constraints;
audio_constraints.AddOptionalConstraint("googEchoCancellation", "true");
audio_constraints.AddOptionalConstraint("googAutoGainControl", "true");
// Create video constraints
MediaConstraints video_constraints;
video_constraints.AddMandatoryConstraint("minWidth", "640");
video_constraints.AddMandatoryConstraint("minHeight", "480");
video_constraints.AddMandatoryConstraint("minFrameRate", "30");
// Create audio source
rtc::scoped_refptr<AudioSourceInterface> audio_source(
peer_connection_factory->CreateAudioSource(&audio_constraints));
// Create video source
rtc::scoped_refptr<VideoTrackSourceInterface> video_source(
peer_connection_factory->CreateVideoSource(video_constraints, nullptr));Key Source Code Implementation:
// media_constraints.cc
bool MediaConstraints::AddMandatoryConstraint(const std::string& key,
const std::string& value) {
mandatory_.push_back(Constraint(key, value));
return true;
}
bool MediaConstraints::AddOptionalConstraint(const std::string& key,
const std::string& value) {
optional_.push_back(Constraint(key, value));
return true;
}
// video_track_source.cc
rtc::scoped_refptr<VideoTrackSourceInterface> PeerConnectionFactory::CreateVideoSource(
const MediaConstraints* constraints,
cricket::VideoCapturer* capturer) {
// Create video source implementation
rtc::scoped_refptr<VideoTrackSource> source(
new rtc::RefCountedObject<VideoTrackSource>(capturer));
// Apply constraints
if (constraints) {
source->ApplyConstraints(*constraints);
}
return source;
}Media Stream Display and Control
Media Stream Display Implementation:
// Get video track
rtc::scoped_refptr<VideoTrackInterface> video_track = stream->GetVideoTracks()[0];
// Create video renderer
rtc::scoped_refptr<VideoRendererInterface> renderer(
new rtc::RefCountedObject<VideoRenderer>(video_element));
// Add renderer to track
video_track->AddOrUpdateSink(renderer.get(), rtc::VideoSinkWants());
// Control media stream
stream->GetAudioTracks()[0]->set_enabled(false); // Mute audio
stream->GetVideoTracks()[0]->set_enabled(false); // Stop videoKey Source Code Implementation:
// media_stream_track.cc
void MediaStreamTrack::set_enabled(bool enabled) {
if (enabled_ == enabled) {
return;
}
enabled_ = enabled;
// Notify observers
for (auto& observer : observers_) {
observer->OnChanged();
}
// Actually enable/disable track
if (enabled) {
Enable();
} else {
Disable();
}
}
// video_track.cc
void VideoTrack::AddOrUpdateSink(rtc::VideoSinkInterface<webrtc::VideoFrame>* sink,
const rtc::VideoSinkWants& wants) {
// Add or update renderer
sinks_[sink] = wants;
// Notify source update
if (source_) {
source_->AddOrUpdateSink(sink, wants);
}
}Screen Sharing Implementation
Screen Sharing Process:
- Obtain screen capture source
- Create video track
- Add to media stream
- Add to PeerConnection
Key Source Code Implementation:
// Create screen capture source
rtc::scoped_refptr<DesktopCapturer> capturer(
DesktopCapturer::CreateScreenCapturer());
// Create video source
rtc::scoped_refptr<VideoTrackSourceInterface> video_source(
peer_connection_factory->CreateVideoSource(
MediaConstraints(), capturer.get()));
// Create video track
rtc::scoped_refptr<VideoTrackInterface> video_track(
peer_connection_factory->CreateVideoTrack("screen_share", video_source));
// Add to media stream
rtc::scoped_refptr<MediaStreamInterface> stream(
peer_connection_factory->CreateLocalMediaStream("screen_stream"));
stream->AddTrack(video_track);
// Add to PeerConnection
peer_connection->AddStream(stream);Screen Capture Source Implementation:
// desktop_capturer.cc
bool DesktopCapturer::CaptureFrame(webrtc::VideoFrame* frame) {
// Capture screen frame
DesktopFrame* desktop_frame = CaptureDesktop();
if (!desktop_frame) {
return false;
}
// Convert to VideoFrame
*frame = webrtc::VideoFrame::Builder()
.set_video_frame_buffer(desktop_frame)
.set_timestamp_us(clock_->TimeInMicroseconds())
.set_rotation(webrtc::kVideoRotation_0)
.build();
return true;
}Media Stream Recording and Playback
Media Stream Recording Implementation:
// Create file writer
rtc::scoped_refptr<FileVideoSink> file_sink(
new rtc::RefCountedObject<FileVideoSink>("output.webm"));
// Add to video track
video_track->AddOrUpdateSink(file_sink.get(), rtc::VideoSinkWants());
// Stop recording
video_track->RemoveSink(file_sink.get());Key Source Code Implementation:
// file_video_sink.cc
void FileVideoSink::OnFrame(const webrtc::VideoFrame& frame) {
// Write frame to file
if (!writer_) {
writer_ = CreateWebmWriter(filename_);
}
// Convert frame format and write
EncodedImage encoded_image;
encoder_->Encode(frame, &encoded_image);
writer_->WriteFrame(encoded_image);
}
// Media stream playback
rtc::scoped_refptr<MediaStreamInterface> LoadRecordedStream(const std::string& filename) {
// Create media stream
rtc::scoped_refptr<MediaStreamInterface> stream(
peer_connection_factory->CreateLocalMediaStream("replay_stream"));
// Create video track
rtc::scoped_refptr<VideoTrackInterface> video_track(
peer_connection_factory->CreateVideoTrack("replay_video", nullptr));
// Set custom video source (read from file)
rtc::scoped_refptr<VideoTrackSourceInterface> video_source(
new rtc::RefCountedObject<FileVideoSource>(filename));
video_track->SetSource(video_source);
// Add to media stream
stream->AddTrack(video_track);
return stream;
}DataChannel Source Code
RTCDataChannel Creation and Configuration
DataChannel Creation Process:
// 1. Create DataChannel configuration
webrtc::DataChannelInit config;
config.ordered = true;
config.maxRetransmitTime = 3000; // 3 seconds
config.maxRetransmits = 10;
config.protocol = "sctp";
// 2. Create DataChannel
rtc::scoped_refptr<RTCDataChannel> channel(
peer_connection->CreateDataChannel("data_channel", &config));
// 3. Set observer
channel->RegisterObserver(this);Key Source Code Implementation:
// data_channel.cc
rtc::scoped_refptr<RTCDataChannel> RTCPeerConnection::CreateDataChannel(
const std::string& label,
const DataChannelInit* config) {
// Create SCTP transport (if not already created)
if (!sctp_transport_) {
sctp_transport_ = CreateSctpTransport();
}
// Create DataChannel implementation
rtc::scoped_refptr<DataChannel> channel(
new rtc::RefCountedObject<DataChannel>(
this, label, config, sctp_transport_));
// Add to channel list
data_channels_.push_back(channel);
return channel;
}
// sctp_transport.cc
rtc::scoped_refptr<SctpTransport> RTCPeerConnection::CreateSctpTransport() {
// Create SCTP transport
rtc::scoped_refptr<SctpTransport> transport(
new rtc::RefCountedObject<SctpTransport>(
network_thread_, ice_transport_));
// Initialize SCTP
transport->Start(5000); // 5-second timeout
return transport;
}Data Sending and Receiving Implementation
Data Sending Implementation:
// Send text data
channel->Send(TextMessage("Hello, WebRTC!"));
// Send binary data
std::vector<uint8_t> binary_data = {0x01, 0x02, 0x03};
channel->Send(BinaryMessage(binary_data));Key Source Code Implementation:
// data_channel.cc
bool DataChannel::Send(const DataBuffer& buffer) {
// Check channel state
if (state_ != kOpen) {
LOG(LS_ERROR) << "Channel is not open";
return false;
}
// Check message size limit
if (buffer.size() > max_message_size_) {
LOG(LS_ERROR) << "Message too large";
return false;
}
// Send data via SCTP
if (!sctp_transport_->Send(buffer)) {
LOG(LS_ERROR) << "Failed to send data via SCTP";
return false;
}
return true;
}
// sctp_transport.cc
bool SctpTransport::Send(const DataBuffer& buffer) {
// Create SCTP data chunk
SctpPacket packet;
packet.AddData(buffer.data.cdata(), buffer.data.size(), buffer.binary);
// Send packet
return socket_->Send(packet);
}Data Receiving Implementation:
// Implement DataChannelObserver interface
class DataChannelObserverImpl : public DataChannelObserver {
public:
void OnMessage(const DataBuffer& buffer) override {
if (buffer.binary) {
// Process binary data
ProcessBinaryData(buffer.data);
} else {
// Process text data
ProcessTextData(buffer.data);
}
}
};
// Register observer
channel->RegisterObserver(new DataChannelObserverImpl());Data Channel State Management
DataChannel State Types:
enum DataChannelState {
kConnecting,
kOpen,
kClosing,
kClosed
};State Management Implementation:
// data_channel.cc
void DataChannel::UpdateState() {
DataChannelState new_state = CalculateState();
if (new_state != state_) {
DataChannelState old_state = state_;
state_ = new_state;
// Notify observer
if (observer_) {
observer_->OnStateChange();
}
// Handle state transition
switch (state_) {
case kOpen:
OnOpen();
break;
case kClosed:
OnClose();
break;
default:
break;
}
}
}
void DataChannel::OnSctpNotification(const SctpNotification& notification) {
switch (notification.type) {
case SCTP_ASSOC_CHANGE:
if (notification.state == SCTP_COMM_UP) {
SetState(kOpen);
} else if (notification.state == SCTP_COMM_LOST ||
notification.state == SCTP_SHUTDOWN_COMP) {
SetState(kClosed);
}
break;
case SCTP_PEER_ADDR_CHANGE:
// Handle peer address change
break;
default:
break;
}
}Data Fragmentation and Reassembly
Data Fragmentation Strategy:
- Fragment by maximum message size
- Fragment by SCTP maximum transmission unit (MTU)
- Reliable/unreliable transmission modes
Key Source Code Implementation:
// data_channel.cc
bool DataChannel::Send(const DataBuffer& buffer) {
// Check if fragmentation is needed
if (buffer.size() <= max_message_size_) {
// Send directly
return sctp_transport_->Send(buffer);
} else {
// Send fragmented
return SendFragments(buffer);
}
}
bool DataChannel::SendFragments(const DataBuffer& buffer) {
size_t offset = 0;
while (offset < buffer.size()) {
size_t fragment_size = std::min(max_message_size_, buffer.size() - offset);
DataBuffer fragment(buffer.data.cdata() + offset, fragment_size, buffer.binary);
if (!sctp_transport_->Send(fragment)) {
return false;
}
offset += fragment_size;
}
return true;
}Data Reassembly Implementation:
// sctp_transport.cc
void SctpTransport::OnDataReceived(const SctpPacket& packet) {
// Extract data chunk
SctpDataChunk chunk;
if (!packet.GetDataChunk(&chunk)) {
return;
}
// Check if data is fragmented
if (chunk.is_unordered()) {
// Handle unordered data
HandleUnorderedData(chunk);
} else {
// Handle ordered data
HandleOrderedData(chunk);
}
}
void SctpTransport::HandleOrderedData(const SctpDataChunk& chunk) {
// Check if it is a fragment
if (chunk.is_beginning_fragment()) {
// Start new fragmented message
current_fragment_ = std::make_unique<DataFragment>();
current_fragment_->stream_id = chunk.stream_id();
current_fragment_->ppid = chunk.ppid();
current_fragment_->data = chunk.data();
current_fragment_->is_complete = false;
} else if (chunk.is_middle_fragment()) {
// Add to current fragment
if (current_fragment_ && current_fragment_->stream_id == chunk.stream_id()) {
current_fragment_->data.append(chunk.data());
}
} else if (chunk.is_end_fragment()) {
// Complete fragment
if (current_fragment_ && current_fragment_->stream_id == chunk.stream_id()) {
current_fragment_->data.append(chunk.data());
current_fragment_->is_complete = true;
// Deliver complete message
if (current_fragment_->is_complete) {
DeliverMessage(*current_fragment_);
current_fragment_.reset();
}
}
} else {
// Single complete message
DeliverMessage(chunk);
}
}Data Transmission Security
Data Security Mechanisms:
- DTLS encryption (mandatory for all WebRTC communication)
- Message integrity protection
- Anti-replay attack protection
Key Source Code Implementation:
// sctp_transport.cc
bool SctpTransport::Send(const DataBuffer& buffer) {
// Encrypt data
std::vector<uint8_t> encrypted_data;
if (!dtls_transport_->Encrypt(buffer.data, &encrypted_data)) {
return false;
}
// Create SCTP data chunk
SctpPacket packet;
packet.AddData(encrypted_data.data(), encrypted_data.size(), buffer.binary);
// Send packet
return socket_->Send(packet);
}
bool SctpTransport::OnDataReceived(const SctpPacket& packet) {
// Extract encrypted data
std::vector<uint8_t> encrypted_data;
if (!packet.GetEncryptedData(&encrypted_data)) {
return false;
}
// Decrypt data
DataBuffer decrypted_buffer;
if (!dtls_transport_->Decrypt(encrypted_data, &decrypted_buffer)) {
return false;
}
// Process decrypted data
// ... (same as previous data processing logic)
}
// dtls_transport.cc
bool DtlsTransport::Encrypt(const std::vector<uint8_t>& plaintext,
std::vector<uint8_t>* ciphertext) {
// Encrypt data using DTLS session
return ssl_socket_->Write(plaintext.data(), plaintext.size(), ciphertext);
}
bool DtlsTransport::Decrypt(const std::vector<uint8_t>& ciphertext,
DataBuffer* plaintext) {
// Decrypt data using DTLS session
std::vector<uint8_t> decrypted_data;
if (!ssl_socket_->Read(ciphertext.data(), ciphertext.size(), &decrypted_data)) {
return false;
}
*plaintext = DataBuffer(decrypted_data.data(), decrypted_data.size(), false);
return true;
}This is a comprehensive analysis of the WebRTC source code, covering the key implementation details of the PeerConnection, MediaStream, and DataChannel core components. These source code analyses help in deeply understanding the working principles and internal mechanisms of WebRTC.



