/* * Copyright 2026 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. */ #include #include #include #include "api/audio_options.h" #include "api/create_modular_peer_connection_factory.h" #include "api/jsep.h" #include "api/make_ref_counted.h" #include "api/media_types.h" #include "api/peer_connection_interface.h" #include "api/rtc_error.h" #include "api/scoped_refptr.h" #include "api/set_local_description_observer_interface.h" #include "media/base/fake_media_engine.h" #include "pc/peer_connection.h" #include "pc/peer_connection_proxy.h" #include "pc/rtp_transceiver.h" #include "pc/test/enable_fake_media.h" #include "pc/test/mock_peer_connection_observers.h" #include "rtc_base/checks.h" #include "rtc_base/thread.h" #include "test/gmock.h" #include "test/gtest.h" #include "test/run_loop.h" namespace webrtc { namespace { using test::RunLoop; using ::testing::IsNull; using ::testing::NotNull; // Helper observers that quit the run loop. class QuitOnSuccessCreateObserver : public MockCreateSessionDescriptionObserver { public: explicit QuitOnSuccessCreateObserver(RunLoop& loop) : loop_(loop) {} void OnSuccess(SessionDescriptionInterface* desc) override { MockCreateSessionDescriptionObserver::OnSuccess(desc); loop_.Quit(); } void OnFailure(RTCError error) override { MockCreateSessionDescriptionObserver::OnFailure(error); loop_.Quit(); } private: RunLoop& loop_; }; class QuitOnSuccessSetObserver : public SetLocalDescriptionObserverInterface { public: explicit QuitOnSuccessSetObserver(RunLoop& loop) : loop_(loop) {} static scoped_refptr Create(RunLoop& loop) { return make_ref_counted(loop); } void OnSetLocalDescriptionComplete(RTCError error) override { EXPECT_TRUE(error.ok()); was_called_ = true; loop_.Quit(); } bool called() const { return was_called_; } private: RunLoop& loop_; bool was_called_ = false; }; } // namespace class PeerConnectionAudioOptionsTest : public ::testing::Test { public: PeerConnectionAudioOptionsTest() : worker_thread_(Thread::Create()), network_thread_(Thread::CreateWithSocketServer()) { network_thread_->Start(); worker_thread_->Start(); PeerConnectionFactoryDependencies dependencies; dependencies.network_thread = network_thread_.get(); dependencies.worker_thread = worker_thread_.get(); dependencies.signaling_thread = Thread::Current(); EnableFakeMedia(dependencies, std::make_unique()); pc_factory_ = CreateModularPeerConnectionFactory(std::move(dependencies)); } RTCError CreatePeerConnection( const PeerConnectionInterface::RTCConfiguration& configuration) { RTC_DCHECK(!pc_); auto result = pc_factory_->CreatePeerConnectionOrError( configuration, PeerConnectionDependencies(&observer_)); if (!result.ok()) { return result.MoveError(); } pc_ = result.MoveValue(); observer_.SetPeerConnectionInterface(pc_.get()); return result.MoveError(); } // Returns a pointer to the internal PeerConnection implementation. PeerConnection* pc() { RTC_DCHECK(pc_); auto* proxy = static_cast*>( pc_.get()); return static_cast(proxy->internal()); } RunLoop loop_; std::unique_ptr worker_thread_; std::unique_ptr network_thread_; scoped_refptr pc_factory_; scoped_refptr pc_; MockPeerConnectionObserver observer_; }; TEST_F(PeerConnectionAudioOptionsTest, AudioOptionsAppliedOnCreateChannel) { PeerConnectionInterface::RTCConfiguration config; // Set specific audio jitter buffer options in the configuration. config.audio_jitter_buffer_max_packets = 123; config.audio_jitter_buffer_fast_accelerate = true; auto result = CreatePeerConnection(config); ASSERT_TRUE(result.ok()); // Add an audio transceiver. Verify that the internal channel() has not been // created yet. auto transceiver_result = pc()->AddTransceiver(MediaType::AUDIO); ASSERT_TRUE(transceiver_result.ok()); auto transceivers = pc()->GetTransceiversInternal(); ASSERT_EQ(transceivers.size(), 1u); auto* transceiver_impl = transceivers[0]->internal(); ASSERT_FALSE(transceiver_impl->HasChannel()); // Create offer and set local description to trigger CreateChannel. auto offer_observer = make_ref_counted(loop_); pc()->CreateOffer(offer_observer.get(), PeerConnectionInterface::RTCOfferAnswerOptions()); loop_.Run(); EXPECT_TRUE(offer_observer->called()); scoped_refptr sld_observer = QuitOnSuccessSetObserver::Create(loop_); pc()->SetLocalDescription(offer_observer->MoveDescription(), sld_observer); loop_.Run(); EXPECT_TRUE(sld_observer->called()); // Verify that now the channel() exists and that the options were applied to // the voice engine. ASSERT_TRUE(transceiver_impl->HasChannel()); auto* media_channel = transceiver_impl->media_receive_channel(); ASSERT_TRUE(media_channel); auto* voice_channel = static_cast(media_channel); EXPECT_EQ(voice_channel->options().audio_jitter_buffer_max_packets, 123); EXPECT_EQ(voice_channel->options().audio_jitter_buffer_fast_accelerate, true); } } // namespace webrtc