mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-26 04:31:37 +08:00
rtc推流和播放添加事件触发
This commit is contained in:
parent
49d8e2f825
commit
fe02f2cf1c
@ -1082,19 +1082,87 @@ void installWebApi() {
|
|||||||
|
|
||||||
#ifdef ENABLE_WEBRTC
|
#ifdef ENABLE_WEBRTC
|
||||||
static list<WebRtcTransportImp::Ptr> rtcs;
|
static list<WebRtcTransportImp::Ptr> rtcs;
|
||||||
api_regist("/index/api/webrtc",[](API_ARGS_STRING){
|
api_regist("/index/api/webrtc",[](API_ARGS_STRING_ASYNC){
|
||||||
CHECK_ARGS("app", "stream");
|
CHECK_ARGS("app", "stream");
|
||||||
auto src = dynamic_pointer_cast<RtspMediaSource>(MediaSource::find(RTSP_SCHEMA, DEFAULT_VHOST, allArgs.getUrlArgs()["app"], allArgs.getUrlArgs()["stream"]));
|
|
||||||
if (!src) {
|
auto offer_sdp = allArgs.Content();
|
||||||
throw ApiRetException("流不存在", API::NotFound);
|
auto type = allArgs.getUrlArgs()["type"];
|
||||||
}
|
MediaInfo info(StrPrinter << "rtc://" << headerIn["Host"] << "/" << allArgs.getUrlArgs()["app"] << "/" << allArgs.getUrlArgs()["stream"] << "?" << allArgs.Params());
|
||||||
headerOut["Content-Type"] = "text/plain";
|
|
||||||
|
//设置返回类型
|
||||||
|
headerOut["Content-Type"] = HttpFileManager::getContentType(".json");
|
||||||
|
//设置跨域
|
||||||
headerOut["Access-Control-Allow-Origin"] = "*";
|
headerOut["Access-Control-Allow-Origin"] = "*";
|
||||||
|
|
||||||
|
if (type.empty() || !strcasecmp(type.data(), "play")) {
|
||||||
|
Broadcast::AuthInvoker authInvoker = [invoker, offer_sdp, val, info, headerOut](const string &err) mutable {
|
||||||
|
try {
|
||||||
|
auto src = dynamic_pointer_cast<RtspMediaSource>(MediaSource::find(RTSP_SCHEMA, info._vhost, info._app, info._streamid));
|
||||||
|
if (!src) {
|
||||||
|
throw runtime_error("流不存在");
|
||||||
|
}
|
||||||
|
if (!err.empty()) {
|
||||||
|
throw runtime_error(StrPrinter << "播放鉴权失败:" << err);
|
||||||
|
}
|
||||||
auto rtc = WebRtcTransportImp::create(EventPollerPool::Instance().getPoller());
|
auto rtc = WebRtcTransportImp::create(EventPollerPool::Instance().getPoller());
|
||||||
rtc->attach(src);
|
rtc->attach(src);
|
||||||
val["sdp"] = rtc->getAnswerSdp(allArgs.Content());
|
val["sdp"] = rtc->getAnswerSdp(offer_sdp);
|
||||||
val["type"] = "answer";
|
val["type"] = "answer";
|
||||||
rtcs.emplace_back(rtc);
|
rtcs.emplace_back(rtc);
|
||||||
|
invoker(200, headerOut, val.toStyledString());
|
||||||
|
} catch (std::exception &ex) {
|
||||||
|
val["code"] = API::Exception;
|
||||||
|
val["msg"] = ex.what();
|
||||||
|
invoker(200, headerOut, val.toStyledString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//广播通用播放url鉴权事件
|
||||||
|
auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed, info, authInvoker, sender);
|
||||||
|
if (!flag) {
|
||||||
|
//该事件无人监听,默认不鉴权
|
||||||
|
authInvoker("");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcasecmp(type.data(), "push")) {
|
||||||
|
Broadcast::PublishAuthInvoker authInvoker = [invoker, offer_sdp, val, info, headerOut](const string &err, bool enableHls, bool enableMP4) mutable {
|
||||||
|
try {
|
||||||
|
auto src = dynamic_pointer_cast<RtspMediaSource>(MediaSource::find(RTSP_SCHEMA, info._vhost, info._app, info._streamid));
|
||||||
|
if (src) {
|
||||||
|
throw std::runtime_error("已经在推流");
|
||||||
|
}
|
||||||
|
if (!err.empty()) {
|
||||||
|
throw runtime_error(StrPrinter << "推流鉴权失败:" << err);
|
||||||
|
}
|
||||||
|
auto push_src = std::make_shared<RtspMediaSourceImp>(info._vhost, info._app, info._streamid);
|
||||||
|
push_src->setProtocolTranslation(enableHls, enableMP4);
|
||||||
|
auto rtc = WebRtcTransportImp::create(EventPollerPool::Instance().getPoller());
|
||||||
|
rtc->attach(push_src);
|
||||||
|
val["sdp"] = rtc->getAnswerSdp(offer_sdp);
|
||||||
|
val["type"] = "answer";
|
||||||
|
rtcs.emplace_back(rtc);
|
||||||
|
invoker(200, headerOut, val.toStyledString());
|
||||||
|
} catch (std::exception &ex) {
|
||||||
|
val["code"] = API::Exception;
|
||||||
|
val["msg"] = ex.what();
|
||||||
|
invoker(200, headerOut, val.toStyledString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//rtsp推流需要鉴权
|
||||||
|
auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPublish, info, authInvoker, sender);
|
||||||
|
if (!flag) {
|
||||||
|
//该事件无人监听,默认不鉴权
|
||||||
|
GET_CONFIG(bool, toHls, General::kPublishToHls);
|
||||||
|
GET_CONFIG(bool, toMP4, General::kPublishToMP4);
|
||||||
|
authInvoker("", toHls, toMP4);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw ApiRetException("不支持该类型", API::InvalidArgs);
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -6,10 +6,10 @@
|
|||||||
#define RTP_CNAME "zlmediakit-rtp"
|
#define RTP_CNAME "zlmediakit-rtp"
|
||||||
#define RTX_CNAME "zlmediakit-rtx"
|
#define RTX_CNAME "zlmediakit-rtx"
|
||||||
|
|
||||||
|
|
||||||
WebRtcTransport::WebRtcTransport(const EventPoller::Ptr &poller) {
|
WebRtcTransport::WebRtcTransport(const EventPoller::Ptr &poller) {
|
||||||
|
_poller = poller;
|
||||||
_dtls_transport = std::make_shared<RTC::DtlsTransport>(poller, this);
|
_dtls_transport = std::make_shared<RTC::DtlsTransport>(poller, this);
|
||||||
_ice_server = std::make_shared<RTC::IceServer>(this, makeRandStr(4), makeRandStr(24));
|
_ice_server = std::make_shared<RTC::IceServer>(this, makeRandStr(4), makeRandStr(28).substr(4));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebRtcTransport::onDestory(){
|
void WebRtcTransport::onDestory(){
|
||||||
@ -17,6 +17,10 @@ void WebRtcTransport::onDestory(){
|
|||||||
_ice_server = nullptr;
|
_ice_server = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const EventPoller::Ptr& WebRtcTransport::getPoller() const{
|
||||||
|
return _poller;
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void WebRtcTransport::OnIceServerSendStunPacket(const RTC::IceServer *iceServer, const RTC::StunPacket *packet, RTC::TransportTuple *tuple) {
|
void WebRtcTransport::OnIceServerSendStunPacket(const RTC::IceServer *iceServer, const RTC::StunPacket *packet, RTC::TransportTuple *tuple) {
|
||||||
@ -127,10 +131,7 @@ std::string WebRtcTransport::getAnswerSdp(const string &offer){
|
|||||||
//// 生成answer sdp ////
|
//// 生成answer sdp ////
|
||||||
_answer_sdp = configure.createAnswer(*_offer_sdp);
|
_answer_sdp = configure.createAnswer(*_offer_sdp);
|
||||||
onCheckSdp(SdpType::answer, *_answer_sdp);
|
onCheckSdp(SdpType::answer, *_answer_sdp);
|
||||||
|
return _answer_sdp->toString();
|
||||||
auto str = _answer_sdp->toString();
|
|
||||||
TraceL << "\r\n" << str;
|
|
||||||
return str;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_dtls(char *buf) {
|
bool is_dtls(char *buf) {
|
||||||
@ -247,11 +248,6 @@ bool WebRtcTransportImp::canRecvRtp() const{
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebRtcTransportImp::onStartWebRTC() {
|
void WebRtcTransportImp::onStartWebRTC() {
|
||||||
if (canRecvRtp()) {
|
|
||||||
_push_src = std::make_shared<RtspMediaSourceImp>(DEFAULT_VHOST, "live", "push");
|
|
||||||
auto rtsp_sdp = getSdp(SdpType::answer).toRtspSdp();
|
|
||||||
_push_src->setSdp(rtsp_sdp);
|
|
||||||
|
|
||||||
for (auto &m : getSdp(SdpType::offer).media) {
|
for (auto &m : getSdp(SdpType::offer).media) {
|
||||||
if (m.type == TrackVideo) {
|
if (m.type == TrackVideo) {
|
||||||
_recv_video_ssrc = m.rtp_ssrc.ssrc;
|
_recv_video_ssrc = m.rtp_ssrc.ssrc;
|
||||||
@ -262,8 +258,8 @@ void WebRtcTransportImp::onStartWebRTC() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
//获取offer端rtp的ssrc和pt相关信息
|
//获取offer端rtp的ssrc和pt相关信息
|
||||||
auto &ref = _rtp_receiver[plan.pt];
|
auto &ref = _rtp_info_pt[plan.pt];
|
||||||
_ssrc_info[m.rtp_ssrc.ssrc] = &ref;
|
_rtp_info_ssrc[m.rtp_ssrc.ssrc] = &ref;
|
||||||
ref.plan = &plan;
|
ref.plan = &plan;
|
||||||
ref.media = &m;
|
ref.media = &m;
|
||||||
ref.is_common_rtp = getCodecId(plan.codec) != CodecInvalid;
|
ref.is_common_rtp = getCodecId(plan.codec) != CodecInvalid;
|
||||||
@ -276,6 +272,9 @@ void WebRtcTransportImp::onStartWebRTC() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (canRecvRtp()) {
|
||||||
|
_src->setSdp(getSdp(SdpType::answer).toRtspSdp());
|
||||||
}
|
}
|
||||||
if (canSendRtp()) {
|
if (canSendRtp()) {
|
||||||
_reader = _src->getRing()->attach(_socket->getPoller(), true);
|
_reader = _src->getRing()->attach(_socket->getPoller(), true);
|
||||||
@ -320,8 +319,12 @@ void WebRtcTransportImp::onCheckSdp(SdpType type, RtcSession &sdp) const{
|
|||||||
|
|
||||||
void WebRtcTransportImp::onRtcConfigure(RtcConfigure &configure) const {
|
void WebRtcTransportImp::onRtcConfigure(RtcConfigure &configure) const {
|
||||||
WebRtcTransport::onRtcConfigure(configure);
|
WebRtcTransport::onRtcConfigure(configure);
|
||||||
_rtsp_send_sdp.loadFrom(_src->getSdp(), false);
|
|
||||||
|
|
||||||
|
if (!_src->getSdp().empty()) {
|
||||||
|
//这是播放
|
||||||
|
configure.video.direction = RtpDirection::sendonly;
|
||||||
|
configure.audio.direction = RtpDirection::sendonly;
|
||||||
|
_rtsp_send_sdp.loadFrom(_src->getSdp(), false);
|
||||||
//根据rtsp流的相关信息,设置rtc最佳编码
|
//根据rtsp流的相关信息,设置rtc最佳编码
|
||||||
for (auto &m : _rtsp_send_sdp.media) {
|
for (auto &m : _rtsp_send_sdp.media) {
|
||||||
switch (m.type) {
|
switch (m.type) {
|
||||||
@ -337,6 +340,11 @@ void WebRtcTransportImp::onRtcConfigure(RtcConfigure &configure) const {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
//这是推流
|
||||||
|
configure.video.direction = RtpDirection::recvonly;
|
||||||
|
configure.audio.direction = RtpDirection::recvonly;
|
||||||
|
}
|
||||||
|
|
||||||
//添加接收端口candidate信息
|
//添加接收端口candidate信息
|
||||||
configure.addCandidate(*getIceCandidate());
|
configure.addCandidate(*getIceCandidate());
|
||||||
@ -395,8 +403,8 @@ void WebRtcTransportImp::onRtcp(const char *buf, size_t len) {
|
|||||||
case RtcpType::RTCP_SR : {
|
case RtcpType::RTCP_SR : {
|
||||||
//对方汇报rtp发送情况
|
//对方汇报rtp发送情况
|
||||||
RtcpSR *sr = (RtcpSR *) rtcp;
|
RtcpSR *sr = (RtcpSR *) rtcp;
|
||||||
auto it = _ssrc_info.find(sr->ssrc);
|
auto it = _rtp_info_ssrc.find(sr->ssrc);
|
||||||
if (it != _ssrc_info.end()) {
|
if (it != _rtp_info_ssrc.end()) {
|
||||||
it->second->rtcp_context_recv->onRtcp(sr);
|
it->second->rtcp_context_recv->onRtcp(sr);
|
||||||
auto rr = it->second->rtcp_context_recv->createRtcpRR(sr->items.ssrc, sr->ssrc);
|
auto rr = it->second->rtcp_context_recv->createRtcpRR(sr->items.ssrc, sr->ssrc);
|
||||||
sendRtcpPacket(rr->data(), rr->size(), true);
|
sendRtcpPacket(rr->data(), rr->size(), true);
|
||||||
@ -407,8 +415,8 @@ void WebRtcTransportImp::onRtcp(const char *buf, size_t len) {
|
|||||||
case RtcpType::RTCP_RR : {
|
case RtcpType::RTCP_RR : {
|
||||||
//对方汇报rtp接收情况
|
//对方汇报rtp接收情况
|
||||||
RtcpRR *rr = (RtcpRR *) rtcp;
|
RtcpRR *rr = (RtcpRR *) rtcp;
|
||||||
auto it = _ssrc_info.find(rr->ssrc);
|
auto it = _rtp_info_ssrc.find(rr->ssrc);
|
||||||
if (it != _ssrc_info.end()) {
|
if (it != _rtp_info_ssrc.end()) {
|
||||||
auto sr = it->second->rtcp_context_send->createRtcpSR(rr->items.ssrc);
|
auto sr = it->second->rtcp_context_send->createRtcpSR(rr->items.ssrc);
|
||||||
sendRtcpPacket(sr->data(), sr->size(), true);
|
sendRtcpPacket(sr->data(), sr->size(), true);
|
||||||
InfoL << "send rtcp sr";
|
InfoL << "send rtcp sr";
|
||||||
@ -431,8 +439,8 @@ void WebRtcTransportImp::onRtcp(const char *buf, size_t len) {
|
|||||||
void WebRtcTransportImp::onRtp(const char *buf, size_t len) {
|
void WebRtcTransportImp::onRtp(const char *buf, size_t len) {
|
||||||
RtpHeader *rtp = (RtpHeader *) buf;
|
RtpHeader *rtp = (RtpHeader *) buf;
|
||||||
//根据接收到的rtp的pt信息,找到该流的信息
|
//根据接收到的rtp的pt信息,找到该流的信息
|
||||||
auto it = _rtp_receiver.find(rtp->pt);
|
auto it = _rtp_info_pt.find(rtp->pt);
|
||||||
if (it == _rtp_receiver.end()) {
|
if (it == _rtp_info_pt.end()) {
|
||||||
WarnL;
|
WarnL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -458,7 +466,7 @@ void WebRtcTransportImp::onSortedRtp(const RtpPayloadInfo &info, RtpPacket::Ptr
|
|||||||
sendRtcpPacket((char *) pli.get(), sizeof(RtcpPli), true);
|
sendRtcpPacket((char *) pli.get(), sizeof(RtcpPli), true);
|
||||||
InfoL << "send pli";
|
InfoL << "send pli";
|
||||||
}
|
}
|
||||||
_push_src->onWrite(std::move(rtp), false);
|
_src->onWrite(std::move(rtp), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebRtcTransportImp::onBeforeSortedRtp(const RtpPayloadInfo &info, const RtpPacket::Ptr &rtp) {
|
void WebRtcTransportImp::onBeforeSortedRtp(const RtpPayloadInfo &info, const RtpPacket::Ptr &rtp) {
|
||||||
@ -474,5 +482,5 @@ void WebRtcTransportImp::onSendRtp(const RtpPacket::Ptr &rtp, bool flush){
|
|||||||
}
|
}
|
||||||
sendRtpPacket(rtp->data() + RtpPacket::kRtpTcpHeaderSize, rtp->size() - RtpPacket::kRtpTcpHeaderSize, flush, pt);
|
sendRtpPacket(rtp->data() + RtpPacket::kRtpTcpHeaderSize, rtp->size() - RtpPacket::kRtpTcpHeaderSize, flush, pt);
|
||||||
//统计rtp发送情况,好做sr汇报
|
//统计rtp发送情况,好做sr汇报
|
||||||
_rtp_receiver[pt].rtcp_context_send->onRtp(rtp->getSeq(), rtp->getStampMS(), rtp->size() - RtpPacket::kRtpTcpHeaderSize);
|
_rtp_info_pt[pt].rtcp_context_send->onRtp(rtp->getSeq(), rtp->getStampMS(), rtp->size() - RtpPacket::kRtpTcpHeaderSize);
|
||||||
}
|
}
|
||||||
|
@ -44,10 +44,14 @@ public:
|
|||||||
* 发送rtp
|
* 发送rtp
|
||||||
* @param buf rtcp内容
|
* @param buf rtcp内容
|
||||||
* @param len rtcp长度
|
* @param len rtcp长度
|
||||||
|
* @param flush 是否flush socket
|
||||||
|
* @param pt rtp payload type
|
||||||
*/
|
*/
|
||||||
void sendRtpPacket(char *buf, size_t len, bool flush, uint8_t pt);
|
void sendRtpPacket(char *buf, size_t len, bool flush, uint8_t pt);
|
||||||
void sendRtcpPacket(char *buf, size_t len, bool flush);
|
void sendRtcpPacket(char *buf, size_t len, bool flush);
|
||||||
|
|
||||||
|
const EventPoller::Ptr& getPoller() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//// dtls相关的回调 ////
|
//// dtls相关的回调 ////
|
||||||
void OnDtlsTransportConnecting(const RTC::DtlsTransport *dtlsTransport) override {};
|
void OnDtlsTransportConnecting(const RTC::DtlsTransport *dtlsTransport) override {};
|
||||||
@ -89,6 +93,7 @@ private:
|
|||||||
void setRemoteDtlsFingerprint(const RtcSession &remote);
|
void setRemoteDtlsFingerprint(const RtcSession &remote);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
EventPoller::Ptr _poller;
|
||||||
std::shared_ptr<RTC::IceServer> _ice_server;
|
std::shared_ptr<RTC::IceServer> _ice_server;
|
||||||
std::shared_ptr<RTC::DtlsTransport> _dtls_transport;
|
std::shared_ptr<RTC::DtlsTransport> _dtls_transport;
|
||||||
std::shared_ptr<RTC::SrtpSession> _srtp_session_send;
|
std::shared_ptr<RTC::SrtpSession> _srtp_session_send;
|
||||||
@ -148,17 +153,16 @@ private:
|
|||||||
void onBeforeSortedRtp(const RtpPayloadInfo &info,const RtpPacket::Ptr &rtp);
|
void onBeforeSortedRtp(const RtpPayloadInfo &info,const RtpPacket::Ptr &rtp);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Socket::Ptr _socket;
|
|
||||||
RtspMediaSource::Ptr _src;
|
|
||||||
RtspMediaSource::RingType::RingReader::Ptr _reader;
|
|
||||||
RtcSession _answer_sdp;
|
|
||||||
mutable RtcSession _rtsp_send_sdp;
|
|
||||||
mutable uint8_t _send_rtp_pt[2] = {0, 0};
|
|
||||||
RtspMediaSourceImp::Ptr _push_src;
|
|
||||||
unordered_map<uint8_t, RtpPayloadInfo> _rtp_receiver;
|
|
||||||
unordered_map<uint32_t, RtpPayloadInfo*> _ssrc_info;
|
|
||||||
uint32_t _recv_video_ssrc;
|
uint32_t _recv_video_ssrc;
|
||||||
|
mutable uint8_t _send_rtp_pt[2] = {0, 0};
|
||||||
Ticker _pli_ticker;
|
Ticker _pli_ticker;
|
||||||
|
Socket::Ptr _socket;
|
||||||
|
RtcSession _answer_sdp;
|
||||||
|
RtspMediaSource::Ptr _src;
|
||||||
|
mutable RtcSession _rtsp_send_sdp;
|
||||||
|
RtspMediaSource::RingType::RingReader::Ptr _reader;
|
||||||
|
unordered_map<uint8_t, RtpPayloadInfo> _rtp_info_pt;
|
||||||
|
unordered_map<uint32_t, RtpPayloadInfo*> _rtp_info_ssrc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user