基于Webrtc和Janus的多人视频会议系统开发6 - 从Janus服务器订阅媒体流

由于前段时间一直忙于开发,没有及时记录开发过程中遇到的问题,现在只能靠回忆来写一些印象深刻的坑了,本篇文章先把本系列的最后一篇补上,前面只是做到了把流推上去,现在还需要把流订阅下来。

记得当时是遇到几个问题的,其中一个是订阅其他流后,自己发布的视频就没有声音了,其他问题已经记不清楚了,大家如果遇到什么问题说下说不定能帮助想起了。

感接时有点疑惑,推流时已经建立了peerconnection,收流时是不是可以直接用这个connection就行了,查了些资料,如果只是两个人通讯确实可行,不过对于我们这个需要拉多个人视频的就不合适了,出发在connection上加上区分流所属用户字段,那就复杂了也没比较,janus也不支持,所以实际的peerconnection是这样的:

推流的peerconnection归推流,拉流的peerconnection归拉流,互补相干.

你在连接Janus,join到一个房间后,如果有另外一个用户publish流成功,你会收到一个信令告诉你有人发布媒体了,并告诉你详细信息,这时发起一个subscribe必须要把该用户的streamname带上,这个是关键,关键,关键,只有这样Janus才知道这个peerconnection是要发该用户的数据的。

Janus收到该信令后,会发起createoffer流程,等待该信令把Janus的SDP发过来,然后我们再回复里把answer 的SDP回复过去(publish是我们发offer,Janus回answer),就完成了SDP的交换:

void KKRtcConnection::onJanusPeerSdp(std::string sdptype, std::string sdp)
{
	webrtc::SdpParseError error;
	rtc::Optional<SdpType> type_maybe = webrtc::SdpTypeFromString(sdptype);
	if (!type_maybe) {
		RTC_LOG(LS_ERROR) << "Unknown SDP type: " << sdptype;
		return;
	}
	SdpType type = *type_maybe;


	if (!InitializePeerConnection())
	{
		///onError callback
		return;
	}

	std::unique_ptr<webrtc::SessionDescriptionInterface> session_description = webrtc::CreateSessionDescription(type, sdp, &error);
	if (!session_description) {
		blog(emLOG_WARNING, "%s Can't parse received session description message. SdpParseError was: %s",__func__ ,error.description.c_str() );
		return;
	}
	blog(emLOG_INFO, "%s Received session description ",__func__);
	peer_connection_->SetRemoteDescription(DummySetSessionDescriptionObserver::Create(), session_description.release());
	if (type == SdpType::kOffer) {
		peer_connection_->CreateAnswer(this, NULL);
	}

#ifdef DEBUG_LOG
	blog(emLOG_INFO, " curthreadId:%u   %s  proccess  end(%d) handleId=%d", rtc::CurrentThreadId(), __func__, __LINE__,handleid_);
#endif
}

然后是创建初始化peerconnection来收集ICE:

	peer_connection_factory_ = webrtc::CreatePeerConnectionFactory( rtc::Thread::Current(),	rtc::Thread::Current(),
		reinterpret_cast<webrtc::AudioDeviceModule *>(adm_.get()),
		webrtc::CreateBuiltinAudioEncoderFactory(),
		webrtc::CreateBuiltinAudioDecoderFactory(),	NULL,NULL);


	webrtc::PeerConnectionInterface::RTCConfiguration config;

	webrtc::FakeConstraints constraints;
	if (dtls) 
	{
		constraints.AddOptional(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,	"true");
	}
	else 
	{
		constraints.AddOptional(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,	"false");
	}

	constraints.AddOptional(webrtc::MediaConstraintsInterface::kCpuOveruseDetection, "false");

	peer_connection_ = peer_connection_factory_->CreatePeerConnection(config, &constraints, NULL, NULL, this);
	auto ptr = new rtc::RefCountedObject<KKRTCStatus>();
	peer_connection_->GetStats(ptr);

CreatePeerConnection调用设置了回调接口PeerConnectionObserver的实现类this, 调用后每次ICE状态回调,主要这三个函数就可以了:

OnIceCandidate

OnIceGatheringChange

OnAddStream

在OnIceCandidate把IceCandidate信令发给Janus, 在OnIceGatheringChange把IceComplete信令发给Janus,

 OnAddStream里设置remote帧来了后的回调处理类:

void KKRtcConnection::OnAddStream(	rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) 
{
#ifdef DEBUG_LOG
	blog(emLOG_INFO,"%s  %d", __func__ ,stream->id() );	
#endif

	webrtc::VideoTrackVector tracks = stream->GetVideoTracks();
	// Only render the first track.
	if (!tracks.empty()) {
		webrtc::VideoTrackInterface* track = tracks[0];
		rendered_track_ = track;
		rendered_track_->AddOrUpdateSink(this, rtc::VideoSinkWants());
	}
	stream->Release();

#ifdef DEBUG_LOG
	blog(emLOG_INFO, " curthreadId:%u   %s  proccess  end(%d) handleId=%d", rtc::CurrentThreadId(), __func__, __LINE__, handleid_);
#endif
}

然后在帧回调里处理对方的帧预览就可以啦。

猜你喜欢

转载自blog.csdn.net/u011382962/article/details/86737076