diff --git a/webrtc/Sdp.h b/webrtc/Sdp.h
index 3eacfe7c..8139f645 100644
--- a/webrtc/Sdp.h
+++ b/webrtc/Sdp.h
@@ -55,36 +55,36 @@ namespace mediakit {
// k=* (encryption key)
// a=* (zero or more media attribute lines)
-enum class RtpDirection {
+enum class RtpDirection : int8_t {
invalid = -1,
// 只发送 [AUTO-TRANSLATED:d7e7fdb7]
// Send only
- sendonly,
+ sendonly = 1 << 0,
// 只接收 [AUTO-TRANSLATED:f75ca789]
// Receive only
- recvonly,
+ recvonly = 1 << 1,
// 同时发送接收 [AUTO-TRANSLATED:7f900ba1]
// Send and receive simultaneously
- sendrecv,
+ sendrecv = sendonly | recvonly,
// 禁止发送数据 [AUTO-TRANSLATED:6045b47e]
// Prohibit sending data
- inactive
+ inactive = 0
};
-enum class DtlsRole {
+enum class DtlsRole : int8_t {
invalid = -1,
// 客户端 [AUTO-TRANSLATED:915417a2]
// Client
- active,
+ active = 1 << 0,
// 服务端 [AUTO-TRANSLATED:03a80b18]
// Server
- passive,
+ passive = 1 << 1,
// 既可作做客户端也可以做服务端 [AUTO-TRANSLATED:5ab1162e]
// Can be used as both client and server
- actpass,
+ actpass = active | passive,
};
-enum class SdpType { invalid = -1, offer, answer };
+enum class SdpType : int8_t { invalid = -1, offer, answer };
DtlsRole getDtlsRole(const std::string &str);
const char *getDtlsRoleString(DtlsRole role);
diff --git a/webrtc/WebRtcTalk.cpp b/webrtc/WebRtcTalk.cpp
new file mode 100644
index 00000000..1c4dc4ce
--- /dev/null
+++ b/webrtc/WebRtcTalk.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
+ *
+ * Use of this source code is governed by MIT-like 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 "WebRtcTalk.h"
+
+#include "Util/base64.h"
+#include "Common/config.h"
+#include "Extension/Factory.h"
+#include "Common/MultiMediaSourceMuxer.h"
+
+using namespace std;
+using namespace toolkit;
+
+namespace mediakit {
+
+WebRtcTalk::Ptr WebRtcTalk::create(
+ const EventPoller::Ptr &poller, const RtspMediaSource::Ptr &src, const MediaInfo &info, WebRtcTransport::Role role,
+ WebRtcTransport::SignalingProtocols signaling_protocols) {
+ WebRtcTalk::Ptr ret(new WebRtcTalk(poller, src, info), [](WebRtcTalk *ptr) {
+ ptr->onDestory();
+ delete ptr;
+ });
+ ret->setRole(role);
+ ret->setSignalingProtocols(signaling_protocols);
+ ret->onCreate();
+ return ret;
+}
+
+WebRtcTalk::WebRtcTalk(const EventPoller::Ptr &poller, const RtspMediaSource::Ptr &src, const MediaInfo &info)
+ : WebRtcTransportImp(poller) {
+ _media_info = info;
+ _play_src = src;
+ CHECK(src);
+ _demuxer = std::make_shared();
+}
+
+void WebRtcTalk::onStartWebRTC() {
+ auto playSrc = _play_src.lock();
+ if (!playSrc) {
+ onShutdown(SockException(Err_shutdown, "rtsp media source was shutdown"));
+ return;
+ }
+ WebRtcTransportImp::onStartWebRTC();
+ // 不支持simulcast
+ CHECK(!_answer_sdp->supportSimulcast());
+ auto sdp = _answer_sdp->toRtspSdp();
+ _demuxer->loadSdp(sdp);
+ auto audio_track = _demuxer->getTrack(TrackAudio, false);
+ // 必须包含音频track
+ CHECK(audio_track);
+ audio_track->addDelegate([this](const Frame::Ptr &frame) {
+ // 发送对讲语音rtp流
+ _sender->inputFrame(frame);
+ return true;
+ });
+
+ MediaSourceEvent::SendRtpArgs args;
+ args.con_type = MediaSourceEvent::SendRtpArgs::kVoiceTalk;
+ args.recv_stream_vhost = playSrc->getMediaTuple().vhost;
+ args.recv_stream_app = playSrc->getMediaTuple().app;
+ args.recv_stream_id = playSrc->getMediaTuple().stream;
+ auto url_args = Parser::parseArgs(_media_info.params);
+ args.data_type = static_cast(atoi(url_args["data_type"].data()));
+ args.only_audio = true;
+ args.pt = static_cast(atoi(url_args["pt"].data()));
+ args.ssrc = url_args["ssrc"];
+
+ std::weak_ptr weak_self = static_pointer_cast(shared_from_this());
+ _sender = std::make_shared(getPoller());
+ _sender->startSend(*(playSrc->getMuxer()), args, [weak_self](uint16_t local_port, const SockException &ex) {
+ if (!ex) {
+ return;
+ }
+ if (auto strong_self = weak_self.lock()) {
+ strong_self->onShutdown(ex);
+ }
+ });
+
+ _sender->addTrack(audio_track);
+ _sender->addTrackCompleted();
+
+ if (canSendRtp()) {
+ playSrc->pause(false);
+ _reader = playSrc->getRing()->attach(getPoller(), true);
+ weak_ptr weak_self = static_pointer_cast(shared_from_this());
+ weak_ptr weak_session = static_pointer_cast(getSession());
+ _reader->setGetInfoCB([weak_session]() {
+ Any ret;
+ ret.set(static_pointer_cast(weak_session.lock()));
+ return ret;
+ });
+ _reader->setReadCB([weak_self](const RtspMediaSource::RingDataType &pkt) {
+ auto strong_self = weak_self.lock();
+ if (!strong_self) {
+ return;
+ }
+
+ size_t i = 0;
+ pkt->for_each([&](const RtpPacket::Ptr &rtp) { strong_self->onSendRtp(rtp, ++i == pkt->size()); });
+ });
+ _reader->setDetachCB([weak_self]() {
+ auto strong_self = weak_self.lock();
+ if (!strong_self) {
+ return;
+ }
+ strong_self->onShutdown(SockException(Err_shutdown, "rtsp ring buffer detached"));
+ });
+
+ _reader->setMessageCB([weak_self](const toolkit::Any &data) {
+ auto strong_self = weak_self.lock();
+ if (!strong_self) {
+ return;
+ }
+ if (data.is()) {
+ auto &buffer = data.get();
+ // PPID 51: 文本string [AUTO-TRANSLATED:69a8cf81]
+ // PPID 51: Text string
+ // PPID 53: 二进制 [AUTO-TRANSLATED:faf00c3e]
+ // PPID 53: Binary
+ strong_self->sendDatachannel(0, 51, buffer.data(), buffer.size());
+ } else {
+ WarnL << "Send unknown message type to webrtc player: " << data.type_name();
+ }
+ });
+ }
+}
+void WebRtcTalk::onDestory() {
+ auto duration = getDuration();
+ auto bytes_usage = getBytesUsage();
+ // 流量统计事件广播 [AUTO-TRANSLATED:6b0b1234]
+ // Traffic statistics event broadcast
+ GET_CONFIG(uint32_t, iFlowThreshold, General::kFlowThreshold);
+ auto session = getSession();
+ if (_reader && session) {
+ WarnL << "RTC对讲(" << _media_info.shortUrl() << ")结束播放,耗时(s):" << duration;
+ if (bytes_usage >= iFlowThreshold * 1024) {
+ NOTICE_EMIT(BroadcastFlowReportArgs, Broadcast::kBroadcastFlowReport, _media_info, bytes_usage, duration, true, *session);
+ }
+ }
+ WebRtcTransportImp::onDestory();
+}
+
+void WebRtcTalk::onRtcConfigure(RtcConfigure &configure) const {
+ WebRtcTransportImp::onRtcConfigure(configure);
+ auto playSrc = _play_src.lock();
+ if (playSrc) {
+ configure.setPlayRtspInfo(playSrc->getSdp());
+ }
+
+ // 不接收视频
+ configure.video.direction = static_cast(static_cast(configure.video.direction) & ~static_cast(RtpDirection::recvonly));
+ // 开启音频接收
+ configure.audio.direction = static_cast(static_cast(configure.audio.direction) | static_cast(RtpDirection::recvonly));
+}
+
+void WebRtcTalk::onRecvRtp(MediaTrack &track, const std::string &rid, RtpPacket::Ptr rtp) {
+ // rtp解析为音频,视频丢弃
+ if (rtp->type == TrackAudio) {
+ _demuxer->inputRtp(rtp);
+ }
+}
+
+
+} // namespace mediakit
\ No newline at end of file
diff --git a/webrtc/WebRtcTalk.h b/webrtc/WebRtcTalk.h
new file mode 100644
index 00000000..c6a3bc05
--- /dev/null
+++ b/webrtc/WebRtcTalk.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2016-present The ZLMediaKit project authors. All Rights Reserved.
+ *
+ * This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
+ *
+ * Use of this source code is governed by MIT-like 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_WEBRTC_TALK_H
+#define ZLMEDIAKIT_WEBRTC_TALK_H
+
+#include "WebRtcTransport.h"
+#include "Rtsp/RtspMediaSource.h"
+#include "Rtsp/RtspDemuxer.h"
+#include "Rtp/RtpSender.h"
+
+namespace mediakit {
+
+class WebRtcTalk : public WebRtcTransportImp {
+public:
+ using Ptr = std::shared_ptr;
+ static Ptr create(const toolkit::EventPoller::Ptr &poller, const RtspMediaSource::Ptr &src, const MediaInfo &info,
+ WebRtcTransport::Role role, WebRtcTransport::SignalingProtocols signaling_protocols);
+
+protected:
+ ///////WebRtcTransportImp override///////
+ void onStartWebRTC() override;
+ void onDestory() override;
+ void onRtcConfigure(RtcConfigure &configure) const override;
+ void onRecvRtp(MediaTrack &track, const std::string &rid, RtpPacket::Ptr rtp) override;
+
+private:
+ WebRtcTalk(const toolkit::EventPoller::Ptr &poller, const RtspMediaSource::Ptr &src, const MediaInfo &info);
+
+private:
+ // 媒体相关元数据 [AUTO-TRANSLATED:f4cf8045]
+ // Media related metadata
+ MediaInfo _media_info;
+ // 播放的rtsp源 [AUTO-TRANSLATED:9963eed1]
+ // Playing rtsp source
+ std::weak_ptr _play_src;
+
+ // 播放rtsp源的reader对象 [AUTO-TRANSLATED:7b305055]
+ // Reader object for playing rtsp source
+ RtspMediaSource::RingType::RingReader::Ptr _reader;
+
+ // 解析对讲语音rtp流为帧数据
+ RtspDemuxer::Ptr _demuxer;
+ // 打包语音帧数据为特定rtp并回复过去
+ RtpSender::Ptr _sender;
+};
+
+}// namespace mediakit
+#endif // ZLMEDIAKIT_WEBRTC_TALK_H
diff --git a/webrtc/WebRtcTransport.cpp b/webrtc/WebRtcTransport.cpp
index 3ac2cd44..2ad0fb10 100644
--- a/webrtc/WebRtcTransport.cpp
+++ b/webrtc/WebRtcTransport.cpp
@@ -28,6 +28,7 @@
#include "WebRtcEchoTest.h"
#include "WebRtcPlayer.h"
#include "WebRtcPusher.h"
+#include "WebRtcTalk.h"
#include "Rtsp/RtspMediaSourceImp.h"
#define RTP_SSRC_OFFSET 1
@@ -1726,6 +1727,7 @@ void push_plugin(SocketHelper& sender, const WebRtcArgs &args, const onCreateWeb
}
}
+template
void play_plugin(SocketHelper &sender, const WebRtcArgs &args, const onCreateWebRtc &cb) {
MediaInfo info(args["url"]);
@@ -1748,7 +1750,7 @@ void play_plugin(SocketHelper &sender, const WebRtcArgs &args, const onCreateWeb
// 还原成rtc,目的是为了hook时识别哪种播放协议 [AUTO-TRANSLATED:fe8dd2dc]
// Restore to RTC, the purpose is to identify which playback protocol during hooking
info.schema = "rtc";
- auto rtc = WebRtcPlayer::create(EventPollerPool::Instance().getPoller(), src, info,
+ auto rtc = Type::create(EventPollerPool::Instance().getPoller(), src, info,
WebRtcTransport::Role::PEER, WebRtcTransport::SignalingProtocols::WHEP_WHIP);
cb(*rtc);
});
@@ -1831,7 +1833,9 @@ static onceToken s_rtc_auto_register([]() {
WebRtcPluginManager::Instance().registerPlugin("echo", echo_plugin);
#endif
WebRtcPluginManager::Instance().registerPlugin("push", push_plugin);
- WebRtcPluginManager::Instance().registerPlugin("play", play_plugin);
+ WebRtcPluginManager::Instance().registerPlugin("play", play_plugin);
+ WebRtcPluginManager::Instance().registerPlugin("talk", play_plugin);
+
WebRtcPluginManager::Instance().setListener([](SocketHelper& sender, const std::string &type, const WebRtcArgs &args, const WebRtcInterface &rtc) {
setWebRtcArgs(args, const_cast(rtc));
});
diff --git a/www/webrtc/index.html b/www/webrtc/index.html
index 704f4790..2e8bedc6 100644
--- a/www/webrtc/index.html
+++ b/www/webrtc/index.html
@@ -66,8 +66,9 @@
-
+
echo
+ talk
push
play