提取webrtc推流、播放代码为单独的派生类

This commit is contained in:
ziyue 2021-10-15 16:27:17 +08:00
parent 8531b5e1cb
commit 7f3f47abbb
7 changed files with 379 additions and 229 deletions

View File

@ -38,7 +38,8 @@
#include "Rtp/RtpServer.h" #include "Rtp/RtpServer.h"
#endif #endif
#ifdef ENABLE_WEBRTC #ifdef ENABLE_WEBRTC
#include "../webrtc/WebRtcTransport.h" #include "../webrtc/WebRtcPlayer.h"
#include "../webrtc/WebRtcPusher.h"
#endif #endif
using namespace toolkit; using namespace toolkit;
@ -1219,8 +1220,7 @@ void installWebApi() {
} }
//还原成rtc目的是为了hook时识别哪种播放协议 //还原成rtc目的是为了hook时识别哪种播放协议
info._schema = "rtc"; info._schema = "rtc";
auto rtc = WebRtcTransportImp::create(EventPollerPool::Instance().getPoller()); auto rtc = WebRtcPlayer::create(EventPollerPool::Instance().getPoller(), src, info);
rtc->attach(src, info, true);
val["sdp"] = rtc->getAnswerSdp(offer_sdp); val["sdp"] = rtc->getAnswerSdp(offer_sdp);
val["type"] = "answer"; val["type"] = "answer";
invoker(200, headerOut, val.toStyledString()); invoker(200, headerOut, val.toStyledString());
@ -1248,9 +1248,8 @@ void installWebApi() {
} }
auto push_src = std::make_shared<RtspMediaSourceImp>(info._vhost, info._app, info._streamid); auto push_src = std::make_shared<RtspMediaSourceImp>(info._vhost, info._app, info._streamid);
push_src->setProtocolTranslation(enableHls, enableMP4); push_src->setProtocolTranslation(enableHls, enableMP4);
auto rtc = WebRtcTransportImp::create(EventPollerPool::Instance().getPoller()); auto rtc = WebRtcPusher::create(EventPollerPool::Instance().getPoller(), push_src, info);
push_src->setListener(rtc); push_src->setListener(rtc);
rtc->attach(push_src, info, false);
val["sdp"] = rtc->getAnswerSdp(offer_sdp); val["sdp"] = rtc->getAnswerSdp(offer_sdp);
val["type"] = "answer"; val["type"] = "answer";
invoker(200, headerOut, val.toStyledString()); invoker(200, headerOut, val.toStyledString());

101
webrtc/WebRtcPlayer.cpp Normal file
View File

@ -0,0 +1,101 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* LICENSE file in the root of the source tree. All contributing project authors
* may be found in the AUTHORS file in the root of the source tree.
*/
#include "WebRtcPlayer.h"
WebRtcPlayer::Ptr WebRtcPlayer::create(const EventPoller::Ptr &poller,
const RtspMediaSource::Ptr &src,
const MediaInfo &info) {
WebRtcPlayer::Ptr ret(new WebRtcPlayer(poller, src, info), [](WebRtcPlayer *ptr) {
ptr->onDestory();
delete ptr;
});
ret->onCreate();
return ret;
}
WebRtcPlayer::WebRtcPlayer(const EventPoller::Ptr &poller,
const RtspMediaSource::Ptr &src,
const MediaInfo &info) : WebRtcTransportImp(poller) {
InfoL << this;
_media_info = info;
_play_src = src;
CHECK(_play_src);
}
void WebRtcPlayer::onStartWebRTC() {
CHECK(_play_src);
WebRtcTransportImp::onStartWebRTC();
if (canSendRtp()) {
_play_src->pause(false);
_reader = _play_src->getRing()->attach(getPoller(), true);
weak_ptr<WebRtcPlayer> weak_self = static_pointer_cast<WebRtcPlayer>(shared_from_this());
_reader->setReadCB([weak_self](const RtspMediaSource::RingDataType &pkt) {
auto strongSelf = weak_self.lock();
if (!strongSelf) {
return;
}
size_t i = 0;
pkt->for_each([&](const RtpPacket::Ptr &rtp) {
strongSelf->beforeSendRtp(rtp, ++i == pkt->size());
});
});
_reader->setDetachCB([weak_self]() {
auto strongSelf = weak_self.lock();
if (!strongSelf) {
return;
}
strongSelf->onShutdown(SockException(Err_shutdown, "rtsp ring buffer detached"));
});
//确保该rtp codec类型对方支持
memset(_can_send_rtp, 0, sizeof(_can_send_rtp));
for (auto &m : _answer_sdp->media) {
_can_send_rtp[m.type] = m.direction == RtpDirection::sendonly || m.direction == RtpDirection::sendrecv;
}
}
//使用完毕后,释放强引用,这样确保推流器断开后能及时注销媒体
_play_src = nullptr;
}
void WebRtcPlayer::onDestory() {
WebRtcTransportImp::onDestory();
auto duration = getDuration();
auto bytes_usage = getBytesUsage();
//流量统计事件广播
GET_CONFIG(uint32_t, iFlowThreshold, General::kFlowThreshold);
if (_reader && getSession()) {
WarnL << "RTC播放器("
<< _media_info._vhost << "/"
<< _media_info._app << "/"
<< _media_info._streamid
<< ")结束播放,耗时(s):" << duration;
if (bytes_usage >= iFlowThreshold * 1024) {
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport, _media_info, bytes_usage, duration,
true, static_cast<SockInfo &>(*getSession()));
}
}
}
void WebRtcPlayer::onRtcConfigure(RtcConfigure &configure) const {
CHECK(_play_src);
WebRtcTransportImp::onRtcConfigure(configure);
//这是播放
configure.audio.direction = configure.video.direction = RtpDirection::sendonly;
configure.setPlayRtspInfo(_play_src->getSdp());
}
void WebRtcPlayer::beforeSendRtp(const RtpPacket::Ptr &rtp, bool flush, bool rtx) {
if (!_can_send_rtp[rtp->type]) {
return;
}
onSendRtp(rtp, flush, rtx);
}

44
webrtc/WebRtcPlayer.h Normal file
View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* LICENSE file in the root of the source tree. All contributing project authors
* may be found in the AUTHORS file in the root of the source tree.
*/
#ifndef ZLMEDIAKIT_WEBRTCPLAYER_H
#define ZLMEDIAKIT_WEBRTCPLAYER_H
#include "WebRtcTransport.h"
class WebRtcPlayer : public WebRtcTransportImp {
public:
using Ptr = std::shared_ptr<WebRtcPlayer>;
~WebRtcPlayer() override = default;
static Ptr create(const EventPoller::Ptr &poller, const RtspMediaSource::Ptr &src, const MediaInfo &info);
protected:
///////WebRtcTransportImp override///////
void onStartWebRTC() override;
void onDestory() override;
void onRtcConfigure(RtcConfigure &configure) const override;
void onRecvRtp(MediaTrack &track, const string &rid, RtpPacket::Ptr rtp) {};
private:
WebRtcPlayer(const EventPoller::Ptr &poller, const RtspMediaSource::Ptr &src, const MediaInfo &info);
void beforeSendRtp(const RtpPacket::Ptr &rtp, bool flush, bool rtx = false);
private:
bool _can_send_rtp[TrackMax];
//媒体相关元数据
MediaInfo _media_info;
//播放的rtsp源
RtspMediaSource::Ptr _play_src;
//播放rtsp源的reader对象
RtspMediaSource::RingType::RingReader::Ptr _reader;
};
#endif //ZLMEDIAKIT_WEBRTCPLAYER_H

131
webrtc/WebRtcPusher.cpp Normal file
View File

@ -0,0 +1,131 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* LICENSE file in the root of the source tree. All contributing project authors
* may be found in the AUTHORS file in the root of the source tree.
*/
#include "WebRtcPusher.h"
WebRtcPusher::Ptr WebRtcPusher::create(const EventPoller::Ptr &poller,
const RtspMediaSource::Ptr &src,
const MediaInfo &info) {
WebRtcPusher::Ptr ret(new WebRtcPusher(poller, src, info), [](WebRtcPusher *ptr) {
ptr->onDestory();
delete ptr;
});
ret->onCreate();
return ret;
}
WebRtcPusher::WebRtcPusher(const EventPoller::Ptr &poller,
const RtspMediaSource::Ptr &src,
const MediaInfo &info) : WebRtcTransportImp(poller) {
InfoL << this;
_media_info = info;
_push_src = src;
CHECK(_push_src);
}
bool WebRtcPusher::close(MediaSource &sender, bool force) {
//此回调在其他线程触发
if (!force && totalReaderCount(sender)) {
return false;
}
string err = StrPrinter << "close media:" << sender.getSchema() << "/" << sender.getVhost() << "/"
<< sender.getApp() << "/" << sender.getId() << " " << force;
weak_ptr<WebRtcPusher> weak_self = static_pointer_cast<WebRtcPusher>(shared_from_this());
getPoller()->async([weak_self, err]() {
auto strong_self = weak_self.lock();
if (strong_self) {
strong_self->onShutdown(SockException(Err_shutdown, err));
}
});
return true;
}
int WebRtcPusher::totalReaderCount(MediaSource &sender) {
auto total_count = 0;
for (auto &src : _push_src_simulcast) {
total_count += src.second->totalReaderCount();
}
return total_count + _push_src->totalReaderCount();
}
MediaOriginType WebRtcPusher::getOriginType(MediaSource &sender) const {
return MediaOriginType::rtc_push;
}
string WebRtcPusher::getOriginUrl(MediaSource &sender) const {
return _media_info._full_url;
}
std::shared_ptr<SockInfo> WebRtcPusher::getOriginSock(MediaSource &sender) const {
return static_pointer_cast<SockInfo>(getSession());
}
void WebRtcPusher::onRecvRtp(MediaTrack &track, const string &rid, RtpPacket::Ptr rtp) {
if (!_simulcast) {
assert(_push_src);
_push_src->onWrite(rtp, false);
return;
}
if (rtp->type == TrackAudio) {
//音频
for (auto &pr : _push_src_simulcast) {
pr.second->onWrite(rtp, false);
}
} else {
//视频
auto &src = _push_src_simulcast[rid];
if (!src) {
auto stream_id = rid.empty() ? _push_src->getId() : _push_src->getId() + "_" + rid;
auto src_imp = std::make_shared<RtspMediaSourceImp>(_push_src->getVhost(), _push_src->getApp(), stream_id);
src_imp->setSdp(_push_src->getSdp());
src_imp->setProtocolTranslation(_push_src->isRecording(Recorder::type_hls),
_push_src->isRecording(Recorder::type_mp4));
src_imp->setListener(static_pointer_cast<WebRtcPusher>(shared_from_this()));
src = src_imp;
}
src->onWrite(std::move(rtp), false);
}
}
void WebRtcPusher::onStartWebRTC() {
WebRtcTransportImp::onStartWebRTC();
_simulcast = _answer_sdp->supportSimulcast();
if (canRecvRtp()) {
_push_src->setSdp(_answer_sdp->toRtspSdp());
}
}
void WebRtcPusher::onDestory() {
WebRtcTransportImp::onDestory();
auto duration = getDuration();
auto bytes_usage = getBytesUsage();
//流量统计事件广播
GET_CONFIG(uint32_t, iFlowThreshold, General::kFlowThreshold);
if (getSession()) {
WarnL << "RTC推流器("
<< _media_info._vhost << "/"
<< _media_info._app << "/"
<< _media_info._streamid
<< ")结束推流,耗时(s):" << duration;
if (bytes_usage >= iFlowThreshold * 1024) {
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport, _media_info, bytes_usage, duration,
false, static_cast<SockInfo &>(*getSession()));
}
}
}
void WebRtcPusher::onRtcConfigure(RtcConfigure &configure) const {
WebRtcTransportImp::onRtcConfigure(configure);
//这只是推流
configure.audio.direction = configure.video.direction = RtpDirection::recvonly;
}

55
webrtc/WebRtcPusher.h Normal file
View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* LICENSE file in the root of the source tree. All contributing project authors
* may be found in the AUTHORS file in the root of the source tree.
*/
#ifndef ZLMEDIAKIT_WEBRTCPUSHER_H
#define ZLMEDIAKIT_WEBRTCPUSHER_H
#include "WebRtcTransport.h"
class WebRtcPusher : public WebRtcTransportImp, public MediaSourceEvent {
public:
using Ptr = std::shared_ptr<WebRtcPusher>;
~WebRtcPusher() override = default;
static Ptr create(const EventPoller::Ptr &poller, const RtspMediaSource::Ptr &src, const MediaInfo &info);
protected:
///////WebRtcTransportImp override///////
void onStartWebRTC() override;
void onDestory() override;
void onRtcConfigure(RtcConfigure &configure) const override;
void onRecvRtp(MediaTrack &track, const string &rid, RtpPacket::Ptr rtp) override;
protected:
///////MediaSourceEvent override///////
// 关闭
bool close(MediaSource &sender, bool force) override;
// 播放总人数
int totalReaderCount(MediaSource &sender) override;
// 获取媒体源类型
MediaOriginType getOriginType(MediaSource &sender) const override;
// 获取媒体源url或者文件路径
string getOriginUrl(MediaSource &sender) const override;
// 获取媒体源客户端相关信息
std::shared_ptr<SockInfo> getOriginSock(MediaSource &sender) const override;
private:
WebRtcPusher(const EventPoller::Ptr &poller, const RtspMediaSource::Ptr &src, const MediaInfo &info);
private:
bool _simulcast = false;
//媒体相关元数据
MediaInfo _media_info;
//推流的rtsp源
RtspMediaSource::Ptr _push_src;
//推流的rtsp源,支持simulcast
unordered_map<string/*rid*/, RtspMediaSource::Ptr> _push_src_simulcast;
};
#endif //ZLMEDIAKIT_WEBRTCPUSHER_H

View File

@ -15,6 +15,7 @@
#include "Rtcp/RtcpFCI.h" #include "Rtcp/RtcpFCI.h"
#include "Rtsp/RtpReceiver.h" #include "Rtsp/RtpReceiver.h"
#define RTP_SSRC_OFFSET 1
#define RTX_SSRC_OFFSET 2 #define RTX_SSRC_OFFSET 2
#define RTP_CNAME "zlmediakit-rtp" #define RTP_CNAME "zlmediakit-rtp"
#define RTP_LABEL "zlmediakit-label" #define RTP_LABEL "zlmediakit-label"
@ -207,16 +208,16 @@ std::string WebRtcTransport::getAnswerSdp(const string &offer){
} }
} }
bool is_dtls(char *buf) { static bool is_dtls(char *buf) {
return ((*buf > 19) && (*buf < 64)); return ((*buf > 19) && (*buf < 64));
} }
bool is_rtp(char *buf) { static bool is_rtp(char *buf) {
RtpHeader *header = (RtpHeader *) buf; RtpHeader *header = (RtpHeader *) buf;
return ((header->pt < 64) || (header->pt >= 96)); return ((header->pt < 64) || (header->pt >= 96));
} }
bool is_rtcp(char *buf) { static bool is_rtcp(char *buf) {
RtpHeader *header = (RtpHeader *) buf; RtpHeader *header = (RtpHeader *) buf;
return ((header->pt >= 64) && (header->pt < 96)); return ((header->pt >= 64) && (header->pt < 96));
} }
@ -285,14 +286,6 @@ void WebRtcTransport::sendRtcpPacket(const char *buf, int len, bool flush, void
} }
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
WebRtcTransportImp::Ptr WebRtcTransportImp::create(const EventPoller::Ptr &poller){
WebRtcTransportImp::Ptr ret(new WebRtcTransportImp(poller), [](WebRtcTransportImp *ptr){
ptr->onDestory();
delete ptr;
});
ret->onCreate();
return ret;
}
void WebRtcTransportImp::onCreate(){ void WebRtcTransportImp::onCreate(){
WebRtcTransport::onCreate(); WebRtcTransport::onCreate();
@ -327,46 +320,6 @@ WebRtcTransportImp::~WebRtcTransportImp() {
void WebRtcTransportImp::onDestory() { void WebRtcTransportImp::onDestory() {
WebRtcTransport::onDestory(); WebRtcTransport::onDestory();
unregisterSelf(); unregisterSelf();
if (!_session) {
return;
}
uint64_t duration = _alive_ticker.createdTime() / 1000;
//流量统计事件广播
GET_CONFIG(uint32_t, iFlowThreshold, General::kFlowThreshold);
if (_reader) {
WarnL << "RTC播放器("
<< _media_info._vhost << "/"
<< _media_info._app << "/"
<< _media_info._streamid
<< ")结束播放,耗时(s):" << duration;
if (_bytes_usage >= iFlowThreshold * 1024) {
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport, _media_info, _bytes_usage, duration, true, static_cast<SockInfo &>(*_session));
}
}
if (_push_src) {
WarnL << "RTC推流器("
<< _media_info._vhost << "/"
<< _media_info._app << "/"
<< _media_info._streamid
<< ")结束推流,耗时(s):" << duration;
if (_bytes_usage >= iFlowThreshold * 1024) {
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport, _media_info, _bytes_usage, duration, false, static_cast<SockInfo &>(*_session));
}
}
}
void WebRtcTransportImp::attach(const RtspMediaSource::Ptr &src, const MediaInfo &info, bool is_play) {
assert(src);
_media_info = info;
if (is_play) {
_play_src = src;
} else {
_push_src = src;
}
} }
void WebRtcTransportImp::onSendSockData(const char *buf, size_t len, struct sockaddr_in *dst, bool flush) { void WebRtcTransportImp::onSendSockData(const char *buf, size_t len, struct sockaddr_in *dst, bool flush) {
@ -384,9 +337,6 @@ void WebRtcTransportImp::onSendSockData(const char *buf, size_t len, struct sock
/////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////
bool WebRtcTransportImp::canSendRtp() const{ bool WebRtcTransportImp::canSendRtp() const{
if (!_play_src) {
return false;
}
for (auto &m : _answer_sdp->media) { for (auto &m : _answer_sdp->media) {
if (m.direction == RtpDirection::sendrecv || m.direction == RtpDirection::sendonly) { if (m.direction == RtpDirection::sendrecv || m.direction == RtpDirection::sendonly) {
return true; return true;
@ -396,9 +346,6 @@ bool WebRtcTransportImp::canSendRtp() const{
} }
bool WebRtcTransportImp::canRecvRtp() const{ bool WebRtcTransportImp::canRecvRtp() const{
if (!_push_src) {
return false;
}
for (auto &m : _answer_sdp->media) { for (auto &m : _answer_sdp->media) {
if (m.direction == RtpDirection::sendrecv || m.direction == RtpDirection::recvonly) { if (m.direction == RtpDirection::sendrecv || m.direction == RtpDirection::recvonly) {
return true; return true;
@ -422,6 +369,8 @@ void WebRtcTransportImp::onStartWebRTC() {
track->plan_rtx = m_answer.getRelatedRtxPlan(track->plan_rtp->pt); track->plan_rtx = m_answer.getRelatedRtxPlan(track->plan_rtp->pt);
track->rtcp_context_send = std::make_shared<RtcpContextForSend>(); track->rtcp_context_send = std::make_shared<RtcpContextForSend>();
//rtp track type --> MediaTrack
_type_to_track[m_answer.type] = track;
//send ssrc --> MediaTrack //send ssrc --> MediaTrack
_ssrc_to_track[track->answer_ssrc_rtp] = track; _ssrc_to_track[track->answer_ssrc_rtp] = track;
_ssrc_to_track[track->answer_ssrc_rtx] = track; _ssrc_to_track[track->answer_ssrc_rtx] = track;
@ -460,50 +409,6 @@ void WebRtcTransportImp::onStartWebRTC() {
} }
} }
} }
if (canRecvRtp()) {
_push_src->setSdp(_answer_sdp->toRtspSdp());
_simulcast = _answer_sdp->supportSimulcast();
}
if (canSendRtp()) {
RtcSession rtsp_send_sdp;
rtsp_send_sdp.loadFrom(_play_src->getSdp(), false);
for (auto &m : _answer_sdp->media) {
if (m.type == TrackApplication) {
continue;
}
auto rtsp_media = rtsp_send_sdp.getMedia(m.type);
if (rtsp_media && getCodecId(rtsp_media->plan[0].codec) == getCodecId(m.plan[0].codec)) {
auto it = _pt_to_track.find(m.plan[0].pt);
CHECK(it != _pt_to_track.end());
//记录发送rtp时约定的信息届时发送rtp时需要修改pt和ssrc
_type_to_track[m.type] = it->second.second;
}
}
_play_src->pause(false);
_reader = _play_src->getRing()->attach(getPoller(), true);
weak_ptr<WebRtcTransportImp> weak_self = static_pointer_cast<WebRtcTransportImp>(shared_from_this());
_reader->setReadCB([weak_self](const RtspMediaSource::RingDataType &pkt) {
auto strongSelf = weak_self.lock();
if (!strongSelf) {
return;
}
size_t i = 0;
pkt->for_each([&](const RtpPacket::Ptr &rtp) {
strongSelf->onSendRtp(rtp, ++i == pkt->size());
});
});
_reader->setDetachCB([weak_self](){
auto strongSelf = weak_self.lock();
if (!strongSelf) {
return;
}
strongSelf->onShutdown(SockException(Err_shutdown, "rtsp ring buffer detached"));
});
}
//使用完毕后,释放强引用,这样确保推流器断开后能及时注销媒体
_play_src = nullptr;
} }
void WebRtcTransportImp::onCheckAnswer(RtcSession &sdp) { void WebRtcTransportImp::onCheckAnswer(RtcSession &sdp) {
@ -533,7 +438,8 @@ void WebRtcTransportImp::onCheckAnswer(RtcSession &sdp) {
//添加answer sdp的ssrc信息 //添加answer sdp的ssrc信息
m.rtp_rtx_ssrc.emplace_back(); m.rtp_rtx_ssrc.emplace_back();
auto &ssrc = m.rtp_rtx_ssrc.back(); auto &ssrc = m.rtp_rtx_ssrc.back();
ssrc.ssrc = _play_src->getSsrc(m.type); //发送的ssrc我们随便定义因为在发送rtp时会修改为此值
ssrc.ssrc = m.type + RTP_SSRC_OFFSET;
ssrc.cname = RTP_CNAME; ssrc.cname = RTP_CNAME;
ssrc.label = RTP_LABEL; ssrc.label = RTP_LABEL;
ssrc.mslabel = RTP_MSLABEL; ssrc.mslabel = RTP_MSLABEL;
@ -557,20 +463,6 @@ void WebRtcTransportImp::onCheckSdp(SdpType type, RtcSession &sdp) {
void WebRtcTransportImp::onRtcConfigure(RtcConfigure &configure) const { void WebRtcTransportImp::onRtcConfigure(RtcConfigure &configure) const {
WebRtcTransport::onRtcConfigure(configure); WebRtcTransport::onRtcConfigure(configure);
if (_play_src) {
//这是播放,同时也可能有推流
configure.video.direction = _push_src ? RtpDirection::sendrecv : RtpDirection::sendonly;
configure.audio.direction = configure.video.direction;
configure.setPlayRtspInfo(_play_src->getSdp());
} else if (_push_src) {
//这只是推流
configure.video.direction = RtpDirection::recvonly;
configure.audio.direction = RtpDirection::recvonly;
} else {
throw std::invalid_argument("未设置播放或推流的媒体源");
}
//添加接收端口candidate信息 //添加接收端口candidate信息
configure.addCandidate(*getIceCandidate()); configure.addCandidate(*getIceCandidate());
} }
@ -872,35 +764,12 @@ void WebRtcTransportImp::onSortedRtp(MediaTrack &track, const string &rid, RtpPa
} }
} }
if (!_simulcast) { onRecvRtp(track, rid, std::move(rtp));
assert(_push_src);
_push_src->onWrite(rtp, false);
return;
}
if (rtp->type == TrackAudio) {
//音频
for (auto &pr : _push_src_simulcast) {
pr.second->onWrite(rtp, false);
}
} else {
//视频
auto &src = _push_src_simulcast[rid];
if (!src) {
auto stream_id = rid.empty() ? _push_src->getId() : _push_src->getId() + "_" + rid;
auto src_imp = std::make_shared<RtspMediaSourceImp>(_push_src->getVhost(), _push_src->getApp(), stream_id);
src_imp->setSdp(_push_src->getSdp());
src_imp->setProtocolTranslation(_push_src->isRecording(Recorder::type_hls),_push_src->isRecording(Recorder::type_mp4));
src_imp->setListener(static_pointer_cast<WebRtcTransportImp>(shared_from_this()));
src = src_imp;
}
src->onWrite(std::move(rtp), false);
}
} }
/////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////
void WebRtcTransportImp::onSendRtp(const RtpPacket::Ptr &rtp, bool flush, bool rtx){ void WebRtcTransportImp::onSendRtp(const RtpPacket::Ptr &rtp, bool flush, bool rtx) {
auto &track = _type_to_track[rtp->type]; auto &track = _type_to_track[rtp->type];
if (!track) { if (!track) {
//忽略,对方不支持该编码类型 //忽略,对方不支持该编码类型
@ -969,48 +838,24 @@ void WebRtcTransportImp::onShutdown(const SockException &ex){
} }
} }
/////////////////////////////////////////////////////////////////////////////////////////////
bool WebRtcTransportImp::close(MediaSource &sender, bool force) {
//此回调在其他线程触发
if (!force && totalReaderCount(sender)) {
return false;
}
string err = StrPrinter << "close media:" << sender.getSchema() << "/" << sender.getVhost() << "/" << sender.getApp() << "/" << sender.getId() << " " << force;
weak_ptr<WebRtcTransportImp> weak_self = static_pointer_cast<WebRtcTransportImp>(shared_from_this());
getPoller()->async([weak_self, err]() {
auto strong_self = weak_self.lock();
if (strong_self) {
strong_self->onShutdown(SockException(Err_shutdown, err));
}
});
return true;
}
int WebRtcTransportImp::totalReaderCount(MediaSource &sender) {
auto total_count = 0;
for (auto &src : _push_src_simulcast) {
total_count += src.second->totalReaderCount();
}
return total_count + _push_src->totalReaderCount();
}
MediaOriginType WebRtcTransportImp::getOriginType(MediaSource &sender) const {
return MediaOriginType::rtc_push;
}
string WebRtcTransportImp::getOriginUrl(MediaSource &sender) const {
return _media_info._full_url;
}
std::shared_ptr<SockInfo> WebRtcTransportImp::getOriginSock(MediaSource &sender) const {
return static_pointer_cast<SockInfo>(_session);
}
void WebRtcTransportImp::setSession(Session::Ptr session) { void WebRtcTransportImp::setSession(Session::Ptr session) {
_session = std::move(session); _session = std::move(session);
} }
const Session::Ptr &WebRtcTransportImp::getSession() const {
return _session;
}
uint64_t WebRtcTransportImp::getBytesUsage() const{
return _bytes_usage;
}
uint64_t WebRtcTransportImp::getDuration() const{
return _alive_ticker.createdTime() / 1000;
}
/////////////////////////////////////////////////////////////////////////////////////////////
class WebRtcTransportManager { class WebRtcTransportManager {
mutable mutex _mtx; mutable mutex _mtx;
unordered_map<string, weak_ptr<WebRtcTransportImp> > _map; unordered_map<string, weak_ptr<WebRtcTransportImp> > _map;

View File

@ -116,8 +116,6 @@ protected:
virtual void onBeforeEncryptRtcp(const char *buf, int &len, void *ctx) = 0; virtual void onBeforeEncryptRtcp(const char *buf, int &len, void *ctx) = 0;
protected: protected:
RtcSession::Ptr _offer_sdp;
RtcSession::Ptr _answer_sdp;
RTC::TransportTuple* getSelectedTuple() const; RTC::TransportTuple* getSelectedTuple() const;
void sendRtcpRemb(uint32_t ssrc, size_t bit_rate); void sendRtcpRemb(uint32_t ssrc, size_t bit_rate);
void sendRtcpPli(uint32_t ssrc); void sendRtcpPli(uint32_t ssrc);
@ -126,6 +124,10 @@ private:
void onSendSockData(const char *buf, size_t len, bool flush = true); void onSendSockData(const char *buf, size_t len, bool flush = true);
void setRemoteDtlsFingerprint(const RtcSession &remote); void setRemoteDtlsFingerprint(const RtcSession &remote);
protected:
RtcSession::Ptr _offer_sdp;
RtcSession::Ptr _answer_sdp;
private: private:
uint8_t _srtp_buf[2000]; uint8_t _srtp_buf[2000];
string _key; string _key;
@ -159,7 +161,7 @@ public:
std::shared_ptr<RtpChannel> getRtpChannel(uint32_t ssrc) const; std::shared_ptr<RtpChannel> getRtpChannel(uint32_t ssrc) const;
}; };
class WebRtcTransportImp : public WebRtcTransport, public MediaSourceEvent{ class WebRtcTransportImp : public WebRtcTransport {
public: public:
using Ptr = std::shared_ptr<WebRtcTransportImp>; using Ptr = std::shared_ptr<WebRtcTransportImp>;
~WebRtcTransportImp() override; ~WebRtcTransportImp() override;
@ -169,20 +171,19 @@ public:
* @param poller 线 * @param poller 线
* @return * @return
*/ */
static Ptr create(const EventPoller::Ptr &poller);
static Ptr get(const string &key); // 借用 static Ptr get(const string &key); // 借用
static Ptr move(const string &key); // 所有权转移 static Ptr move(const string &key); // 所有权转移
void setSession(Session::Ptr session); void setSession(Session::Ptr session);
const Session::Ptr& getSession() const;
/** uint64_t getBytesUsage() const;
* rtsp媒体源 uint64_t getDuration() const;
* @param src bool canSendRtp() const;
* @param is_play bool canRecvRtp() const;
*/ void onSendRtp(const RtpPacket::Ptr &rtp, bool flush, bool rtx = false);
void attach(const RtspMediaSource::Ptr &src, const MediaInfo &info, bool is_play = true);
protected: protected:
WebRtcTransportImp(const EventPoller::Ptr &poller);
void onStartWebRTC() override; void onStartWebRTC() override;
void onSendSockData(const char *buf, size_t len, struct sockaddr_in *dst, bool flush = true) override; void onSendSockData(const char *buf, size_t len, struct sockaddr_in *dst, bool flush = true) override;
void onCheckSdp(SdpType type, RtcSession &sdp) override; void onCheckSdp(SdpType type, RtcSession &sdp) override;
@ -192,30 +193,13 @@ protected:
void onRtcp(const char *buf, size_t len) override; void onRtcp(const char *buf, size_t len) override;
void onBeforeEncryptRtp(const char *buf, int &len, void *ctx) override; void onBeforeEncryptRtp(const char *buf, int &len, void *ctx) override;
void onBeforeEncryptRtcp(const char *buf, int &len, void *ctx) override {}; void onBeforeEncryptRtcp(const char *buf, int &len, void *ctx) override {};
void onShutdown(const SockException &ex) override;
///////MediaSourceEvent override///////
// 关闭
bool close(MediaSource &sender, bool force) override;
// 播放总人数
int totalReaderCount(MediaSource &sender) override;
// 获取媒体源类型
MediaOriginType getOriginType(MediaSource &sender) const override;
// 获取媒体源url或者文件路径
string getOriginUrl(MediaSource &sender) const override;
// 获取媒体源客户端相关信息
std::shared_ptr<SockInfo> getOriginSock(MediaSource &sender) const override;
private:
WebRtcTransportImp(const EventPoller::Ptr &poller);
void onCreate() override; void onCreate() override;
void onDestory() override; void onDestory() override;
void onSendRtp(const RtpPacket::Ptr &rtp, bool flush, bool rtx = false); void onShutdown(const SockException &ex) override;
SdpAttrCandidate::Ptr getIceCandidate() const; virtual void onRecvRtp(MediaTrack &track, const string &rid, RtpPacket::Ptr rtp) = 0;
bool canSendRtp() const;
bool canRecvRtp() const;
private:
SdpAttrCandidate::Ptr getIceCandidate() const;
void onSortedRtp(MediaTrack &track, const string &rid, RtpPacket::Ptr rtp); void onSortedRtp(MediaTrack &track, const string &rid, RtpPacket::Ptr rtp);
void onSendNack(MediaTrack &track, const FCI_NACK &nack, uint32_t ssrc); void onSendNack(MediaTrack &track, const FCI_NACK &nack, uint32_t ssrc);
void onSendTwcc(uint32_t ssrc, const string &twcc_fci); void onSendTwcc(uint32_t ssrc, const string &twcc_fci);
@ -226,14 +210,11 @@ private:
void onCheckAnswer(RtcSession &sdp); void onCheckAnswer(RtcSession &sdp);
private: private:
bool _simulcast = false;
uint16_t _rtx_seq[2] = {0, 0}; uint16_t _rtx_seq[2] = {0, 0};
//用掉的总流量 //用掉的总流量
uint64_t _bytes_usage = 0; uint64_t _bytes_usage = 0;
//保持自我强引用 //保持自我强引用
Ptr _self; Ptr _self;
//媒体相关元数据
MediaInfo _media_info;
//检测超时的定时器 //检测超时的定时器
Timer::Ptr _timer; Timer::Ptr _timer;
//刷新计时器 //刷新计时器
@ -242,18 +223,12 @@ private:
Ticker _pli_ticker; Ticker _pli_ticker;
//udp session //udp session
Session::Ptr _session; Session::Ptr _session;
//推流的rtsp源 //twcc rtcp发送上下文对象
RtspMediaSource::Ptr _push_src; TwccContext _twcc_ctx;
unordered_map<string/*rid*/, RtspMediaSource::Ptr> _push_src_simulcast;
//播放的rtsp源
RtspMediaSource::Ptr _play_src;
//播放rtsp源的reader对象
RtspMediaSource::RingType::RingReader::Ptr _reader;
//根据发送rtp的track类型获取相关信息 //根据发送rtp的track类型获取相关信息
MediaTrack::Ptr _type_to_track[2]; MediaTrack::Ptr _type_to_track[2];
//根据接收rtp的pt获取相关信息
unordered_map<uint8_t/*pt*/, std::pair<bool/*is rtx*/,MediaTrack::Ptr> > _pt_to_track;
//根据rtcp的ssrc获取相关信息收发rtp和rtx的ssrc都会记录 //根据rtcp的ssrc获取相关信息收发rtp和rtx的ssrc都会记录
unordered_map<uint32_t/*ssrc*/, MediaTrack::Ptr> _ssrc_to_track; unordered_map<uint32_t/*ssrc*/, MediaTrack::Ptr> _ssrc_to_track;
TwccContext _twcc_ctx; //根据接收rtp的pt获取相关信息
unordered_map<uint8_t/*pt*/, std::pair<bool/*is rtx*/,MediaTrack::Ptr> > _pt_to_track;
}; };