/* * Copyright 2018 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 "api/test/loopback_media_transport.h" #include #include "absl/algorithm/container.h" #include "rtc_base/time_utils.h" namespace webrtc { namespace { constexpr size_t kLoopbackMaxDatagramSize = 1200; class WrapperDatagramTransport : public DatagramTransportInterface { public: explicit WrapperDatagramTransport(DatagramTransportInterface* wrapped) : wrapped_(wrapped) {} // Datagram transport overrides. void Connect(rtc::PacketTransportInternal* packet_transport) override { return wrapped_->Connect(packet_transport); } CongestionControlInterface* congestion_control() override { return wrapped_->congestion_control(); } void SetTransportStateCallback( MediaTransportStateCallback* callback) override { return wrapped_->SetTransportStateCallback(callback); } RTCError SendDatagram(rtc::ArrayView data, DatagramId datagram_id) override { return wrapped_->SendDatagram(data, datagram_id); } size_t GetLargestDatagramSize() const override { return wrapped_->GetLargestDatagramSize(); } void SetDatagramSink(DatagramSinkInterface* sink) override { return wrapped_->SetDatagramSink(sink); } std::string GetTransportParameters() const override { return wrapped_->GetTransportParameters(); } // Data channel overrides. RTCError OpenChannel(int channel_id) override { return wrapped_->OpenChannel(channel_id); } RTCError SendData(int channel_id, const SendDataParams& params, const rtc::CopyOnWriteBuffer& buffer) override { return wrapped_->SendData(channel_id, params, buffer); } RTCError CloseChannel(int channel_id) override { return wrapped_->CloseChannel(channel_id); } void SetDataSink(DataChannelSink* sink) override { wrapped_->SetDataSink(sink); } bool IsReadyToSend() const override { return wrapped_->IsReadyToSend(); } private: DatagramTransportInterface* wrapped_; }; } // namespace WrapperMediaTransportFactory::WrapperMediaTransportFactory( DatagramTransportInterface* wrapped_datagram_transport) : wrapped_datagram_transport_(wrapped_datagram_transport) {} WrapperMediaTransportFactory::WrapperMediaTransportFactory( MediaTransportFactory* wrapped) : wrapped_factory_(wrapped) {} RTCErrorOr> WrapperMediaTransportFactory::CreateMediaTransport( rtc::PacketTransportInternal* packet_transport, rtc::Thread* network_thread, const MediaTransportSettings& settings) { return RTCError(RTCErrorType::UNSUPPORTED_OPERATION); } RTCErrorOr> WrapperMediaTransportFactory::CreateDatagramTransport( rtc::Thread* network_thread, const MediaTransportSettings& settings) { created_transport_count_++; if (wrapped_factory_) { return wrapped_factory_->CreateDatagramTransport(network_thread, settings); } return { std::make_unique(wrapped_datagram_transport_)}; } std::string WrapperMediaTransportFactory::GetTransportName() const { if (wrapped_factory_) { return wrapped_factory_->GetTransportName(); } return "wrapped-transport"; } int WrapperMediaTransportFactory::created_transport_count() const { return created_transport_count_; } RTCErrorOr> WrapperMediaTransportFactory::CreateMediaTransport( rtc::Thread* network_thread, const MediaTransportSettings& settings) { return RTCError(RTCErrorType::UNSUPPORTED_OPERATION); } MediaTransportPair::MediaTransportPair(rtc::Thread* thread) : first_datagram_transport_(thread), second_datagram_transport_(thread), first_factory_(&first_datagram_transport_), second_factory_(&second_datagram_transport_) { first_datagram_transport_.Connect(&second_datagram_transport_); second_datagram_transport_.Connect(&first_datagram_transport_); } MediaTransportPair::~MediaTransportPair() = default; MediaTransportPair::LoopbackDataChannelTransport::LoopbackDataChannelTransport( rtc::Thread* thread) : thread_(thread) {} MediaTransportPair::LoopbackDataChannelTransport:: ~LoopbackDataChannelTransport() { RTC_CHECK(data_sink_ == nullptr); } void MediaTransportPair::LoopbackDataChannelTransport::Connect( LoopbackDataChannelTransport* other) { other_ = other; } RTCError MediaTransportPair::LoopbackDataChannelTransport::OpenChannel( int channel_id) { // No-op. No need to open channels for the loopback. return RTCError::OK(); } RTCError MediaTransportPair::LoopbackDataChannelTransport::SendData( int channel_id, const SendDataParams& params, const rtc::CopyOnWriteBuffer& buffer) { invoker_.AsyncInvoke(RTC_FROM_HERE, thread_, [this, channel_id, params, buffer] { other_->OnData(channel_id, params.type, buffer); }); return RTCError::OK(); } RTCError MediaTransportPair::LoopbackDataChannelTransport::CloseChannel( int channel_id) { invoker_.AsyncInvoke(RTC_FROM_HERE, thread_, [this, channel_id] { other_->OnRemoteCloseChannel(channel_id); rtc::CritScope lock(&sink_lock_); if (data_sink_) { data_sink_->OnChannelClosed(channel_id); } }); return RTCError::OK(); } void MediaTransportPair::LoopbackDataChannelTransport::SetDataSink( DataChannelSink* sink) { rtc::CritScope lock(&sink_lock_); data_sink_ = sink; if (data_sink_ && ready_to_send_) { data_sink_->OnReadyToSend(); } } bool MediaTransportPair::LoopbackDataChannelTransport::IsReadyToSend() const { rtc::CritScope lock(&sink_lock_); return ready_to_send_; } void MediaTransportPair::LoopbackDataChannelTransport::FlushAsyncInvokes() { invoker_.Flush(thread_); } void MediaTransportPair::LoopbackDataChannelTransport::OnData( int channel_id, DataMessageType type, const rtc::CopyOnWriteBuffer& buffer) { rtc::CritScope lock(&sink_lock_); if (data_sink_) { data_sink_->OnDataReceived(channel_id, type, buffer); } } void MediaTransportPair::LoopbackDataChannelTransport::OnRemoteCloseChannel( int channel_id) { rtc::CritScope lock(&sink_lock_); if (data_sink_) { data_sink_->OnChannelClosing(channel_id); data_sink_->OnChannelClosed(channel_id); } } void MediaTransportPair::LoopbackDataChannelTransport::OnReadyToSend( bool ready_to_send) { invoker_.AsyncInvoke(RTC_FROM_HERE, thread_, [this, ready_to_send] { rtc::CritScope lock(&sink_lock_); ready_to_send_ = ready_to_send; // Propagate state to data channel sink, if present. if (data_sink_ && ready_to_send_) { data_sink_->OnReadyToSend(); } }); } MediaTransportPair::LoopbackDatagramTransport::LoopbackDatagramTransport( rtc::Thread* thread) : thread_(thread), dc_transport_(thread) {} void MediaTransportPair::LoopbackDatagramTransport::Connect( LoopbackDatagramTransport* other) { other_ = other; dc_transport_.Connect(&other->dc_transport_); } void MediaTransportPair::LoopbackDatagramTransport::Connect( rtc::PacketTransportInternal* packet_transport) { if (state_after_connect_) { SetState(*state_after_connect_); } } CongestionControlInterface* MediaTransportPair::LoopbackDatagramTransport::congestion_control() { return nullptr; } void MediaTransportPair::LoopbackDatagramTransport::SetTransportStateCallback( MediaTransportStateCallback* callback) { RTC_DCHECK_RUN_ON(thread_); state_callback_ = callback; if (state_callback_) { state_callback_->OnStateChanged(state_); } } RTCError MediaTransportPair::LoopbackDatagramTransport::SendDatagram( rtc::ArrayView data, DatagramId datagram_id) { rtc::CopyOnWriteBuffer buffer; buffer.SetData(data.data(), data.size()); invoker_.AsyncInvoke( RTC_FROM_HERE, thread_, [this, datagram_id, buffer = std::move(buffer)] { RTC_DCHECK_RUN_ON(thread_); other_->DeliverDatagram(std::move(buffer)); if (sink_) { DatagramAck ack; ack.datagram_id = datagram_id; ack.receive_timestamp = Timestamp::us(rtc::TimeMicros()); sink_->OnDatagramAcked(ack); } }); return RTCError::OK(); } size_t MediaTransportPair::LoopbackDatagramTransport::GetLargestDatagramSize() const { return kLoopbackMaxDatagramSize; } void MediaTransportPair::LoopbackDatagramTransport::SetDatagramSink( DatagramSinkInterface* sink) { RTC_DCHECK_RUN_ON(thread_); sink_ = sink; } std::string MediaTransportPair::LoopbackDatagramTransport::GetTransportParameters() const { return transport_parameters_; } RTCError MediaTransportPair::LoopbackDatagramTransport::OpenChannel( int channel_id) { return dc_transport_.OpenChannel(channel_id); } RTCError MediaTransportPair::LoopbackDatagramTransport::SendData( int channel_id, const SendDataParams& params, const rtc::CopyOnWriteBuffer& buffer) { return dc_transport_.SendData(channel_id, params, buffer); } RTCError MediaTransportPair::LoopbackDatagramTransport::CloseChannel( int channel_id) { return dc_transport_.CloseChannel(channel_id); } void MediaTransportPair::LoopbackDatagramTransport::SetDataSink( DataChannelSink* sink) { dc_transport_.SetDataSink(sink); } bool MediaTransportPair::LoopbackDatagramTransport::IsReadyToSend() const { return dc_transport_.IsReadyToSend(); } void MediaTransportPair::LoopbackDatagramTransport::SetState( MediaTransportState state) { invoker_.AsyncInvoke(RTC_FROM_HERE, thread_, [this, state] { RTC_DCHECK_RUN_ON(thread_); state_ = state; if (state_callback_) { state_callback_->OnStateChanged(state_); } }); dc_transport_.OnReadyToSend(state == MediaTransportState::kWritable); } void MediaTransportPair::LoopbackDatagramTransport::SetStateAfterConnect( MediaTransportState state) { state_after_connect_ = state; } void MediaTransportPair::LoopbackDatagramTransport::FlushAsyncInvokes() { dc_transport_.FlushAsyncInvokes(); } void MediaTransportPair::LoopbackDatagramTransport::DeliverDatagram( rtc::CopyOnWriteBuffer buffer) { RTC_DCHECK_RUN_ON(thread_); if (sink_) { sink_->OnDatagramReceived(buffer); } } } // namespace webrtc