diff --git a/.gitignore b/.gitignore index 73b1ac8d..1d040fd7 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ compile_commands.json # Vim temporal files. *.swp *.swo +deps +.vscode diff --git a/CHANGELOG.md b/CHANGELOG.md index 33df93a5..34235328 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog +### NEXT + +* Update to libwebrtc M120/6099 ([#173](https://github.com/versatica/libmediasoupclient/pull/173)). Thanks @Poldraunic, @janreyho, @copiltembel. + ### 3.4.2 * Fix explicit codec selection ([#164](https://github.com/versatica/libmediasoupclient/pull/164)). Thanks @fedulvtubudul. diff --git a/CMakeLists.txt b/CMakeLists.txt index f3f9256c..9e6a25ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ configure_file ( ) # C++ standard requirements. -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # Project options. diff --git a/include/Handler.hpp b/include/Handler.hpp index 6658a43c..52ccfed0 100644 --- a/include/Handler.hpp +++ b/include/Handler.hpp @@ -21,7 +21,7 @@ namespace mediasoupclient class PrivateListener { public: - virtual ~PrivateListener() = default; + virtual ~PrivateListener() = default; virtual void OnConnect(nlohmann::json& dtlsParameters) = 0; virtual void OnConnectionStateChange( webrtc::PeerConnectionInterface::IceConnectionState connectionState) = 0; @@ -69,7 +69,8 @@ namespace mediasoupclient // Got transport local and remote parameters. bool transportReady{ false }; // Map of RTCTransceivers indexed by MID. - std::unordered_map mapMidTransceiver{}; + std::unordered_map> + mapMidTransceiver{}; // PeerConnection instance. std::unique_ptr pc{ nullptr }; bool hasDataChannelMediaSection = false; diff --git a/include/Logger.hpp b/include/Logger.hpp index e629b637..4bc3fab5 100644 --- a/include/Logger.hpp +++ b/include/Logger.hpp @@ -65,7 +65,7 @@ namespace mediasoupclient class LogHandlerInterface { public: - virtual ~LogHandlerInterface() = default; + virtual ~LogHandlerInterface() = default; virtual void OnLog(LogLevel level, char* payload, size_t len) = 0; }; diff --git a/include/PeerConnection.hpp b/include/PeerConnection.hpp index 93b81470..e102ec95 100644 --- a/include/PeerConnection.hpp +++ b/include/PeerConnection.hpp @@ -48,6 +48,40 @@ namespace mediasoupclient void OnInterestingUsage(int usagePattern) override; }; + class SetLocalDescriptionObserver : public webrtc::SetLocalDescriptionObserverInterface + { + public: + SetLocalDescriptionObserver() = default; + ~SetLocalDescriptionObserver() override = default; + + std::future GetFuture(); + void Reject(const std::string& error); + + /* Virtual methods inherited from webrtc::SetLocalDescriptionObserver. */ + public: + void OnSetLocalDescriptionComplete(webrtc::RTCError error) override; + + private: + std::promise promise; + }; + + class SetRemoteDescriptionObserver : public webrtc::SetRemoteDescriptionObserverInterface + { + public: + SetRemoteDescriptionObserver() = default; + ~SetRemoteDescriptionObserver() override = default; + + std::future GetFuture(); + void Reject(const std::string& error); + + /* Virtual methods inherited from webrtc::SetRemoteDescriptionObserver. */ + public: + void OnSetRemoteDescriptionComplete(webrtc::RTCError error) override; + + private: + std::promise promise; + }; + class SetSessionDescriptionObserver : public webrtc::SetSessionDescriptionObserver { public: @@ -126,7 +160,7 @@ namespace mediasoupclient rtc::scoped_refptr track, webrtc::RtpTransceiverInit rtpTransceiverInit); std::vector> GetSenders(); - bool RemoveTrack(webrtc::RtpSenderInterface* sender); + bool RemoveTrack(rtc::scoped_refptr sender); nlohmann::json GetStats(); nlohmann::json GetStats(rtc::scoped_refptr selector); nlohmann::json GetStats(rtc::scoped_refptr selector); diff --git a/package.json b/package.json index 54f6e1c4..26dbecb9 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,5 @@ "clang-tools-prebuilt": "^0.1.4", "gulp": "^4.0.2", "gulp-clang-format": "^1.0.27" - }, - "dependencies": {} + } } diff --git a/src/Handler.cpp b/src/Handler.cpp index d2ff7210..139da1d7 100644 --- a/src/Handler.cpp +++ b/src/Handler.cpp @@ -212,7 +212,8 @@ namespace mediasoupclient if (encodings && !encodings->empty()) transceiverInit.send_encodings = *encodings; - webrtc::RtpTransceiverInterface* transceiver = this->pc->AddTransceiver(track, transceiverInit); + rtc::scoped_refptr scopedTrack{ track }; + auto transceiver = this->pc->AddTransceiver(scopedTrack, transceiverInit); if (!transceiver) MSC_THROW_ERROR("error creating transceiver"); @@ -359,7 +360,7 @@ namespace mediasoupclient SendResult sendResult; sendResult.localId = localId; - sendResult.rtpSender = transceiver->sender(); + sendResult.rtpSender = transceiver->sender().get(); sendResult.rtpParameters = sendingRtpParameters; return sendResult; @@ -413,10 +414,10 @@ namespace mediasoupclient const Sdp::RemoteSdp::MediaSectionIdx mediaSectionIdx = this->remoteSdp->GetNextMediaSectionIdx(); - auto offerMediaObject = - find_if(localSdpObject["media"].begin(), localSdpObject["media"].end(), [](const json& m) { - return m.at("type").get() == "application"; - }); + auto offerMediaObject = find_if( + localSdpObject["media"].begin(), + localSdpObject["media"].end(), + [](const json& m) { return m.at("type").get() == "application"; }); if (offerMediaObject == localSdpObject["media"].end()) { @@ -461,7 +462,7 @@ namespace mediasoupclient if (locaIdIt == this->mapMidTransceiver.end()) MSC_THROW_ERROR("associated RtpTransceiver not found"); - auto* transceiver = locaIdIt->second; + auto transceiver = locaIdIt->second; transceiver->sender()->SetTrack(nullptr); this->pc->RemoveTrack(transceiver->sender()); @@ -500,7 +501,7 @@ namespace mediasoupclient if (localIdIt == this->mapMidTransceiver.end()) MSC_THROW_ERROR("associated RtpTransceiver not found"); - auto* transceiver = localIdIt->second; + auto transceiver = localIdIt->second; transceiver->sender()->SetTrack(track); } @@ -516,8 +517,8 @@ namespace mediasoupclient if (localIdIt == this->mapMidTransceiver.end()) MSC_THROW_ERROR("associated RtpTransceiver not found"); - auto* transceiver = localIdIt->second; - auto parameters = transceiver->sender()->GetParameters(); + auto transceiver = localIdIt->second; + auto parameters = transceiver->sender()->GetParameters(); bool hasLowEncoding{ false }; bool hasMediumEncoding{ false }; @@ -583,8 +584,8 @@ namespace mediasoupclient if (localIdIt == this->mapMidTransceiver.end()) MSC_THROW_ERROR("associated RtpTransceiver not found"); - auto* transceiver = localIdIt->second; - auto stats = this->pc->GetStats(transceiver->sender()); + auto transceiver = localIdIt->second; + auto stats = this->pc->GetStats(transceiver->sender()); return stats; } @@ -667,9 +668,9 @@ namespace mediasoupclient auto answer = this->pc->CreateAnswer(options); auto localSdpObject = sdptransform::parse(answer); auto mediaIt = find_if( - localSdpObject["media"].begin(), localSdpObject["media"].end(), [&localId](const json& m) { - return m["mid"].get() == localId; - }); + localSdpObject["media"].begin(), + localSdpObject["media"].end(), + [&localId](const json& m) { return m["mid"].get() == localId; }); auto& answerMediaObject = *mediaIt; @@ -690,9 +691,10 @@ namespace mediasoupclient auto transceivers = this->pc->GetTransceivers(); auto transceiverIt = std::find_if( - transceivers.begin(), transceivers.end(), [&localId](webrtc::RtpTransceiverInterface* t) { - return t->mid() == localId; - }); + transceivers.begin(), + transceivers.end(), + [&localId](rtc::scoped_refptr t) + { return t->mid() == localId; }); if (transceiverIt == transceivers.end()) MSC_THROW_ERROR("new RTCRtpTransceiver not found"); @@ -705,8 +707,8 @@ namespace mediasoupclient RecvResult recvResult; recvResult.localId = localId; - recvResult.rtpReceiver = transceiver->receiver(); - recvResult.track = transceiver->receiver()->track(); + recvResult.rtpReceiver = transceiver->receiver().get(); + recvResult.track = transceiver->receiver()->track().get(); return recvResult; } diff --git a/src/PeerConnection.cpp b/src/PeerConnection.cpp index 849db1fc..52804371 100644 --- a/src/PeerConnection.cpp +++ b/src/PeerConnection.cpp @@ -11,6 +11,19 @@ #include #include +#include "api/video_codecs/video_decoder_factory.h" +#include "api/video_codecs/video_decoder_factory_template.h" +#include "api/video_codecs/video_decoder_factory_template_dav1d_adapter.h" +#include "api/video_codecs/video_decoder_factory_template_libvpx_vp8_adapter.h" +#include "api/video_codecs/video_decoder_factory_template_libvpx_vp9_adapter.h" +#include "api/video_codecs/video_decoder_factory_template_open_h264_adapter.h" +#include "api/video_codecs/video_encoder_factory.h" +#include "api/video_codecs/video_encoder_factory_template.h" +#include "api/video_codecs/video_encoder_factory_template_libaom_av1_adapter.h" +#include "api/video_codecs/video_encoder_factory_template_libvpx_vp8_adapter.h" +#include "api/video_codecs/video_encoder_factory_template_libvpx_vp9_adapter.h" +#include "api/video_codecs/video_encoder_factory_template_open_h264_adapter.h" + using json = nlohmann::json; namespace mediasoupclient @@ -97,8 +110,16 @@ namespace mediasoupclient nullptr /*default_adm*/, webrtc::CreateBuiltinAudioEncoderFactory(), webrtc::CreateBuiltinAudioDecoderFactory(), - webrtc::CreateBuiltinVideoEncoderFactory(), - webrtc::CreateBuiltinVideoDecoderFactory(), + std::make_unique>(), + std::make_unique>(), nullptr /*audio_mixer*/, nullptr /*audio_processing*/); } @@ -138,7 +159,7 @@ namespace mediasoupclient MSC_WARN( "webrtc::PeerConnection::SetConfiguration failed [%s:%s]", - webrtc::ToString(error.type()), + webrtc::ToString(error.type()).data(), error.message()); return false; @@ -179,14 +200,14 @@ namespace mediasoupclient MSC_TRACE(); webrtc::SdpParseError error; - webrtc::SessionDescriptionInterface* sessionDescription; - rtc::scoped_refptr observer( - new rtc::RefCountedObject()); + std::unique_ptr sessionDescription; + rtc::scoped_refptr observer( + new rtc::RefCountedObject()); const auto& typeStr = sdpType2String[type]; auto future = observer->GetFuture(); - sessionDescription = webrtc::CreateSessionDescription(typeStr, sdp, &error); + sessionDescription.reset(webrtc::CreateSessionDescription(typeStr, sdp, &error)); if (sessionDescription == nullptr) { MSC_WARN( @@ -199,7 +220,7 @@ namespace mediasoupclient return future.get(); } - this->pc->SetLocalDescription(observer, sessionDescription); + this->pc->SetLocalDescription(std::move(sessionDescription), observer); return future.get(); } @@ -209,14 +230,14 @@ namespace mediasoupclient MSC_TRACE(); webrtc::SdpParseError error; - webrtc::SessionDescriptionInterface* sessionDescription; - rtc::scoped_refptr observer( - new rtc::RefCountedObject()); + std::unique_ptr sessionDescription; + rtc::scoped_refptr observer( + new rtc::RefCountedObject()); const auto& typeStr = sdpType2String[type]; auto future = observer->GetFuture(); - sessionDescription = webrtc::CreateSessionDescription(typeStr, sdp, &error); + sessionDescription.reset(webrtc::CreateSessionDescription(typeStr, sdp, &error)); if (sessionDescription == nullptr) { MSC_WARN( @@ -229,7 +250,7 @@ namespace mediasoupclient return future.get(); } - this->pc->SetRemoteDescription(observer, sessionDescription); + this->pc->SetRemoteDescription(std::move(sessionDescription), observer); return future.get(); } @@ -317,11 +338,13 @@ namespace mediasoupclient return this->pc->GetSenders(); } - bool PeerConnection::RemoveTrack(webrtc::RtpSenderInterface* sender) + bool PeerConnection::RemoveTrack(rtc::scoped_refptr sender) { MSC_TRACE(); - return this->pc->RemoveTrack(sender); + const auto result = this->pc->RemoveTrackOrError(sender); + + return result.ok(); } json PeerConnection::GetStats() @@ -371,10 +394,9 @@ namespace mediasoupclient { MSC_TRACE(); - rtc::scoped_refptr webrtcDataChannel = - this->pc->CreateDataChannel(label, config); + const auto result = this->pc->CreateDataChannelOrError(label, config); - if (webrtcDataChannel.get()) + if (result.ok()) { MSC_DEBUG("Success creating data channel"); } @@ -383,9 +405,83 @@ namespace mediasoupclient MSC_THROW_ERROR("Failed creating data channel"); } - return webrtcDataChannel; + return result.value(); + } + + /* SetLocalDescriptionObserver */ + + std::future PeerConnection::SetLocalDescriptionObserver::GetFuture() + { + MSC_TRACE(); + + return this->promise.get_future(); + } + + void PeerConnection::SetLocalDescriptionObserver::Reject(const std::string& error) + { + MSC_TRACE(); + + this->promise.set_exception(std::make_exception_ptr(MediaSoupClientError(error.c_str()))); } + void PeerConnection::SetLocalDescriptionObserver::OnSetLocalDescriptionComplete(webrtc::RTCError error) + { + MSC_TRACE(); + + if (!error.ok()) + { + MSC_WARN( + "webtc::SetLocalDescriptionObserver failure [%s:%s]", + webrtc::ToString(error.type()).data(), + error.message()); + + auto message = std::string(error.message()); + + this->Reject(message); + } + else + { + this->promise.set_value(); + } + }; + + /* SetRemoteDescriptionObserver */ + + std::future PeerConnection::SetRemoteDescriptionObserver::GetFuture() + { + MSC_TRACE(); + + return this->promise.get_future(); + } + + void PeerConnection::SetRemoteDescriptionObserver::Reject(const std::string& error) + { + MSC_TRACE(); + + this->promise.set_exception(std::make_exception_ptr(MediaSoupClientError(error.c_str()))); + } + + void PeerConnection::SetRemoteDescriptionObserver::OnSetRemoteDescriptionComplete(webrtc::RTCError error) + { + MSC_TRACE(); + + if (!error.ok()) + { + MSC_WARN( + "webtc::SetRemoteDescriptionObserver failure [%s:%s]", + webrtc::ToString(error.type()).data(), + error.message()); + + auto message = std::string(error.message()); + + this->Reject(message); + } + else + { + this->promise.set_value(); + } + }; + /* SetSessionDescriptionObserver */ std::future PeerConnection::SetSessionDescriptionObserver::GetFuture() @@ -415,7 +511,7 @@ namespace mediasoupclient MSC_WARN( "webtc::SetSessionDescriptionObserver failure [%s:%s]", - webrtc::ToString(error.type()), + webrtc::ToString(error.type()).data(), error.message()); auto message = std::string(error.message()); @@ -459,7 +555,7 @@ namespace mediasoupclient MSC_WARN( "webtc::CreateSessionDescriptionObserver failure [%s:%s]", - webrtc::ToString(error.type()), + webrtc::ToString(error.type()).data(), error.message()); auto message = std::string(error.message()); diff --git a/src/Transport.cpp b/src/Transport.cpp index fb57be53..478351ea 100644 --- a/src/Transport.cpp +++ b/src/Transport.cpp @@ -202,7 +202,8 @@ namespace mediasoupclient std::for_each( encodings->begin(), encodings->end(), - [&normalizedEncodings](const webrtc::RtpEncodingParameters& entry) { + [&normalizedEncodings](const webrtc::RtpEncodingParameters& entry) + { webrtc::RtpEncodingParameters encoding; encoding.active = entry.active; diff --git a/src/ortc.cpp b/src/ortc.cpp index 7c0a99a0..6807531a 100644 --- a/src/ortc.cpp +++ b/src/ortc.cpp @@ -1008,10 +1008,11 @@ namespace mediasoupclient json& localCodecs = localCaps["codecs"]; - auto matchingLocalCodecIt = - std::find_if(localCodecs.begin(), localCodecs.end(), [&remoteCodec](json& localCodec) { - return matchCodecs(localCodec, remoteCodec, /*strict*/ true, /*modify*/ true); - }); + auto matchingLocalCodecIt = std::find_if( + localCodecs.begin(), + localCodecs.end(), + [&remoteCodec](json& localCodec) + { return matchCodecs(localCodec, remoteCodec, /*strict*/ true, /*modify*/ true); }); if (matchingLocalCodecIt == localCodecs.end()) continue; @@ -1047,7 +1048,10 @@ namespace mediasoupclient { auto& localCodecs = localCaps["codecs"]; auto localCodecIt = std::find_if( - localCodecs.begin(), localCodecs.end(), [&extendedCodec](const json& localCodec) { + localCodecs.begin(), + localCodecs.end(), + [&extendedCodec](const json& localCodec) + { return isRtxCodec(localCodec) && localCodec["parameters"]["apt"] == extendedCodec["localPayloadType"]; }); @@ -1058,7 +1062,10 @@ namespace mediasoupclient auto& matchingLocalRtxCodec = *localCodecIt; auto& remoteCodecs = remoteCaps["codecs"]; auto remoteCodecIt = std::find_if( - remoteCodecs.begin(), remoteCodecs.end(), [&extendedCodec](const json& remoteCodec) { + remoteCodecs.begin(), + remoteCodecs.end(), + [&extendedCodec](const json& remoteCodec) + { return isRtxCodec(remoteCodec) && remoteCodec["parameters"]["apt"] == extendedCodec["remotePayloadType"]; }); @@ -1078,10 +1085,10 @@ namespace mediasoupclient for (auto& remoteExt : remoteExts) { auto& localExts = localCaps["headerExtensions"]; - auto localExtIt = - std::find_if(localExts.begin(), localExts.end(), [&remoteExt](const json& localExt) { - return matchHeaderExtensions(localExt, remoteExt); - }); + auto localExtIt = std::find_if( + localExts.begin(), + localExts.end(), + [&remoteExt](const json& localExt) { return matchHeaderExtensions(localExt, remoteExt); }); if (localExtIt == localExts.end()) continue; @@ -1390,8 +1397,11 @@ namespace mediasoupclient auto headerExtensionsIt = rtpParameters.find("headerExtensions"); // Reduce codecs' RTCP feedback. Use Transport-CC if available, REMB otherwise. - auto headerExtensionIt = - std::find_if(headerExtensionsIt->begin(), headerExtensionsIt->end(), [](json& ext) { + auto headerExtensionIt = std::find_if( + headerExtensionsIt->begin(), + headerExtensionsIt->end(), + [](json& ext) + { return ext["uri"].get() == "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01"; }); @@ -1417,8 +1427,11 @@ namespace mediasoupclient return rtpParameters; } - headerExtensionIt = - std::find_if(headerExtensionsIt->begin(), headerExtensionsIt->end(), [](json& ext) { + headerExtensionIt = std::find_if( + headerExtensionsIt->begin(), + headerExtensionsIt->end(), + [](json& ext) + { return ext["uri"].get() == "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time"; }); @@ -1524,9 +1537,10 @@ namespace mediasoupclient MSC_TRACE(); const auto& codecs = extendedRtpCapabilities["codecs"]; - auto codecIt = std::find_if(codecs.begin(), codecs.end(), [&kind](const json& codec) { - return kind == codec["kind"].get(); - }); + auto codecIt = std::find_if( + codecs.begin(), + codecs.end(), + [&kind](const json& codec) { return kind == codec["kind"].get(); }); return codecIt != codecs.end(); } @@ -1547,10 +1561,11 @@ namespace mediasoupclient auto& firstMediaCodec = rtpParameters["codecs"][0]; const auto& codecs = extendedRtpCapabilities["codecs"]; - auto codecIt = - std::find_if(codecs.begin(), codecs.end(), [&firstMediaCodec](const json& codec) { - return codec["remotePayloadType"] == firstMediaCodec["payloadType"]; - }); + auto codecIt = std::find_if( + codecs.begin(), + codecs.end(), + [&firstMediaCodec](const json& codec) + { return codec["remotePayloadType"] == firstMediaCodec["payloadType"]; }); return codecIt != codecs.end(); } @@ -1722,10 +1737,11 @@ static json reduceRtcpFeedback(const json& codecA, const json& codecB) for (const auto& aFb : *rtcpFeedbackAIt) { - auto rtcpFeedbackIt = - std::find_if(rtcpFeedbackBIt->begin(), rtcpFeedbackBIt->end(), [&aFb](const json& bFb) { - return (aFb["type"] == bFb["type"] && aFb["parameter"] == bFb["parameter"]); - }); + auto rtcpFeedbackIt = std::find_if( + rtcpFeedbackBIt->begin(), + rtcpFeedbackBIt->end(), + [&aFb](const json& bFb) + { return (aFb["type"] == bFb["type"] && aFb["parameter"] == bFb["parameter"]); }); if (rtcpFeedbackIt != rtcpFeedbackBIt->end()) reducedRtcpFeedback.push_back(*rtcpFeedbackIt); diff --git a/src/sdp/MediaSection.cpp b/src/sdp/MediaSection.cpp index af7cc957..67241863 100644 --- a/src/sdp/MediaSection.cpp +++ b/src/sdp/MediaSection.cpp @@ -172,10 +172,11 @@ namespace mediasoupclient if (codecOptions != nullptr && !codecOptions->empty()) { auto& offerCodecs = offerRtpParameters["codecs"]; - auto codecIt = - find_if(offerCodecs.begin(), offerCodecs.end(), [&codec](json& offerCodec) { - return offerCodec["payloadType"] == codec["payloadType"]; - }); + auto codecIt = find_if( + offerCodecs.begin(), + offerCodecs.end(), + [&codec](json& offerCodec) + { return offerCodec["payloadType"] == codec["payloadType"]; }); auto& offerCodec = *codecIt; auto mimeType = codec["mimeType"].get(); @@ -323,9 +324,10 @@ namespace mediasoupclient for (auto& ext : answerRtpParameters["headerExtensions"]) { const auto& localExts = offerMediaObject["ext"]; - auto localExtIt = find_if(localExts.begin(), localExts.end(), [&ext](const json& localExt) { - return localExt["uri"] == ext["uri"]; - }); + auto localExtIt = find_if( + localExts.begin(), + localExts.end(), + [&ext](const json& localExt) { return localExt["uri"] == ext["uri"]; }); if (localExtIt == localExts.end()) continue; diff --git a/src/sdp/RemoteSdp.cpp b/src/sdp/RemoteSdp.cpp index b3ee5a1d..03860100 100644 --- a/src/sdp/RemoteSdp.cpp +++ b/src/sdp/RemoteSdp.cpp @@ -230,9 +230,9 @@ namespace mediasoupclient // Let's try to recycle a closed media section (if any). // NOTE: We can recycle a closed m=audio section with a new m=video. auto mediaSectionIt = find_if( - this->mediaSections.begin(), this->mediaSections.end(), [](const MediaSection* mediaSection) { - return mediaSection->IsClosed(); - }); + this->mediaSections.begin(), + this->mediaSections.end(), + [](const MediaSection* mediaSection) { return mediaSection->IsClosed(); }); if (mediaSectionIt != this->mediaSections.end()) { diff --git a/src/sdp/Utils.cpp b/src/sdp/Utils.cpp index d8edc4f3..eb28c5a3 100644 --- a/src/sdp/Utils.cpp +++ b/src/sdp/Utils.cpp @@ -227,14 +227,18 @@ namespace mediasoupclient // Get the SSRC. auto mSsrcs = offerMediaObject["ssrcs"]; - auto jsonSsrcIt = std::find_if(mSsrcs.begin(), mSsrcs.end(), [](const json& line) { - auto jsonAttributeIt = line.find("attribute"); - - if (jsonAttributeIt == line.end() || !jsonAttributeIt->is_string()) - return false; + auto jsonSsrcIt = std::find_if( + mSsrcs.begin(), + mSsrcs.end(), + [](const json& line) + { + auto jsonAttributeIt = line.find("attribute"); + + if (jsonAttributeIt == line.end() || !jsonAttributeIt->is_string()) + return false; - return jsonAttributeIt->get() == "msid"; - }); + return jsonAttributeIt->get() == "msid"; + }); if (jsonSsrcIt == mSsrcs.end()) { @@ -256,42 +260,46 @@ namespace mediasoupclient { auto& ssrcGroups = *jsonSsrcGroupsIt; - std::find_if( - ssrcGroups.begin(), ssrcGroups.end(), [&firstSsrc, &firstRtxSsrc](const json& line) { - auto jsonSemanticsIt = line.find("semantics"); + for (const auto& line : ssrcGroups) + { + auto jsonSemanticsIt = line.find("semantics"); - if (jsonSemanticsIt == line.end() || !jsonSemanticsIt->is_string()) - return false; + if (jsonSemanticsIt == line.end() || !jsonSemanticsIt->is_string()) + continue; - auto jsonSsrcsIt = line.find("ssrcs"); + auto jsonSsrcsIt = line.find("ssrcs"); - if (jsonSsrcsIt == line.end() || !jsonSsrcsIt->is_string()) - return false; + if (jsonSsrcsIt == line.end() || !jsonSsrcsIt->is_string()) + continue; - auto v = mediasoupclient::Utils::split(jsonSsrcsIt->get(), ' '); + auto v = mediasoupclient::Utils::split(jsonSsrcsIt->get(), ' '); - if (std::stoull(v[0]) == firstSsrc) - { - firstRtxSsrc = std::stoull(v[1]); + if (std::stoull(v[0]) == firstSsrc) + { + firstRtxSsrc = std::stoull(v[1]); - return true; - } + break; + } - return false; - }); + continue; + }; } - jsonSsrcIt = std::find_if(mSsrcs.begin(), mSsrcs.end(), [](const json& line) { - auto jsonAttributeIt = line.find("attribute"); - if (jsonAttributeIt == line.end() || !jsonAttributeIt->is_string()) - return false; + jsonSsrcIt = std::find_if( + mSsrcs.begin(), + mSsrcs.end(), + [](const json& line) + { + auto jsonAttributeIt = line.find("attribute"); + if (jsonAttributeIt == line.end() || !jsonAttributeIt->is_string()) + return false; - auto jsonIdIt = line.find("id"); - if (jsonIdIt == line.end() || !jsonIdIt->is_number()) - return false; + auto jsonIdIt = line.find("id"); + if (jsonIdIt == line.end() || !jsonIdIt->is_number()) + return false; - return (jsonAttributeIt->get() == "cname"); - }); + return (jsonAttributeIt->get() == "cname"); + }); if (jsonSsrcIt == mSsrcs.end()) MSC_THROW_ERROR("CNAME line not found"); @@ -396,11 +404,15 @@ namespace mediasoupclient const json& mSsrcs = *jsonMssrcsIt; - auto jsonSsrcIt = find_if(mSsrcs.begin(), mSsrcs.end(), [](const json& line) { - auto jsonAttributeIt = line.find("attribute"); + auto jsonSsrcIt = find_if( + mSsrcs.begin(), + mSsrcs.end(), + [](const json& line) + { + auto jsonAttributeIt = line.find("attribute"); - return (jsonAttributeIt != line.end() && jsonAttributeIt->is_string()); - }); + return (jsonAttributeIt != line.end() && jsonAttributeIt->is_string()); + }); if (jsonSsrcIt == mSsrcs.end()) return ""; @@ -490,9 +502,10 @@ namespace mediasoupclient continue; auto& rtps = answerMediaObject["rtp"]; - auto jsonRtpIt = find_if(rtps.begin(), rtps.end(), [&codec](const json& r) { - return r["payload"] == codec["payloadType"]; - }); + auto jsonRtpIt = find_if( + rtps.begin(), + rtps.end(), + [&codec](const json& r) { return r["payload"] == codec["payloadType"]; }); if (jsonRtpIt == rtps.end()) continue; @@ -502,9 +515,10 @@ namespace mediasoupclient answerMediaObject["fmtp"] = json::array(); auto& fmtps = answerMediaObject["fmtp"]; - auto jsonFmtpIt = find_if(fmtps.begin(), fmtps.end(), [&codec](const json& f) { - return f["payload"] == codec["payloadType"]; - }); + auto jsonFmtpIt = find_if( + fmtps.begin(), + fmtps.end(), + [&codec](const json& f) { return f["payload"] == codec["payloadType"]; }); if (jsonFmtpIt == fmtps.end()) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 21ff3d26..79911c7d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -80,4 +80,8 @@ add_subdirectory(deps/libwebrtc "${CMAKE_CURRENT_BINARY_DIR}/libwebrtc") # Public (interface) dependencies. target_link_libraries(test_mediasoupclient PUBLIC webrtc + ${LIBWEBRTC_BINARY_PATH}/api/video_codecs/libbuiltin_video_encoder_factory${CMAKE_STATIC_LIBRARY_SUFFIX} + ${LIBWEBRTC_BINARY_PATH}/api/video_codecs/libbuiltin_video_decoder_factory${CMAKE_STATIC_LIBRARY_SUFFIX} + ${LIBWEBRTC_BINARY_PATH}/media/librtc_simulcast_encoder_adapter${CMAKE_STATIC_LIBRARY_SUFFIX} + ${LIBWEBRTC_BINARY_PATH}/media/librtc_internal_video_codecs${CMAKE_STATIC_LIBRARY_SUFFIX} ) diff --git a/test/deps/libwebrtc/pc/test/fake_audio_capture_module.cc b/test/deps/libwebrtc/pc/test/fake_audio_capture_module.cc index 214ed6b5..6ffa18c8 100644 --- a/test/deps/libwebrtc/pc/test/fake_audio_capture_module.cc +++ b/test/deps/libwebrtc/pc/test/fake_audio_capture_module.cc @@ -12,12 +12,14 @@ #include +#include "api/make_ref_counted.h" +#include "api/units/time_delta.h" #include "rtc_base/checks.h" -#include "rtc_base/location.h" -#include "rtc_base/ref_counted_object.h" #include "rtc_base/thread.h" #include "rtc_base/time_utils.h" +using ::webrtc::TimeDelta; + // Audio sample value that is high enough that it doesn't occur naturally when // frames are being faked. E.g. NetEq will not generate this large sample value // unless it has received an audio frame containing a sample of this value. @@ -33,11 +35,6 @@ static const int kTotalDelayMs = 0; static const int kClockDriftMs = 0; static const uint32_t kMaxVolume = 14392; -enum { - MSG_START_PROCESS, - MSG_RUN_PROCESS, -}; - FakeAudioCaptureModule::FakeAudioCaptureModule() : audio_callback_(nullptr), recording_(false), @@ -47,9 +44,7 @@ FakeAudioCaptureModule::FakeAudioCaptureModule() current_mic_level_(kMaxVolume), started_(false), next_frame_time_(0), - frames_received_(0) { - process_thread_checker_.Detach(); -} + frames_received_(0) {} FakeAudioCaptureModule::~FakeAudioCaptureModule() { if (process_thread_) { @@ -72,7 +67,7 @@ int FakeAudioCaptureModule::frames_received() const { int32_t FakeAudioCaptureModule::ActiveAudioLayer( AudioLayer* /*audio_layer*/) const { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } @@ -94,17 +89,17 @@ int32_t FakeAudioCaptureModule::Terminate() { } bool FakeAudioCaptureModule::Initialized() const { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } int16_t FakeAudioCaptureModule::PlayoutDevices() { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } int16_t FakeAudioCaptureModule::RecordingDevices() { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } @@ -112,7 +107,7 @@ int32_t FakeAudioCaptureModule::PlayoutDeviceName( uint16_t /*index*/, char /*name*/[webrtc::kAdmMaxDeviceNameSize], char /*guid*/[webrtc::kAdmMaxGuidSize]) { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } @@ -120,7 +115,7 @@ int32_t FakeAudioCaptureModule::RecordingDeviceName( uint16_t /*index*/, char /*name*/[webrtc::kAdmMaxDeviceNameSize], char /*guid*/[webrtc::kAdmMaxGuidSize]) { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } @@ -150,7 +145,7 @@ int32_t FakeAudioCaptureModule::SetRecordingDevice( } int32_t FakeAudioCaptureModule::PlayoutIsAvailable(bool* /*available*/) { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } @@ -164,7 +159,7 @@ bool FakeAudioCaptureModule::PlayoutIsInitialized() const { } int32_t FakeAudioCaptureModule::RecordingIsAvailable(bool* /*available*/) { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } @@ -241,7 +236,7 @@ int32_t FakeAudioCaptureModule::InitSpeaker() { } bool FakeAudioCaptureModule::SpeakerIsInitialized() const { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } @@ -251,40 +246,40 @@ int32_t FakeAudioCaptureModule::InitMicrophone() { } bool FakeAudioCaptureModule::MicrophoneIsInitialized() const { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::SpeakerVolumeIsAvailable(bool* /*available*/) { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::SetSpeakerVolume(uint32_t /*volume*/) { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::SpeakerVolume(uint32_t* /*volume*/) const { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::MaxSpeakerVolume( uint32_t* /*max_volume*/) const { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::MinSpeakerVolume( uint32_t* /*min_volume*/) const { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::MicrophoneVolumeIsAvailable( bool* /*available*/) { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } @@ -308,37 +303,37 @@ int32_t FakeAudioCaptureModule::MaxMicrophoneVolume( int32_t FakeAudioCaptureModule::MinMicrophoneVolume( uint32_t* /*min_volume*/) const { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::SpeakerMuteIsAvailable(bool* /*available*/) { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::SetSpeakerMute(bool /*enable*/) { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::SpeakerMute(bool* /*enabled*/) const { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::MicrophoneMuteIsAvailable(bool* /*available*/) { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::SetMicrophoneMute(bool /*enable*/) { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::MicrophoneMute(bool* /*enabled*/) const { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } @@ -357,7 +352,7 @@ int32_t FakeAudioCaptureModule::SetStereoPlayout(bool /*enable*/) { } int32_t FakeAudioCaptureModule::StereoPlayout(bool* /*enabled*/) const { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } @@ -376,7 +371,7 @@ int32_t FakeAudioCaptureModule::SetStereoRecording(bool enable) { } int32_t FakeAudioCaptureModule::StereoRecording(bool* /*enabled*/) const { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } @@ -386,21 +381,6 @@ int32_t FakeAudioCaptureModule::PlayoutDelay(uint16_t* delay_ms) const { return 0; } -void FakeAudioCaptureModule::OnMessage(rtc::Message* msg) { - switch (msg->message_id) { - case MSG_START_PROCESS: - StartProcessP(); - break; - case MSG_RUN_PROCESS: - ProcessFrameP(); - break; - default: - // All existing messages should be caught. Getting here should never - // happen. - RTC_NOTREACHED(); - } -} - bool FakeAudioCaptureModule::Initialize() { // Set the send buffer samples high enough that it would not occur on the // remote side unless a packet containing a sample of that magnitude has been @@ -444,7 +424,7 @@ void FakeAudioCaptureModule::UpdateProcessing(bool start) { process_thread_ = rtc::Thread::Create(); process_thread_->Start(); } - process_thread_->Post(RTC_FROM_HERE, this, MSG_START_PROCESS); + process_thread_->PostTask([this] { StartProcessP(); }); } else { if (process_thread_) { process_thread_->Stop(); @@ -490,7 +470,8 @@ void FakeAudioCaptureModule::ProcessFrameP() { const int64_t current_time = rtc::TimeMillis(); const int64_t wait_time = (next_frame_time_ > current_time) ? next_frame_time_ - current_time : 0; - process_thread_->PostDelayed(RTC_FROM_HERE, wait_time, this, MSG_RUN_PROCESS); + process_thread_->PostDelayedTask([this] { ProcessFrameP(); }, + TimeDelta::Millis(wait_time)); } void FakeAudioCaptureModule::ReceiveFrameP() { @@ -506,7 +487,7 @@ void FakeAudioCaptureModule::ReceiveFrameP() { kNumberOfChannels, kSamplesPerSecond, rec_buffer_, nSamplesOut, &elapsed_time_ms, &ntp_time_ms) != 0) { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } RTC_CHECK(nSamplesOut == kNumberSamples); @@ -532,7 +513,7 @@ void FakeAudioCaptureModule::SendFrameP() { send_buffer_, kNumberSamples, kNumberBytesPerSample, kNumberOfChannels, kSamplesPerSecond, kTotalDelayMs, kClockDriftMs, current_mic_level, key_pressed, current_mic_level) != 0) { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); } current_mic_level_ = current_mic_level; } diff --git a/test/deps/libwebrtc/pc/test/fake_audio_capture_module.h b/test/deps/libwebrtc/pc/test/fake_audio_capture_module.h index 0af38102..c04373cd 100644 --- a/test/deps/libwebrtc/pc/test/fake_audio_capture_module.h +++ b/test/deps/libwebrtc/pc/test/fake_audio_capture_module.h @@ -20,19 +20,23 @@ #ifndef PC_TEST_FAKE_AUDIO_CAPTURE_MODULE_H_ #define PC_TEST_FAKE_AUDIO_CAPTURE_MODULE_H_ +#include +#include + #include #include "api/scoped_refptr.h" +#include "api/sequence_checker.h" #include "modules/audio_device/include/audio_device.h" -#include "rtc_base/critical_section.h" -#include "rtc_base/message_handler.h" +#include "modules/audio_device/include/audio_device_defines.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/thread_annotations.h" namespace rtc { class Thread; } // namespace rtc -class FakeAudioCaptureModule : public webrtc::AudioDeviceModule, - public rtc::MessageHandler { +class FakeAudioCaptureModule : public webrtc::AudioDeviceModule { public: typedef uint16_t Sample; @@ -47,13 +51,13 @@ class FakeAudioCaptureModule : public webrtc::AudioDeviceModule, // Returns the number of frames that have been successfully pulled by the // instance. Note that correctly detecting success can only be done if the // pulled frame was generated/pushed from a FakeAudioCaptureModule. - int frames_received() const; + int frames_received() const RTC_LOCKS_EXCLUDED(mutex_); int32_t ActiveAudioLayer(AudioLayer* audio_layer) const override; // Note: Calling this method from a callback may result in deadlock. - int32_t RegisterAudioCallback( - webrtc::AudioTransport* audio_callback) override; + int32_t RegisterAudioCallback(webrtc::AudioTransport* audio_callback) override + RTC_LOCKS_EXCLUDED(mutex_); int32_t Init() override; int32_t Terminate() override; @@ -80,12 +84,12 @@ class FakeAudioCaptureModule : public webrtc::AudioDeviceModule, int32_t InitRecording() override; bool RecordingIsInitialized() const override; - int32_t StartPlayout() override; - int32_t StopPlayout() override; - bool Playing() const override; - int32_t StartRecording() override; - int32_t StopRecording() override; - bool Recording() const override; + int32_t StartPlayout() RTC_LOCKS_EXCLUDED(mutex_) override; + int32_t StopPlayout() RTC_LOCKS_EXCLUDED(mutex_) override; + bool Playing() const RTC_LOCKS_EXCLUDED(mutex_) override; + int32_t StartRecording() RTC_LOCKS_EXCLUDED(mutex_) override; + int32_t StopRecording() RTC_LOCKS_EXCLUDED(mutex_) override; + bool Recording() const RTC_LOCKS_EXCLUDED(mutex_) override; int32_t InitSpeaker() override; bool SpeakerIsInitialized() const override; @@ -99,8 +103,10 @@ class FakeAudioCaptureModule : public webrtc::AudioDeviceModule, int32_t MinSpeakerVolume(uint32_t* min_volume) const override; int32_t MicrophoneVolumeIsAvailable(bool* available) override; - int32_t SetMicrophoneVolume(uint32_t volume) override; - int32_t MicrophoneVolume(uint32_t* volume) const override; + int32_t SetMicrophoneVolume(uint32_t volume) + RTC_LOCKS_EXCLUDED(mutex_) override; + int32_t MicrophoneVolume(uint32_t* volume) const + RTC_LOCKS_EXCLUDED(mutex_) override; int32_t MaxMicrophoneVolume(uint32_t* max_volume) const override; int32_t MinMicrophoneVolume(uint32_t* min_volume) const override; @@ -130,6 +136,10 @@ class FakeAudioCaptureModule : public webrtc::AudioDeviceModule, int32_t EnableBuiltInNS(bool enable) override { return -1; } int32_t GetPlayoutUnderrunCount() const override { return -1; } + + absl::optional GetStats() const override { + return webrtc::AudioDeviceModule::Stats(); + } #if defined(WEBRTC_IOS) int GetPlayoutAudioParameters( webrtc::AudioParameters* params) const override { @@ -142,9 +152,6 @@ class FakeAudioCaptureModule : public webrtc::AudioDeviceModule, // End of functions inherited from webrtc::AudioDeviceModule. - // The following function is inherited from rtc::MessageHandler. - void OnMessage(rtc::Message* msg) override; - protected: // The constructor is protected because the class needs to be created as a // reference counted object (for memory managment reasons). It could be @@ -160,36 +167,38 @@ class FakeAudioCaptureModule : public webrtc::AudioDeviceModule, // Initializes the state of the FakeAudioCaptureModule. This API is called on // creation by the Create() API. bool Initialize(); - // SetBuffer() sets all samples in send_buffer_ to |value|. + // SetBuffer() sets all samples in send_buffer_ to `value`. void SetSendBuffer(int value); // Resets rec_buffer_. I.e., sets all rec_buffer_ samples to 0. void ResetRecBuffer(); // Returns true if rec_buffer_ contains one or more sample greater than or - // equal to |value|. + // equal to `value`. bool CheckRecBuffer(int value); // Returns true/false depending on if recording or playback has been // enabled/started. - bool ShouldStartProcessing(); + bool ShouldStartProcessing() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); // Starts or stops the pushing and pulling of audio frames. - void UpdateProcessing(bool start); + void UpdateProcessing(bool start) RTC_LOCKS_EXCLUDED(mutex_); // Starts the periodic calling of ProcessFrame() in a thread safe way. void StartProcessP(); // Periodcally called function that ensures that frames are pulled and pushed // periodically if enabled/started. - void ProcessFrameP(); + void ProcessFrameP() RTC_LOCKS_EXCLUDED(mutex_); // Pulls frames from the registered webrtc::AudioTransport. - void ReceiveFrameP(); + void ReceiveFrameP() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); // Pushes frames to the registered webrtc::AudioTransport. - void SendFrameP(); + void SendFrameP() RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); // Callback for playout and recording. - webrtc::AudioTransport* audio_callback_; + webrtc::AudioTransport* audio_callback_ RTC_GUARDED_BY(mutex_); - bool recording_; // True when audio is being pushed from the instance. - bool playing_; // True when audio is being pulled by the instance. + bool recording_ RTC_GUARDED_BY( + mutex_); // True when audio is being pushed from the instance. + bool playing_ RTC_GUARDED_BY( + mutex_); // True when audio is being pulled by the instance. bool play_is_initialized_; // True when the instance is ready to pull audio. bool rec_is_initialized_; // True when the instance is ready to push audio. @@ -197,13 +206,13 @@ class FakeAudioCaptureModule : public webrtc::AudioDeviceModule, // Input to and output from RecordedDataIsAvailable(..) makes it possible to // modify the current mic level. The implementation does not care about the // mic level so it just feeds back what it receives. - uint32_t current_mic_level_; + uint32_t current_mic_level_ RTC_GUARDED_BY(mutex_); // next_frame_time_ is updated in a non-drifting manner to indicate the next // wall clock time the next frame should be generated and received. started_ // ensures that next_frame_time_ can be initialized properly on first call. - bool started_; - int64_t next_frame_time_; + bool started_ RTC_GUARDED_BY(mutex_); + int64_t next_frame_time_ RTC_GUARDED_BY(process_thread_checker_); std::unique_ptr process_thread_; @@ -219,10 +228,9 @@ class FakeAudioCaptureModule : public webrtc::AudioDeviceModule, // Protects variables that are accessed from process_thread_ and // the main thread. - rtc::CriticalSection crit_; - // Protects |audio_callback_| that is accessed from process_thread_ and - // the main thread. - rtc::CriticalSection crit_callback_; + mutable webrtc::Mutex mutex_; + webrtc::SequenceChecker process_thread_checker_{ + webrtc::SequenceChecker::kDetached}; }; #endif // PC_TEST_FAKE_AUDIO_CAPTURE_MODULE_H_ diff --git a/test/include/MediaStreamTrackFactory.hpp b/test/include/MediaStreamTrackFactory.hpp index ecd63613..509cb313 100644 --- a/test/include/MediaStreamTrackFactory.hpp +++ b/test/include/MediaStreamTrackFactory.hpp @@ -1,7 +1,56 @@ #ifndef MSC_TEST_MEDIA_STREAM_TRACK_FACTORY_HPP #define MSC_TEST_MEDIA_STREAM_TRACK_FACTORY_HPP +#include "MediaSoupClientErrors.hpp" +#include "MediaStreamTrackFactory.hpp" +#include "api/audio_codecs/builtin_audio_decoder_factory.h" +#include "api/audio_codecs/builtin_audio_encoder_factory.h" +#include "api/create_peerconnection_factory.h" #include "api/media_stream_interface.h" +#include "api/video_codecs/builtin_video_decoder_factory.h" +#include "api/video_codecs/builtin_video_encoder_factory.h" +#include "mediasoupclient.hpp" +#include "pc/test/fake_audio_capture_module.h" +#include "pc/test/fake_video_track_source.h" +#include + +class MediaStreamTrackFactory +{ +public: + static MediaStreamTrackFactory& getInstance() + { + static MediaStreamTrackFactory instance; + return instance; + } + + MediaStreamTrackFactory(const MediaStreamTrackFactory&) = delete; + MediaStreamTrackFactory& operator=(const MediaStreamTrackFactory&) = delete; + + void Create(); + + void ReleaseThreads(); + + rtc::scoped_refptr Factory; + mediasoupclient::PeerConnection::Options PeerConnectionOptions; + +private: + MediaStreamTrackFactory() + { + Create(); + } + ~MediaStreamTrackFactory() + { + ReleaseThreads(); + } + + /** + * MediaStreamTrack holds reference to the threads of the PeerConnectionFactory. + * Use plain pointers in order to avoid threads being destructed before tracks. + */ + std::unique_ptr NetworkThread; + std::unique_ptr WorkerThread; + std::unique_ptr SignalingThread; +}; rtc::scoped_refptr createAudioTrack(const std::string& label); diff --git a/test/src/Handler.test.cpp b/test/src/Handler.test.cpp index a3591984..19632cf2 100644 --- a/test/src/Handler.test.cpp +++ b/test/src/Handler.test.cpp @@ -9,8 +9,6 @@ static const json TransportRemoteParameters = generateTransportRemoteParameters(); static const json RtpParametersByKind = generateRtpParametersByKind(); -static mediasoupclient::PeerConnection::Options PeerConnectionOptions; - class FakeHandlerListener : public mediasoupclient::Handler::PrivateListener { public: @@ -22,11 +20,14 @@ class FakeHandlerListener : public mediasoupclient::Handler::PrivateListener TEST_CASE("Handler", "[Handler]") { + MediaStreamTrackFactory& singleton = MediaStreamTrackFactory::getInstance(); SECTION("Handler::GetNativeRtpCapabilities() succeeds") { json rtpCapabilities; - REQUIRE_NOTHROW(rtpCapabilities = mediasoupclient::Handler::GetNativeRtpCapabilities()); + REQUIRE_NOTHROW( + rtpCapabilities = + mediasoupclient::Handler::GetNativeRtpCapabilities(&singleton.PeerConnectionOptions)); REQUIRE(rtpCapabilities["codecs"].is_array()); REQUIRE(rtpCapabilities["fecMechanisms"].is_array()); @@ -37,6 +38,7 @@ TEST_CASE("Handler", "[Handler]") TEST_CASE("SendHandler", "[Handler][SendHandler]") { static FakeHandlerListener handlerListener; + MediaStreamTrackFactory& singleton = MediaStreamTrackFactory::getInstance(); static mediasoupclient::SendHandler sendHandler( &handlerListener, @@ -44,13 +46,10 @@ TEST_CASE("SendHandler", "[Handler][SendHandler]") TransportRemoteParameters["iceCandidates"], TransportRemoteParameters["dtlsParameters"], TransportRemoteParameters["sctpParameters"], - &PeerConnectionOptions, + &singleton.PeerConnectionOptions, RtpParametersByKind, RtpParametersByKind); - static std::unique_ptr pc( - new mediasoupclient::PeerConnection(nullptr, &PeerConnectionOptions)); - static rtc::scoped_refptr track; static std::string localId; @@ -66,7 +65,7 @@ TEST_CASE("SendHandler", "[Handler][SendHandler]") mediasoupclient::SendHandler::SendResult sendResult; - REQUIRE_NOTHROW(sendResult = sendHandler.Send(track, nullptr, nullptr, nullptr)); + REQUIRE_NOTHROW(sendResult = sendHandler.Send(track.get(), nullptr, nullptr, nullptr)); localId = sendResult.localId; @@ -76,7 +75,7 @@ TEST_CASE("SendHandler", "[Handler][SendHandler]") SECTION("sendHandler.Send() succeeds if track is already handled") { - REQUIRE_NOTHROW(sendHandler.Send(track, nullptr, nullptr, nullptr)); + REQUIRE_NOTHROW(sendHandler.Send(track.get(), nullptr, nullptr, nullptr)); } SECTION("sendHandler.ReplaceTrack() fails if an invalid localId is provided") @@ -88,7 +87,7 @@ TEST_CASE("SendHandler", "[Handler][SendHandler]") { auto newTrack = createAudioTrack("test-new-track-id"); - REQUIRE_NOTHROW(sendHandler.ReplaceTrack(localId, newTrack)); + REQUIRE_NOTHROW(sendHandler.ReplaceTrack(localId, newTrack.get())); track = newTrack; } @@ -122,7 +121,7 @@ TEST_CASE("SendHandler", "[Handler][SendHandler]") { mediasoupclient::SendHandler::SendResult sendResult; - REQUIRE_NOTHROW(sendResult = sendHandler.Send(track, nullptr, nullptr, nullptr)); + REQUIRE_NOTHROW(sendResult = sendHandler.Send(track.get(), nullptr, nullptr, nullptr)); localId = sendResult.localId; } @@ -142,6 +141,7 @@ TEST_CASE("SendHandler", "[Handler][SendHandler]") SECTION("sendHandler.UpdateIceServers() succeeds") { REQUIRE_NOTHROW(sendHandler.UpdateIceServers(json::array())); + sendHandler.Close(); } } @@ -156,6 +156,7 @@ TEST_CASE("RecvHandler", "[Handler][RecvHandler]") static std::string localId; static FakeHandlerListener handlerListener; + MediaStreamTrackFactory& singleton = MediaStreamTrackFactory::getInstance(); static mediasoupclient::RecvHandler recvHandler( &handlerListener, @@ -163,7 +164,7 @@ TEST_CASE("RecvHandler", "[Handler][RecvHandler]") TransportRemoteParameters["iceCandidates"], TransportRemoteParameters["dtlsParameters"], TransportRemoteParameters["sctpParameters"], - &PeerConnectionOptions); + &singleton.PeerConnectionOptions); SECTION("recvHander.Receive() succeeds if correct rtpParameters are provided") { @@ -204,5 +205,6 @@ TEST_CASE("RecvHandler", "[Handler][RecvHandler]") SECTION("recvHandler.UpdateIceServers() succeeds") { REQUIRE_NOTHROW(recvHandler.UpdateIceServers(json::array())); + recvHandler.Close(); } } diff --git a/test/src/MediaStreamTrackFactory.cpp b/test/src/MediaStreamTrackFactory.cpp index 69d0ae69..b974c5b3 100644 --- a/test/src/MediaStreamTrackFactory.cpp +++ b/test/src/MediaStreamTrackFactory.cpp @@ -1,3 +1,6 @@ +#ifndef MEDIA_STREAM_TRACK_FACTORY_H +#define MEDIA_STREAM_TRACK_FACTORY_H + #define MSC_CLASS "MediaStreamTrackFactory" #include "MediaStreamTrackFactory.hpp" @@ -7,25 +10,20 @@ #include "api/create_peerconnection_factory.h" #include "api/video_codecs/builtin_video_decoder_factory.h" #include "api/video_codecs/builtin_video_encoder_factory.h" +#include "mediasoupclient.hpp" #include "pc/test/fake_audio_capture_module.h" #include "pc/test/fake_video_track_source.h" +#include using namespace mediasoupclient; -static rtc::scoped_refptr Factory; - -/* MediaStreamTrack holds reference to the threads of the PeerConnectionFactory. - * Use plain pointers in order to avoid threads being destructed before tracks. - */ -static rtc::Thread* NetworkThread; -static rtc::Thread* SignalingThread; -static rtc::Thread* WorkerThread; - -static void createFactory() +void MediaStreamTrackFactory::Create() { - NetworkThread = rtc::Thread::Create().release(); - SignalingThread = rtc::Thread::Create().release(); - WorkerThread = rtc::Thread::Create().release(); + if (Factory) + return; + NetworkThread = rtc::Thread::CreateWithSocketServer(); + WorkerThread = rtc::Thread::Create(); + SignalingThread = rtc::Thread::Create(); NetworkThread->SetName("network_thread", nullptr); SignalingThread->SetName("signaling_thread", nullptr); @@ -45,9 +43,9 @@ static void createFactory() } Factory = webrtc::CreatePeerConnectionFactory( - NetworkThread, - WorkerThread, - SignalingThread, + NetworkThread.get(), + WorkerThread.get(), + SignalingThread.get(), fakeAudioCaptureModule, webrtc::CreateBuiltinAudioEncoderFactory(), webrtc::CreateBuiltinAudioDecoderFactory(), @@ -60,27 +58,61 @@ static void createFactory() { MSC_THROW_ERROR("error ocurred creating peerconnection factory"); } + PeerConnectionOptions.factory = Factory.get(); +} + +void MediaStreamTrackFactory::ReleaseThreads() +{ + if (Factory) + { + PeerConnectionOptions.factory = nullptr; + Factory = nullptr; + } + + if (NetworkThread) + { + NetworkThread->Stop(); + NetworkThread.reset(); + NetworkThread = nullptr; + } + + if (WorkerThread) + { + WorkerThread->Stop(); + WorkerThread.reset(); + WorkerThread = nullptr; + } + + if (SignalingThread) + { + SignalingThread->Stop(); + SignalingThread.reset(); + SignalingThread = nullptr; + } } // Audio track creation. rtc::scoped_refptr createAudioTrack(const std::string& label) { - if (!Factory) - createFactory(); + MediaStreamTrackFactory& singleton = MediaStreamTrackFactory::getInstance(); cricket::AudioOptions options; options.highpass_filter = false; - rtc::scoped_refptr source = Factory->CreateAudioSource(options); + rtc::scoped_refptr source = + singleton.Factory->CreateAudioSource(options); - return Factory->CreateAudioTrack(label, source); + return singleton.Factory->CreateAudioTrack(label, source.get()); } // Video track creation. rtc::scoped_refptr createVideoTrack(const std::string& label) { - if (!Factory) - createFactory(); + MediaStreamTrackFactory& singleton = MediaStreamTrackFactory::getInstance(); - return Factory->CreateVideoTrack(label, webrtc::FakeVideoTrackSource::Create()); + rtc::scoped_refptr source = webrtc::FakeVideoTrackSource::Create(); + + return singleton.Factory->CreateVideoTrack(source, label); } + +#endif // MEDIA_STREAM_TRACK_FACTORY_H diff --git a/test/src/PeerConnection.test.cpp b/test/src/PeerConnection.test.cpp index dbec7dfe..1aba0673 100644 --- a/test/src/PeerConnection.test.cpp +++ b/test/src/PeerConnection.test.cpp @@ -1,5 +1,5 @@ -#include "MediaSoupClientErrors.hpp" #include "PeerConnection.hpp" +#include "MediaSoupClientErrors.hpp" #include "helpers.hpp" #include "sdp/Utils.hpp" #include diff --git a/test/src/RemoteSdp.test.cpp b/test/src/RemoteSdp.test.cpp index cab0a726..efd5cdec 100644 --- a/test/src/RemoteSdp.test.cpp +++ b/test/src/RemoteSdp.test.cpp @@ -1,6 +1,6 @@ +#include "sdp/RemoteSdp.hpp" #include "helpers.hpp" #include "sdptransform.hpp" -#include "sdp/RemoteSdp.hpp" #include TEST_CASE("SendRemoteSdp", "[SendRemoteSdp]") diff --git a/test/src/mediasoupclient.test.cpp b/test/src/mediasoupclient.test.cpp index 7ea32375..0a9c040d 100644 --- a/test/src/mediasoupclient.test.cpp +++ b/test/src/mediasoupclient.test.cpp @@ -1,9 +1,10 @@ +#include "mediasoupclient.hpp" #include "FakeTransportListener.hpp" #include "MediaSoupClientErrors.hpp" #include "MediaStreamTrackFactory.hpp" #include "fakeParameters.hpp" -#include "mediasoupclient.hpp" #include +#include #include TEST_CASE("mediasoupclient", "[mediasoupclient]") @@ -34,6 +35,8 @@ TEST_CASE("mediasoupclient", "[mediasoupclient]") static json routerRtpCapabilities; + MediaStreamTrackFactory& singleton = MediaStreamTrackFactory::getInstance(); + SECTION("create a Device succeeds") { REQUIRE_NOTHROW(device.reset(new mediasoupclient::Device())); @@ -60,7 +63,7 @@ TEST_CASE("mediasoupclient", "[mediasoupclient]") TransportRemoteParameters["iceParameters"], TransportRemoteParameters["iceCandidates"], TransportRemoteParameters["dtlsParameters"], - nullptr), + &singleton.PeerConnectionOptions), MediaSoupClientInvalidStateError); } @@ -132,7 +135,7 @@ TEST_CASE("mediasoupclient", "[mediasoupclient]") TransportRemoteParameters["iceCandidates"], TransportRemoteParameters["dtlsParameters"], TransportRemoteParameters["sctpParameters"], - nullptr, + &singleton.PeerConnectionOptions, appData))); REQUIRE(sendTransport->GetId() == TransportRemoteParameters["id"].get()); @@ -149,7 +152,7 @@ TEST_CASE("mediasoupclient", "[mediasoupclient]") TransportRemoteParameters["iceParameters"], TransportRemoteParameters["iceCandidates"], TransportRemoteParameters["dtlsParameters"], - nullptr))); + &singleton.PeerConnectionOptions))); REQUIRE(recvTransport->GetId() == TransportRemoteParameters["id"].get()); REQUIRE(!recvTransport->IsClosed()); @@ -191,7 +194,7 @@ TEST_CASE("mediasoupclient", "[mediasoupclient]") /* clang-format on */ REQUIRE_NOTHROW(audioProducer.reset(sendTransport->Produce( - &producerListener, audioTrack, nullptr, &codecOptions, nullptr, appData))); + &producerListener, audioTrack.get(), nullptr, &codecOptions, nullptr, appData))); REQUIRE( sendTransportListener.onConnectTimesCalled == @@ -235,7 +238,7 @@ TEST_CASE("mediasoupclient", "[mediasoupclient]") audioProducer->Resume(); REQUIRE_NOTHROW(videoProducer.reset( - sendTransport->Produce(&producerListener, videoTrack, &encodings, nullptr, nullptr))); + sendTransport->Produce(&producerListener, videoTrack.get(), &encodings, nullptr, nullptr))); REQUIRE( sendTransportListener.onConnectTimesCalled == @@ -324,7 +327,7 @@ TEST_CASE("mediasoupclient", "[mediasoupclient]") TransportRemoteParameters["iceParameters"], TransportRemoteParameters["iceCandidates"], TransportRemoteParameters["dtlsParameters"], - nullptr, + &singleton.PeerConnectionOptions, appData))); REQUIRE_THROWS_AS( @@ -647,7 +650,7 @@ TEST_CASE("mediasoupclient", "[mediasoupclient]") auto newAudioTrack = createAudioTrack("audio-track-id-2"); - REQUIRE_NOTHROW(audioProducer->ReplaceTrack(newAudioTrack)); + REQUIRE_NOTHROW(audioProducer->ReplaceTrack(newAudioTrack.get())); REQUIRE(audioProducer->GetTrack() == newAudioTrack); // Producer was already paused. REQUIRE(audioProducer->IsPaused()); @@ -657,7 +660,7 @@ TEST_CASE("mediasoupclient", "[mediasoupclient]") auto newVideoTrack = createVideoTrack("video-track-id-2"); - REQUIRE_NOTHROW(videoProducer->ReplaceTrack(newVideoTrack)); + REQUIRE_NOTHROW(videoProducer->ReplaceTrack(newVideoTrack.get())); REQUIRE(videoProducer->GetTrack() == newVideoTrack); REQUIRE(!videoProducer->IsPaused()); @@ -767,7 +770,7 @@ TEST_CASE("mediasoupclient", "[mediasoupclient]") REQUIRE_THROWS_AS( sendTransport->Produce( &producerListener, - audioTrack, nullptr, nullptr, nullptr), + audioTrack.get(), nullptr, nullptr, nullptr), MediaSoupClientError); } diff --git a/test/src/ortc.test.cpp b/test/src/ortc.test.cpp index ef75536b..5536abfa 100644 --- a/test/src/ortc.test.cpp +++ b/test/src/ortc.test.cpp @@ -1,5 +1,5 @@ -#include "fakeParameters.hpp" #include "ortc.hpp" +#include "fakeParameters.hpp" #include using namespace mediasoupclient;