From 747316760e5f284a5ba4d25bd91656adc833e965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Tue, 13 Feb 2024 15:28:43 +0100 Subject: [PATCH 01/10] m120 --- CMakeLists.txt | 2 +- include/Handler.hpp | 2 +- include/PeerConnection.hpp | 35 ++++++++++- src/Handler.cpp | 19 +++--- src/PeerConnection.cpp | 115 +++++++++++++++++++++++++++++++------ src/sdp/Utils.cpp | 14 ++--- 6 files changed, 149 insertions(+), 38 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b1c097dc..ded4b4b1 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..41cc0ce7 100644 --- a/include/Handler.hpp +++ b/include/Handler.hpp @@ -69,7 +69,7 @@ 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/PeerConnection.hpp b/include/PeerConnection.hpp index 93b81470..f7cee7a3 100644 --- a/include/PeerConnection.hpp +++ b/include/PeerConnection.hpp @@ -48,6 +48,39 @@ 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 +159,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/src/Handler.cpp b/src/Handler.cpp index d2ff7210..aef49c2b 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; @@ -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,7 +517,7 @@ namespace mediasoupclient if (localIdIt == this->mapMidTransceiver.end()) MSC_THROW_ERROR("associated RtpTransceiver not found"); - auto* transceiver = localIdIt->second; + auto transceiver = localIdIt->second; auto parameters = transceiver->sender()->GetParameters(); bool hasLowEncoding{ false }; @@ -583,7 +584,7 @@ namespace mediasoupclient if (localIdIt == this->mapMidTransceiver.end()) MSC_THROW_ERROR("associated RtpTransceiver not found"); - auto* transceiver = localIdIt->second; + auto transceiver = localIdIt->second; auto stats = this->pc->GetStats(transceiver->sender()); return stats; @@ -690,7 +691,7 @@ namespace mediasoupclient auto transceivers = this->pc->GetTransceivers(); auto transceiverIt = std::find_if( - transceivers.begin(), transceivers.end(), [&localId](webrtc::RtpTransceiverInterface* t) { + transceivers.begin(), transceivers.end(), [&localId](rtc::scoped_refptr t) { return t->mid() == localId; }); @@ -705,8 +706,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..aaedcf63 100644 --- a/src/PeerConnection.cpp +++ b/src/PeerConnection.cpp @@ -138,7 +138,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 +179,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 +199,7 @@ namespace mediasoupclient return future.get(); } - this->pc->SetLocalDescription(observer, sessionDescription); + this->pc->SetLocalDescription(std::move(sessionDescription), observer); return future.get(); } @@ -209,14 +209,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 +229,7 @@ namespace mediasoupclient return future.get(); } - this->pc->SetRemoteDescription(observer, sessionDescription); + this->pc->SetRemoteDescription(std::move(sessionDescription), observer); return future.get(); } @@ -317,11 +317,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 +373,10 @@ 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 +385,84 @@ 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 + { + MSC_THROW_ERROR("Failed creating data channel"); + 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 +492,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 +536,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/sdp/Utils.cpp b/src/sdp/Utils.cpp index d8edc4f3..ec2aba51 100644 --- a/src/sdp/Utils.cpp +++ b/src/sdp/Utils.cpp @@ -256,17 +256,17 @@ namespace mediasoupclient { auto& ssrcGroups = *jsonSsrcGroupsIt; - std::find_if( - ssrcGroups.begin(), ssrcGroups.end(), [&firstSsrc, &firstRtxSsrc](const json& line) { + for (const auto& line : ssrcGroups) + { auto jsonSemanticsIt = line.find("semantics"); if (jsonSemanticsIt == line.end() || !jsonSemanticsIt->is_string()) - return false; + continue; auto jsonSsrcsIt = line.find("ssrcs"); if (jsonSsrcsIt == line.end() || !jsonSsrcsIt->is_string()) - return false; + continue; auto v = mediasoupclient::Utils::split(jsonSsrcsIt->get(), ' '); @@ -274,11 +274,11 @@ namespace mediasoupclient { firstRtxSsrc = std::stoull(v[1]); - return true; + break; } - return false; - }); + continue; + }; } jsonSsrcIt = std::find_if(mSsrcs.begin(), mSsrcs.end(), [](const json& line) { From 940bf4c572a81ba398ee0de028d55d11326ededb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Tue, 13 Feb 2024 16:07:38 +0100 Subject: [PATCH 02/10] tests --- .../pc/test/fake_audio_capture_module.cc | 89 ++++++++----------- .../pc/test/fake_audio_capture_module.h | 78 ++++++++-------- test/src/Handler.test.cpp | 8 +- test/src/MediaStreamTrackFactory.cpp | 6 +- test/src/mediasoupclient.test.cpp | 10 +-- 5 files changed, 91 insertions(+), 100 deletions(-) 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/src/Handler.test.cpp b/test/src/Handler.test.cpp index a3591984..ccfbd614 100644 --- a/test/src/Handler.test.cpp +++ b/test/src/Handler.test.cpp @@ -66,7 +66,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 +76,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 +88,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 +122,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; } diff --git a/test/src/MediaStreamTrackFactory.cpp b/test/src/MediaStreamTrackFactory.cpp index 69d0ae69..3a207459 100644 --- a/test/src/MediaStreamTrackFactory.cpp +++ b/test/src/MediaStreamTrackFactory.cpp @@ -73,7 +73,7 @@ rtc::scoped_refptr createAudioTrack(const std::stri rtc::scoped_refptr source = Factory->CreateAudioSource(options); - return Factory->CreateAudioTrack(label, source); + return Factory->CreateAudioTrack(label, source.get()); } // Video track creation. @@ -82,5 +82,7 @@ rtc::scoped_refptr createVideoTrack(const std::stri if (!Factory) createFactory(); - return Factory->CreateVideoTrack(label, webrtc::FakeVideoTrackSource::Create()); + rtc::scoped_refptr source = webrtc::FakeVideoTrackSource::Create(); + + return Factory->CreateVideoTrack(source, label); } diff --git a/test/src/mediasoupclient.test.cpp b/test/src/mediasoupclient.test.cpp index 7ea32375..93e9056c 100644 --- a/test/src/mediasoupclient.test.cpp +++ b/test/src/mediasoupclient.test.cpp @@ -191,7 +191,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 +235,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 == @@ -647,7 +647,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 +657,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 +767,7 @@ TEST_CASE("mediasoupclient", "[mediasoupclient]") REQUIRE_THROWS_AS( sendTransport->Produce( &producerListener, - audioTrack, nullptr, nullptr, nullptr), + audioTrack.get(), nullptr, nullptr, nullptr), MediaSoupClientError); } From 5f8c6e2910e2a7ca17f11b0abec4a7c4dd3cc5ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Tue, 13 Feb 2024 16:26:19 +0100 Subject: [PATCH 03/10] add missing new line --- include/PeerConnection.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/PeerConnection.hpp b/include/PeerConnection.hpp index f7cee7a3..e102ec95 100644 --- a/include/PeerConnection.hpp +++ b/include/PeerConnection.hpp @@ -81,6 +81,7 @@ namespace mediasoupclient private: std::promise promise; }; + class SetSessionDescriptionObserver : public webrtc::SetSessionDescriptionObserver { public: From 2afd24262265fd8a4d5d3aadebb99477b597aea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 21 Feb 2024 17:01:10 +0100 Subject: [PATCH 04/10] cont. --- src/PeerConnection.cpp | 4 +++- test/CMakeLists.txt | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/PeerConnection.cpp b/src/PeerConnection.cpp index aaedcf63..64976cc7 100644 --- a/src/PeerConnection.cpp +++ b/src/PeerConnection.cpp @@ -92,7 +92,9 @@ namespace mediasoupclient this->peerConnectionFactory = webrtc::CreatePeerConnectionFactory( this->networkThread.get(), - this->workerThread.get(), + // TMP: Use the same thread for signaling and worker. + // this->workerThread.get(), + this->signalingThread.get(), this->signalingThread.get(), nullptr /*default_adm*/, webrtc::CreateBuiltinAudioEncoderFactory(), 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} ) From f8c73fc8401f83e526e4f02a6e88c3f5e31e379a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 21 Feb 2024 17:09:10 +0100 Subject: [PATCH 05/10] cont. --- src/PeerConnection.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/PeerConnection.cpp b/src/PeerConnection.cpp index 64976cc7..7f43a7ef 100644 --- a/src/PeerConnection.cpp +++ b/src/PeerConnection.cpp @@ -423,7 +423,6 @@ namespace mediasoupclient } else { - MSC_THROW_ERROR("Failed creating data channel"); this->promise.set_value(); } }; From 1ced31748f6ca631df6fc898314266431f8a528c Mon Sep 17 00:00:00 2001 From: janreyho Date: Wed, 19 Jun 2024 16:23:00 +0800 Subject: [PATCH 06/10] =?UTF-8?q?upgrade=20to=20webrtc=20m120-6099?= =?UTF-8?q?=E3=80=82=20(#179)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * upgrade to webrtc m120-6099。 You can successfully enter the room, publish the video stream。 On mac m3max test OK。 * Create a singleton class for createFactory and ReleaseThreads --- .gitignore | 2 + src/PeerConnection.cpp | 25 ++++- test/include/MediaStreamTrackFactory.hpp | 50 +++++++++ test/src/Handler.test.cpp | 17 +-- test/src/MediaStreamTrackFactory.cpp | 127 ++++++++++++++--------- test/src/mediasoupclient.test.cpp | 16 ++- 6 files changed, 177 insertions(+), 60 deletions(-) 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/src/PeerConnection.cpp b/src/PeerConnection.cpp index 7f43a7ef..df82a44f 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 @@ -99,8 +112,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*/); } diff --git a/test/include/MediaStreamTrackFactory.hpp b/test/include/MediaStreamTrackFactory.hpp index ecd63613..906fdc7e 100644 --- a/test/include/MediaStreamTrackFactory.hpp +++ b/test/include/MediaStreamTrackFactory.hpp @@ -2,6 +2,56 @@ #define MSC_TEST_MEDIA_STREAM_TRACK_FACTORY_HPP #include "api/media_stream_interface.h" +#include "MediaStreamTrackFactory.hpp" +#include "MediaSoupClientErrors.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/video_codecs/builtin_video_decoder_factory.h" +#include "api/video_codecs/builtin_video_encoder_factory.h" +#include "pc/test/fake_audio_capture_module.h" +#include "pc/test/fake_video_track_source.h" +#include "mediasoupclient.hpp" +#include + + +class Singleton { +public: + static Singleton& getInstance() { + static Singleton instance; // 唯一实例 + return instance; + } + + // 防止拷贝和赋值 + Singleton(const Singleton&) = delete; + Singleton& operator=(const Singleton&) = delete; + + void createFactory(); + + void ReleaseThreads(); + + + rtc::scoped_refptr Factory; + mediasoupclient::PeerConnection::Options PeerConnectionOptions; + +private: + Singleton() { + std::cout << "Singleton created\n"; + createFactory(); + } + ~Singleton() { + std::cout << "Singleton destroyed\n"; + 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 ccfbd614..e9135a96 100644 --- a/test/src/Handler.test.cpp +++ b/test/src/Handler.test.cpp @@ -9,7 +9,6 @@ static const json TransportRemoteParameters = generateTransportRemoteParameters(); static const json RtpParametersByKind = generateRtpParametersByKind(); -static mediasoupclient::PeerConnection::Options PeerConnectionOptions; class FakeHandlerListener : public mediasoupclient::Handler::PrivateListener { @@ -22,11 +21,12 @@ class FakeHandlerListener : public mediasoupclient::Handler::PrivateListener TEST_CASE("Handler", "[Handler]") { + Singleton& singleton = Singleton::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 +37,7 @@ TEST_CASE("Handler", "[Handler]") TEST_CASE("SendHandler", "[Handler][SendHandler]") { static FakeHandlerListener handlerListener; + Singleton& singleton = Singleton::getInstance(); static mediasoupclient::SendHandler sendHandler( &handlerListener, @@ -44,12 +45,12 @@ 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 std::unique_ptr pc( + // new mediasoupclient::PeerConnection(nullptr, &PeerConnectionOptions)); static rtc::scoped_refptr track; @@ -142,6 +143,8 @@ TEST_CASE("SendHandler", "[Handler][SendHandler]") SECTION("sendHandler.UpdateIceServers() succeeds") { REQUIRE_NOTHROW(sendHandler.UpdateIceServers(json::array())); + sendHandler.Close(); + // context = nullptr; } } @@ -156,6 +159,7 @@ TEST_CASE("RecvHandler", "[Handler][RecvHandler]") static std::string localId; static FakeHandlerListener handlerListener; + Singleton& singleton = Singleton::getInstance(); static mediasoupclient::RecvHandler recvHandler( &handlerListener, @@ -163,7 +167,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 +208,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 3a207459..efdf773c 100644 --- a/test/src/MediaStreamTrackFactory.cpp +++ b/test/src/MediaStreamTrackFactory.cpp @@ -1,3 +1,6 @@ +#ifndef SINGLETON_H +#define SINGLETON_H + #define MSC_CLASS "MediaStreamTrackFactory" #include "MediaStreamTrackFactory.hpp" @@ -9,80 +12,108 @@ #include "api/video_codecs/builtin_video_encoder_factory.h" #include "pc/test/fake_audio_capture_module.h" #include "pc/test/fake_video_track_source.h" +#include "mediasoupclient.hpp" +#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() -{ - NetworkThread = rtc::Thread::Create().release(); - SignalingThread = rtc::Thread::Create().release(); - WorkerThread = rtc::Thread::Create().release(); - NetworkThread->SetName("network_thread", nullptr); - SignalingThread->SetName("signaling_thread", nullptr); - WorkerThread->SetName("worker_thread", nullptr); - if (!NetworkThread->Start() || !SignalingThread->Start() || !WorkerThread->Start()) + void Singleton::createFactory() { - MSC_THROW_INVALID_STATE_ERROR("thread start errored"); + 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); + WorkerThread->SetName("worker_thread", nullptr); + + if (!NetworkThread->Start() || !SignalingThread->Start() || !WorkerThread->Start()) + { + MSC_THROW_INVALID_STATE_ERROR("thread start errored"); + } + + webrtc::PeerConnectionInterface::RTCConfiguration config; + + auto fakeAudioCaptureModule = FakeAudioCaptureModule::Create(); + if (!fakeAudioCaptureModule) + { + MSC_THROW_INVALID_STATE_ERROR("audio capture module creation errored"); + } + + Factory = webrtc::CreatePeerConnectionFactory( + NetworkThread.get(), + WorkerThread.get(), + SignalingThread.get(), + fakeAudioCaptureModule, + webrtc::CreateBuiltinAudioEncoderFactory(), + webrtc::CreateBuiltinAudioDecoderFactory(), + webrtc::CreateBuiltinVideoEncoderFactory(), + webrtc::CreateBuiltinVideoDecoderFactory(), + nullptr /*audio_mixer*/, + nullptr /*audio_processing*/); + + if (!Factory) + { + MSC_THROW_ERROR("error ocurred creating peerconnection factory"); + } + PeerConnectionOptions.factory = Factory.get(); } - webrtc::PeerConnectionInterface::RTCConfiguration config; + void Singleton::ReleaseThreads() { + // 调用 reset 函数以释放资源 + if (Factory) { + // Factory->Release(); + 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; + // } - auto fakeAudioCaptureModule = FakeAudioCaptureModule::Create(); - if (!fakeAudioCaptureModule) - { - MSC_THROW_INVALID_STATE_ERROR("audio capture module creation errored"); } - Factory = webrtc::CreatePeerConnectionFactory( - NetworkThread, - WorkerThread, - SignalingThread, - fakeAudioCaptureModule, - webrtc::CreateBuiltinAudioEncoderFactory(), - webrtc::CreateBuiltinAudioDecoderFactory(), - webrtc::CreateBuiltinVideoEncoderFactory(), - webrtc::CreateBuiltinVideoDecoderFactory(), - nullptr /*audio_mixer*/, - nullptr /*audio_processing*/); - - if (!Factory) - { - MSC_THROW_ERROR("error ocurred creating peerconnection factory"); - } -} + + // Audio track creation. rtc::scoped_refptr createAudioTrack(const std::string& label) { - if (!Factory) - createFactory(); + Singleton& singleton = Singleton::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.get()); + return singleton.Factory->CreateAudioTrack(label, source.get()); } // Video track creation. rtc::scoped_refptr createVideoTrack(const std::string& label) { - if (!Factory) - createFactory(); + Singleton& singleton = Singleton::getInstance(); rtc::scoped_refptr source = webrtc::FakeVideoTrackSource::Create(); - return Factory->CreateVideoTrack(source, label); + return singleton.Factory->CreateVideoTrack(source, label); } + +#endif // SINGLETON_H \ No newline at end of file diff --git a/test/src/mediasoupclient.test.cpp b/test/src/mediasoupclient.test.cpp index 93e9056c..116b0501 100644 --- a/test/src/mediasoupclient.test.cpp +++ b/test/src/mediasoupclient.test.cpp @@ -5,6 +5,9 @@ #include "mediasoupclient.hpp" #include #include +#include + + TEST_CASE("mediasoupclient", "[mediasoupclient]") { @@ -34,6 +37,8 @@ TEST_CASE("mediasoupclient", "[mediasoupclient]") static json routerRtpCapabilities; + Singleton& singleton = Singleton::getInstance(); + SECTION("create a Device succeeds") { REQUIRE_NOTHROW(device.reset(new mediasoupclient::Device())); @@ -49,6 +54,7 @@ TEST_CASE("mediasoupclient", "[mediasoupclient]") { REQUIRE_THROWS_AS(device->CanProduce("audio"), MediaSoupClientInvalidStateError); REQUIRE_THROWS_AS(device->CanProduce("video"), MediaSoupClientInvalidStateError); + } SECTION("device.CreateSendTransport() throws if not loaded") @@ -60,7 +66,7 @@ TEST_CASE("mediasoupclient", "[mediasoupclient]") TransportRemoteParameters["iceParameters"], TransportRemoteParameters["iceCandidates"], TransportRemoteParameters["dtlsParameters"], - nullptr), + &singleton.PeerConnectionOptions), MediaSoupClientInvalidStateError); } @@ -132,7 +138,7 @@ TEST_CASE("mediasoupclient", "[mediasoupclient]") TransportRemoteParameters["iceCandidates"], TransportRemoteParameters["dtlsParameters"], TransportRemoteParameters["sctpParameters"], - nullptr, + &singleton.PeerConnectionOptions, appData))); REQUIRE(sendTransport->GetId() == TransportRemoteParameters["id"].get()); @@ -149,7 +155,7 @@ TEST_CASE("mediasoupclient", "[mediasoupclient]") TransportRemoteParameters["iceParameters"], TransportRemoteParameters["iceCandidates"], TransportRemoteParameters["dtlsParameters"], - nullptr))); + &singleton.PeerConnectionOptions))); REQUIRE(recvTransport->GetId() == TransportRemoteParameters["id"].get()); REQUIRE(!recvTransport->IsClosed()); @@ -324,7 +330,7 @@ TEST_CASE("mediasoupclient", "[mediasoupclient]") TransportRemoteParameters["iceParameters"], TransportRemoteParameters["iceCandidates"], TransportRemoteParameters["dtlsParameters"], - nullptr, + &singleton.PeerConnectionOptions, appData))); REQUIRE_THROWS_AS( @@ -809,5 +815,7 @@ TEST_CASE("mediasoupclient", "[mediasoupclient]") REQUIRE_THROWS_AS( sendTransport->UpdateIceServers(iceServers), MediaSoupClientError); + + // context = nullptr; } } From 2d46309c7b84c2e4d994096eb8a7f6c94ba8253d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 19 Jun 2024 10:39:38 +0200 Subject: [PATCH 07/10] format, comments --- test/include/MediaStreamTrackFactory.hpp | 28 ++++++------- test/src/Handler.test.cpp | 10 ++--- test/src/MediaStreamTrackFactory.cpp | 51 ++++++++++++------------ test/src/mediasoupclient.test.cpp | 4 +- 4 files changed, 42 insertions(+), 51 deletions(-) diff --git a/test/include/MediaStreamTrackFactory.hpp b/test/include/MediaStreamTrackFactory.hpp index 906fdc7e..cc60e2f3 100644 --- a/test/include/MediaStreamTrackFactory.hpp +++ b/test/include/MediaStreamTrackFactory.hpp @@ -15,18 +15,17 @@ #include -class Singleton { +class MediaStreamTrackFactory { public: - static Singleton& getInstance() { - static Singleton instance; // 唯一实例 + static MediaStreamTrackFactory& getInstance() { + static MediaStreamTrackFactory instance; return instance; } - // 防止拷贝和赋值 - Singleton(const Singleton&) = delete; - Singleton& operator=(const Singleton&) = delete; + MediaStreamTrackFactory(const MediaStreamTrackFactory&) = delete; + MediaStreamTrackFactory& operator=(const MediaStreamTrackFactory&) = delete; - void createFactory(); + void Create(); void ReleaseThreads(); @@ -35,18 +34,17 @@ class Singleton { mediasoupclient::PeerConnection::Options PeerConnectionOptions; private: - Singleton() { - std::cout << "Singleton created\n"; - createFactory(); + MediaStreamTrackFactory() { + Create(); } - ~Singleton() { - std::cout << "Singleton destroyed\n"; + ~MediaStreamTrackFactory() { ReleaseThreads(); } - /* MediaStreamTrack holds reference to the threads of the PeerConnectionFactory. - * Use plain pointers in order to avoid threads being destructed before tracks. - */ + /** + * 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; diff --git a/test/src/Handler.test.cpp b/test/src/Handler.test.cpp index e9135a96..98f23f48 100644 --- a/test/src/Handler.test.cpp +++ b/test/src/Handler.test.cpp @@ -21,7 +21,7 @@ class FakeHandlerListener : public mediasoupclient::Handler::PrivateListener TEST_CASE("Handler", "[Handler]") { - Singleton& singleton = Singleton::getInstance(); + MediaStreamTrackFactory& singleton = MediaStreamTrackFactory::getInstance(); SECTION("Handler::GetNativeRtpCapabilities() succeeds") { json rtpCapabilities; @@ -37,7 +37,7 @@ TEST_CASE("Handler", "[Handler]") TEST_CASE("SendHandler", "[Handler][SendHandler]") { static FakeHandlerListener handlerListener; - Singleton& singleton = Singleton::getInstance(); + MediaStreamTrackFactory& singleton = MediaStreamTrackFactory::getInstance(); static mediasoupclient::SendHandler sendHandler( &handlerListener, @@ -49,9 +49,6 @@ TEST_CASE("SendHandler", "[Handler][SendHandler]") RtpParametersByKind, RtpParametersByKind); - // static std::unique_ptr pc( - // new mediasoupclient::PeerConnection(nullptr, &PeerConnectionOptions)); - static rtc::scoped_refptr track; static std::string localId; @@ -144,7 +141,6 @@ TEST_CASE("SendHandler", "[Handler][SendHandler]") { REQUIRE_NOTHROW(sendHandler.UpdateIceServers(json::array())); sendHandler.Close(); - // context = nullptr; } } @@ -159,7 +155,7 @@ TEST_CASE("RecvHandler", "[Handler][RecvHandler]") static std::string localId; static FakeHandlerListener handlerListener; - Singleton& singleton = Singleton::getInstance(); + MediaStreamTrackFactory& singleton = MediaStreamTrackFactory::getInstance(); static mediasoupclient::RecvHandler recvHandler( &handlerListener, diff --git a/test/src/MediaStreamTrackFactory.cpp b/test/src/MediaStreamTrackFactory.cpp index efdf773c..ad90ae27 100644 --- a/test/src/MediaStreamTrackFactory.cpp +++ b/test/src/MediaStreamTrackFactory.cpp @@ -1,5 +1,5 @@ -#ifndef SINGLETON_H -#define SINGLETON_H +#ifndef MEDIA_STREAM_TRACK_FACTORY_H +#define MEDIA_STREAM_TRACK_FACTORY_H #define MSC_CLASS "MediaStreamTrackFactory" @@ -19,7 +19,7 @@ using namespace mediasoupclient; - void Singleton::createFactory() + void MediaStreamTrackFactory::Create() { if(Factory) return; @@ -63,30 +63,29 @@ using namespace mediasoupclient; PeerConnectionOptions.factory = Factory.get(); } - void Singleton::ReleaseThreads() { - // 调用 reset 函数以释放资源 + void MediaStreamTrackFactory::ReleaseThreads() { if (Factory) { - // Factory->Release(); 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; - // } + + if (NetworkThread) { + NetworkThread->Stop(); + NetworkThread.reset(); + NetworkThread = nullptr; + } + + if (WorkerThread) { + WorkerThread->Stop(); + WorkerThread.reset(); + WorkerThread = nullptr; + } + + if (SignalingThread) { + SignalingThread->Stop(); + SignalingThread.reset(); + SignalingThread = nullptr; + } } @@ -96,7 +95,7 @@ using namespace mediasoupclient; // Audio track creation. rtc::scoped_refptr createAudioTrack(const std::string& label) { - Singleton& singleton = Singleton::getInstance(); + MediaStreamTrackFactory& singleton = MediaStreamTrackFactory::getInstance(); cricket::AudioOptions options; options.highpass_filter = false; @@ -109,11 +108,11 @@ rtc::scoped_refptr createAudioTrack(const std::stri // Video track creation. rtc::scoped_refptr createVideoTrack(const std::string& label) { - Singleton& singleton = Singleton::getInstance(); + MediaStreamTrackFactory& singleton = MediaStreamTrackFactory::getInstance(); rtc::scoped_refptr source = webrtc::FakeVideoTrackSource::Create(); return singleton.Factory->CreateVideoTrack(source, label); } -#endif // SINGLETON_H \ No newline at end of file +#endif // MEDIA_STREAM_TRACK_FACTORY_H diff --git a/test/src/mediasoupclient.test.cpp b/test/src/mediasoupclient.test.cpp index 116b0501..1427a44e 100644 --- a/test/src/mediasoupclient.test.cpp +++ b/test/src/mediasoupclient.test.cpp @@ -37,7 +37,7 @@ TEST_CASE("mediasoupclient", "[mediasoupclient]") static json routerRtpCapabilities; - Singleton& singleton = Singleton::getInstance(); + MediaStreamTrackFactory& singleton = MediaStreamTrackFactory::getInstance(); SECTION("create a Device succeeds") { @@ -815,7 +815,5 @@ TEST_CASE("mediasoupclient", "[mediasoupclient]") REQUIRE_THROWS_AS( sendTransport->UpdateIceServers(iceServers), MediaSoupClientError); - - // context = nullptr; } } From 780c21592fa99a478ca7ef3f0db2adf2a10da758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 19 Jun 2024 10:45:55 +0200 Subject: [PATCH 08/10] tidy --- include/Handler.hpp | 5 +- include/Logger.hpp | 2 +- package.json | 3 +- src/Handler.cpp | 25 ++--- src/PeerConnection.cpp | 31 +++--- src/Transport.cpp | 3 +- src/ortc.cpp | 66 +++++++----- src/sdp/MediaSection.cpp | 16 +-- src/sdp/RemoteSdp.cpp | 6 +- src/sdp/Utils.cpp | 92 +++++++++------- test/include/MediaStreamTrackFactory.hpp | 39 +++---- test/src/Handler.test.cpp | 5 +- test/src/MediaStreamTrackFactory.cpp | 132 +++++++++++------------ test/src/PeerConnection.test.cpp | 2 +- test/src/RemoteSdp.test.cpp | 2 +- test/src/mediasoupclient.test.cpp | 7 +- test/src/ortc.test.cpp | 2 +- 17 files changed, 235 insertions(+), 203 deletions(-) diff --git a/include/Handler.hpp b/include/Handler.hpp index 41cc0ce7..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/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 aef49c2b..139da1d7 100644 --- a/src/Handler.cpp +++ b/src/Handler.cpp @@ -414,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()) { @@ -518,7 +518,7 @@ namespace mediasoupclient MSC_THROW_ERROR("associated RtpTransceiver not found"); auto transceiver = localIdIt->second; - auto parameters = transceiver->sender()->GetParameters(); + auto parameters = transceiver->sender()->GetParameters(); bool hasLowEncoding{ false }; bool hasMediumEncoding{ false }; @@ -585,7 +585,7 @@ namespace mediasoupclient MSC_THROW_ERROR("associated RtpTransceiver not found"); auto transceiver = localIdIt->second; - auto stats = this->pc->GetStats(transceiver->sender()); + auto stats = this->pc->GetStats(transceiver->sender()); return stats; } @@ -668,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; @@ -691,9 +691,10 @@ namespace mediasoupclient auto transceivers = this->pc->GetTransceivers(); auto transceiverIt = std::find_if( - transceivers.begin(), transceivers.end(), [&localId](rtc::scoped_refptr 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"); diff --git a/src/PeerConnection.cpp b/src/PeerConnection.cpp index df82a44f..efce101c 100644 --- a/src/PeerConnection.cpp +++ b/src/PeerConnection.cpp @@ -113,15 +113,15 @@ namespace mediasoupclient webrtc::CreateBuiltinAudioEncoderFactory(), webrtc::CreateBuiltinAudioDecoderFactory(), std::make_unique>(), + webrtc::LibvpxVp8EncoderTemplateAdapter, + webrtc::LibvpxVp9EncoderTemplateAdapter, + webrtc::OpenH264EncoderTemplateAdapter, + webrtc::LibaomAv1EncoderTemplateAdapter>>(), std::make_unique>(), + webrtc::LibvpxVp8DecoderTemplateAdapter, + webrtc::LibvpxVp9DecoderTemplateAdapter, + webrtc::OpenH264DecoderTemplateAdapter, + webrtc::Dav1dDecoderTemplateAdapter>>(), nullptr /*audio_mixer*/, nullptr /*audio_processing*/); } @@ -396,8 +396,7 @@ namespace mediasoupclient { MSC_TRACE(); - const auto result = - this->pc->CreateDataChannelOrError(label, config); + const auto result = this->pc->CreateDataChannelOrError(label, config); if (result.ok()) { @@ -434,9 +433,9 @@ namespace mediasoupclient if (!error.ok()) { MSC_WARN( - "webtc::SetLocalDescriptionObserver failure [%s:%s]", - webrtc::ToString(error.type()).data(), - error.message()); + "webtc::SetLocalDescriptionObserver failure [%s:%s]", + webrtc::ToString(error.type()).data(), + error.message()); auto message = std::string(error.message()); @@ -471,9 +470,9 @@ namespace mediasoupclient if (!error.ok()) { MSC_WARN( - "webtc::SetRemoteDescriptionObserver failure [%s:%s]", - webrtc::ToString(error.type()).data(), - error.message()); + "webtc::SetRemoteDescriptionObserver failure [%s:%s]", + 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 c44519ba..c8d6d592 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 ec2aba51..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"); + 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; + if (jsonAttributeIt == line.end() || !jsonAttributeIt->is_string()) + return false; - return jsonAttributeIt->get() == "msid"; - }); + return jsonAttributeIt->get() == "msid"; + }); if (jsonSsrcIt == mSsrcs.end()) { @@ -258,40 +262,44 @@ namespace mediasoupclient for (const auto& line : ssrcGroups) { - auto jsonSemanticsIt = line.find("semantics"); + auto jsonSemanticsIt = line.find("semantics"); - if (jsonSemanticsIt == line.end() || !jsonSemanticsIt->is_string()) - continue; + 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()) - continue; + 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]); - break; - } + break; + } - continue; - }; + 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/include/MediaStreamTrackFactory.hpp b/test/include/MediaStreamTrackFactory.hpp index cc60e2f3..509cb313 100644 --- a/test/include/MediaStreamTrackFactory.hpp +++ b/test/include/MediaStreamTrackFactory.hpp @@ -1,45 +1,47 @@ #ifndef MSC_TEST_MEDIA_STREAM_TRACK_FACTORY_HPP #define MSC_TEST_MEDIA_STREAM_TRACK_FACTORY_HPP -#include "api/media_stream_interface.h" -#include "MediaStreamTrackFactory.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 "mediasoupclient.hpp" #include - -class MediaStreamTrackFactory { +class MediaStreamTrackFactory +{ public: - static MediaStreamTrackFactory& getInstance() { - static MediaStreamTrackFactory instance; - return instance; - } + static MediaStreamTrackFactory& getInstance() + { + static MediaStreamTrackFactory instance; + return instance; + } - MediaStreamTrackFactory(const MediaStreamTrackFactory&) = delete; - MediaStreamTrackFactory& operator=(const MediaStreamTrackFactory&) = delete; + 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(); - } + MediaStreamTrackFactory() + { + Create(); + } + ~MediaStreamTrackFactory() + { + ReleaseThreads(); + } /** * MediaStreamTrack holds reference to the threads of the PeerConnectionFactory. @@ -50,7 +52,6 @@ class MediaStreamTrackFactory { std::unique_ptr SignalingThread; }; - rtc::scoped_refptr createAudioTrack(const std::string& label); rtc::scoped_refptr createVideoTrack(const std::string& label); diff --git a/test/src/Handler.test.cpp b/test/src/Handler.test.cpp index 98f23f48..19632cf2 100644 --- a/test/src/Handler.test.cpp +++ b/test/src/Handler.test.cpp @@ -9,7 +9,6 @@ static const json TransportRemoteParameters = generateTransportRemoteParameters(); static const json RtpParametersByKind = generateRtpParametersByKind(); - class FakeHandlerListener : public mediasoupclient::Handler::PrivateListener { public: @@ -26,7 +25,9 @@ TEST_CASE("Handler", "[Handler]") { json rtpCapabilities; - REQUIRE_NOTHROW(rtpCapabilities = mediasoupclient::Handler::GetNativeRtpCapabilities(&singleton.PeerConnectionOptions)); + REQUIRE_NOTHROW( + rtpCapabilities = + mediasoupclient::Handler::GetNativeRtpCapabilities(&singleton.PeerConnectionOptions)); REQUIRE(rtpCapabilities["codecs"].is_array()); REQUIRE(rtpCapabilities["fecMechanisms"].is_array()); diff --git a/test/src/MediaStreamTrackFactory.cpp b/test/src/MediaStreamTrackFactory.cpp index ad90ae27..b974c5b3 100644 --- a/test/src/MediaStreamTrackFactory.cpp +++ b/test/src/MediaStreamTrackFactory.cpp @@ -10,87 +10,86 @@ #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 "mediasoupclient.hpp" #include using namespace mediasoupclient; +void MediaStreamTrackFactory::Create() +{ + 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); + WorkerThread->SetName("worker_thread", nullptr); - void MediaStreamTrackFactory::Create() + if (!NetworkThread->Start() || !SignalingThread->Start() || !WorkerThread->Start()) { - 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); - WorkerThread->SetName("worker_thread", nullptr); - - if (!NetworkThread->Start() || !SignalingThread->Start() || !WorkerThread->Start()) - { - MSC_THROW_INVALID_STATE_ERROR("thread start errored"); - } - - webrtc::PeerConnectionInterface::RTCConfiguration config; - - auto fakeAudioCaptureModule = FakeAudioCaptureModule::Create(); - if (!fakeAudioCaptureModule) - { - MSC_THROW_INVALID_STATE_ERROR("audio capture module creation errored"); - } - - Factory = webrtc::CreatePeerConnectionFactory( - NetworkThread.get(), - WorkerThread.get(), - SignalingThread.get(), - fakeAudioCaptureModule, - webrtc::CreateBuiltinAudioEncoderFactory(), - webrtc::CreateBuiltinAudioDecoderFactory(), - webrtc::CreateBuiltinVideoEncoderFactory(), - webrtc::CreateBuiltinVideoDecoderFactory(), - nullptr /*audio_mixer*/, - nullptr /*audio_processing*/); - - if (!Factory) - { - MSC_THROW_ERROR("error ocurred creating peerconnection factory"); - } - PeerConnectionOptions.factory = Factory.get(); + MSC_THROW_INVALID_STATE_ERROR("thread start errored"); } - 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; - } + webrtc::PeerConnectionInterface::RTCConfiguration config; + auto fakeAudioCaptureModule = FakeAudioCaptureModule::Create(); + if (!fakeAudioCaptureModule) + { + MSC_THROW_INVALID_STATE_ERROR("audio capture module creation errored"); } + Factory = webrtc::CreatePeerConnectionFactory( + NetworkThread.get(), + WorkerThread.get(), + SignalingThread.get(), + fakeAudioCaptureModule, + webrtc::CreateBuiltinAudioEncoderFactory(), + webrtc::CreateBuiltinAudioDecoderFactory(), + webrtc::CreateBuiltinVideoEncoderFactory(), + webrtc::CreateBuiltinVideoDecoderFactory(), + nullptr /*audio_mixer*/, + nullptr /*audio_processing*/); + + if (!Factory) + { + 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) @@ -100,7 +99,8 @@ rtc::scoped_refptr createAudioTrack(const std::stri cricket::AudioOptions options; options.highpass_filter = false; - rtc::scoped_refptr source = singleton.Factory->CreateAudioSource(options); + rtc::scoped_refptr source = + singleton.Factory->CreateAudioSource(options); return singleton.Factory->CreateAudioTrack(label, source.get()); } 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 1427a44e..0a9c040d 100644 --- a/test/src/mediasoupclient.test.cpp +++ b/test/src/mediasoupclient.test.cpp @@ -1,13 +1,11 @@ +#include "mediasoupclient.hpp" #include "FakeTransportListener.hpp" #include "MediaSoupClientErrors.hpp" #include "MediaStreamTrackFactory.hpp" #include "fakeParameters.hpp" -#include "mediasoupclient.hpp" #include -#include #include - - +#include TEST_CASE("mediasoupclient", "[mediasoupclient]") { @@ -54,7 +52,6 @@ TEST_CASE("mediasoupclient", "[mediasoupclient]") { REQUIRE_THROWS_AS(device->CanProduce("audio"), MediaSoupClientInvalidStateError); REQUIRE_THROWS_AS(device->CanProduce("video"), MediaSoupClientInvalidStateError); - } SECTION("device.CreateSendTransport() throws if not loaded") 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; From 35d663964024b165a9693b266c22847f14f21385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 19 Jun 2024 11:00:04 +0200 Subject: [PATCH 09/10] remove temporal change --- src/PeerConnection.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/PeerConnection.cpp b/src/PeerConnection.cpp index efce101c..52804371 100644 --- a/src/PeerConnection.cpp +++ b/src/PeerConnection.cpp @@ -105,9 +105,7 @@ namespace mediasoupclient this->peerConnectionFactory = webrtc::CreatePeerConnectionFactory( this->networkThread.get(), - // TMP: Use the same thread for signaling and worker. - // this->workerThread.get(), - this->signalingThread.get(), + this->workerThread.get(), this->signalingThread.get(), nullptr /*default_adm*/, webrtc::CreateBuiltinAudioEncoderFactory(), From 5429fb1d19b2ab9daff37ab0043a5c034ccea5a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Mill=C3=A1n?= Date: Wed, 19 Jun 2024 11:09:49 +0200 Subject: [PATCH 10/10] Update: CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) 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.