当前位置:网站首页>基于Webrtc和Janus的多人视频会议系统开发6 - 从Janus服务器订阅媒体流
基于Webrtc和Janus的多人视频会议系统开发6 - 从Janus服务器订阅媒体流
2022-08-04 05:32:00 【睏哥RTC】
由于前段时间一直忙于开发,没有及时记录开发过程中遇到的问题,现在只能靠回忆来写一些印象深刻的坑了,本篇文章先把本系列的最后一篇补上,前面只是做到了把流推上去,现在还需要把流订阅下来。
记得当时是遇到几个问题的,其中一个是订阅其他流后,自己发布的视频就没有声音了,其他问题已经记不清楚了,大家如果遇到什么问题说下说不定能帮助想起了。
感接时有点疑惑,推流时已经建立了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
}
然后在帧回调里处理对方的帧预览就可以啦。
边栏推荐
- Janus转发丢包导致音视频不同步原因分析
- [daily office][ssh]cheatsheet
- MNIST Handwritten Digit Recognition - Building a Perceptron from Zero for Two-Classification
- LeetCode_22_Apr_2nd_Week
- 指针的运算【C语言】
- AWS uses EC2 to reduce the training cost of DeepRacer: DeepRacer-for-cloud practical operation
- LeetCode_Dec_2nd_Week
- Shell基础
- EL表达式
- 代码庆端午--粽你心意
猜你喜欢
[Deep Learning Diary] Day 1: Hello world, Hello CNN MNIST
Tencent and NetEase have taken action one after another. What is the metaverse that is so popular that it is out of the circle?
题目1000:输入两个整数a和b,计算a+b的和,此题是多组测试数据
(位操作符)按位与、按位或、按位异或
文件编辑器
淘宝分布式文件系统存储(二)
Socket编程详解
Fabric v1.1 环境搭建
LeetCode_Dec_1st_Week
LeetCode_Dec_3rd_Week
随机推荐
[日常办公][ssh]cheatsheet
虚幻引擎 5 完整指南[2022六月最新课程学习内容]
题目1000:输入两个整数a和b,计算a+b的和,此题是多组测试数据
彻底删除MySQL教程
MNIST Handwritten Digit Recognition - Building a Perceptron from Zero for Two-Classification
[English learning][sentence] good sentence
Copy Siege Lions "sticky" to AI couplets
bind()系统调用的用处
A code example of the PCL method in the domain of DG (Domain Generalization)
2020-03-27
抽象类、内部类和接口
淘宝分布式文件系统存储(二)
MNIST Handwritten Digit Recognition - Lenet-5's First Commercial Grade Convolutional Neural Network
Object. RequireNonNull method
Design and implementation of legal aid platform based on asp.net (with project link)
MNIST handwritten digit recognition, sorted by from two to ten
Brief description of database and common operation guide
C语言静态变量static的分析
The usefulness of bind() system call
网络通信与Socket编程概述