目录
1. 引言
创建完PeerConnectionFactory 和 PeerConnection这两个API层的操盘对象之后;紧接着需要初始化本地的媒体,也即创建本地的音频轨、视频轨、数据通道,并将这些本地的媒体轨道添加到PeerConnection对象中。然后即可调用PeerConnection::CreateOffer()创建本地SDP对象。
本文将详细描述PeerConnection::CreateOffer()过程,相关的知识点。如下图
2 CreateOffer声明 && 两个参数
2.1 CreateOffer声明
void CreateOffer(CreateSessionDescriptionObserver* observer,
const RTCOfferAnswerOptions& options) override;
2.2 参数CreateSessionDescriptionObserver
class RTC_EXPORT CreateSessionDescriptionObserver
: public rtc::RefCountInterface {
public:
virtual void OnSuccess(SessionDescriptionInterface* desc) = 0;
virtual void OnFailure(RTCError error);
virtual void OnFailure(const std::string& error);
protected:
~CreateSessionDescriptionObserver() override = default;
};
注意:CreateSessionDescriptionObserver只是一个接口,没有具体实现。一般用户层需要继承,并实现CreateSessionDescriptionObserver的方法,以便用户侧感知CreateOffer状态。
另外,WebRTC内部提供了两个实现了CreateSessionDescriptionObserver接口的类,ImplicitCreateSessionDescriptionObserver && CreateSessionDescriptionObserverOperationWrapper。在后续分析过程中再来聊聊这两个实现所起的作用。
2.3 参数RTCOfferAnswerOptions
RTCOfferAnswerOptions源码如下(省略了构造函数):
struct RTCOfferAnswerOptions {
static const int kUndefined = -1;
static const int kMaxOfferToReceiveMedia = 1;
// The default value for constraint offerToReceiveX:true.
static const int kOfferToReceiveMediaTrue = 1;
// These options are left as backwards compatibility for clients who need
// "Plan B" semantics. Clients who have switched to "Unified Plan" semantics
// should use the RtpTransceiver API (AddTransceiver) instead.
//
// offer_to_receive_X set to 1 will cause a media description to be
// generated in the offer, even if no tracks of that type have been added.
// Values greater than 1 are treated the same.
//
// If set to 0, the generated directional attribute will not include the
// "recv" direction (meaning it will be "sendonly" or "inactive".
int offer_to_receive_video = kUndefined;
int offer_to_receive_audio = kUndefined;
bool voice_activity_detection = true;
bool ice_restart = false;
// If true, will offer to BUNDLE audio/video/data together. Not to be
// confused with RTCP mux (multiplexing RTP and RTCP together).
bool use_rtp_mux = true;
// If true, "a=packetization:<payload_type> raw" attribute will be offered
// in the SDP for all video payload and accepted in the answer if offered.
bool raw_packetization_for_video = false;
// This will apply to all video tracks with a Plan B SDP offer/answer.
int num_simulcast_layers = 1;
// If true: Use SDP format from draft-ietf-mmusic-scdp-sdp-03
// If false: Use SDP format from draft-ietf-mmusic-sdp-sdp-26 or later
bool use_obsolete_sctp_sdp = false;
};
RTCOfferAnswerOptions提供的参数,英文注释写得非常清楚,此处就不多赘述。特别值得注意的是use_rtp_mux 默认为真,使得所有媒体都集合到一个Bundle group,复用底层的同一个传输通道DTLS Transport。
3 PeerConnection::CreateOffer
接下来,我们来抽丝剥茧,一步步分析CreateOffer的整个流程。
void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
const RTCOfferAnswerOptions& options) {
// 1. 信令线程执行
RTC_DCHECK_RUN_ON(signaling_thread());
// 2. 排队执行
// Chain this operation. If asynchronous operations are pending on the chain,
// this operation will be queued to be invoked, otherwise the contents of the
// lambda will execute immediately.
operations_chain_->ChainOperation(
[this_weak_ptr = weak_ptr_factory_.GetWeakPtr(),
observer_refptr =
rtc::scoped_refptr<CreateSessionDescriptionObserver>(observer),
options](std::function<void()> operations_chain_callback) {
// 2.1 如果this_weak_ptr为空,意味着当前PC已经不存在,会话被关闭
// Abort early if |this_weak_ptr| is no longer valid.
if (!this_weak_ptr) {
// 2.1.1 通知用户侧CreateOffer失败及失败原因
observer_refptr->OnFailure(
RTCError(RTCErrorType::INTERNAL_ERROR,
"CreateOffer failed because the session was shut down"));
// 2.1.2 执行操作结束的回调,通知执行下一个Operation
operations_chain_callback();
return;
}
// 2.2 执行真正的DoCreateOffer
// The operation completes asynchronously when the wrapper is invoked.
// 2.2.1 创建入参Observer的一个Wrapper对象,该对象还封装了操作回调函数的指针,
// 使得CreatOffer结束后,能够调用回调函数,通知执行下一个Operation,同时能够通知
// 用户侧本次CreatOffer的结果。
rtc::scoped_refptr<CreateSessionDescriptionObserverOperationWrapper>
observer_wrapper(new rtc::RefCountedObject<
CreateSessionDescriptionObserverOperationWrapper>(
std::move(observer_refptr),
std::move(operations_chain_callback)));
// 2.2.2 调用DoCreateOffer进一步去创建Offer
this_weak_ptr->DoCreateOffer(options, observer_wrapper);
});
}
CreateOffer方法执行过程是比较明朗的,也有必要将涉及的基本观念、设计方式交代下:
- WebRTC中将CreateOffer、CreateAnswer、SetLocalDescription、SetRemoteDescription、AddIceCandidate这5个与SDP会话相关的API认为是一个Operation,这些Operation必须是挨个执行,不能乱序,不能同时有两个交互执行。因此,设计了一套操作链的接口,由OperationsChain类提供此功能。当链入一个操作时,如果队列中没有其他操作,那么该操作会被立马执行;若是操作链中存在操作,那么本操作就入队操作链,等待上一个操作执行完成之后,以回调的形式(即上述代码中的operations_chain_callback回调方法)来告知执行下一步操作。具体实现可见文章:WebRTC源码分析——操作链实现OperationsChain
- CreateSessionDescriptionObserverOperationWrapper相当于一个封装了 "Offer操作结果回调 + 操作链操作完成回调"的一个对象,一直沿着CreateOffer调用链往下传,直到能够判断是否能成功创建Offer的地方,创建Offer这个操作完成的地方,然后去触发其承载的回调函数,以便告知上层操作结果,然后触发下一个操作。具体见源码
```cpp
// Wraps a CreateSessionDescriptionObserver and an OperationsChain operation
// complete callback. When the observer is invoked, the wrapped observer is
// invoked followed by invoking the completion callback.
class CreateSessionDescriptionObserverOperationWrapper
: public CreateSessionDescriptionObserver {
public:
CreateSessionDescriptionObserverOperationWrapper(
rtc::scoped_refptr<CreateSessionDescriptionObserver> observer,
std::function<void()> operation_complete_callback)
: observer_(std::move(observer)),
operation_complete_callback_(std::move(operation_complete_callback)) {
RTC_DCHECK(observer_);
}
~CreateSessionDescriptionObserverOperationWrapper() override {
RTC_DCHECK(was_called_);
}
void OnSuccess(SessionDescriptionInterface* desc) override {
RTC_DCHECK(!was_called_);
#ifdef RTC_DCHECK_IS_ON
was_called_ = true;
#endif // RTC_DCHECK_IS_ON
// Completing the operation before invoking the observer allows the observer
// to execute SetLocalDescription() without delay.
operation_complete_callback_();
observer_->OnSuccess(desc);
}
void OnFailure(RTCError error) override {
RTC_DCHECK(!was_called_);
#ifdef RTC_DCHECK_IS_ON
was_called_ = true;
#endif // RTC_DCHECK_IS_ON
operation_complete_callback_();
observer_->OnFailure(std::move(error));
}
private:
#ifdef RTC_DCHECK_IS_ON
bool was_called_ = false;
#endif // RTC_DCHECK_IS_ON
rtc::scoped_refptr<CreateSessionDescriptionObserver> observer_;
std::function<void()> operation_complete_callback_;
};
- rtc::WeakPtrFactory<PeerConnection> weak_ptr_factory_:在构造PeerConnection时,传入了this指针。当从weak_ptr_factory_获取弱指针this_weak_ptr不存在时,意味着PC已经不存在了,也即当前会话已被关闭。这样的功能是由rtc::WeakPtrFactory && WeakPtr带来的,详见 WebRTC源码分析——弱指针WeakPtrFactory && WeakPtr。要注意的是weak_ptr_factory_必须声明在PC的最后,这样是为了:
// |weak_ptr_factory_| must be declared last to make sure all WeakPtr's are
// invalidated before any other members are destroyed.
3.1 PeerConnection::DoCreateOffer
void PeerConnection::DoCreateOffer(
const RTCOfferAnswerOptions& options,
rtc::scoped_refptr<CreateSessionDescriptionObserver> observer) {
// 1. 状态判断
// 1.1 运行在信令线程
RTC_DCHECK_RUN_ON(signaling_thread());
TRACE_EVENT0("webrtc", "PeerConnection::DoCreateOffer");
// 1.2 观察者不能为空
if (!observer) {
RTC_LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
return;
}
// 1.3 PC的信令状态不能是已关闭状态——kClose
// 信令状态: enum SignalingState {
// kStable,
// kHaveLocalOffer,
// kHaveLocalPrAnswer,
// kHaveRemoteOffer,
// kHaveRemotePrAnswer,
// kClosed,};
// PC创建时默认为kStable状态,只有PC调用Close方法时,会使得其处于kClosed状态
if (IsClosed()) {
std::string error = "CreateOffer called when PeerConnection is closed.";
RTC_LOG(LS_ERROR) << error;
PostCreateSessionDescriptionFailure(
observer, RTCError(RTCErrorType::INVALID_STATE, std::move(error)));
return;
}
// 1.4 会话状态判断
// If a session error has occurred the PeerConnection is in a possibly
// inconsistent state so fail right away.
if (session_error() != SessionError::kNone) {
std::string error_message = GetSessionErrorMsg(

深入解析WebRTC中创建SDP Offer的过程,包括参数处理、状态检查、信息收集及最终Offer的构建。覆盖关键步骤如CreateOffer声明、参数解析、状态验证、信息收集、Offer构建及结果通知。
最低0.47元/天 解锁文章
945

被折叠的 条评论
为什么被折叠?



