mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-29 22:55:52 +08:00
提取webrtc推流、播放代码为单独的派生类
This commit is contained in:
parent
8531b5e1cb
commit
7f3f47abbb
@ -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
101
webrtc/WebRtcPlayer.cpp
Normal 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
44
webrtc/WebRtcPlayer.h
Normal 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
131
webrtc/WebRtcPusher.cpp
Normal 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
55
webrtc/WebRtcPusher.h
Normal 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
|
@ -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,30 +764,7 @@ 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////
|
||||||
@ -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;
|
||||||
|
@ -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;
|
||||||
};
|
};
|
Loading…
Reference in New Issue
Block a user