整理代码

This commit is contained in:
xiongziliang 2020-08-30 11:40:03 +08:00
parent fbd711a6bb
commit a7e99b9d37
10 changed files with 438 additions and 419 deletions

View File

@ -91,14 +91,14 @@ void RtmpPlayer::onErr(const SockException &ex){
onPlayResult_l(ex, !_play_timer); onPlayResult_l(ex, !_play_timer);
} }
void RtmpPlayer::onPlayResult_l(const SockException &ex, bool handshakeCompleted) { void RtmpPlayer::onPlayResult_l(const SockException &ex, bool handshake_done) {
if (ex.getErrCode() == Err_shutdown) { if (ex.getErrCode() == Err_shutdown) {
//主动shutdown的不触发回调 //主动shutdown的不触发回调
return; return;
} }
WarnL << ex.getErrCode() << " " << ex.what(); WarnL << ex.getErrCode() << " " << ex.what();
if (!handshakeCompleted) { if (!handshake_done) {
//开始播放阶段 //开始播放阶段
_play_timer.reset(); _play_timer.reset();
//是否为性能测试模式 //是否为性能测试模式
@ -152,14 +152,14 @@ void RtmpPlayer::onConnect(const SockException &err){
}); });
} }
void RtmpPlayer::onRecv(const Buffer::Ptr &pBuf){ void RtmpPlayer::onRecv(const Buffer::Ptr &buf){
try { try {
if (_benchmark_mode && !_play_timer) { if (_benchmark_mode && !_play_timer) {
//在性能测试模式下如果rtmp握手完毕后不再解析rtmp包 //在性能测试模式下如果rtmp握手完毕后不再解析rtmp包
_rtmp_recv_ticker.resetTime(); _rtmp_recv_ticker.resetTime();
return; return;
} }
onParseRtmp(pBuf->data(), pBuf->size()); onParseRtmp(buf->data(), buf->size());
} catch (exception &e) { } catch (exception &e) {
SockException ex(Err_other, e.what()); SockException ex(Err_other, e.what());
//定时器_pPlayTimer为空后表明握手结束了 //定时器_pPlayTimer为空后表明握手结束了
@ -226,21 +226,21 @@ inline void RtmpPlayer::send_play() {
addOnStatusCB(fun); addOnStatusCB(fun);
} }
inline void RtmpPlayer::send_pause(bool bPause) { inline void RtmpPlayer::send_pause(bool pause) {
AMFEncoder enc; AMFEncoder enc;
enc << "pause" << ++_send_req_id << nullptr << bPause; enc << "pause" << ++_send_req_id << nullptr << pause;
sendRequest(MSG_CMD, enc.data()); sendRequest(MSG_CMD, enc.data());
auto fun = [this, bPause](AMFValue &val) { auto fun = [this, pause](AMFValue &val) {
//TraceL << "pause onStatus"; //TraceL << "pause onStatus";
auto level = val["level"].as_string(); auto level = val["level"].as_string();
auto code = val["code"].as_string(); auto code = val["code"].as_string();
if (level != "status") { if (level != "status") {
if (!bPause) { if (!pause) {
throw std::runtime_error(StrPrinter << "pause 恢复播放失败:" << level << " " << code << endl); throw std::runtime_error(StrPrinter << "pause 恢复播放失败:" << level << " " << code << endl);
} }
} else { } else {
_paused = bPause; _paused = pause;
if (!bPause) { if (!pause) {
onPlayResult_l(SockException(Err_success, "resum rtmp success"), true); onPlayResult_l(SockException(Err_success, "resum rtmp success"), true);
} else { } else {
//暂停播放 //暂停播放
@ -251,7 +251,7 @@ inline void RtmpPlayer::send_pause(bool bPause) {
addOnStatusCB(fun); addOnStatusCB(fun);
_beat_timer.reset(); _beat_timer.reset();
if (bPause) { if (pause) {
weak_ptr<RtmpPlayer> weakSelf = dynamic_pointer_cast<RtmpPlayer>(shared_from_this()); weak_ptr<RtmpPlayer> weakSelf = dynamic_pointer_cast<RtmpPlayer>(shared_from_this());
_beat_timer.reset(new Timer((*this)[kBeatIntervalMS].as<int>() / 1000.0, [weakSelf]() { _beat_timer.reset(new Timer((*this)[kBeatIntervalMS].as<int>() / 1000.0, [weakSelf]() {
auto strongSelf = weakSelf.lock(); auto strongSelf = weakSelf.lock();
@ -314,32 +314,32 @@ void RtmpPlayer::onCmd_onMetaData(AMFDecoder &dec) {
_metadata_got = true; _metadata_got = true;
} }
void RtmpPlayer::onStreamDry(uint32_t stream_id) { void RtmpPlayer::onStreamDry(uint32_t stream_index) {
//TraceL << stream_id; //TraceL << stream_index;
onPlayResult_l(SockException(Err_other, "rtmp stream dry"), true); onPlayResult_l(SockException(Err_other, "rtmp stream dry"), true);
} }
void RtmpPlayer::onMediaData_l(const RtmpPacket::Ptr &packet) { void RtmpPlayer::onMediaData_l(const RtmpPacket::Ptr &chunk_data) {
_rtmp_recv_ticker.resetTime(); _rtmp_recv_ticker.resetTime();
if (!_play_timer) { if (!_play_timer) {
//已经触发了onPlayResult事件直接触发onMediaData事件 //已经触发了onPlayResult事件直接触发onMediaData事件
onMediaData(packet); onMediaData(chunk_data);
return; return;
} }
if (packet->isCfgFrame()) { if (chunk_data->isCfgFrame()) {
//输入配置帧以便初始化完成各个track //输入配置帧以便初始化完成各个track
onMediaData(packet); onMediaData(chunk_data);
} else { } else {
//先触发onPlayResult事件这个时候解码器才能初始化完毕 //先触发onPlayResult事件这个时候解码器才能初始化完毕
onPlayResult_l(SockException(Err_success, "play rtmp success"), false); onPlayResult_l(SockException(Err_success, "play rtmp success"), false);
//触发onPlayResult事件后再把帧数据输入到解码器 //触发onPlayResult事件后再把帧数据输入到解码器
onMediaData(packet); onMediaData(chunk_data);
} }
} }
void RtmpPlayer::onRtmpChunk(RtmpPacket &chunkData) { void RtmpPlayer::onRtmpChunk(RtmpPacket &chunk_data) {
typedef void (RtmpPlayer::*rtmp_func_ptr)(AMFDecoder &dec); typedef void (RtmpPlayer::*rtmp_func_ptr)(AMFDecoder &dec);
static unordered_map<string, rtmp_func_ptr> s_func_map; static unordered_map<string, rtmp_func_ptr> s_func_map;
static onceToken token([]() { static onceToken token([]() {
@ -349,12 +349,12 @@ void RtmpPlayer::onRtmpChunk(RtmpPacket &chunkData) {
s_func_map.emplace("onMetaData", &RtmpPlayer::onCmd_onMetaData); s_func_map.emplace("onMetaData", &RtmpPlayer::onCmd_onMetaData);
}); });
switch (chunkData.type_id) { switch (chunk_data.type_id) {
case MSG_CMD: case MSG_CMD:
case MSG_CMD3: case MSG_CMD3:
case MSG_DATA: case MSG_DATA:
case MSG_DATA3: { case MSG_DATA3: {
AMFDecoder dec(chunkData.buffer, 0); AMFDecoder dec(chunk_data.buffer, 0);
std::string type = dec.load<std::string>(); std::string type = dec.load<std::string>();
auto it = s_func_map.find(type); auto it = s_func_map.find(type);
if (it != s_func_map.end()) { if (it != s_func_map.end()) {
@ -368,10 +368,10 @@ void RtmpPlayer::onRtmpChunk(RtmpPacket &chunkData) {
case MSG_AUDIO: case MSG_AUDIO:
case MSG_VIDEO: { case MSG_VIDEO: {
auto idx = chunkData.type_id % 2; auto idx = chunk_data.type_id % 2;
if (_now_stamp_ticker[idx].elapsedTime() > 500) { if (_now_stamp_ticker[idx].elapsedTime() > 500) {
//计算播放进度时间轴用 //计算播放进度时间轴用
_now_stamp[idx] = chunkData.time_stamp; _now_stamp[idx] = chunk_data.time_stamp;
} }
if (!_metadata_got) { if (!_metadata_got) {
if (!onCheckMeta(TitleMeta().getMetadata())) { if (!onCheckMeta(TitleMeta().getMetadata())) {
@ -379,7 +379,7 @@ void RtmpPlayer::onRtmpChunk(RtmpPacket &chunkData) {
} }
_metadata_got = true; _metadata_got = true;
} }
onMediaData_l(std::make_shared<RtmpPacket>(std::move(chunkData))); onMediaData_l(std::make_shared<RtmpPacket>(std::move(chunk_data)));
break; break;
} }

View File

@ -41,34 +41,34 @@ public:
void teardown() override; void teardown() override;
protected: protected:
virtual bool onCheckMeta(const AMFValue &val) =0; virtual bool onCheckMeta(const AMFValue &val) = 0;
virtual void onMediaData(const RtmpPacket::Ptr &chunkData) =0; virtual void onMediaData(const RtmpPacket::Ptr &chunk_data) = 0;
uint32_t getProgressMilliSecond() const; uint32_t getProgressMilliSecond() const;
void seekToMilliSecond(uint32_t ms); void seekToMilliSecond(uint32_t ms);
protected: protected:
void onMediaData_l(const RtmpPacket::Ptr &chunkData); void onMediaData_l(const RtmpPacket::Ptr &chunk_data);
//在获取config帧后才触发onPlayResult_l(而不是收到play命令回复)所以此时所有track都初始化完毕了 //在获取config帧后才触发onPlayResult_l(而不是收到play命令回复)所以此时所有track都初始化完毕了
void onPlayResult_l(const SockException &ex, bool handshakeCompleted); void onPlayResult_l(const SockException &ex, bool handshake_done);
//form Tcpclient //form Tcpclient
void onRecv(const Buffer::Ptr &pBuf) override; void onRecv(const Buffer::Ptr &buf) override;
void onConnect(const SockException &err) override; void onConnect(const SockException &err) override;
void onErr(const SockException &ex) override; void onErr(const SockException &ex) override;
//from RtmpProtocol //from RtmpProtocol
void onRtmpChunk(RtmpPacket &chunkData) override; void onRtmpChunk(RtmpPacket &chunk_data) override;
void onStreamDry(uint32_t ui32StreamId) override; void onStreamDry(uint32_t stream_index) override;
void onSendRawData(const Buffer::Ptr &buffer) override{ void onSendRawData(const Buffer::Ptr &buffer) override {
send(buffer); send(buffer);
} }
template<typename FUNC> template<typename FUNC>
inline void addOnResultCB(const FUNC &func) { void addOnResultCB(const FUNC &func) {
lock_guard<recursive_mutex> lck(_mtx_on_result); lock_guard<recursive_mutex> lck(_mtx_on_result);
_map_on_result.emplace(_send_req_id, func); _map_on_result.emplace(_send_req_id, func);
} }
template<typename FUNC> template<typename FUNC>
inline void addOnStatusCB(const FUNC &func) { void addOnStatusCB(const FUNC &func) {
lock_guard<recursive_mutex> lck(_mtx_on_status); lock_guard<recursive_mutex> lck(_mtx_on_status);
_deque_on_status.emplace_back(func); _deque_on_status.emplace_back(func);
} }
@ -77,10 +77,10 @@ protected:
void onCmd_onStatus(AMFDecoder &dec); void onCmd_onStatus(AMFDecoder &dec);
void onCmd_onMetaData(AMFDecoder &dec); void onCmd_onMetaData(AMFDecoder &dec);
inline void send_connect(); void send_connect();
inline void send_createStream(); void send_createStream();
inline void send_play(); void send_play();
inline void send_pause(bool bPause); void send_pause(bool pause);
private: private:
string _app; string _app;

View File

@ -15,11 +15,6 @@
#include "Thread/ThreadPool.h" #include "Thread/ThreadPool.h"
using namespace toolkit; using namespace toolkit;
#ifdef ENABLE_OPENSSL
#include "Util/SSLBox.h"
#include <openssl/hmac.h>
#include <openssl/opensslv.h>
#define C1_DIGEST_SIZE 32 #define C1_DIGEST_SIZE 32
#define C1_KEY_SIZE 128 #define C1_KEY_SIZE 128
#define C1_SCHEMA_SIZE 764 #define C1_SCHEMA_SIZE 764
@ -29,6 +24,11 @@ using namespace toolkit;
#define S2_FMS_KEY_SIZE 68 #define S2_FMS_KEY_SIZE 68
#define C1_OFFSET_SIZE 4 #define C1_OFFSET_SIZE 4
#ifdef ENABLE_OPENSSL
#include "Util/SSLBox.h"
#include <openssl/hmac.h>
#include <openssl/opensslv.h>
static string openssl_HMACsha256(const void *key, unsigned int key_len, const void *data,unsigned int data_len){ static string openssl_HMACsha256(const void *key, unsigned int key_len, const void *data,unsigned int data_len){
std::shared_ptr<char> out(new char[32], [](char *ptr) { delete[] ptr; }); std::shared_ptr<char> out(new char[32], [](char *ptr) { delete[] ptr; });
unsigned int out_len; unsigned int out_len;

View File

@ -18,141 +18,147 @@ using namespace mediakit::Client;
namespace mediakit { namespace mediakit {
RtmpPusher::RtmpPusher(const EventPoller::Ptr &poller,const RtmpMediaSource::Ptr &src) : TcpClient(poller){ RtmpPusher::RtmpPusher(const EventPoller::Ptr &poller, const RtmpMediaSource::Ptr &src) : TcpClient(poller){
_pMediaSrc=src; _publish_src = src;
} }
RtmpPusher::~RtmpPusher() { RtmpPusher::~RtmpPusher() {
teardown(); teardown();
DebugL << endl; DebugL << endl;
} }
void RtmpPusher::teardown() { void RtmpPusher::teardown() {
if (alive()) { if (alive()) {
_strApp.clear(); _app.clear();
_strStream.clear(); _stream_id.clear();
_strTcUrl.clear(); _tc_url.clear();
{ {
lock_guard<recursive_mutex> lck(_mtxOnResultCB); lock_guard<recursive_mutex> lck(_mtx_on_result);
_mapOnResultCB.clear(); _map_on_result.clear();
} }
{ {
lock_guard<recursive_mutex> lck(_mtxOnStatusCB); lock_guard<recursive_mutex> lck(_mtx_on_status);
_dqOnStatusCB.clear(); _deque_on_status.clear();
} }
_pPublishTimer.reset(); _publish_timer.reset();
reset(); reset();
shutdown(SockException(Err_shutdown,"teardown")); shutdown(SockException(Err_shutdown, "teardown"));
} }
} }
void RtmpPusher::onPublishResult(const SockException &ex,bool handshakeCompleted) { void RtmpPusher::onPublishResult(const SockException &ex, bool handshake_done) {
if(!handshakeCompleted){ if (ex.getErrCode() == Err_shutdown) {
//主动shutdown的不触发回调
return;
}
if (!handshake_done) {
//播放结果回调 //播放结果回调
_pPublishTimer.reset(); _publish_timer.reset();
if(_onPublished){ if (_on_published) {
_onPublished(ex); _on_published(ex);
} }
} else { } else {
//播放成功后异常断开回调 //播放成功后异常断开回调
if(_onShutdown){ if (_on_shutdown) {
_onShutdown(ex); _on_shutdown(ex);
} }
} }
if(ex){ if (ex) {
teardown(); teardown();
} }
} }
void RtmpPusher::publish(const string &strUrl) { void RtmpPusher::publish(const string &url) {
teardown(); teardown();
string strHost = FindField(strUrl.data(), "://", "/"); string host_url = FindField(url.data(), "://", "/");
_strApp = FindField(strUrl.data(), (strHost + "/").data(), "/"); _app = FindField(url.data(), (host_url + "/").data(), "/");
_strStream = FindField(strUrl.data(), (strHost + "/" + _strApp + "/").data(), NULL); _stream_id = FindField(url.data(), (host_url + "/" + _app + "/").data(), NULL);
_strTcUrl = string("rtmp://") + strHost + "/" + _strApp; _tc_url = string("rtmp://") + host_url + "/" + _app;
if (!_strApp.size() || !_strStream.size()) { if (!_app.size() || !_stream_id.size()) {
onPublishResult(SockException(Err_other,"rtmp url非法"),false); onPublishResult(SockException(Err_other, "rtmp url非法"), false);
return; return;
} }
DebugL << strHost << " " << _strApp << " " << _strStream; DebugL << host_url << " " << _app << " " << _stream_id;
auto iPort = atoi(FindField(strHost.data(), ":", NULL).data()); auto iPort = atoi(FindField(host_url.data(), ":", NULL).data());
if (iPort <= 0) { if (iPort <= 0) {
//rtmp 默认端口1935 //rtmp 默认端口1935
iPort = 1935; iPort = 1935;
} else { } else {
//服务器域名 //服务器域名
strHost = FindField(strHost.data(), NULL, ":"); host_url = FindField(host_url.data(), NULL, ":");
} }
weak_ptr<RtmpPusher> weakSelf = dynamic_pointer_cast<RtmpPusher>(shared_from_this()); weak_ptr<RtmpPusher> weakSelf = dynamic_pointer_cast<RtmpPusher>(shared_from_this());
float publishTimeOutSec = (*this)[kTimeoutMS].as<int>() / 1000.0; float publishTimeOutSec = (*this)[kTimeoutMS].as<int>() / 1000.0;
_pPublishTimer.reset( new Timer(publishTimeOutSec, [weakSelf]() { _publish_timer.reset(new Timer(publishTimeOutSec, [weakSelf]() {
auto strongSelf=weakSelf.lock(); auto strongSelf = weakSelf.lock();
if(!strongSelf) { if (!strongSelf) {
return false; return false;
} }
strongSelf->onPublishResult(SockException(Err_timeout,"publish rtmp timeout"), false); strongSelf->onPublishResult(SockException(Err_timeout, "publish rtmp timeout"), false);
return false; return false;
},getPoller())); }, getPoller()));
if(!(*this)[kNetAdapter].empty()){ if (!(*this)[kNetAdapter].empty()) {
setNetAdapter((*this)[kNetAdapter]); setNetAdapter((*this)[kNetAdapter]);
} }
startConnect(strHost, iPort); startConnect(host_url, iPort);
} }
void RtmpPusher::onErr(const SockException &ex){ void RtmpPusher::onErr(const SockException &ex){
//定时器_pPublishTimer为空后表明握手结束了 //定时器_pPublishTimer为空后表明握手结束了
onPublishResult(ex,!_pPublishTimer); onPublishResult(ex, !_publish_timer);
} }
void RtmpPusher::onConnect(const SockException &err){ void RtmpPusher::onConnect(const SockException &err){
if(err) { if (err) {
onPublishResult(err,false); onPublishResult(err, false);
return; return;
} }
//推流器不需要多大的接收缓存,节省内存占用 //推流器不需要多大的接收缓存,节省内存占用
_sock->setReadBuffer(std::make_shared<BufferRaw>(1 * 1024)); _sock->setReadBuffer(std::make_shared<BufferRaw>(1 * 1024));
weak_ptr<RtmpPusher> weakSelf = dynamic_pointer_cast<RtmpPusher>(shared_from_this()); weak_ptr<RtmpPusher> weak_self = dynamic_pointer_cast<RtmpPusher>(shared_from_this());
startClientSession([weakSelf](){ startClientSession([weak_self]() {
auto strongSelf=weakSelf.lock(); auto strong_self = weak_self.lock();
if(!strongSelf) { if (!strong_self) {
return; return;
} }
strongSelf->sendChunkSize(60000); strong_self->sendChunkSize(60000);
strongSelf->send_connect(); strong_self->send_connect();
}); });
} }
void RtmpPusher::onRecv(const Buffer::Ptr &pBuf){
void RtmpPusher::onRecv(const Buffer::Ptr &buf){
try { try {
onParseRtmp(pBuf->data(), pBuf->size()); onParseRtmp(buf->data(), buf->size());
} catch (exception &e) { } catch (exception &e) {
SockException ex(Err_other, e.what()); SockException ex(Err_other, e.what());
//定时器_pPublishTimer为空后表明握手结束了 //定时器_pPublishTimer为空后表明握手结束了
onPublishResult(ex,!_pPublishTimer); onPublishResult(ex, !_publish_timer);
} }
} }
inline void RtmpPusher::send_connect() { inline void RtmpPusher::send_connect() {
AMFValue obj(AMF_OBJECT); AMFValue obj(AMF_OBJECT);
obj.set("app", _strApp); obj.set("app", _app);
obj.set("type", "nonprivate"); obj.set("type", "nonprivate");
obj.set("tcUrl", _strTcUrl); obj.set("tcUrl", _tc_url);
obj.set("swfUrl", _strTcUrl); obj.set("swfUrl", _tc_url);
sendInvoke("connect", obj); sendInvoke("connect", obj);
addOnResultCB([this](AMFDecoder &dec){ addOnResultCB([this](AMFDecoder &dec) {
//TraceL << "connect result"; //TraceL << "connect result";
dec.load<AMFValue>(); dec.load<AMFValue>();
auto val = dec.load<AMFValue>(); auto val = dec.load<AMFValue>();
auto level = val["level"].as_string(); auto level = val["level"].as_string();
auto code = val["code"].as_string(); auto code = val["code"].as_string();
if(level != "status"){ if (level != "status") {
throw std::runtime_error(StrPrinter <<"connect 失败:" << level << " " << code << endl); throw std::runtime_error(StrPrinter << "connect 失败:" << level << " " << code << endl);
} }
send_createStream(); send_createStream();
}); });
@ -161,23 +167,24 @@ inline void RtmpPusher::send_connect() {
inline void RtmpPusher::send_createStream() { inline void RtmpPusher::send_createStream() {
AMFValue obj(AMF_NULL); AMFValue obj(AMF_NULL);
sendInvoke("createStream", obj); sendInvoke("createStream", obj);
addOnResultCB([this](AMFDecoder &dec){ addOnResultCB([this](AMFDecoder &dec) {
//TraceL << "createStream result"; //TraceL << "createStream result";
dec.load<AMFValue>(); dec.load<AMFValue>();
_stream_index = dec.load<int>(); _stream_index = dec.load<int>();
send_publish(); send_publish();
}); });
} }
inline void RtmpPusher::send_publish() { inline void RtmpPusher::send_publish() {
AMFEncoder enc; AMFEncoder enc;
enc << "publish" << ++_send_req_id << nullptr << _strStream << _strApp ; enc << "publish" << ++_send_req_id << nullptr << _stream_id << _app;
sendRequest(MSG_CMD, enc.data()); sendRequest(MSG_CMD, enc.data());
addOnStatusCB([this](AMFValue &val) { addOnStatusCB([this](AMFValue &val) {
auto level = val["level"].as_string(); auto level = val["level"].as_string();
auto code = val["code"].as_string(); auto code = val["code"].as_string();
if(level != "status") { if (level != "status") {
throw std::runtime_error(StrPrinter <<"publish 失败:" << level << " " << code << endl); throw std::runtime_error(StrPrinter << "publish 失败:" << level << " " << code << endl);
} }
//start send media //start send media
send_metaData(); send_metaData();
@ -185,7 +192,7 @@ inline void RtmpPusher::send_publish() {
} }
inline void RtmpPusher::send_metaData(){ inline void RtmpPusher::send_metaData(){
auto src = _pMediaSrc.lock(); auto src = _publish_src.lock();
if (!src) { if (!src) {
throw std::runtime_error("the media source was released"); throw std::runtime_error("the media source was released");
} }
@ -194,42 +201,42 @@ inline void RtmpPusher::send_metaData(){
enc << "@setDataFrame" << "onMetaData" << src->getMetaData(); enc << "@setDataFrame" << "onMetaData" << src->getMetaData();
sendRequest(MSG_DATA, enc.data()); sendRequest(MSG_DATA, enc.data());
src->getConfigFrame([&](const RtmpPacket::Ptr &pkt){ src->getConfigFrame([&](const RtmpPacket::Ptr &pkt) {
sendRtmp(pkt->type_id, _stream_index, pkt, pkt->time_stamp, pkt->chunk_id ); sendRtmp(pkt->type_id, _stream_index, pkt, pkt->time_stamp, pkt->chunk_id);
}); });
_pRtmpReader = src->getRing()->attach(getPoller()); _rtmp_reader = src->getRing()->attach(getPoller());
weak_ptr<RtmpPusher> weakSelf = dynamic_pointer_cast<RtmpPusher>(shared_from_this()); weak_ptr<RtmpPusher> weak_self = dynamic_pointer_cast<RtmpPusher>(shared_from_this());
_pRtmpReader->setReadCB([weakSelf](const RtmpMediaSource::RingDataType &pkt){ _rtmp_reader->setReadCB([weak_self](const RtmpMediaSource::RingDataType &pkt) {
auto strongSelf = weakSelf.lock(); auto strong_self = weak_self.lock();
if(!strongSelf) { if (!strong_self) {
return; return;
} }
int i = 0; int i = 0;
int size = pkt->size(); int size = pkt->size();
strongSelf->setSendFlushFlag(false); strong_self->setSendFlushFlag(false);
pkt->for_each([&](const RtmpPacket::Ptr &rtmp){ pkt->for_each([&](const RtmpPacket::Ptr &rtmp) {
if(++i == size){ if (++i == size) {
strongSelf->setSendFlushFlag(true); strong_self->setSendFlushFlag(true);
} }
strongSelf->sendRtmp(rtmp->type_id, strongSelf->_stream_index, rtmp, rtmp->time_stamp, rtmp->chunk_id); strong_self->sendRtmp(rtmp->type_id, strong_self->_stream_index, rtmp, rtmp->time_stamp, rtmp->chunk_id);
}); });
}); });
_pRtmpReader->setDetachCB([weakSelf](){ _rtmp_reader->setDetachCB([weak_self]() {
auto strongSelf = weakSelf.lock(); auto strong_self = weak_self.lock();
if(strongSelf){ if (strong_self) {
strongSelf->onPublishResult(SockException(Err_other,"媒体源被释放"), !strongSelf->_pPublishTimer); strong_self->onPublishResult(SockException(Err_other, "媒体源被释放"), !strong_self->_publish_timer);
} }
}); });
onPublishResult(SockException(Err_success,"success"), false); onPublishResult(SockException(Err_success, "success"), false);
//提升发送性能 //提升发送性能
setSocketFlags(); setSocketFlags();
} }
void RtmpPusher::setSocketFlags(){ void RtmpPusher::setSocketFlags(){
GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS); GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS);
if(mergeWriteMS > 0) { if (mergeWriteMS > 0) {
//提高发送性能 //提高发送性能
setSendFlags(SOCKET_DEFAULE_FLAGS | FLAG_MORE); setSendFlags(SOCKET_DEFAULE_FLAGS | FLAG_MORE);
SockUtil::setNoDelay(_sock->rawFD(), false); SockUtil::setNoDelay(_sock->rawFD(), false);
@ -237,68 +244,70 @@ void RtmpPusher::setSocketFlags(){
} }
void RtmpPusher::onCmd_result(AMFDecoder &dec){ void RtmpPusher::onCmd_result(AMFDecoder &dec){
auto iReqId = dec.load<int>(); auto req_id = dec.load<int>();
lock_guard<recursive_mutex> lck(_mtxOnResultCB); lock_guard<recursive_mutex> lck(_mtx_on_result);
auto it = _mapOnResultCB.find(iReqId); auto it = _map_on_result.find(req_id);
if(it != _mapOnResultCB.end()){ if (it != _map_on_result.end()) {
it->second(dec); it->second(dec);
_mapOnResultCB.erase(it); _map_on_result.erase(it);
}else{ } else {
WarnL << "unhandled _result"; WarnL << "unhandled _result";
} }
} }
void RtmpPusher::onCmd_onStatus(AMFDecoder &dec) { void RtmpPusher::onCmd_onStatus(AMFDecoder &dec) {
AMFValue val; AMFValue val;
while(true){ while (true) {
val = dec.load<AMFValue>(); val = dec.load<AMFValue>();
if(val.type() == AMF_OBJECT){ if (val.type() == AMF_OBJECT) {
break; break;
} }
} }
if(val.type() != AMF_OBJECT){ if (val.type() != AMF_OBJECT) {
throw std::runtime_error("onStatus:the result object was not found"); throw std::runtime_error("onStatus:the result object was not found");
} }
lock_guard<recursive_mutex> lck(_mtxOnStatusCB); lock_guard<recursive_mutex> lck(_mtx_on_status);
if(_dqOnStatusCB.size()){ if (_deque_on_status.size()) {
_dqOnStatusCB.front()(val); _deque_on_status.front()(val);
_dqOnStatusCB.pop_front(); _deque_on_status.pop_front();
}else{ } else {
auto level = val["level"]; auto level = val["level"];
auto code = val["code"].as_string(); auto code = val["code"].as_string();
if(level.type() == AMF_STRING){ if (level.type() == AMF_STRING) {
if(level.as_string() != "status"){ if (level.as_string() != "status") {
throw std::runtime_error(StrPrinter <<"onStatus 失败:" << level.as_string() << " " << code << endl); throw std::runtime_error(StrPrinter << "onStatus 失败:" << level.as_string() << " " << code << endl);
} }
} }
} }
} }
void RtmpPusher::onRtmpChunk(RtmpPacket &chunkData) { void RtmpPusher::onRtmpChunk(RtmpPacket &chunk_data) {
switch (chunkData.type_id) { switch (chunk_data.type_id) {
case MSG_CMD: case MSG_CMD:
case MSG_CMD3: { case MSG_CMD3: {
typedef void (RtmpPusher::*rtmpCMDHandle)(AMFDecoder &dec); typedef void (RtmpPusher::*rtmpCMDHandle)(AMFDecoder &dec);
static unordered_map<string, rtmpCMDHandle> g_mapCmd; static unordered_map<string, rtmpCMDHandle> g_mapCmd;
static onceToken token([]() { static onceToken token([]() {
g_mapCmd.emplace("_error",&RtmpPusher::onCmd_result); g_mapCmd.emplace("_error", &RtmpPusher::onCmd_result);
g_mapCmd.emplace("_result",&RtmpPusher::onCmd_result); g_mapCmd.emplace("_result", &RtmpPusher::onCmd_result);
g_mapCmd.emplace("onStatus",&RtmpPusher::onCmd_onStatus); g_mapCmd.emplace("onStatus", &RtmpPusher::onCmd_onStatus);
}); });
AMFDecoder dec(chunkData.buffer, 0); AMFDecoder dec(chunk_data.buffer, 0);
std::string type = dec.load<std::string>(); std::string type = dec.load<std::string>();
auto it = g_mapCmd.find(type); auto it = g_mapCmd.find(type);
if(it != g_mapCmd.end()){ if (it != g_mapCmd.end()) {
auto fun = it->second; auto fun = it->second;
(this->*fun)(dec); (this->*fun)(dec);
}else{ } else {
WarnL << "can not support cmd:" << type; WarnL << "can not support cmd:" << type;
} }
}
break; break;
}
default: default:
//WarnL << "unhandled message:" << (int) chunkData.type_id << hexdump(chunkData.buffer.data(), chunkData.buffer.size()); //WarnL << "unhandled message:" << (int) chunk_data.type_id << hexdump(chunk_data.buffer.data(), chunk_data.buffer.size());
break; break;
} }
} }

View File

@ -18,46 +18,47 @@
namespace mediakit { namespace mediakit {
class RtmpPusher: public RtmpProtocol , public TcpClient , public PusherBase{ class RtmpPusher : public RtmpProtocol, public TcpClient, public PusherBase {
public: public:
typedef std::shared_ptr<RtmpPusher> Ptr; typedef std::shared_ptr<RtmpPusher> Ptr;
RtmpPusher(const EventPoller::Ptr &poller,const RtmpMediaSource::Ptr &src); RtmpPusher(const EventPoller::Ptr &poller,const RtmpMediaSource::Ptr &src);
virtual ~RtmpPusher(); ~RtmpPusher() override;
void publish(const string &strUrl) override ;
void publish(const string &url) override ;
void teardown() override; void teardown() override;
void setOnPublished(const Event &cb) override { void setOnPublished(const Event &cb) override {
_onPublished = cb; _on_published = cb;
} }
void setOnShutdown(const Event &cb) override{ void setOnShutdown(const Event &cb) override{
_onShutdown = cb; _on_shutdown = cb;
} }
protected: protected:
//for Tcpclient override //for Tcpclient override
void onRecv(const Buffer::Ptr &pBuf) override; void onRecv(const Buffer::Ptr &buf) override;
void onConnect(const SockException &err) override; void onConnect(const SockException &err) override;
void onErr(const SockException &ex) override; void onErr(const SockException &ex) override;
//for RtmpProtocol override //for RtmpProtocol override
void onRtmpChunk(RtmpPacket &chunkData) override; void onRtmpChunk(RtmpPacket &chunk_data) override;
void onSendRawData(const Buffer::Ptr &buffer) override{ void onSendRawData(const Buffer::Ptr &buffer) override{
send(buffer); send(buffer);
} }
private: private:
void onPublishResult(const SockException &ex,bool handshakeCompleted); void onPublishResult(const SockException &ex, bool handshake_done);
template<typename FUN> template<typename FUN>
inline void addOnResultCB(const FUN &fun) { inline void addOnResultCB(const FUN &fun) {
lock_guard<recursive_mutex> lck(_mtxOnResultCB); lock_guard<recursive_mutex> lck(_mtx_on_result);
_mapOnResultCB.emplace(_send_req_id, fun); _map_on_result.emplace(_send_req_id, fun);
} }
template<typename FUN> template<typename FUN>
inline void addOnStatusCB(const FUN &fun) { inline void addOnStatusCB(const FUN &fun) {
lock_guard<recursive_mutex> lck(_mtxOnStatusCB); lock_guard<recursive_mutex> lck(_mtx_on_status);
_dqOnStatusCB.emplace_back(fun); _deque_on_status.emplace_back(fun);
} }
void onCmd_result(AMFDecoder &dec); void onCmd_result(AMFDecoder &dec);
@ -69,23 +70,25 @@ private:
inline void send_publish(); inline void send_publish();
inline void send_metaData(); inline void send_metaData();
void setSocketFlags(); void setSocketFlags();
private:
string _strApp;
string _strStream;
string _strTcUrl;
unordered_map<int, function<void(AMFDecoder &dec)> > _mapOnResultCB; private:
recursive_mutex _mtxOnResultCB; string _app;
deque<function<void(AMFValue &dec)> > _dqOnStatusCB; string _stream_id;
recursive_mutex _mtxOnStatusCB; string _tc_url;
//超时功能实现
std::shared_ptr<Timer> _pPublishTimer; recursive_mutex _mtx_on_result;
//源 recursive_mutex _mtx_on_status;
std::weak_ptr<RtmpMediaSource> _pMediaSrc; deque<function<void(AMFValue &dec)> > _deque_on_status;
RtmpMediaSource::RingType::RingReader::Ptr _pRtmpReader; unordered_map<int, function<void(AMFDecoder &dec)> > _map_on_result;
//事件监听 //事件监听
Event _onShutdown; Event _on_shutdown;
Event _onPublished; Event _on_published;
//推流超时定时器
std::shared_ptr<Timer> _publish_timer;
std::weak_ptr<RtmpMediaSource> _publish_src;
RtmpMediaSource::RingType::RingReader::Ptr _rtmp_reader;
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -732,14 +732,14 @@ void RtspPlayer::onRecvRTP_l(const RtpPacket::Ptr &rtp, const SdpTrack::Ptr &tra
} }
} }
void RtspPlayer::onPlayResult_l(const SockException &ex , bool handshakeCompleted) { void RtspPlayer::onPlayResult_l(const SockException &ex , bool handshake_done) {
if (ex.getErrCode() == Err_shutdown) { if (ex.getErrCode() == Err_shutdown) {
//主动shutdown的不触发回调 //主动shutdown的不触发回调
return; return;
} }
WarnL << ex.getErrCode() << " " << ex.what(); WarnL << ex.getErrCode() << " " << ex.what();
if (!handshakeCompleted) { if (!handshake_done) {
//开始播放阶段 //开始播放阶段
_play_check_timer.reset(); _play_check_timer.reset();
onPlayResult(ex); onPlayResult(ex);

View File

@ -87,7 +87,7 @@ protected:
private: private:
void onRecvRTP_l(const RtpPacket::Ptr &rtp, const SdpTrack::Ptr &track); void onRecvRTP_l(const RtpPacket::Ptr &rtp, const SdpTrack::Ptr &track);
void onPlayResult_l(const SockException &ex , bool handshakeCompleted); void onPlayResult_l(const SockException &ex , bool handshake_done);
int getTrackIndexByInterleaved(int interleaved) const; int getTrackIndexByInterleaved(int interleaved) const;
int getTrackIndexByTrackType(TrackType track_type) const; int getTrackIndexByTrackType(TrackType track_type) const;

View File

@ -25,46 +25,51 @@ using namespace toolkit;
namespace mediakit { namespace mediakit {
class RtspPlayerImp: public PlayerImp<RtspPlayer,RtspDemuxer> { class RtspPlayerImp : public PlayerImp<RtspPlayer,RtspDemuxer> {
public: public:
typedef std::shared_ptr<RtspPlayerImp> Ptr; typedef std::shared_ptr<RtspPlayerImp> Ptr;
RtspPlayerImp(const EventPoller::Ptr &poller) : PlayerImp<RtspPlayer,RtspDemuxer>(poller){}
virtual ~RtspPlayerImp(){ RtspPlayerImp(const EventPoller::Ptr &poller) : PlayerImp<RtspPlayer, RtspDemuxer>(poller) {}
DebugL<<endl; ~RtspPlayerImp() override{
}; DebugL << endl;
float getProgress() const override{ }
if(getDuration() > 0){
float getProgress() const override {
if (getDuration() > 0) {
return getProgressMilliSecond() / (getDuration() * 1000); return getProgressMilliSecond() / (getDuration() * 1000);
} }
return PlayerBase::getProgress(); return PlayerBase::getProgress();
}; }
void seekTo(float fProgress) override{
fProgress = MAX(float(0),MIN(fProgress,float(1.0))); void seekTo(float fProgress) override {
fProgress = MAX(float(0), MIN(fProgress, float(1.0)));
seekToMilliSecond(fProgress * getDuration() * 1000); seekToMilliSecond(fProgress * getDuration() * 1000);
}; }
private: private:
//派生类回调函数 //派生类回调函数
bool onCheckSDP(const string &sdp) override { bool onCheckSDP(const string &sdp) override {
_pRtspMediaSrc = dynamic_pointer_cast<RtspMediaSource>(_pMediaSrc); _rtsp_media_src = dynamic_pointer_cast<RtspMediaSource>(_pMediaSrc);
if(_pRtspMediaSrc){ if (_rtsp_media_src) {
_pRtspMediaSrc->setSdp(sdp); _rtsp_media_src->setSdp(sdp);
} }
_delegate.reset(new RtspDemuxer); _delegate.reset(new RtspDemuxer);
_delegate->loadSdp(sdp); _delegate->loadSdp(sdp);
return true; return true;
} }
void onRecvRTP(const RtpPacket::Ptr &rtp, const SdpTrack::Ptr &track) override { void onRecvRTP(const RtpPacket::Ptr &rtp, const SdpTrack::Ptr &track) override {
if(_pRtspMediaSrc){ if (_rtsp_media_src) {
// rtsp直接代理是无法判断该rtp是否是I帧所以GOP缓存基本是无效的 // rtsp直接代理是无法判断该rtp是否是I帧所以GOP缓存基本是无效的
// 为了减少内存使用那么我们设置为一直关键帧以便清空GOP缓存 // 为了减少内存使用那么我们设置为一直关键帧以便清空GOP缓存
_pRtspMediaSrc->onWrite(rtp,true); _rtsp_media_src->onWrite(rtp, true);
} }
_delegate->inputRtp(rtp); _delegate->inputRtp(rtp);
if(_maxAnalysisMS && _delegate->isInited(_maxAnalysisMS)){ if (_max_analysis_ms && _delegate->isInited(_max_analysis_ms)) {
PlayerImp<RtspPlayer,RtspDemuxer>::onPlayResult(SockException(Err_success,"play rtsp success")); PlayerImp<RtspPlayer, RtspDemuxer>::onPlayResult(SockException(Err_success, "play rtsp success"));
_maxAnalysisMS = 0; _max_analysis_ms = 0;
} }
} }
@ -74,17 +79,18 @@ private:
//如果超过这个时间还未获取成功那么会强制触发onPlayResult事件(虽然此时有些track还未初始化成功) //如果超过这个时间还未获取成功那么会强制触发onPlayResult事件(虽然此时有些track还未初始化成功)
void onPlayResult(const SockException &ex) override { void onPlayResult(const SockException &ex) override {
//isInited判断条件无超时 //isInited判断条件无超时
if(ex || _delegate->isInited(0)){ if (ex || _delegate->isInited(0)) {
//已经初始化成功说明sdp里面有完善的信息 //已经初始化成功说明sdp里面有完善的信息
PlayerImp<RtspPlayer,RtspDemuxer>::onPlayResult(ex); PlayerImp<RtspPlayer, RtspDemuxer>::onPlayResult(ex);
}else{ } else {
//还没初始化成功说明sdp里面信息不完善还有一些track未初始化成功 //还没初始化成功说明sdp里面信息不完善还有一些track未初始化成功
_maxAnalysisMS = (*this)[Client::kMaxAnalysisMS]; _max_analysis_ms = (*this)[Client::kMaxAnalysisMS];
} }
} }
private: private:
RtspMediaSource::Ptr _pRtspMediaSrc; int _max_analysis_ms = 0;
int _maxAnalysisMS = 0; RtspMediaSource::Ptr _rtsp_media_src;
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -17,8 +17,8 @@ using namespace mediakit::Client;
namespace mediakit { namespace mediakit {
RtspPusher::RtspPusher(const EventPoller::Ptr &poller,const RtspMediaSource::Ptr &src) : TcpClient(poller){ RtspPusher::RtspPusher(const EventPoller::Ptr &poller, const RtspMediaSource::Ptr &src) : TcpClient(poller) {
_pMediaSrc = src; _push_src = src;
} }
RtspPusher::~RtspPusher() { RtspPusher::~RtspPusher() {
@ -28,30 +28,30 @@ RtspPusher::~RtspPusher() {
void RtspPusher::teardown() { void RtspPusher::teardown() {
if (alive()) { if (alive()) {
sendRtspRequest("TEARDOWN" ,_strContentBase); sendRtspRequest("TEARDOWN", _content_base);
shutdown(SockException(Err_shutdown,"teardown")); shutdown(SockException(Err_shutdown, "teardown"));
} }
reset(); reset();
CLEAR_ARR(_apUdpSock); CLEAR_ARR(_udp_socks);
_rtspMd5Nonce.clear(); _nonce.clear();
_rtspRealm.clear(); _realm.clear();
_aTrackInfo.clear(); _track_vec.clear();
_strSession.clear(); _session_id.clear();
_strContentBase.clear(); _content_base.clear();
_strSession.clear(); _session_id.clear();
_uiCseq = 1; _cseq = 1;
_pPublishTimer.reset(); _publish_timer.reset();
_pBeatTimer.reset(); _beat_timer.reset();
_pRtspReader.reset(); _rtsp_reader.reset();
_aTrackInfo.clear(); _track_vec.clear();
_onHandshake = nullptr; _on_res_func = nullptr;
} }
void RtspPusher::publish(const string &strUrl) { void RtspPusher::publish(const string &url_str) {
RtspUrl url; RtspUrl url;
if(!url.parse(strUrl)){ if (!url.parse(url_str)) {
onPublishResult(SockException(Err_other,StrPrinter << "illegal rtsp url:" << strUrl),false); onPublishResult(SockException(Err_other, StrPrinter << "illegal rtsp url:" << url_str), false);
return; return;
} }
@ -65,55 +65,60 @@ void RtspPusher::publish(const string &strUrl) {
(*this)[kRtspPwdIsMD5] = false; (*this)[kRtspPwdIsMD5] = false;
} }
_strUrl = strUrl; _url = url_str;
_eType = (Rtsp::eRtpType)(int)(*this)[kRtpType]; _rtp_type = (Rtsp::eRtpType) (int) (*this)[kRtpType];
DebugL << url._url << " " << (url._user.size() ? url._user : "null") << " " << (url._passwd.size() ? url._passwd : "null") << " " << _eType; DebugL << url._url << " " << (url._user.size() ? url._user : "null") << " "
<< (url._passwd.size() ? url._passwd : "null") << " " << _rtp_type;
weak_ptr<RtspPusher> weakSelf = dynamic_pointer_cast<RtspPusher>(shared_from_this()); weak_ptr<RtspPusher> weak_self = dynamic_pointer_cast<RtspPusher>(shared_from_this());
float publishTimeOutSec = (*this)[kTimeoutMS].as<int>() / 1000.0; float publish_timeout_sec = (*this)[kTimeoutMS].as<int>() / 1000.0;
_pPublishTimer.reset( new Timer(publishTimeOutSec, [weakSelf]() { _publish_timer.reset(new Timer(publish_timeout_sec, [weak_self]() {
auto strongSelf=weakSelf.lock(); auto strong_self = weak_self.lock();
if(!strongSelf) { if (!strong_self) {
return false; return false;
} }
strongSelf->onPublishResult(SockException(Err_timeout,"publish rtsp timeout"),false); strong_self->onPublishResult(SockException(Err_timeout, "publish rtsp timeout"), false);
return false; return false;
},getPoller())); }, getPoller()));
if(!(*this)[kNetAdapter].empty()){ if (!(*this)[kNetAdapter].empty()) {
setNetAdapter((*this)[kNetAdapter]); setNetAdapter((*this)[kNetAdapter]);
} }
startConnect(url._host, url._port, publishTimeOutSec); startConnect(url._host, url._port, publish_timeout_sec);
} }
void RtspPusher::onPublishResult(const SockException &ex, bool handshakeCompleted) { void RtspPusher::onPublishResult(const SockException &ex, bool handshake_done) {
if(!handshakeCompleted){ if (ex.getErrCode() == Err_shutdown) {
//主动shutdown的不触发回调
return;
}
if (!handshake_done) {
//播放结果回调 //播放结果回调
_pPublishTimer.reset(); _publish_timer.reset();
if(_onPublished){ if (_on_published) {
_onPublished(ex); _on_published(ex);
} }
} else { } else {
//播放成功后异常断开回调 //播放成功后异常断开回调
if(_onShutdown){ if (_on_shutdown) {
_onShutdown(ex); _on_shutdown(ex);
} }
} }
if(ex){ if (ex) {
teardown(); teardown();
} }
} }
void RtspPusher::onErr(const SockException &ex) { void RtspPusher::onErr(const SockException &ex) {
//定时器_pPublishTimer为空后表明握手结束了 //定时器_pPublishTimer为空后表明握手结束了
onPublishResult(ex,!_pPublishTimer); onPublishResult(ex, !_publish_timer);
} }
void RtspPusher::onConnect(const SockException &err) { void RtspPusher::onConnect(const SockException &err) {
if(err) { if (err) {
onPublishResult(err,false); onPublishResult(err, false);
return; return;
} }
//推流器不需要多大的接收缓存,节省内存占用 //推流器不需要多大的接收缓存,节省内存占用
@ -121,41 +126,40 @@ void RtspPusher::onConnect(const SockException &err) {
sendAnnounce(); sendAnnounce();
} }
void RtspPusher::onRecv(const Buffer::Ptr &pBuf){ void RtspPusher::onRecv(const Buffer::Ptr &buf){
try { try {
input(pBuf->data(), pBuf->size()); input(buf->data(), buf->size());
} catch (exception &e) { } catch (exception &e) {
SockException ex(Err_other, e.what()); SockException ex(Err_other, e.what());
//定时器_pPublishTimer为空后表明握手结束了 //定时器_pPublishTimer为空后表明握手结束了
onPublishResult(ex,!_pPublishTimer); onPublishResult(ex, !_publish_timer);
} }
} }
void RtspPusher::onWholeRtspPacket(Parser &parser) { void RtspPusher::onWholeRtspPacket(Parser &parser) {
decltype(_onHandshake) fun; decltype(_on_res_func) func;
_onHandshake.swap(fun); _on_res_func.swap(func);
if(fun){ if (func) {
fun(parser); func(parser);
} }
parser.Clear(); parser.Clear();
} }
void RtspPusher::sendAnnounce() { void RtspPusher::sendAnnounce() {
auto src = _pMediaSrc.lock(); auto src = _push_src.lock();
if (!src) { if (!src) {
throw std::runtime_error("the media source was released"); throw std::runtime_error("the media source was released");
} }
//解析sdp //解析sdp
_sdpParser.load(src->getSdp()); _sdp_parser.load(src->getSdp());
_aTrackInfo = _sdpParser.getAvailableTrack(); _track_vec = _sdp_parser.getAvailableTrack();
if (_aTrackInfo.empty()) { if (_track_vec.empty()) {
throw std::runtime_error("无有效的Sdp Track"); throw std::runtime_error("无有效的Sdp Track");
} }
_onHandshake = std::bind(&RtspPusher::handleResAnnounce,this, placeholders::_1); _on_res_func = std::bind(&RtspPusher::handleResAnnounce, this, placeholders::_1);
sendRtspRequest("ANNOUNCE",_strUrl,{},src->getSdp()); sendRtspRequest("ANNOUNCE", _url, {}, src->getSdp());
} }
void RtspPusher::handleResAnnounce(const Parser &parser) { void RtspPusher::handleResAnnounce(const Parser &parser) {
@ -165,9 +169,9 @@ void RtspPusher::handleResAnnounce(const Parser &parser) {
sendAnnounce(); sendAnnounce();
return; return;
} }
if(parser.Url() == "302"){ if (parser.Url() == "302") {
auto newUrl = parser["Location"]; auto newUrl = parser["Location"];
if(newUrl.empty()){ if (newUrl.empty()) {
throw std::runtime_error("未找到Location字段(跳转url)"); throw std::runtime_error("未找到Location字段(跳转url)");
} }
publish(newUrl); publish(newUrl);
@ -176,45 +180,45 @@ void RtspPusher::handleResAnnounce(const Parser &parser) {
if (parser.Url() != "200") { if (parser.Url() != "200") {
throw std::runtime_error(StrPrinter << "ANNOUNCE:" << parser.Url() << " " << parser.Tail()); throw std::runtime_error(StrPrinter << "ANNOUNCE:" << parser.Url() << " " << parser.Tail());
} }
_strContentBase = parser["Content-Base"]; _content_base = parser["Content-Base"];
if(_strContentBase.empty()){ if (_content_base.empty()) {
_strContentBase = _strUrl; _content_base = _url;
} }
if (_strContentBase.back() == '/') { if (_content_base.back() == '/') {
_strContentBase.pop_back(); _content_base.pop_back();
} }
sendSetup(0); sendSetup(0);
} }
bool RtspPusher::handleAuthenticationFailure(const string &paramsStr) { bool RtspPusher::handleAuthenticationFailure(const string &params_str) {
if(!_rtspRealm.empty()){ if (!_realm.empty()) {
//已经认证过了 //已经认证过了
return false; return false;
} }
char *realm = new char[paramsStr.size()]; char *realm = new char[params_str.size()];
char *nonce = new char[paramsStr.size()]; char *nonce = new char[params_str.size()];
char *stale = new char[paramsStr.size()]; char *stale = new char[params_str.size()];
onceToken token(nullptr,[&](){ onceToken token(nullptr, [&]() {
delete[] realm; delete[] realm;
delete[] nonce; delete[] nonce;
delete[] stale; delete[] stale;
}); });
if (sscanf(paramsStr.data(), "Digest realm=\"%[^\"]\", nonce=\"%[^\"]\", stale=%[a-zA-Z]", realm, nonce, stale) == 3) { if (sscanf(params_str.data(), "Digest realm=\"%[^\"]\", nonce=\"%[^\"]\", stale=%[a-zA-Z]", realm, nonce, stale) == 3) {
_rtspRealm = (const char *)realm; _realm = (const char *) realm;
_rtspMd5Nonce = (const char *)nonce; _nonce = (const char *) nonce;
return true; return true;
} }
if (sscanf(paramsStr.data(), "Digest realm=\"%[^\"]\", nonce=\"%[^\"]\"", realm, nonce) == 2) { if (sscanf(params_str.data(), "Digest realm=\"%[^\"]\", nonce=\"%[^\"]\"", realm, nonce) == 2) {
_rtspRealm = (const char *)realm; _realm = (const char *) realm;
_rtspMd5Nonce = (const char *)nonce; _nonce = (const char *) nonce;
return true; return true;
} }
if (sscanf(paramsStr.data(), "Basic realm=\"%[^\"]\"", realm) == 1) { if (sscanf(params_str.data(), "Basic realm=\"%[^\"]\"", realm) == 1) {
_rtspRealm = (const char *)realm; _realm = (const char *) realm;
return true; return true;
} }
return false; return false;
@ -222,30 +226,33 @@ bool RtspPusher::handleAuthenticationFailure(const string &paramsStr) {
//有必要的情况下创建udp端口 //有必要的情况下创建udp端口
void RtspPusher::createUdpSockIfNecessary(int track_idx){ void RtspPusher::createUdpSockIfNecessary(int track_idx){
auto &rtpSockRef = _apUdpSock[track_idx]; auto &rtp_sock = _udp_socks[track_idx];
if(!rtpSockRef){ if (!rtp_sock) {
rtpSockRef.reset(new Socket(getPoller())); rtp_sock.reset(new Socket(getPoller()));
//rtp随机端口 //rtp随机端口
if (!rtpSockRef->bindUdpSock(0, get_local_ip().data())) { if (!rtp_sock->bindUdpSock(0, get_local_ip().data())) {
rtpSockRef.reset(); rtp_sock.reset();
throw std::runtime_error("open rtp sock failed"); throw std::runtime_error("open rtp sock failed");
} }
} }
} }
void RtspPusher::sendSetup(unsigned int trackIndex) { void RtspPusher::sendSetup(unsigned int track_idx) {
_onHandshake = std::bind(&RtspPusher::handleResSetup,this, placeholders::_1,trackIndex); _on_res_func = std::bind(&RtspPusher::handleResSetup, this, placeholders::_1, track_idx);
auto &track = _aTrackInfo[trackIndex]; auto &track = _track_vec[track_idx];
auto baseUrl = _strContentBase + "/" + track->_control_surffix; auto base_url = _content_base + "/" + track->_control_surffix;
switch (_eType) { switch (_rtp_type) {
case Rtsp::RTP_TCP: { case Rtsp::RTP_TCP: {
sendRtspRequest("SETUP",baseUrl,{"Transport",StrPrinter << "RTP/AVP/TCP;unicast;interleaved=" << track->_type * 2 << "-" << track->_type * 2 + 1}); sendRtspRequest("SETUP", base_url, {"Transport",
StrPrinter << "RTP/AVP/TCP;unicast;interleaved=" << track->_type * 2
<< "-" << track->_type * 2 + 1});
} }
break; break;
case Rtsp::RTP_UDP: { case Rtsp::RTP_UDP: {
createUdpSockIfNecessary(trackIndex); createUdpSockIfNecessary(track_idx);
int port = _apUdpSock[trackIndex]->get_local_port(); int port = _udp_socks[track_idx]->get_local_port();
sendRtspRequest("SETUP",baseUrl,{"Transport",StrPrinter << "RTP/AVP;unicast;client_port=" << port << "-" << port + 1}); sendRtspRequest("SETUP", base_url,
{"Transport", StrPrinter << "RTP/AVP;unicast;client_port=" << port << "-" << port + 1});
} }
break; break;
default: default:
@ -254,42 +261,41 @@ void RtspPusher::sendSetup(unsigned int trackIndex) {
} }
void RtspPusher::handleResSetup(const Parser &parser, unsigned int uiTrackIndex) { void RtspPusher::handleResSetup(const Parser &parser, unsigned int track_idx) {
if (parser.Url() != "200") { if (parser.Url() != "200") {
throw std::runtime_error( throw std::runtime_error(StrPrinter << "SETUP:" << parser.Url() << " " << parser.Tail() << endl);
StrPrinter << "SETUP:" << parser.Url() << " " << parser.Tail() << endl);
} }
if (uiTrackIndex == 0) { if (track_idx == 0) {
_strSession = parser["Session"]; _session_id = parser["Session"];
_strSession.append(";"); _session_id.append(";");
_strSession = FindField(_strSession.data(), nullptr, ";"); _session_id = FindField(_session_id.data(), nullptr, ";");
} }
auto strTransport = parser["Transport"]; auto transport = parser["Transport"];
if(strTransport.find("TCP") != string::npos || strTransport.find("interleaved") != string::npos){ if (transport.find("TCP") != string::npos || transport.find("interleaved") != string::npos) {
_eType = Rtsp::RTP_TCP; _rtp_type = Rtsp::RTP_TCP;
string interleaved = FindField( FindField((strTransport + ";").data(), "interleaved=", ";").data(), NULL, "-"); string interleaved = FindField(FindField((transport + ";").data(), "interleaved=", ";").data(), NULL, "-");
_aTrackInfo[uiTrackIndex]->_interleaved = atoi(interleaved.data()); _track_vec[track_idx]->_interleaved = atoi(interleaved.data());
}else if(strTransport.find("multicast") != string::npos){ } else if (transport.find("multicast") != string::npos) {
throw std::runtime_error("SETUP rtsp pusher can not support multicast!"); throw std::runtime_error("SETUP rtsp pusher can not support multicast!");
}else{ } else {
_eType = Rtsp::RTP_UDP; _rtp_type = Rtsp::RTP_UDP;
createUdpSockIfNecessary(uiTrackIndex); createUdpSockIfNecessary(track_idx);
const char *strPos = "server_port=" ; const char *strPos = "server_port=";
auto port_str = FindField((strTransport + ";").data(), strPos, ";"); auto port_str = FindField((transport + ";").data(), strPos, ";");
uint16_t port = atoi(FindField(port_str.data(), NULL, "-").data()); uint16_t port = atoi(FindField(port_str.data(), NULL, "-").data());
struct sockaddr_in rtpto; struct sockaddr_in rtpto;
rtpto.sin_port = ntohs(port); rtpto.sin_port = ntohs(port);
rtpto.sin_family = AF_INET; rtpto.sin_family = AF_INET;
rtpto.sin_addr.s_addr = inet_addr(get_peer_ip().data()); rtpto.sin_addr.s_addr = inet_addr(get_peer_ip().data());
_apUdpSock[uiTrackIndex]->setSendPeerAddr((struct sockaddr *)&(rtpto)); _udp_socks[track_idx]->setSendPeerAddr((struct sockaddr *) &(rtpto));
} }
RtspSplitter::enableRecvRtp(_eType == Rtsp::RTP_TCP); RtspSplitter::enableRecvRtp(_rtp_type == Rtsp::RTP_TCP);
if (uiTrackIndex < _aTrackInfo.size() - 1) { if (track_idx < _track_vec.size() - 1) {
//需要继续发送SETUP命令 //需要继续发送SETUP命令
sendSetup(uiTrackIndex + 1); sendSetup(track_idx + 1);
return; return;
} }
@ -297,13 +303,12 @@ void RtspPusher::handleResSetup(const Parser &parser, unsigned int uiTrackIndex)
} }
void RtspPusher::sendOptions() { void RtspPusher::sendOptions() {
_onHandshake = [this](const Parser& parser){}; _on_res_func = [this](const Parser &parser) {};
sendRtspRequest("OPTIONS",_strContentBase); sendRtspRequest("OPTIONS", _content_base);
} }
inline void RtspPusher::sendRtpPacket(const RtspMediaSource::RingDataType &pkt) { inline void RtspPusher::sendRtpPacket(const RtspMediaSource::RingDataType &pkt) {
//InfoL<<(int)pkt.Interleaved; switch (_rtp_type) {
switch (_eType) {
case Rtsp::RTP_TCP: { case Rtsp::RTP_TCP: {
int i = 0; int i = 0;
int size = pkt->size(); int size = pkt->size();
@ -315,85 +320,84 @@ inline void RtspPusher::sendRtpPacket(const RtspMediaSource::RingDataType &pkt)
BufferRtp::Ptr buffer(new BufferRtp(rtp)); BufferRtp::Ptr buffer(new BufferRtp(rtp));
send(buffer); send(buffer);
}); });
}
break; break;
}
case Rtsp::RTP_UDP: { case Rtsp::RTP_UDP: {
int i = 0; int i = 0;
int size = pkt->size(); int size = pkt->size();
pkt->for_each([&](const RtpPacket::Ptr &rtp) { pkt->for_each([&](const RtpPacket::Ptr &rtp) {
int iTrackIndex = getTrackIndexByTrackType(rtp->type); int iTrackIndex = getTrackIndexByTrackType(rtp->type);
auto &pSock = _apUdpSock[iTrackIndex]; auto &pSock = _udp_socks[iTrackIndex];
if (!pSock) { if (!pSock) {
shutdown(SockException(Err_shutdown,"udp sock not opened yet")); shutdown(SockException(Err_shutdown, "udp sock not opened yet"));
return; return;
} }
BufferRtp::Ptr buffer(new BufferRtp(rtp,4)); BufferRtp::Ptr buffer(new BufferRtp(rtp, 4));
pSock->send(buffer, nullptr, 0, ++i == size); pSock->send(buffer, nullptr, 0, ++i == size);
}); });
break;
} }
break; default : break;
default:
break;
} }
} }
inline int RtspPusher::getTrackIndexByTrackType(TrackType type) { inline int RtspPusher::getTrackIndexByTrackType(TrackType type) {
for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { for (unsigned int i = 0; i < _track_vec.size(); i++) {
if (type == _aTrackInfo[i]->_type) { if (type == _track_vec[i]->_type) {
return i; return i;
} }
} }
if(_aTrackInfo.size() == 1){ if (_track_vec.size() == 1) {
return 0; return 0;
} }
throw SockException(Err_shutdown, StrPrinter << "no such track with type:" << (int) type); throw SockException(Err_shutdown, StrPrinter << "no such track with type:" << (int) type);
} }
void RtspPusher::sendRecord() { void RtspPusher::sendRecord() {
_onHandshake = [this](const Parser& parser){ _on_res_func = [this](const Parser &parser) {
auto src = _pMediaSrc.lock(); auto src = _push_src.lock();
if (!src) { if (!src) {
throw std::runtime_error("the media source was released"); throw std::runtime_error("the media source was released");
} }
_pRtspReader = src->getRing()->attach(getPoller()); _rtsp_reader = src->getRing()->attach(getPoller());
weak_ptr<RtspPusher> weakSelf = dynamic_pointer_cast<RtspPusher>(shared_from_this()); weak_ptr<RtspPusher> weak_self = dynamic_pointer_cast<RtspPusher>(shared_from_this());
_pRtspReader->setReadCB([weakSelf](const RtspMediaSource::RingDataType &pkt){ _rtsp_reader->setReadCB([weak_self](const RtspMediaSource::RingDataType &pkt) {
auto strongSelf = weakSelf.lock(); auto strong_self = weak_self.lock();
if(!strongSelf) { if (!strong_self) {
return; return;
} }
strongSelf->sendRtpPacket(pkt); strong_self->sendRtpPacket(pkt);
}); });
_pRtspReader->setDetachCB([weakSelf](){ _rtsp_reader->setDetachCB([weak_self]() {
auto strongSelf = weakSelf.lock(); auto strong_self = weak_self.lock();
if(strongSelf){ if (strong_self) {
strongSelf->onPublishResult(SockException(Err_other,"媒体源被释放"), !strongSelf->_pPublishTimer); strong_self->onPublishResult(SockException(Err_other, "媒体源被释放"), !strong_self->_publish_timer);
} }
}); });
if(_eType != Rtsp::RTP_TCP){ if (_rtp_type != Rtsp::RTP_TCP) {
/////////////////////////心跳///////////////////////////////// /////////////////////////心跳/////////////////////////////////
weak_ptr<RtspPusher> weakSelf = dynamic_pointer_cast<RtspPusher>(shared_from_this()); _beat_timer.reset(new Timer((*this)[kBeatIntervalMS].as<int>() / 1000.0, [weak_self]() {
_pBeatTimer.reset(new Timer((*this)[kBeatIntervalMS].as<int>() / 1000.0, [weakSelf](){ auto strong_self = weak_self.lock();
auto strongSelf = weakSelf.lock(); if (!strong_self) {
if (!strongSelf){
return false; return false;
} }
strongSelf->sendOptions(); strong_self->sendOptions();
return true; return true;
},getPoller())); }, getPoller()));
} }
onPublishResult(SockException(Err_success,"success"), false); onPublishResult(SockException(Err_success, "success"), false);
//提升发送性能 //提升发送性能
setSocketFlags(); setSocketFlags();
}; };
sendRtspRequest("RECORD",_strContentBase,{"Range","npt=0.000-"}); sendRtspRequest("RECORD", _content_base, {"Range", "npt=0.000-"});
} }
void RtspPusher::setSocketFlags(){ void RtspPusher::setSocketFlags(){
GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS); GET_CONFIG(int, merge_write_ms, General::kMergeWriteMS);
if(mergeWriteMS > 0) { if (merge_write_ms > 0) {
//提高发送性能 //提高发送性能
setSendFlags(SOCKET_DEFAULE_FLAGS | FLAG_MORE); setSendFlags(SOCKET_DEFAULE_FLAGS | FLAG_MORE);
SockUtil::setNoDelay(_sock->rawFD(), false); SockUtil::setNoDelay(_sock->rawFD(), false);
@ -404,26 +408,26 @@ void RtspPusher::sendRtspRequest(const string &cmd, const string &url, const std
string key; string key;
StrCaseMap header_map; StrCaseMap header_map;
int i = 0; int i = 0;
for(auto &val : header){ for (auto &val : header) {
if(++i % 2 == 0){ if (++i % 2 == 0) {
header_map.emplace(key,val); header_map.emplace(key, val);
}else{ } else {
key = val; key = val;
} }
} }
sendRtspRequest(cmd,url,header_map,sdp); sendRtspRequest(cmd, url, header_map, sdp);
} }
void RtspPusher::sendRtspRequest(const string &cmd, const string &url,const StrCaseMap &header_const,const string &sdp ) { void RtspPusher::sendRtspRequest(const string &cmd, const string &url,const StrCaseMap &header_const,const string &sdp ) {
auto header = header_const; auto header = header_const;
header.emplace("CSeq",StrPrinter << _uiCseq++); header.emplace("CSeq", StrPrinter << _cseq++);
header.emplace("User-Agent",SERVER_NAME); header.emplace("User-Agent", SERVER_NAME);
if(!_strSession.empty()){ if (!_session_id.empty()) {
header.emplace("Session",_strSession); header.emplace("Session", _session_id);
} }
if(!_rtspRealm.empty() && !(*this)[kRtspUser].empty()){ if (!_realm.empty() && !(*this)[kRtspUser].empty()) {
if(!_rtspMd5Nonce.empty()){ if (!_nonce.empty()) {
//MD5认证 //MD5认证
/* /*
response计算方法如下 response计算方法如下
@ -434,41 +438,41 @@ void RtspPusher::sendRtspRequest(const string &cmd, const string &url,const StrC
response= md5( md5(username:realm:password):nonce:md5(public_method:url) ); response= md5( md5(username:realm:password):nonce:md5(public_method:url) );
*/ */
string encrypted_pwd = (*this)[kRtspPwd]; string encrypted_pwd = (*this)[kRtspPwd];
if(!(*this)[kRtspPwdIsMD5].as<bool>()){ if (!(*this)[kRtspPwdIsMD5].as<bool>()) {
encrypted_pwd = MD5((*this)[kRtspUser]+ ":" + _rtspRealm + ":" + encrypted_pwd).hexdigest(); encrypted_pwd = MD5((*this)[kRtspUser] + ":" + _realm + ":" + encrypted_pwd).hexdigest();
} }
auto response = MD5( encrypted_pwd + ":" + _rtspMd5Nonce + ":" + MD5(cmd + ":" + url).hexdigest()).hexdigest(); auto response = MD5(encrypted_pwd + ":" + _nonce + ":" + MD5(cmd + ":" + url).hexdigest()).hexdigest();
_StrPrinter printer; _StrPrinter printer;
printer << "Digest "; printer << "Digest ";
printer << "username=\"" << (*this)[kRtspUser] << "\", "; printer << "username=\"" << (*this)[kRtspUser] << "\", ";
printer << "realm=\"" << _rtspRealm << "\", "; printer << "realm=\"" << _realm << "\", ";
printer << "nonce=\"" << _rtspMd5Nonce << "\", "; printer << "nonce=\"" << _nonce << "\", ";
printer << "uri=\"" << url << "\", "; printer << "uri=\"" << url << "\", ";
printer << "response=\"" << response << "\""; printer << "response=\"" << response << "\"";
header.emplace("Authorization",printer); header.emplace("Authorization", printer);
}else if(!(*this)[kRtspPwdIsMD5].as<bool>()){ } else if (!(*this)[kRtspPwdIsMD5].as<bool>()) {
//base64认证 //base64认证
string authStr = StrPrinter << (*this)[kRtspUser] << ":" << (*this)[kRtspPwd]; string authStr = StrPrinter << (*this)[kRtspUser] << ":" << (*this)[kRtspPwd];
char authStrBase64[1024] = {0}; char authStrBase64[1024] = {0};
av_base64_encode(authStrBase64,sizeof(authStrBase64),(uint8_t *)authStr.data(),authStr.size()); av_base64_encode(authStrBase64, sizeof(authStrBase64), (uint8_t *) authStr.data(), authStr.size());
header.emplace("Authorization",StrPrinter << "Basic " << authStrBase64 ); header.emplace("Authorization", StrPrinter << "Basic " << authStrBase64);
} }
} }
if(!sdp.empty()){ if (!sdp.empty()) {
header.emplace("Content-Length",StrPrinter << sdp.size()); header.emplace("Content-Length", StrPrinter << sdp.size());
header.emplace("Content-Type","application/sdp"); header.emplace("Content-Type", "application/sdp");
} }
_StrPrinter printer; _StrPrinter printer;
printer << cmd << " " << url << " RTSP/1.0\r\n"; printer << cmd << " " << url << " RTSP/1.0\r\n";
for (auto &pr : header){ for (auto &pr : header) {
printer << pr.first << ": " << pr.second << "\r\n"; printer << pr.first << ": " << pr.second << "\r\n";
} }
printer << "\r\n"; printer << "\r\n";
if(!sdp.empty()){ if (!sdp.empty()) {
printer << sdp; printer << sdp;
} }
SockSender::send(printer); SockSender::send(printer);

View File

@ -31,39 +31,39 @@ class RtspPusher : public TcpClient, public RtspSplitter, public PusherBase {
public: public:
typedef std::shared_ptr<RtspPusher> Ptr; typedef std::shared_ptr<RtspPusher> Ptr;
RtspPusher(const EventPoller::Ptr &poller,const RtspMediaSource::Ptr &src); RtspPusher(const EventPoller::Ptr &poller,const RtspMediaSource::Ptr &src);
virtual ~RtspPusher(); ~RtspPusher() override;
void publish(const string &url) override;
void publish(const string &strUrl) override;
void teardown() override; void teardown() override;
void setOnPublished(const Event &cb) override { void setOnPublished(const Event &cb) override {
_onPublished = cb; _on_published = cb;
} }
void setOnShutdown(const Event & cb) override{ void setOnShutdown(const Event & cb) override{
_onShutdown = cb; _on_shutdown = cb;
} }
protected: protected:
//for Tcpclient override //for Tcpclient override
void onRecv(const Buffer::Ptr &pBuf) override; void onRecv(const Buffer::Ptr &buf) override;
void onConnect(const SockException &err) override; void onConnect(const SockException &err) override;
void onErr(const SockException &ex) override; void onErr(const SockException &ex) override;
//RtspSplitter override //RtspSplitter override
void onWholeRtspPacket(Parser &parser) override ; void onWholeRtspPacket(Parser &parser) override ;
void onRtpPacket(const char *data,uint64_t len) override {}; void onRtpPacket(const char *data,uint64_t len) override {};
private: private:
void onPublishResult(const SockException &ex, bool handshakeCompleted); void onPublishResult(const SockException &ex, bool handshake_done);
void sendAnnounce(); void sendAnnounce();
void sendSetup(unsigned int uiTrackIndex); void sendSetup(unsigned int track_idx);
void sendRecord(); void sendRecord();
void sendOptions(); void sendOptions();
void handleResAnnounce(const Parser &parser); void handleResAnnounce(const Parser &parser);
void handleResSetup(const Parser &parser, unsigned int uiTrackIndex); void handleResSetup(const Parser &parser, unsigned int track_idx);
bool handleAuthenticationFailure(const string &paramsStr); bool handleAuthenticationFailure(const string &params_str);
inline int getTrackIndexByTrackType(TrackType type); inline int getTrackIndexByTrackType(TrackType type);
@ -73,33 +73,30 @@ private:
void createUdpSockIfNecessary(int track_idx); void createUdpSockIfNecessary(int track_idx);
void setSocketFlags(); void setSocketFlags();
private: private:
unsigned int _cseq = 1;
Rtsp::eRtpType _rtp_type = Rtsp::RTP_TCP;
//rtsp鉴权相关 //rtsp鉴权相关
string _rtspMd5Nonce; string _nonce;
string _rtspRealm; string _realm;
string _url;
string _session_id;
string _content_base;
SdpParser _sdp_parser;
vector<SdpTrack::Ptr> _track_vec;
Socket::Ptr _udp_socks[2];
//超时功能实现 //超时功能实现
std::shared_ptr<Timer> _pPublishTimer; std::shared_ptr<Timer> _publish_timer;
//源
std::weak_ptr<RtspMediaSource> _pMediaSrc;
RtspMediaSource::RingType::RingReader::Ptr _pRtspReader;
//事件监听
Event _onShutdown;
Event _onPublished;
string _strUrl;
SdpParser _sdpParser;
vector<SdpTrack::Ptr> _aTrackInfo;
string _strSession;
unsigned int _uiCseq = 1;
string _strContentBase;
Rtsp::eRtpType _eType = Rtsp::RTP_TCP;
Socket::Ptr _apUdpSock[2];
function<void(const Parser&)> _onHandshake;
//心跳定时器 //心跳定时器
std::shared_ptr<Timer> _pBeatTimer; std::shared_ptr<Timer> _beat_timer;
std::weak_ptr<RtspMediaSource> _push_src;
RtspMediaSource::RingType::RingReader::Ptr _rtsp_reader;
//事件监听
Event _on_shutdown;
Event _on_published;
function<void(const Parser&)> _on_res_func;
}; };
} /* namespace mediakit */ } /* namespace mediakit */