diff --git a/.github/workflows/peerconnection-test.yml b/.github/workflows/peerconnection-test.yml index 5d24d17..f72e62d 100644 --- a/.github/workflows/peerconnection-test.yml +++ b/.github/workflows/peerconnection-test.yml @@ -151,7 +151,7 @@ jobs: - name: Replace Peer Connection Test Results in README run: | - # Read the new content from DPeerConnection_test_results.md + # Read the new content from PeerConnection_test_results.md new_content="$(CreatePeerConnection(http_req_buffer, http_req_body_len); + std::string answer = _pcFactory->CreatePeerConnection(http_req_buffer, http_req_body_len); + std::cout << "Answer: " << answer << std::endl; evhttp_add_header(req->output_headers, "Content-type", "application/json"); - evbuffer_add_printf(resp_buffer, answer.c_str()); + evbuffer_add_printf(resp_buffer, "%s", answer.c_str()); evhttp_send_reply(req, 200, "OK", resp_buffer); } else { diff --git a/libwebrtc/HttpSimpleServer.h b/libwebrtc/HttpSimpleServer.h old mode 100644 new mode 100755 index ec3f6c4..4499b1a --- a/libwebrtc/HttpSimpleServer.h +++ b/libwebrtc/HttpSimpleServer.h @@ -10,6 +10,7 @@ * * History: * 08 Mar 2021 Aaron Clauson Created, Dublin, Ireland. +* 21 Dec 2024 Aaron Clauson Updated for libwebrtc version m132. * * License: Public Domain (no warranty, use at own risk) /******************************************************************************/ @@ -47,7 +48,6 @@ class HttpSimpleServer event_base* _evtBase; evhttp* _httpSvr; event* _signalEvent; - std::thread _httpSvrThread; bool _isDisposed; static PcFactory* _pcFactory; diff --git a/libwebrtc/PcFactory.cpp b/libwebrtc/PcFactory.cpp old mode 100644 new mode 100755 index 573f639..a1bf6e3 --- a/libwebrtc/PcFactory.cpp +++ b/libwebrtc/PcFactory.cpp @@ -8,6 +8,7 @@ * * History: * 08 Mar 2021 Aaron Clauson Created, Dublin, Ireland. +* 21 Dec 2024 Aaron Clauson Updated for libwebrtc version m132. * * License: Public Domain (no warranty, use at own risk) /******************************************************************************/ @@ -15,6 +16,10 @@ #include "PcFactory.h" #include "json.hpp" +#include "api/audio/audio_processing.h" +#include "api/audio/builtin_audio_processing_builder.h" +#include "api/environment/environment.h" +#include "api/environment/environment_factory.h" #include "api/audio_codecs/audio_decoder_factory_template.h" #include "api/audio_codecs/audio_encoder_factory_template.h" #include @@ -32,72 +37,40 @@ #include #include #include +#include "api/enable_media.h" +#include "fake_audio_capture_module.h" #include #include +// Number of seconds to wait for the remote SDP offer to be set on the peer connection. +#define SET_REMOTE_SDP_TIMEOUT_SECONDS 3 + PcFactory::PcFactory() : _peerConnections() -{ - //webrtc::PeerConnectionFactoryDependencies _pcf_deps; - //_pcf_deps.task_queue_factory = webrtc::CreateDefaultTaskQueueFactory(); - //_pcf_deps.signaling_thread = rtc::Thread::Create().release(); - //_pcf_deps.network_thread = rtc::Thread::CreateWithSocketServer().release(); - //_pcf_deps.worker_thread = rtc::Thread::Create().release(); - //_pcf_deps.call_factory = webrtc::CreateCallFactory(); - //_pcf_deps.event_log_factory = std::make_unique( - //_pcf_deps.task_queue_factory.get()); - - //cricket::MediaEngineDependencies media_deps; - //media_deps.task_queue_factory = _pcf_deps.task_queue_factory.get(); - //media_deps.adm = webrtc::AudioDeviceModule::CreateForTest( - // webrtc::AudioDeviceModule::kDummyAudio, _pcf_deps.task_queue_factory.get()); - //media_deps.audio_encoder_factory = - // webrtc::CreateAudioEncoderFactory(); - //media_deps.audio_decoder_factory = - // webrtc::CreateAudioDecoderFactory(); - //media_deps.video_encoder_factory = webrtc::CreateBuiltinVideoEncoderFactory(); - //media_deps.video_decoder_factory = webrtc::CreateBuiltinVideoDecoderFactory(); - //media_deps.audio_processing = webrtc::AudioProcessingBuilder().Create(); - - //_pcf_deps.media_engine = cricket::CreateMediaEngine(std::move(media_deps)); - - //_peerConnectionFactory = webrtc::CreatePeerConnectionFactory( - // rtc::Thread::CreateWithSocketServer().release()/* network_thread */, - // rtc::Thread::Create().release() /* worker_thread */, - // rtc::Thread::Create().release() /* signaling_thread */, - // webrtc::AudioDeviceModuleForTest::CreateForTest(webrtc::AudioDeviceModule::AudioLayer::kDummyAudio, webrtc::CreateDefaultTaskQueueFactory().release()), - // webrtc::CreateAudioEncoderFactory(), //webrtc::CreateBuiltinAudioEncoderFactory(), - // webrtc::CreateAudioDecoderFactory(), //webrtc::CreateBuiltinAudioDecoderFactory(), - // webrtc::CreateBuiltinVideoEncoderFactory(), - // webrtc::CreateBuiltinVideoDecoderFactory(), - // nullptr /* audio_mixer */, - // webrtc::AudioProcessingBuilder().Create() /* audio_processing */); - - //_peerConnectionFactory = webrtc::CreateModularPeerConnectionFactory(std::move(_pcf_deps)); - - _networkThread = rtc::Thread::CreateWithSocketServer(); - _networkThread->Start(); - _workerThread = rtc::Thread::Create(); - _workerThread->Start(); - _signalingThread = rtc::Thread::Create(); - _signalingThread->Start(); - - _fakeAudioCapture = FakeAudioCaptureModule::Create(); - - _peerConnectionFactory = webrtc::CreatePeerConnectionFactory( - _networkThread.get() /* network_thread */, - _workerThread.get() /* worker_thread */, - _signalingThread.get() /* signaling_thread */, - //nullptr /* default_adm */, - //webrtc::AudioDeviceModuleForTest::CreateForTest(webrtc::AudioDeviceModule::AudioLayer::kDummyAudio, webrtc::CreateDefaultTaskQueueFactory().release()), - rtc::scoped_refptr(_fakeAudioCapture), - webrtc::CreateAudioEncoderFactory(), - webrtc::CreateAudioDecoderFactory(), - webrtc::CreateBuiltinVideoEncoderFactory(), - webrtc::CreateBuiltinVideoDecoderFactory(), - nullptr /* audio_mixer */, - nullptr); //webrtc::AudioProcessingBuilder().Create() /* audio_processing */); +{ + std::cout << "PcFactory initialise on " << std::this_thread::get_id() << std::endl; + + SignalingThread = rtc::Thread::Create(); + SignalingThread->Start(); + + webrtc::AudioProcessing::Config apmConfig; + apmConfig.gain_controller1.enabled = false; + apmConfig.gain_controller2.enabled = false; + auto apm = webrtc::BuiltinAudioProcessingBuilder(apmConfig).Build(webrtc::CreateEnvironment()); + + webrtc::PeerConnectionFactoryDependencies _pcf_deps; + _pcf_deps.task_queue_factory = webrtc::CreateDefaultTaskQueueFactory(); + _pcf_deps.signaling_thread = SignalingThread.get(); + _pcf_deps.event_log_factory = std::make_unique(_pcf_deps.task_queue_factory.get()); + _pcf_deps.audio_encoder_factory = webrtc::CreateBuiltinAudioEncoderFactory(); + _pcf_deps.audio_decoder_factory = webrtc::CreateBuiltinAudioDecoderFactory(); + _pcf_deps.adm = rtc::scoped_refptr(FakeAudioCaptureModule::Create()); + _pcf_deps.audio_processing = apm; // Gets moved in EnableMedia. + + webrtc::EnableMedia(_pcf_deps); + + _peerConnectionFactory = webrtc::CreateModularPeerConnectionFactory(std::move(_pcf_deps)); } PcFactory::~PcFactory() @@ -112,18 +85,22 @@ PcFactory::~PcFactory() std::string PcFactory::CreatePeerConnection(const char* buffer, int length) { std::string offerStr(buffer, length); + + std::cout << offerStr << std::endl; + auto offerJson = nlohmann::json::parse(offerStr); - std::cout << offerJson.dump() << std::endl; + //std::cout << "CreatePeerConnection on thread " << std::this_thread::get_id() << " supplied with offer : " << std::endl << offerJson.dump() << std::endl; + std::cout << "CreatePeerConnection on thread " << std::this_thread::get_id() << " supplied with offer : " << std::endl; webrtc::PeerConnectionInterface::RTCConfiguration config; config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan; - config.enable_dtls_srtp = true; - - auto observer = new rtc::RefCountedObject(); + //config.media_config.audio = new cricket::MediaConfig::Audio(); + //config.continual_gathering_policy = webrtc::PeerConnectionInterface::ContinualGatheringPolicy::GATHER_ONCE; + + auto dependencies = webrtc::PeerConnectionDependencies(new PcObserver()); - auto pcOrError = _peerConnectionFactory->CreatePeerConnectionOrError( - config, webrtc::PeerConnectionDependencies(observer)); + auto pcOrError = _peerConnectionFactory->CreatePeerConnectionOrError(config, std::move(dependencies)); rtc::scoped_refptr pc = nullptr; @@ -134,34 +111,75 @@ std::string PcFactory::CreatePeerConnection(const char* buffer, int length) { else { pc = pcOrError.MoveValue(); + // Create a local audio source + rtc::scoped_refptr audio_source = + _peerConnectionFactory->CreateAudioSource(cricket::AudioOptions()); + + // Create a local audio track + rtc::scoped_refptr audio_track = + _peerConnectionFactory->CreateAudioTrack("audio_label", audio_source.get()); + + if (!audio_track) { + std::cerr << "Failed to create AudioTrack." << std::endl; + return "error"; + } + + std::cout << "AudioTrack created successfully." << std::endl; + + auto sender = pc->AddTrack(audio_track, { "stream_id" }); + + if (!sender.ok()) { + std::cerr << "Failed to add AudioTrack to PeerConnection." << std::endl; + return "error"; + } + + std::cout << "AudioTrack added to PeerConnection successfully." << std::endl; + + //webrtc::DataChannelInit config; + //auto dc = pc->CreateDataChannel("data_channel", &config); + _peerConnections.push_back(pc); webrtc::SdpParseError sdpError; auto remoteOffer = webrtc::CreateSessionDescription(webrtc::SdpType::kOffer, offerJson["sdp"], &sdpError); if (remoteOffer == nullptr) { - std::cerr << "Failed to get parse remote SDP." << std::endl; + std::cerr << "Failed to get parse remote SDP. " << sdpError.description << std::endl; return "error"; } else { - std::cout << "Setting remote description on peer connection." << std::endl; - auto setRemoteObserver = new rtc::RefCountedObject(); - pc->SetRemoteDescription(remoteOffer->Clone(), setRemoteObserver); std::mutex mtx; std::condition_variable cv; bool isReady = false; - auto createObs = new rtc::RefCountedObject(mtx, cv, isReady); - pc->SetLocalDescription(createObs); + SignalingThread->PostTask([&]() { + std::cout << "Setting remote description on peer connection, thread ID " << std::this_thread::get_id() << std::endl; + + pc->SetRemoteDescription(remoteOffer->Clone(), SetRemoteSdpObserver::Create()); + + std::cout << "SetLocalDescription on thread, thread ID " << std::this_thread::get_id() << std::endl; + pc->SetLocalDescription(CreateSdpObserver::Create(mtx, cv, isReady)); + }); std::unique_lock lck(mtx); if (!isReady) { std::cout << "Waiting for create answer to complete..." << std::endl; - cv.wait(lck); - } + bool completed = cv.wait_for(lck, std::chrono::seconds(SET_REMOTE_SDP_TIMEOUT_SECONDS), [&]() { + return isReady; + }); + + if (!completed) { + std::cout << "Timed out waiting for isReady." << std::endl; + return std::string(); + } + else { + std::cout << "isReady is now true within 3s." << std::endl; + } + } + auto localDescription = pc->local_description(); if (localDescription == nullptr) { diff --git a/libwebrtc/PcFactory.h b/libwebrtc/PcFactory.h old mode 100644 new mode 100755 index 9709424..04e8dc9 --- a/libwebrtc/PcFactory.h +++ b/libwebrtc/PcFactory.h @@ -1,4 +1,4 @@ -/****************************************************************************** +/* * Filename: PcFactory.h * * Description: @@ -9,9 +9,10 @@ * * History: * 08 Mar 2021 Aaron Clauson Created, Dublin, Ireland. +* 21 Dec 2024 Aaron Clauson Updated for libwebrtc version m132. * * License: Public Domain (no warranty, use at own risk) -/******************************************************************************/ +*/ #ifndef __PEER_CONNECTION_FACTORY__ #define __PEER_CONNECTION_FACTORY__ @@ -20,7 +21,13 @@ #include #include -#include +#include +#include "absl/base/nullability.h" +#include "api/environment/environment.h" +#include "call/call.h" +#include "call/call_config.h" +#include "pc/media_factory.h" +#include "rtc_base/checks.h" #include #include @@ -33,13 +40,20 @@ class PcFactory { ~PcFactory(); std::string CreatePeerConnection(const char* buffer, int length); + /* The thread logic is now tricky. I was not able to get even a basic peer connection + * example working on Windows in debug mode due to the failing thread checks, see + * https://groups.google.com/u/2/g/discuss-webrtc/c/HG9hzDP2djA +// From peer_connection_interface.h line 1632 +// If `network_thread` or `worker_thread` are null, the PeerConnectionFactory +// will create the necessary thread internally. If `signaling_thread` is null, +// the PeerConnectionFactory will use the thread on which this method is called +// as the signaling thread, wrapping it in an rtc::Thread object if needed. + */ + std::unique_ptr SignalingThread; + private: rtc::scoped_refptr _peerConnectionFactory; std::vector> _peerConnections; - std::unique_ptr _networkThread; - std::unique_ptr _workerThread; - std::unique_ptr _signalingThread; - rtc::scoped_refptr _fakeAudioCapture; }; #endif \ No newline at end of file diff --git a/libwebrtc/PcObserver.cpp b/libwebrtc/PcObserver.cpp old mode 100644 new mode 100755 index 2ed4a31..8fa1639 --- a/libwebrtc/PcObserver.cpp +++ b/libwebrtc/PcObserver.cpp @@ -8,6 +8,7 @@ * * History : * 08 Mar 2021 Aaron Clauson Created, Dublin, Ireland. +* 21 Dec 2024 Aaron Clauson Updated for libwebrtc version m132. * * License: Public Domain (no warranty, use at own risk) /******************************************************************************/ diff --git a/libwebrtc/PcObserver.h b/libwebrtc/PcObserver.h old mode 100644 new mode 100755 index 185cdbd..31dbeb0 --- a/libwebrtc/PcObserver.h +++ b/libwebrtc/PcObserver.h @@ -9,6 +9,7 @@ * * History: * 08 Mar 2021 Aaron Clauson Created, Dublin, Ireland. +* 21 Dec 2024 Aaron Clauson Updated for libwebrtc version m132. * * License: Public Domain (no warranty, use at own risk) /******************************************************************************/ @@ -43,8 +44,12 @@ class PcObserver : class SetRemoteSdpObserver : public webrtc::SetRemoteDescriptionObserverInterface - { +public: + static rtc::scoped_refptr Create() { + return rtc::scoped_refptr(new rtc::RefCountedObject()); + } + void OnSetRemoteDescriptionComplete(webrtc::RTCError error) { std::cout << "OnSetRemoteDescriptionComplete ok ? " << std::boolalpha << error.ok() << "." << std::endl; @@ -55,9 +60,14 @@ class CreateSdpObserver : public webrtc::SetLocalDescriptionObserverInterface { public: + + static rtc::scoped_refptr Create(std::mutex& mtx, std::condition_variable& cv, bool& isReady) { + return rtc::scoped_refptr(new rtc::RefCountedObject(mtx, cv, isReady)); + } CreateSdpObserver(std::mutex& mtx, std::condition_variable& cv, bool& isReady) : _mtx(mtx), _cv(cv), _isReady(isReady) { + std::cout << "CreateSdpObserver Constructor." << std::endl; } ~CreateSdpObserver() { @@ -82,4 +92,56 @@ class CreateSdpObserver : bool& _isReady; }; +class SetRemoteDescriptionObserver : public webrtc::SetSessionDescriptionObserver { +public: + + static rtc::scoped_refptr Create() { + return rtc::scoped_refptr(new rtc::RefCountedObject()); + } + + SetRemoteDescriptionObserver() { + std::cout << "SetRemoteDescriptionObserver Constructor." << std::endl; + } + + void OnSuccess() override { + std::cout << "SetRemoteDescriptionObserver::OnSuccess" << std::endl; + } + + void OnFailure(webrtc::RTCError error) override { + std::cerr << "SetRemoteDescriptionObserver::OnFailure: " << error.message() << std::endl; + } +}; + +class SetLocalDescriptionObserver : public webrtc::SetSessionDescriptionObserver { +public: + + static rtc::scoped_refptr Create() { + return rtc::scoped_refptr(new rtc::RefCountedObject()); + } + + void OnSuccess() override { + std::cout << "SetLocalDescriptionObserver::OnSuccess" << std::endl; + } + + void OnFailure(webrtc::RTCError error) override { + std::cerr << "SetLocalDescriptionObserver::OnFailure: " << error.message() << std::endl; + } +}; + +class CreateAnswerObserver : public webrtc::CreateSessionDescriptionObserver { +public: + + static std::unique_ptr Create() { + return std::unique_ptr(); + } + + void OnSuccess(webrtc::SessionDescriptionInterface* desc) override { + std::cout << "CreateAnswerObserver::OnSuccess" << std::endl; + } + + void OnFailure(webrtc::RTCError error) override { + std::cerr << "CreateAnswerObserver::OnFailure: " << error.message() << std::endl; + } +}; + #endif \ No newline at end of file diff --git a/libwebrtc/README.md b/libwebrtc/README.md old mode 100644 new mode 100755 index 5697f9d..6fd4f54 --- a/libwebrtc/README.md +++ b/libwebrtc/README.md @@ -2,22 +2,45 @@ This image gets as far as producing `libwebrtc-full.a` so that it can be used for application builds. -`docker build -t libwebrtc-builder:m90 -f Dockerfile-Builder --progress=plain .` +`docker build -t libwebrtc-builder:m132 -f Dockerfile-Builder --progress=plain .` -## Building docker image +If the build fails: + +1. Comment out the failing steps, generally that will be the ones from the `gn gen` command on. + +2. `docker run -it --init --rm libwebrtc-builder:m132` + +## Building echo application docker image The application image. It builds the application on an instance of the builder image and then copies the binary to a new ubuntu image and installs the required shared library packages. -`docker build -t libwebrtc-webrtc-echo:0.9 --progress=plain .` +`docker build -t libwebrtc-webrtc-echo:m132 --progress=plain .` + +If the build fails: + +1. Comment out the failing steps, generally that will be the ones from the `cmake` command on. + +2. `docker run -it --init --rm libwebrtc-webrtc-echo:m132` -## Running docker image +## Running echo application docker image -`docker run -it --init --rm -p 8080:8080 libwebrtc-webrtc-echo:0.9` +`docker run -it --init --rm -p 8080:8080 libwebrtc-webrtc-echo:m132` + +## Generate Ninja (GN) Reference + +The options supplied to the gn command are critical for buiding a working webrtc.lib (and equivalent object files on linux) as well as ensuring all the required symbols are included. + +gn --help # Get all command line args for gn. +gn args out/Default --list > gnargs.txt # See what options are available for controlling the libwebrtc build. + +https://gn.googlesource.com/gn/+/main/docs/reference.md ## Building webrtc.lib on Windows Follow the standard instructions at https://webrtc.github.io/webrtc-org/native-code/development/ and then use the steps below. Pay particular attention to the `--args` argument supplied to the `gn` command. +It seems the latest version of the build instructions are available directly in the source tree at https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/development/. + ```` src> git checkout branch-heads/4430 -b m90 # See https://chromiumdash.appspot.com/branches for remote branch info. src> set PATH=C:\Tools\depot_tools;%PATH% @@ -30,10 +53,35 @@ src> gn clean out/Default # If previous compilation. src> ninja -C out/Default ```` +Update Dec 2024 for version m132. + +NOTE: Only the clang build chain is now supported for the libwebrtc build. To use webrtc.lib with Visual Studio the clang build chain can be installed via the Visual Studio Installer and then selected as the option in the project settings. + +Install the Google depot tools as per https://webrtc.googlesource.com/src/+/main/docs/native-code/development/prerequisite-sw/. + +In the webrtc-checkout directory, e.g. c:\dev\webrtc-checkout: + +```` +c:\dev\webrtc-checkout\src> set PATH=C:\Tools\depot_tools;%PATH% +c:\dev\webrtc-checkout\src> git checkout branch-heads/6834 -b m132 # See https://chromiumdash.appspot.com/branches for remote branch info. +c:\dev\webrtc-checkout\src> gclient sync -D +c:\dev\webrtc-checkout\src> SET DEPOT_TOOLS_WIN_TOOLCHAIN=0 # Use Visual Studio installed clang toolchain instead of devtools one. +c:\dev\webrtc-checkout\src> rmdir /q /s out\Default +# Setting use_custom_libcxx=false is critical. If it is true, the build uses the libc++ standard library from the third-party source tree, +# making it incompatible when linking with Visual Studio. By setting it to false, the MSVC standard library will be used (e.g msvcp140.dll), +# ensuring that Visual Studio can properly resolve all the required symbols. +c:\dev\webrtc-checkout\src> gn gen out/Default --args="is_debug=false rtc_include_tests=false treat_warnings_as_errors=false use_custom_libcxx=false" +c:\dev\webrtc-checkout\src> autoninja -C out/Default # DON'T use "ninja all -C out/Default", as listed on the build instructions site, it attempts to build everything in the out/Default directory rather than just libwebrtc. +# The resultant webrtc.lib should be in out/Default/obj. +# Note as an added bonus vcpkg installed binaries that are build the the standard msbuild toolcahin, e.g. cl and ld, are compatible with the clang and lld-ld linker. +```` + ## Building libwebrtc-full.a on Ubuntu Follow the standard instructions at https://webrtc.github.io/webrtc-org/native-code/development/ and then use the steps below. Pay particular attention to the `--args` argument supplied to the `gn` command. +It seems the latest version of the build instructions are available directly in the source tree at https://webrtc.googlesource.com/src/+/refs/heads/main/docs/native-code/development/. + To update to the latest source or build a specific branch (see https://chromiumdash.appspot.com/branches for Chromium branch names): ```` @@ -79,3 +127,7 @@ sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt update sudo apt install libstdc++-9-dev libevent-dev ```` + +## Support Group + +The main place to get support for building libwebrtc is the Google Group at https://groups.google.com/u/2/g/discuss-webrtc. diff --git a/libwebrtc/fake_audio_capture_module.cc b/libwebrtc/fake_audio_capture_module.cc old mode 100644 new mode 100755 index 5847232..1484a61 --- a/libwebrtc/fake_audio_capture_module.cc +++ b/libwebrtc/fake_audio_capture_module.cc @@ -1,3 +1,21 @@ +/****************************************************************************** +* Filename: fake_Audio_capture_module.cc +* +* Description: +* This class does not implement anything useful. Even most of the "fake" audio +* funcitonality has been stripped out. It's purpose is to get the WebRTC lib +* to recognise there is an audio device and answer an SDP audio offer. +* +* Original: +* https://webrtc.googlesource.com/src/+/refs/heads/main/pc/test/fake_audio_capture_module.cc +* +* History: +* 21 Dec 2024 Aaron Clauson Copied from original source. +* +* License: +* Original copyright notice is retained below. +/******************************************************************************/ + /* * Copyright 2012 The WebRTC project authors. All Rights Reserved. * @@ -8,15 +26,16 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "pc/test/fake_audio_capture_module.h" +#include "fake_audio_capture_module.h" #include -#include "rtc_base/checks.h" -#include "rtc_base/location.h" -#include "rtc_base/ref_counted_object.h" -#include "rtc_base/thread.h" +#include "api/make_ref_counted.h" +#include "api/units/time_delta.h" #include "rtc_base/time_utils.h" +#include + +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 @@ -33,33 +52,25 @@ 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), - playing_(false), - play_is_initialized_(false), - rec_is_initialized_(false), - current_mic_level_(kMaxVolume), - started_(false), - next_frame_time_(0), - frames_received_(0) { - process_thread_checker_.Detach(); + : audio_callback_(nullptr), + recording_(false), + playing_(false), + play_is_initialized_(false), + rec_is_initialized_(false), + current_mic_level_(kMaxVolume), + started_(false), + next_frame_time_(0), + frames_received_(0) { } FakeAudioCaptureModule::~FakeAudioCaptureModule() { - if (process_thread_) { - process_thread_->Stop(); - } + std::cout << "~FakeAudioCaptureModule" << std::endl; } rtc::scoped_refptr FakeAudioCaptureModule::Create() { - rtc::scoped_refptr capture_module( - new rtc::RefCountedObject()); + std::cout << "FakeAudioCaptureModule" << std::endl; + auto capture_module = rtc::make_ref_counted(); if (!capture_module->Initialize()) { return nullptr; } @@ -67,19 +78,17 @@ rtc::scoped_refptr FakeAudioCaptureModule::Create() { } int FakeAudioCaptureModule::frames_received() const { - webrtc::MutexLock lock(&mutex_); return frames_received_; } int32_t FakeAudioCaptureModule::ActiveAudioLayer( - AudioLayer* /*audio_layer*/) const { - RTC_NOTREACHED(); + AudioLayer* /*audio_layer*/) const { + RTC_DCHECK_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::RegisterAudioCallback( - webrtc::AudioTransport* audio_callback) { - webrtc::MutexLock lock(&mutex_); + webrtc::AudioTransport* audio_callback) { audio_callback_ = audio_callback; return 0; } @@ -95,33 +104,33 @@ 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; } int32_t FakeAudioCaptureModule::PlayoutDeviceName( - uint16_t /*index*/, - char /*name*/[webrtc::kAdmMaxDeviceNameSize], - char /*guid*/[webrtc::kAdmMaxGuidSize]) { - RTC_NOTREACHED(); + uint16_t /*index*/, + char /*name*/[webrtc::kAdmMaxDeviceNameSize], + char /*guid*/[webrtc::kAdmMaxGuidSize]) { + RTC_DCHECK_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::RecordingDeviceName( - uint16_t /*index*/, - char /*name*/[webrtc::kAdmMaxDeviceNameSize], - char /*guid*/[webrtc::kAdmMaxGuidSize]) { - RTC_NOTREACHED(); + uint16_t /*index*/, + char /*name*/[webrtc::kAdmMaxDeviceNameSize], + char /*guid*/[webrtc::kAdmMaxGuidSize]) { + RTC_DCHECK_NOTREACHED(); return 0; } @@ -143,7 +152,7 @@ int32_t FakeAudioCaptureModule::SetRecordingDevice(uint16_t /*index*/) { } int32_t FakeAudioCaptureModule::SetRecordingDevice( - WindowsDeviceType /*device*/) { + WindowsDeviceType /*device*/) { if (rec_is_initialized_) { return -1; } @@ -151,7 +160,7 @@ int32_t FakeAudioCaptureModule::SetRecordingDevice( } int32_t FakeAudioCaptureModule::PlayoutIsAvailable(bool* /*available*/) { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } @@ -165,7 +174,7 @@ bool FakeAudioCaptureModule::PlayoutIsInitialized() const { } int32_t FakeAudioCaptureModule::RecordingIsAvailable(bool* /*available*/) { - RTC_NOTREACHED(); + RTC_DCHECK_NOTREACHED(); return 0; } @@ -183,7 +192,6 @@ int32_t FakeAudioCaptureModule::StartPlayout() { return -1; } { - webrtc::MutexLock lock(&mutex_); playing_ = true; } bool start = true; @@ -194,7 +202,6 @@ int32_t FakeAudioCaptureModule::StartPlayout() { int32_t FakeAudioCaptureModule::StopPlayout() { bool start = false; { - webrtc::MutexLock lock(&mutex_); playing_ = false; start = ShouldStartProcessing(); } @@ -203,7 +210,6 @@ int32_t FakeAudioCaptureModule::StopPlayout() { } bool FakeAudioCaptureModule::Playing() const { - webrtc::MutexLock lock(&mutex_); return playing_; } @@ -212,7 +218,6 @@ int32_t FakeAudioCaptureModule::StartRecording() { return -1; } { - webrtc::MutexLock lock(&mutex_); recording_ = true; } bool start = true; @@ -223,7 +228,6 @@ int32_t FakeAudioCaptureModule::StartRecording() { int32_t FakeAudioCaptureModule::StopRecording() { bool start = false; { - webrtc::MutexLock lock(&mutex_); recording_ = false; start = ShouldStartProcessing(); } @@ -232,7 +236,6 @@ int32_t FakeAudioCaptureModule::StopRecording() { } bool FakeAudioCaptureModule::Recording() const { - webrtc::MutexLock lock(&mutex_); return recording_; } @@ -242,7 +245,6 @@ int32_t FakeAudioCaptureModule::InitSpeaker() { } bool FakeAudioCaptureModule::SpeakerIsInitialized() const { - RTC_NOTREACHED(); return 0; } @@ -252,99 +254,83 @@ int32_t FakeAudioCaptureModule::InitMicrophone() { } bool FakeAudioCaptureModule::MicrophoneIsInitialized() const { - RTC_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::SpeakerVolumeIsAvailable(bool* /*available*/) { - RTC_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::SetSpeakerVolume(uint32_t /*volume*/) { - RTC_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::SpeakerVolume(uint32_t* /*volume*/) const { - RTC_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::MaxSpeakerVolume( - uint32_t* /*max_volume*/) const { - RTC_NOTREACHED(); + uint32_t* /*max_volume*/) const { return 0; } int32_t FakeAudioCaptureModule::MinSpeakerVolume( - uint32_t* /*min_volume*/) const { - RTC_NOTREACHED(); + uint32_t* /*min_volume*/) const { return 0; } int32_t FakeAudioCaptureModule::MicrophoneVolumeIsAvailable( - bool* /*available*/) { - RTC_NOTREACHED(); + bool* /*available*/) { return 0; } int32_t FakeAudioCaptureModule::SetMicrophoneVolume(uint32_t volume) { - webrtc::MutexLock lock(&mutex_); current_mic_level_ = volume; return 0; } int32_t FakeAudioCaptureModule::MicrophoneVolume(uint32_t* volume) const { - webrtc::MutexLock lock(&mutex_); *volume = current_mic_level_; return 0; } int32_t FakeAudioCaptureModule::MaxMicrophoneVolume( - uint32_t* max_volume) const { + uint32_t* max_volume) const { *max_volume = kMaxVolume; return 0; } int32_t FakeAudioCaptureModule::MinMicrophoneVolume( - uint32_t* /*min_volume*/) const { - RTC_NOTREACHED(); + uint32_t* /*min_volume*/) const { return 0; } int32_t FakeAudioCaptureModule::SpeakerMuteIsAvailable(bool* /*available*/) { - RTC_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::SetSpeakerMute(bool /*enable*/) { - RTC_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::SpeakerMute(bool* /*enabled*/) const { - RTC_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::MicrophoneMuteIsAvailable(bool* /*available*/) { - RTC_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::SetMicrophoneMute(bool /*enable*/) { - RTC_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::MicrophoneMute(bool* /*enabled*/) const { - RTC_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::StereoPlayoutIsAvailable( - bool* available) const { + bool* available) const { // No recording device, just dropping audio. Stereo can be dropped just // as easily as mono. *available = true; @@ -358,12 +344,11 @@ int32_t FakeAudioCaptureModule::SetStereoPlayout(bool /*enable*/) { } int32_t FakeAudioCaptureModule::StereoPlayout(bool* /*enabled*/) const { - RTC_NOTREACHED(); return 0; } int32_t FakeAudioCaptureModule::StereoRecordingIsAvailable( - bool* available) const { + bool* available) const { // Keep thing simple. No stereo recording. *available = false; return 0; @@ -377,7 +362,6 @@ int32_t FakeAudioCaptureModule::SetStereoRecording(bool enable) { } int32_t FakeAudioCaptureModule::StereoRecording(bool* /*enabled*/) const { - RTC_NOTREACHED(); return 0; } @@ -387,21 +371,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 @@ -414,7 +383,7 @@ bool FakeAudioCaptureModule::Initialize() { void FakeAudioCaptureModule::SetSendBuffer(int value) { Sample* buffer_ptr = reinterpret_cast(send_buffer_); const size_t buffer_size_in_samples = - sizeof(send_buffer_) / kNumberBytesPerSample; + sizeof(send_buffer_) / kNumberBytesPerSample; for (size_t i = 0; i < buffer_size_in_samples; ++i) { buffer_ptr[i] = value; } @@ -427,7 +396,7 @@ void FakeAudioCaptureModule::ResetRecBuffer() { bool FakeAudioCaptureModule::CheckRecBuffer(int value) { const Sample* buffer_ptr = reinterpret_cast(rec_buffer_); const size_t buffer_size_in_samples = - sizeof(rec_buffer_) / kNumberBytesPerSample; + sizeof(rec_buffer_) / kNumberBytesPerSample; for (size_t i = 0; i < buffer_size_in_samples; ++i) { if (buffer_ptr[i] >= value) return true; @@ -440,62 +409,41 @@ bool FakeAudioCaptureModule::ShouldStartProcessing() { } void FakeAudioCaptureModule::UpdateProcessing(bool start) { - if (start) { - if (!process_thread_) { - process_thread_ = rtc::Thread::Create(); - process_thread_->Start(); - } - process_thread_->Post(RTC_FROM_HERE, this, MSG_START_PROCESS); - } else { - if (process_thread_) { - process_thread_->Stop(); - process_thread_.reset(nullptr); - process_thread_checker_.Detach(); - } - webrtc::MutexLock lock(&mutex_); + if (!start) { started_ = false; } } void FakeAudioCaptureModule::StartProcessP() { - RTC_DCHECK_RUN_ON(&process_thread_checker_); - { - webrtc::MutexLock lock(&mutex_); - if (started_) { - // Already started. - return; - } + if (started_) { + // Already started. + return; } ProcessFrameP(); } void FakeAudioCaptureModule::ProcessFrameP() { - RTC_DCHECK_RUN_ON(&process_thread_checker_); - { - webrtc::MutexLock lock(&mutex_); - if (!started_) { - next_frame_time_ = rtc::TimeMillis(); - started_ = true; - } - - // Receive and send frames every kTimePerFrameMs. - if (playing_) { - ReceiveFrameP(); - } - if (recording_) { - SendFrameP(); - } + if (!started_) { + next_frame_time_ = rtc::TimeMillis(); + started_ = true; + } + + // Receive and send frames every kTimePerFrameMs. + if (playing_) { + ReceiveFrameP(); + } + if (recording_) { + SendFrameP(); } next_frame_time_ += kTimePerFrameMs; 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); + (next_frame_time_ > current_time) ? next_frame_time_ - current_time : 0; + TimeDelta::Millis(wait_time); } void FakeAudioCaptureModule::ReceiveFrameP() { - RTC_DCHECK_RUN_ON(&process_thread_checker_); if (!audio_callback_) { return; } @@ -504,12 +452,10 @@ void FakeAudioCaptureModule::ReceiveFrameP() { int64_t elapsed_time_ms = 0; int64_t ntp_time_ms = 0; if (audio_callback_->NeedMorePlayData(kNumberSamples, kNumberBytesPerSample, - kNumberOfChannels, kSamplesPerSecond, - rec_buffer_, nSamplesOut, - &elapsed_time_ms, &ntp_time_ms) != 0) { - RTC_NOTREACHED(); + kNumberOfChannels, kSamplesPerSecond, + rec_buffer_, nSamplesOut, + &elapsed_time_ms, &ntp_time_ms) != 0) { } - RTC_CHECK(nSamplesOut == kNumberSamples); // The SetBuffer() function ensures that after decoding, the audio buffer // should contain samples of similar magnitude (there is likely to be some @@ -523,38 +469,15 @@ void FakeAudioCaptureModule::ReceiveFrameP() { } void FakeAudioCaptureModule::SendFrameP() { - RTC_DCHECK_RUN_ON(&process_thread_checker_); if (!audio_callback_) { return; } bool key_pressed = false; uint32_t current_mic_level = current_mic_level_; if (audio_callback_->RecordedDataIsAvailable( - send_buffer_, kNumberSamples, kNumberBytesPerSample, - kNumberOfChannels, kSamplesPerSecond, kTotalDelayMs, kClockDriftMs, - current_mic_level, key_pressed, current_mic_level) != 0) { - RTC_NOTREACHED(); + send_buffer_, kNumberSamples, kNumberBytesPerSample, + kNumberOfChannels, kSamplesPerSecond, kTotalDelayMs, kClockDriftMs, + current_mic_level, key_pressed, current_mic_level) != 0) { } current_mic_level_ = current_mic_level; } - -#include "rtc_base/message_handler.h" - -#include "rtc_base/thread.h" - -namespace rtc { - - MessageHandlerAutoCleanup::MessageHandlerAutoCleanup() {} - - MessageHandlerAutoCleanup::~MessageHandlerAutoCleanup() { - // Note that even though this clears currently pending messages for the - // message handler, it's still racy since it doesn't prevent threads that - // might be in the process of posting new messages with would-be dangling - // pointers. - // This is related to the design of Message having a raw pointer. - // We could consider whether it would be safer to require message handlers - // to be reference counted (as some are). - ThreadManager::Clear(this); - } - -} // namespace rtc diff --git a/libwebrtc/fake_audio_capture_module.h b/libwebrtc/fake_audio_capture_module.h new file mode 100755 index 0000000..da9f231 --- /dev/null +++ b/libwebrtc/fake_audio_capture_module.h @@ -0,0 +1,222 @@ +/****************************************************************************** +* Filename: fake_Audio_capture_module.h +* +* Description: +* This class does not implement anything useful. Even most of the "fake" audio +* funcitonality has been stripped out. It's purpose is to get the WebRTC lib +* to recognise there is an audio device and answer an SDP audio offer. +* +* Original: +* https://webrtc.googlesource.com/src/+/refs/heads/main/pc/test/fake_audio_capture_module.h +* +* History: +* 21 Dec 2024 Aaron Clauson Copied from original source. +* +* License: +* Original copyright notice is retained below. +/******************************************************************************/ + +/* + * Copyright 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef PC_TEST_FAKE_AUDIO_CAPTURE_MODULE_H_ +#define PC_TEST_FAKE_AUDIO_CAPTURE_MODULE_H_ + +#include +#include + +#include + +#include "api/audio/audio_device.h" +#include "api/audio/audio_device_defines.h" +#include "api/scoped_refptr.h" + +class FakeAudioCaptureModule : public webrtc::AudioDeviceModule { +public: + typedef uint16_t Sample; + + // The value for the following constants have been derived by running VoE + // using a real ADM. The constants correspond to 10ms of mono audio at 44kHz. + static const size_t kNumberSamples = 440; + static const size_t kNumberBytesPerSample = sizeof(Sample); + + // Creates a FakeAudioCaptureModule or returns NULL on failure. + static rtc::scoped_refptr Create(); + + // 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; + + 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 Init() override; + int32_t Terminate() override; + bool Initialized() const override; + + int16_t PlayoutDevices() override; + int16_t RecordingDevices() override; + int32_t PlayoutDeviceName(uint16_t index, + char name[webrtc::kAdmMaxDeviceNameSize], + char guid[webrtc::kAdmMaxGuidSize]) override; + int32_t RecordingDeviceName(uint16_t index, + char name[webrtc::kAdmMaxDeviceNameSize], + char guid[webrtc::kAdmMaxGuidSize]) override; + + int32_t SetPlayoutDevice(uint16_t index) override; + int32_t SetPlayoutDevice(WindowsDeviceType device) override; + int32_t SetRecordingDevice(uint16_t index) override; + int32_t SetRecordingDevice(WindowsDeviceType device) override; + + int32_t PlayoutIsAvailable(bool* available) override; + int32_t InitPlayout() override; + bool PlayoutIsInitialized() const override; + int32_t RecordingIsAvailable(bool* available) override; + 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 InitSpeaker() override; + bool SpeakerIsInitialized() const override; + int32_t InitMicrophone() override; + bool MicrophoneIsInitialized() const override; + + int32_t SpeakerVolumeIsAvailable(bool* available) override; + int32_t SetSpeakerVolume(uint32_t volume) override; + int32_t SpeakerVolume(uint32_t* volume) const override; + int32_t MaxSpeakerVolume(uint32_t* max_volume) const override; + 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 MaxMicrophoneVolume(uint32_t* max_volume) const override; + + int32_t MinMicrophoneVolume(uint32_t* min_volume) const override; + + int32_t SpeakerMuteIsAvailable(bool* available) override; + int32_t SetSpeakerMute(bool enable) override; + int32_t SpeakerMute(bool* enabled) const override; + + int32_t MicrophoneMuteIsAvailable(bool* available) override; + int32_t SetMicrophoneMute(bool enable) override; + int32_t MicrophoneMute(bool* enabled) const override; + + int32_t StereoPlayoutIsAvailable(bool* available) const override; + int32_t SetStereoPlayout(bool enable) override; + int32_t StereoPlayout(bool* enabled) const override; + int32_t StereoRecordingIsAvailable(bool* available) const override; + int32_t SetStereoRecording(bool enable) override; + int32_t StereoRecording(bool* enabled) const override; + + int32_t PlayoutDelay(uint16_t* delay_ms) const override; + + bool BuiltInAECIsAvailable() const override { return false; } + int32_t EnableBuiltInAEC(bool enable) override { return -1; } + bool BuiltInAGCIsAvailable() const override { return false; } + int32_t EnableBuiltInAGC(bool enable) override { return -1; } + bool BuiltInNSIsAvailable() const override { return false; } + int32_t EnableBuiltInNS(bool enable) override { return -1; } + + int32_t GetPlayoutUnderrunCount() const override { return -1; } + + std::optional GetStats() const override { + return webrtc::AudioDeviceModule::Stats(); + } + + // End of functions inherited from webrtc::AudioDeviceModule. + +protected: + // The constructor is protected because the class needs to be created as a + // reference counted object (for memory managment reasons). It could be + // exposed in which case the burden of proper instantiation would be put on + // the creator of a FakeAudioCaptureModule instance. To create an instance of + // this class use the Create(..) API. + FakeAudioCaptureModule(); + // The destructor is protected because it is reference counted and should not + // be deleted directly. + virtual ~FakeAudioCaptureModule(); + +private: + // 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`. + 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`. + bool CheckRecBuffer(int value); + + // Returns true/false depending on if recording or playback has been + // enabled/started. + bool ShouldStartProcessing(); + + // Starts or stops the pushing and pulling of audio frames. + void UpdateProcessing(bool start); + + // 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(); + // Pulls frames from the registered webrtc::AudioTransport. + void ReceiveFrameP(); + // Pushes frames to the registered webrtc::AudioTransport. + void SendFrameP(); + + // Callback for playout and recording. + webrtc::AudioTransport* audio_callback_; + + bool recording_; // True when audio is being pushed from the instance. + bool playing_; // 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. + + // 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_; + + // 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_; + + // Buffer for storing samples received from the webrtc::AudioTransport. + char rec_buffer_[kNumberSamples * kNumberBytesPerSample]; + // Buffer for samples to send to the webrtc::AudioTransport. + char send_buffer_[kNumberSamples * kNumberBytesPerSample]; + + // Counter of frames received that have samples of high enough amplitude to + // indicate that the frames are not faked somewhere in the audio pipeline + // (e.g. by a jitter buffer). + int frames_received_; + + // Protects variables that are accessed from process_thread_ and + // the main thread. + //mutable webrtc::Mutex mutex_; + //webrtc::SequenceChecker process_thread_checker_{ + // webrtc::SequenceChecker::kDetached }; +}; + +#endif // PC_TEST_FAKE_AUDIO_CAPTURE_MODULE_H_ diff --git a/libwebrtc/libwebrtc-webrtc-echo.cpp b/libwebrtc/libwebrtc-webrtc-echo.cpp old mode 100644 new mode 100755 index e42d568..88deb18 --- a/libwebrtc/libwebrtc-webrtc-echo.cpp +++ b/libwebrtc/libwebrtc-webrtc-echo.cpp @@ -4,7 +4,7 @@ * Description: * Main program for a test program that creates a echo peer using Google's * webrtc library, https://webrtc.googlesource.com/src/webrtc/. -* +* * Dependencies: * vcpkg install libevent:x64-windows * @@ -13,6 +13,7 @@ * * History: * 08 Mar 2021 Aaron Clauson Created, Dublin, Ireland. +* 21 DEc 2024 Aaron Clauson Updated for libwebrtc version m132. * * License: Public Domain (no warranty, use at own risk) /******************************************************************************/ @@ -20,13 +21,17 @@ #include "HttpSimpleServer.h" #include "PcFactory.h" +#include +#include #include +#include #include #include #include #include #include +#include #define HTTP_SERVER_ADDRESS "0.0.0.0" #define HTTP_SERVER_PORT 8080 @@ -48,13 +53,15 @@ int main() std::cout << "libevent version " << event_get_version() << "." << std::endl; - rtc::LogMessage::LogToDebug(rtc::LoggingSeverity::WARNING); + rtc::LogMessage::LogToDebug(rtc::LoggingSeverity::LS_WARNING); { - HttpSimpleServer httpSvr; - httpSvr.Init(HTTP_SERVER_ADDRESS, HTTP_SERVER_PORT, HTTP_OFFER_URL); + std::cout << "On main thread, thread ID " << std::this_thread::get_id() << std::endl; PcFactory pcFactory; + + HttpSimpleServer httpSvr; + httpSvr.Init(HTTP_SERVER_ADDRESS, HTTP_SERVER_PORT, HTTP_OFFER_URL); HttpSimpleServer::SetPeerConnectionFactory(&pcFactory); httpSvr.Run(); diff --git a/libwebrtc/libwebrtc-webrtc-echo.sln b/libwebrtc/libwebrtc-webrtc-echo.sln index 7e53ba7..263729e 100644 --- a/libwebrtc/libwebrtc-webrtc-echo.sln +++ b/libwebrtc/libwebrtc-webrtc-echo.sln @@ -1,20 +1,32 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31025.194 +# Visual Studio Version 17 +VisualStudioVersion = 17.12.35527.113 d17.12 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libwebrtc-webrtc-echo", "libwebrtc-webrtc-echo.vcxproj", "{D52A1111-536E-44F2-AA70-B322343FD453}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Win32 = Release|Win32 Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D52A1111-536E-44F2-AA70-B322343FD453}.Debug|Win32.ActiveCfg = Debug|Win32 + {D52A1111-536E-44F2-AA70-B322343FD453}.Debug|Win32.Build.0 = Debug|Win32 {D52A1111-536E-44F2-AA70-B322343FD453}.Debug|x64.ActiveCfg = Debug|x64 {D52A1111-536E-44F2-AA70-B322343FD453}.Debug|x64.Build.0 = Debug|x64 + {D52A1111-536E-44F2-AA70-B322343FD453}.Debug|x86.ActiveCfg = Debug|Win32 + {D52A1111-536E-44F2-AA70-B322343FD453}.Debug|x86.Build.0 = Debug|Win32 + {D52A1111-536E-44F2-AA70-B322343FD453}.Release|Win32.ActiveCfg = Release|Win32 + {D52A1111-536E-44F2-AA70-B322343FD453}.Release|Win32.Build.0 = Release|Win32 {D52A1111-536E-44F2-AA70-B322343FD453}.Release|x64.ActiveCfg = Release|x64 {D52A1111-536E-44F2-AA70-B322343FD453}.Release|x64.Build.0 = Release|x64 + {D52A1111-536E-44F2-AA70-B322343FD453}.Release|x86.ActiveCfg = Release|Win32 + {D52A1111-536E-44F2-AA70-B322343FD453}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/libwebrtc/libwebrtc-webrtc-echo.vcxproj b/libwebrtc/libwebrtc-webrtc-echo.vcxproj old mode 100644 new mode 100755 index 1065884..1b5f1cf --- a/libwebrtc/libwebrtc-webrtc-echo.vcxproj +++ b/libwebrtc/libwebrtc-webrtc-echo.vcxproj @@ -1,10 +1,18 @@ + + Debug + Win32 + Debug x64 + + Release + Win32 + Release x64 @@ -21,13 +29,26 @@ Application true - v142 + ClangCL + Unicode + + + Application + true + ClangCL Unicode Application false - v142 + ClangCL + true + Unicode + + + Application + false + ClangCL true Unicode @@ -39,35 +60,91 @@ + + + + + + true C:\Dev\webrtc-checkout\src\out\Default\obj;$(LibraryPath) + + true + C:\Dev\webrtc-checkout\src\out\Default\obj;$(LibraryPath) + false C:\Dev\webrtc-checkout\src\out\Default\obj;$(LibraryPath) + + false + C:\Dev\webrtc-checkout\src\out\Default\obj;$(LibraryPath) + Level3 true - _WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;WEBRTC_WIN;_ITERATOR_DEBUG_LEVEL=0;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + USE_AURA=1;_HAS_EXCEPTIONS=0;__STD_C;_CRT_RAND_S;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_ATL_NO_OPENGL;_WINDOWS;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;PSAPI_VERSION=2;WIN32;_SECURE_ATL;WINUWP;__WRL_NO_DEFAULT_LIB__;WINAPI_FAMILY=WINAPI_FAMILY_PC_APP;WIN10=_WIN32_WINNT_WIN10;WIN32_LEAN_AND_MEAN;NOMINMAX;_UNICODE;UNICODE;NTDDI_VERSION=NTDDI_WIN10_RS2;_WIN32_WINNT=0x0A00;WINVER=0x0A00;NDEBUG;NVALGRIND;DYNAMIC_ANNOTATIONS_ENABLED=0;WEBRTC_ENABLE_PROTOBUF=0;WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE;RTC_ENABLE_VP9;HAVE_SCTP;WEBRTC_LIBRARY_IMPL;WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS=0;WEBRTC_WIN;ABSL_ALLOCATOR_NOTHROW=1;HAVE_SCTP;WEBRTC_VIDEO_CAPTURE_WINRT;_SILENCE_ALL_CXX20_DEPRECATION_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;WEBRTC_WIN;_ITERATOR_DEBUG_LEVEL=0;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true C:\Dev\webrtc-checkout\src;C:\Dev\webrtc-checkout\src\third_party\abseil-cpp;%(AdditionalIncludeDirectories) MultiThreadedDebug - Default - stdc11 + stdcpp20 + stdc17 + Cdecl Console true - Iphlpapi.lib;ws2_32.lib;wmcodecdspuuid.lib;Msdmo.lib;Dmoguids.lib;secur32.lib;winmm.lib;webrtc.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + C:\Dev\webrtc-checkout\src\out\Default\obj;%(AdditionalLibraryDirectories) + eventd.lib;Iphlpapi.lib;ws2_32.lib;wmcodecdspuuid.lib;Msdmo.lib;Dmoguids.lib;secur32.lib;winmm.lib;C:\Dev\webrtc-checkout\src\out\Default\obj\webrtc.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + true + _SILENCE_ALL_CXX20_DEPRECATION_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;WEBRTC_WIN;_ITERATOR_DEBUG_LEVEL=0;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + C:\Dev\webrtc-checkout\src;C:\Dev\webrtc-checkout\src\third_party\abseil-cpp;%(AdditionalIncludeDirectories) + MultiThreadedDebug + stdcpp20 + stdc17 + Cdecl + + + Console + true + C:\Dev\webrtc-checkout\src\out\Default\obj;%(AdditionalLibraryDirectories) + Iphlpapi.lib;ws2_32.lib;wmcodecdspuuid.lib;Msdmo.lib;Dmoguids.lib;secur32.lib;winmm.lib;C:\Dev\webrtc-checkout\src\out\Default\obj\webrtc.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + Level3 + true + true + true + USE_AURA=1;_HAS_EXCEPTIONS=0;__STD_C;_CRT_RAND_S;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_ATL_NO_OPENGL;_WINDOWS;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;PSAPI_VERSION=2;WIN32;_SECURE_ATL;WINUWP;__WRL_NO_DEFAULT_LIB__;WINAPI_FAMILY=WINAPI_FAMILY_PC_APP;WIN10=_WIN32_WINNT_WIN10;WIN32_LEAN_AND_MEAN;NOMINMAX;_UNICODE;UNICODE;NTDDI_VERSION=NTDDI_WIN10_RS2;_WIN32_WINNT=0x0A00;WINVER=0x0A00;NDEBUG;NVALGRIND;DYNAMIC_ANNOTATIONS_ENABLED=0;WEBRTC_ENABLE_PROTOBUF=0;WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE;RTC_ENABLE_VP9;HAVE_SCTP;WEBRTC_LIBRARY_IMPL;WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS=0;WEBRTC_WIN;ABSL_ALLOCATOR_NOTHROW=1;HAVE_SCTP;WEBRTC_VIDEO_CAPTURE_WINRT;_SILENCE_ALL_CXX20_DEPRECATION_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;WEBRTC_WIN;_ITERATOR_DEBUG_LEVEL=0;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + C:\Dev\webrtc-checkout\src\third_party\abseil-cpp;C:\Dev\webrtc-checkout\src;%(AdditionalIncludeDirectories) + MultiThreaded + stdcpp20 + stdc17 + + + Console + true + true + true + event.lib;webrtc.lib;dmoguids.lib;wmcodecdspuuid.lib;msdmo.lib;ws2_32.lib;iphlpapi.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + Level3 true @@ -77,6 +154,8 @@ true C:\Dev\webrtc-checkout\src\third_party\abseil-cpp;C:\Dev\webrtc-checkout\src;%(AdditionalIncludeDirectories) MultiThreaded + stdcpp20 + stdc17 Console @@ -102,6 +181,7 @@ + diff --git a/libwebrtc/libwebrtc-webrtc-echo.vcxproj.filters b/libwebrtc/libwebrtc-webrtc-echo.vcxproj.filters old mode 100644 new mode 100755 diff --git a/libwebrtc/libwebrtc-webrtc-echo.vcxproj.user b/libwebrtc/libwebrtc-webrtc-echo.vcxproj.user old mode 100644 new mode 100755 diff --git a/sipsorcery/client/Program.cs b/sipsorcery/client/Program.cs old mode 100644 new mode 100755 index bb52e51..4bf6e8e --- a/sipsorcery/client/Program.cs +++ b/sipsorcery/client/Program.cs @@ -19,6 +19,7 @@ using System; using System.Linq; using System.Net.Http; +using System.Runtime.ExceptionServices; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -99,10 +100,12 @@ static async Task Main(string[] args) logger.LogDebug($"Performing test {testType} to {echoServerUrl}."); - var pc = await CreatePeerConnection(); + var pc = CreatePeerConnection(); var offer = pc.createOffer(); await pc.setLocalDescription(offer); + logger.LogDebug("Offer SDP:\r\n" + offer.sdp); + bool success = false; ManualResetEventSlim testComplete = new ManualResetEventSlim(); @@ -180,6 +183,8 @@ static async Task Main(string[] args) pc.OnClosed += testComplete.Set; + await pc.Start(); + logger.LogDebug($"Test timeout is {pcTimeout} seconds."); testComplete.Wait(pcTimeout * 1000); @@ -194,7 +199,7 @@ static async Task Main(string[] args) return (success) ? SUCCESS_RESULT : FAILURE_RESULT; } - private static async Task CreatePeerConnection() + private static RTCPeerConnection CreatePeerConnection() { RTCConfiguration config = new RTCConfiguration { @@ -206,7 +211,7 @@ private static async Task CreatePeerConnection() MediaStreamTrack audioTrack = new MediaStreamTrack(SDPWellKnownMediaFormatsEnum.PCMU); pc.addTrack(audioTrack); - var dc = await pc.createDataChannel("sipsocery-dc"); + //var dc = await pc.createDataChannel("sipsocery-dc"); pc.onicecandidateerror += (candidate, error) => logger.LogWarning($"Error adding remote ICE candidate. {error} {candidate}"); pc.OnTimeout += (mediaType) => logger.LogWarning($"Timeout for {mediaType}."); @@ -215,6 +220,7 @@ private static async Task CreatePeerConnection() pc.OnReceiveReport += (re, media, rr) => logger.LogDebug($"RTCP Receive for {media} from {re}\n{rr.GetDebugSummary()}"); pc.OnSendReport += (media, sr) => logger.LogDebug($"RTCP Send for {media}\n{sr.GetDebugSummary()}"); pc.OnRtcpBye += (reason) => logger.LogDebug($"RTCP BYE receive, reason: {(string.IsNullOrWhiteSpace(reason) ? "" : reason)}."); + pc.GetRtpChannel().OnStunMessageReceived += (msg, ep, isRelay) => logger.LogDebug($"STUN {msg.Header.MessageType} received from {ep}."); pc.onsignalingstatechange += () => { diff --git a/sipsorcery/client/README.md b/sipsorcery/client/README.md index 95fac7c..56c1a23 100755 --- a/sipsorcery/client/README.md +++ b/sipsorcery/client/README.md @@ -4,7 +4,7 @@ A .NET console application that acts as a peer for a WebRTC Echo Server. **Prerequisites** -The .NET 5 SDK needs to be installed as per https://dotnet.microsoft.com/download/dotnet/8.0. +The .NET 8 SDK needs to be installed as per https://dotnet.microsoft.com/download/dotnet/8.0. Note the full SDK install is required, and not the runtime-only option, so as the console application can be built from source. diff --git a/test/collate-results.py b/test/collate-results.py index 8d3eb12..a1bb7ea 100755 --- a/test/collate-results.py +++ b/test/collate-results.py @@ -72,7 +72,7 @@ print(f'| {serverKey: <12} ', end='') for clientKey in clientKeys: if clientKey in results_dict[serverKey]: - resultChar = '✔' if results_dict[serverKey][clientKey] == '0' else 'X' + resultChar = '✔' if results_dict[serverKey][clientKey] == '0' else '✘' print(f'| {resultChar: <7}', end='') else: print(f'| {" ":<7}', end='')