blob: fcf80ad692b0fb09a4ea9bd1ef8c73577de3b222 [file] [log] [blame]
// Copyright (c) 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender_impl.h"
#include <memory>
#include <utility>
#include "base/check_op.h"
#include "base/notreached.h"
#include "third_party/blink/renderer/platform/peerconnection/rtc_dtmf_sender_handler.h"
#include "third_party/blink/renderer/platform/peerconnection/rtc_encoded_audio_stream_transformer.h"
#include "third_party/blink/renderer/platform/peerconnection/rtc_encoded_video_stream_transformer.h"
#include "third_party/blink/renderer/platform/peerconnection/rtc_stats.h"
#include "third_party/blink/renderer/platform/peerconnection/rtc_void_request.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
namespace WTF {
template <>
struct CrossThreadCopier<webrtc::RtpParameters>
: public CrossThreadCopierPassThrough<webrtc::RtpParameters> {
STATIC_ONLY(CrossThreadCopier);
};
template <>
struct CrossThreadCopier<webrtc::RTCError>
: public CrossThreadCopierPassThrough<webrtc::RTCError> {
STATIC_ONLY(CrossThreadCopier);
};
} // namespace WTF
namespace blink {
namespace {
// TODO(hbos): Replace RTCVoidRequest with something resolving promises based
// on RTCError, as to surface both exception type and error message.
// https://crbug.com/790007
void OnReplaceTrackCompleted(blink::RTCVoidRequest* request, bool result) {
if (result) {
request->RequestSucceeded();
} else {
request->RequestFailed(
webrtc::RTCError(webrtc::RTCErrorType::INVALID_MODIFICATION));
}
}
void OnSetParametersCompleted(blink::RTCVoidRequest* request,
webrtc::RTCError result) {
if (result.ok())
request->RequestSucceeded();
else
request->RequestFailed(result);
}
} // namespace
RtpSenderState::RtpSenderState(
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> signaling_task_runner,
scoped_refptr<webrtc::RtpSenderInterface> webrtc_sender,
std::unique_ptr<blink::WebRtcMediaStreamTrackAdapterMap::AdapterRef>
track_ref,
std::vector<std::string> stream_ids)
: main_task_runner_(std::move(main_task_runner)),
signaling_task_runner_(std::move(signaling_task_runner)),
webrtc_sender_(std::move(webrtc_sender)),
webrtc_dtls_transport_(webrtc_sender_->dtls_transport()),
webrtc_dtls_transport_information_(webrtc::DtlsTransportState::kNew),
is_initialized_(false),
track_ref_(std::move(track_ref)),
stream_ids_(std::move(stream_ids)) {
DCHECK(main_task_runner_);
DCHECK(signaling_task_runner_);
DCHECK(webrtc_sender_);
if (webrtc_dtls_transport_) {
webrtc_dtls_transport_information_ = webrtc_dtls_transport_->Information();
}
}
RtpSenderState::RtpSenderState(RtpSenderState&& other)
: main_task_runner_(other.main_task_runner_),
signaling_task_runner_(other.signaling_task_runner_),
webrtc_sender_(std::move(other.webrtc_sender_)),
webrtc_dtls_transport_(std::move(other.webrtc_dtls_transport_)),
webrtc_dtls_transport_information_(
other.webrtc_dtls_transport_information_),
is_initialized_(other.is_initialized_),
track_ref_(std::move(other.track_ref_)),
stream_ids_(std::move(other.stream_ids_)) {
other.main_task_runner_ = nullptr;
other.signaling_task_runner_ = nullptr;
}
RtpSenderState::~RtpSenderState() {
// It's OK to not be on the main thread if this state has been moved, in which
// case |main_task_runner_| is null.
DCHECK(!main_task_runner_ || main_task_runner_->BelongsToCurrentThread());
}
RtpSenderState& RtpSenderState::operator=(RtpSenderState&& other) {
DCHECK_EQ(main_task_runner_, other.main_task_runner_);
DCHECK_EQ(signaling_task_runner_, other.signaling_task_runner_);
other.main_task_runner_ = nullptr;
other.signaling_task_runner_ = nullptr;
webrtc_sender_ = std::move(other.webrtc_sender_);
webrtc_dtls_transport_ = std::move(other.webrtc_dtls_transport_);
webrtc_dtls_transport_information_ = other.webrtc_dtls_transport_information_;
is_initialized_ = other.is_initialized_;
track_ref_ = std::move(other.track_ref_);
stream_ids_ = std::move(other.stream_ids_);
return *this;
}
bool RtpSenderState::is_initialized() const {
DCHECK(main_task_runner_->BelongsToCurrentThread());
return is_initialized_;
}
void RtpSenderState::Initialize() {
DCHECK(main_task_runner_->BelongsToCurrentThread());
if (track_ref_)
track_ref_->InitializeOnMainThread();
is_initialized_ = true;
}
scoped_refptr<base::SingleThreadTaskRunner> RtpSenderState::main_task_runner()
const {
DCHECK(main_task_runner_->BelongsToCurrentThread());
return main_task_runner_;
}
scoped_refptr<base::SingleThreadTaskRunner>
RtpSenderState::signaling_task_runner() const {
DCHECK(main_task_runner_->BelongsToCurrentThread());
return signaling_task_runner_;
}
scoped_refptr<webrtc::RtpSenderInterface> RtpSenderState::webrtc_sender()
const {
DCHECK(main_task_runner_->BelongsToCurrentThread());
return webrtc_sender_;
}
rtc::scoped_refptr<webrtc::DtlsTransportInterface>
RtpSenderState::webrtc_dtls_transport() const {
DCHECK(main_task_runner_->BelongsToCurrentThread());
return webrtc_dtls_transport_;
}
webrtc::DtlsTransportInformation
RtpSenderState::webrtc_dtls_transport_information() const {
DCHECK(main_task_runner_->BelongsToCurrentThread());
return webrtc_dtls_transport_information_;
}
const std::unique_ptr<blink::WebRtcMediaStreamTrackAdapterMap::AdapterRef>&
RtpSenderState::track_ref() const {
DCHECK(main_task_runner_->BelongsToCurrentThread());
return track_ref_;
}
void RtpSenderState::set_track_ref(
std::unique_ptr<blink::WebRtcMediaStreamTrackAdapterMap::AdapterRef>
track_ref) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
DCHECK(!is_initialized_ || !track_ref || track_ref->is_initialized());
track_ref_ = std::move(track_ref);
}
std::vector<std::string> RtpSenderState::stream_ids() const {
DCHECK(main_task_runner_->BelongsToCurrentThread());
return stream_ids_;
}
class RTCRtpSenderImpl::RTCRtpSenderInternal
: public WTF::ThreadSafeRefCounted<
RTCRtpSenderImpl::RTCRtpSenderInternal,
RTCRtpSenderImpl::RTCRtpSenderInternalTraits> {
public:
RTCRtpSenderInternal(
scoped_refptr<webrtc::PeerConnectionInterface> native_peer_connection,
scoped_refptr<blink::WebRtcMediaStreamTrackAdapterMap> track_map,
RtpSenderState state,
bool force_encoded_audio_insertable_streams,
bool force_encoded_video_insertable_streams)
: native_peer_connection_(std::move(native_peer_connection)),
track_map_(std::move(track_map)),
main_task_runner_(state.main_task_runner()),
signaling_task_runner_(state.signaling_task_runner()),
webrtc_sender_(state.webrtc_sender()),
state_(std::move(state)) {
DCHECK(track_map_);
DCHECK(state_.is_initialized());
if (force_encoded_audio_insertable_streams &&
webrtc_sender_->media_type() == cricket::MEDIA_TYPE_AUDIO) {
encoded_audio_transformer_ =
std::make_unique<RTCEncodedAudioStreamTransformer>(main_task_runner_);
webrtc_sender_->SetEncoderToPacketizerFrameTransformer(
encoded_audio_transformer_->Delegate());
}
if (force_encoded_video_insertable_streams &&
webrtc_sender_->media_type() == cricket::MEDIA_TYPE_VIDEO) {
encoded_video_transformer_ =
std::make_unique<RTCEncodedVideoStreamTransformer>(main_task_runner_);
webrtc_sender_->SetEncoderToPacketizerFrameTransformer(
encoded_video_transformer_->Delegate());
}
DCHECK(!encoded_audio_transformer_ || !encoded_video_transformer_);
}
const RtpSenderState& state() const {
DCHECK(main_task_runner_->BelongsToCurrentThread());
return state_;
}
void set_state(RtpSenderState state) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
DCHECK_EQ(state.main_task_runner(), main_task_runner_);
DCHECK_EQ(state.signaling_task_runner(), signaling_task_runner_);
DCHECK(state.webrtc_sender() == webrtc_sender_);
DCHECK(state.is_initialized());
state_ = std::move(state);
}
void ReplaceTrack(MediaStreamComponent* with_track,
base::OnceCallback<void(bool)> callback) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
std::unique_ptr<blink::WebRtcMediaStreamTrackAdapterMap::AdapterRef>
track_ref;
webrtc::MediaStreamTrackInterface* webrtc_track = nullptr;
if (with_track) {
track_ref = track_map_->GetOrCreateLocalTrackAdapter(with_track);
webrtc_track = track_ref->webrtc_track();
}
PostCrossThreadTask(
*signaling_task_runner_.get(), FROM_HERE,
CrossThreadBindOnce(&RTCRtpSenderImpl::RTCRtpSenderInternal::
ReplaceTrackOnSignalingThread,
WrapRefCounted(this), std::move(track_ref),
CrossThreadUnretained(webrtc_track),
CrossThreadBindOnce(std::move(callback))));
}
std::unique_ptr<blink::RtcDtmfSenderHandler> GetDtmfSender() const {
// The webrtc_sender() is a proxy, so this is a blocking call to the
// webrtc signalling thread.
DCHECK(main_task_runner_->BelongsToCurrentThread());
auto dtmf_sender = webrtc_sender_->GetDtmfSender();
return std::make_unique<RtcDtmfSenderHandler>(main_task_runner_,
dtmf_sender);
}
std::unique_ptr<webrtc::RtpParameters> GetParameters() {
// The webrtc_sender() is a proxy, so this is a blocking call to the
// webrtc signalling thread.
parameters_ = webrtc_sender_->GetParameters();
return std::make_unique<webrtc::RtpParameters>(parameters_);
}
void SetParameters(
Vector<webrtc::RtpEncodingParameters> encodings,
absl::optional<webrtc::DegradationPreference> degradation_preference,
base::OnceCallback<void(webrtc::RTCError)> callback) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
webrtc::RtpParameters new_parameters = parameters_;
new_parameters.degradation_preference = degradation_preference;
for (WTF::wtf_size_t i = 0; i < new_parameters.encodings.size(); ++i) {
// Encodings have other parameters in the native layer that aren't exposed
// to the blink layer. So instead of copying the new struct over the old
// one, we copy the members one by one over the old struct, effectively
// patching the changes done by the user.
const auto& encoding = encodings[i];
new_parameters.encodings[i].active = encoding.active;
new_parameters.encodings[i].bitrate_priority = encoding.bitrate_priority;
new_parameters.encodings[i].network_priority = encoding.network_priority;
new_parameters.encodings[i].max_bitrate_bps = encoding.max_bitrate_bps;
new_parameters.encodings[i].max_framerate = encoding.max_framerate;
new_parameters.encodings[i].rid = encoding.rid;
new_parameters.encodings[i].scale_resolution_down_by =
encoding.scale_resolution_down_by;
new_parameters.encodings[i].adaptive_ptime = encoding.adaptive_ptime;
}
PostCrossThreadTask(
*signaling_task_runner_.get(), FROM_HERE,
CrossThreadBindOnce(&RTCRtpSenderImpl::RTCRtpSenderInternal::
SetParametersOnSignalingThread,
WrapRefCounted(this), std::move(new_parameters),
CrossThreadBindOnce(std::move(callback))));
}
void GetStats(RTCStatsReportCallback callback,
const Vector<webrtc::NonStandardGroupId>& exposed_group_ids) {
PostCrossThreadTask(
*signaling_task_runner_.get(), FROM_HERE,
CrossThreadBindOnce(
&RTCRtpSenderImpl::RTCRtpSenderInternal::GetStatsOnSignalingThread,
WrapRefCounted(this), CrossThreadBindOnce(std::move(callback)),
exposed_group_ids));
}
bool RemoveFromPeerConnection(webrtc::PeerConnectionInterface* pc) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
if (!pc->RemoveTrack(webrtc_sender_.get()))
return false;
// TODO(hbos): Removing the track should null the sender's track, or we
// should do |webrtc_sender_->SetTrack(null)| but that is not allowed on a
// stopped sender. In the meantime, there is a discrepancy between layers.
// https://crbug.com/webrtc/7945
state_.set_track_ref(nullptr);
return true;
}
void SetStreams(const Vector<String>& stream_ids) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
PostCrossThreadTask(
*signaling_task_runner_.get(), FROM_HERE,
CrossThreadBindOnce(&RTCRtpSenderImpl::RTCRtpSenderInternal::
SetStreamsOnSignalingThread,
WrapRefCounted(this), stream_ids));
}
RTCEncodedAudioStreamTransformer* GetEncodedAudioStreamTransformer() const {
return encoded_audio_transformer_.get();
}
RTCEncodedVideoStreamTransformer* GetEncodedVideoStreamTransformer() const {
return encoded_video_transformer_.get();
}
private:
friend class WTF::ThreadSafeRefCounted<RTCRtpSenderInternal,
RTCRtpSenderInternalTraits>;
friend struct RTCRtpSenderImpl::RTCRtpSenderInternalTraits;
~RTCRtpSenderInternal() {
// Ensured by destructor traits.
DCHECK(main_task_runner_->BelongsToCurrentThread());
}
// |webrtc_track| is passed as an argument because |track_ref->webrtc_track()|
// cannot be accessed on the signaling thread. https://crbug.com/756436
void ReplaceTrackOnSignalingThread(
std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef> track_ref,
webrtc::MediaStreamTrackInterface* webrtc_track,
CrossThreadOnceFunction<void(bool)> callback) {
DCHECK(signaling_task_runner_->BelongsToCurrentThread());
bool result = webrtc_sender_->SetTrack(webrtc_track);
PostCrossThreadTask(
*main_task_runner_.get(), FROM_HERE,
CrossThreadBindOnce(
&RTCRtpSenderImpl::RTCRtpSenderInternal::ReplaceTrackCallback,
WrapRefCounted(this), result, std::move(track_ref),
std::move(callback)));
}
void ReplaceTrackCallback(
bool result,
std::unique_ptr<blink::WebRtcMediaStreamTrackAdapterMap::AdapterRef>
track_ref,
CrossThreadOnceFunction<void(bool)> callback) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
if (result)
state_.set_track_ref(std::move(track_ref));
std::move(callback).Run(result);
}
using RTCStatsReportCallbackInternal =
CrossThreadOnceFunction<void(std::unique_ptr<RTCStatsReportPlatform>)>;
void GetStatsOnSignalingThread(
RTCStatsReportCallbackInternal callback,
const Vector<webrtc::NonStandardGroupId>& exposed_group_ids) {
native_peer_connection_->GetStats(
webrtc_sender_.get(),
CreateRTCStatsCollectorCallback(
main_task_runner_, ConvertToBaseOnceCallback(std::move(callback)),
exposed_group_ids));
}
void SetParametersOnSignalingThread(
webrtc::RtpParameters parameters,
CrossThreadOnceFunction<void(webrtc::RTCError)> callback) {
DCHECK(signaling_task_runner_->BelongsToCurrentThread());
webrtc::RTCError result = webrtc_sender_->SetParameters(parameters);
PostCrossThreadTask(
*main_task_runner_.get(), FROM_HERE,
CrossThreadBindOnce(
&RTCRtpSenderImpl::RTCRtpSenderInternal::SetParametersCallback,
WrapRefCounted(this), std::move(result), std::move(callback)));
}
void SetParametersCallback(
webrtc::RTCError result,
CrossThreadOnceFunction<void(webrtc::RTCError)> callback) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
std::move(callback).Run(std::move(result));
}
void SetStreamsOnSignalingThread(const Vector<String>& stream_ids) {
DCHECK(signaling_task_runner_->BelongsToCurrentThread());
std::vector<std::string> ids;
for (auto stream_id : stream_ids)
ids.emplace_back(stream_id.Utf8());
webrtc_sender_->SetStreams(std::move(ids));
}
const scoped_refptr<webrtc::PeerConnectionInterface> native_peer_connection_;
const scoped_refptr<blink::WebRtcMediaStreamTrackAdapterMap> track_map_;
// Task runners and webrtc sender: Same information as stored in
// |state_| but const and safe to touch on the signaling thread to
// avoid race with set_state().
const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
const scoped_refptr<base::SingleThreadTaskRunner> signaling_task_runner_;
const scoped_refptr<webrtc::RtpSenderInterface> webrtc_sender_;
std::unique_ptr<RTCEncodedAudioStreamTransformer> encoded_audio_transformer_;
std::unique_ptr<RTCEncodedVideoStreamTransformer> encoded_video_transformer_;
RtpSenderState state_;
webrtc::RtpParameters parameters_;
};
struct RTCRtpSenderImpl::RTCRtpSenderInternalTraits {
static void Destruct(const RTCRtpSenderInternal* sender) {
// RTCRtpSenderInternal owns AdapterRefs which have to be destroyed on the
// main thread, this ensures delete always happens there.
if (!sender->main_task_runner_->BelongsToCurrentThread()) {
PostCrossThreadTask(
*sender->main_task_runner_.get(), FROM_HERE,
CrossThreadBindOnce(
&RTCRtpSenderImpl::RTCRtpSenderInternalTraits::Destruct,
CrossThreadUnretained(sender)));
return;
}
delete sender;
}
};
uintptr_t RTCRtpSenderImpl::getId(
const webrtc::RtpSenderInterface* webrtc_sender) {
return reinterpret_cast<uintptr_t>(webrtc_sender);
}
RTCRtpSenderImpl::RTCRtpSenderImpl(
scoped_refptr<webrtc::PeerConnectionInterface> native_peer_connection,
scoped_refptr<blink::WebRtcMediaStreamTrackAdapterMap> track_map,
RtpSenderState state,
bool force_encoded_audio_insertable_streams,
bool force_encoded_video_insertable_streams)
: internal_(base::MakeRefCounted<RTCRtpSenderInternal>(
std::move(native_peer_connection),
std::move(track_map),
std::move(state),
force_encoded_audio_insertable_streams,
force_encoded_video_insertable_streams)) {}
RTCRtpSenderImpl::RTCRtpSenderImpl(const RTCRtpSenderImpl& other)
: internal_(other.internal_) {}
RTCRtpSenderImpl::~RTCRtpSenderImpl() {}
RTCRtpSenderImpl& RTCRtpSenderImpl::operator=(const RTCRtpSenderImpl& other) {
internal_ = other.internal_;
return *this;
}
const RtpSenderState& RTCRtpSenderImpl::state() const {
return internal_->state();
}
void RTCRtpSenderImpl::set_state(RtpSenderState state) {
internal_->set_state(std::move(state));
}
std::unique_ptr<blink::RTCRtpSenderPlatform> RTCRtpSenderImpl::ShallowCopy()
const {
return std::make_unique<RTCRtpSenderImpl>(*this);
}
uintptr_t RTCRtpSenderImpl::Id() const {
return getId(internal_->state().webrtc_sender().get());
}
rtc::scoped_refptr<webrtc::DtlsTransportInterface>
RTCRtpSenderImpl::DtlsTransport() {
return internal_->state().webrtc_dtls_transport();
}
webrtc::DtlsTransportInformation RTCRtpSenderImpl::DtlsTransportInformation() {
return internal_->state().webrtc_dtls_transport_information();
}
MediaStreamComponent* RTCRtpSenderImpl::Track() const {
const auto& track_ref = internal_->state().track_ref();
return track_ref ? track_ref->track() : nullptr;
}
Vector<String> RTCRtpSenderImpl::StreamIds() const {
const auto& stream_ids = internal_->state().stream_ids();
Vector<String> wtf_stream_ids(
static_cast<WTF::wtf_size_t>(stream_ids.size()));
for (WTF::wtf_size_t i = 0; i < stream_ids.size(); ++i)
wtf_stream_ids[i] = String::FromUTF8(stream_ids[i]);
return wtf_stream_ids;
}
void RTCRtpSenderImpl::ReplaceTrack(MediaStreamComponent* with_track,
RTCVoidRequest* request) {
internal_->ReplaceTrack(
with_track, WTF::Bind(&OnReplaceTrackCompleted, WrapPersistent(request)));
}
std::unique_ptr<blink::RtcDtmfSenderHandler> RTCRtpSenderImpl::GetDtmfSender()
const {
return internal_->GetDtmfSender();
}
std::unique_ptr<webrtc::RtpParameters> RTCRtpSenderImpl::GetParameters() const {
return internal_->GetParameters();
}
void RTCRtpSenderImpl::SetParameters(
Vector<webrtc::RtpEncodingParameters> encodings,
absl::optional<webrtc::DegradationPreference> degradation_preference,
blink::RTCVoidRequest* request) {
internal_->SetParameters(
std::move(encodings), degradation_preference,
WTF::Bind(&OnSetParametersCompleted, WrapPersistent(request)));
}
void RTCRtpSenderImpl::GetStats(
RTCStatsReportCallback callback,
const Vector<webrtc::NonStandardGroupId>& exposed_group_ids) {
internal_->GetStats(std::move(callback), exposed_group_ids);
}
void RTCRtpSenderImpl::SetStreams(const Vector<String>& stream_ids) {
internal_->SetStreams(stream_ids);
}
void RTCRtpSenderImpl::ReplaceTrack(MediaStreamComponent* with_track,
base::OnceCallback<void(bool)> callback) {
internal_->ReplaceTrack(with_track, std::move(callback));
}
bool RTCRtpSenderImpl::RemoveFromPeerConnection(
webrtc::PeerConnectionInterface* pc) {
return internal_->RemoveFromPeerConnection(pc);
}
RTCEncodedAudioStreamTransformer*
RTCRtpSenderImpl::GetEncodedAudioStreamTransformer() const {
return internal_->GetEncodedAudioStreamTransformer();
}
RTCEncodedVideoStreamTransformer*
RTCRtpSenderImpl::GetEncodedVideoStreamTransformer() const {
return internal_->GetEncodedVideoStreamTransformer();
}
RTCRtpSenderOnlyTransceiver::RTCRtpSenderOnlyTransceiver(
std::unique_ptr<blink::RTCRtpSenderPlatform> sender)
: sender_(std::move(sender)) {
DCHECK(sender_);
}
RTCRtpSenderOnlyTransceiver::~RTCRtpSenderOnlyTransceiver() {}
RTCRtpTransceiverPlatformImplementationType
RTCRtpSenderOnlyTransceiver::ImplementationType() const {
return RTCRtpTransceiverPlatformImplementationType::kPlanBSenderOnly;
}
uintptr_t RTCRtpSenderOnlyTransceiver::Id() const {
NOTIMPLEMENTED();
return 0u;
}
String RTCRtpSenderOnlyTransceiver::Mid() const {
NOTIMPLEMENTED();
return String();
}
std::unique_ptr<blink::RTCRtpSenderPlatform>
RTCRtpSenderOnlyTransceiver::Sender() const {
return sender_->ShallowCopy();
}
std::unique_ptr<RTCRtpReceiverPlatform> RTCRtpSenderOnlyTransceiver::Receiver()
const {
NOTIMPLEMENTED();
return nullptr;
}
bool RTCRtpSenderOnlyTransceiver::Stopped() const {
NOTIMPLEMENTED();
return false;
}
webrtc::RtpTransceiverDirection RTCRtpSenderOnlyTransceiver::Direction() const {
NOTIMPLEMENTED();
return webrtc::RtpTransceiverDirection::kSendOnly;
}
webrtc::RTCError RTCRtpSenderOnlyTransceiver::SetDirection(
webrtc::RtpTransceiverDirection direction) {
NOTIMPLEMENTED();
return webrtc::RTCError::OK();
}
base::Optional<webrtc::RtpTransceiverDirection>
RTCRtpSenderOnlyTransceiver::CurrentDirection() const {
NOTIMPLEMENTED();
return webrtc::RtpTransceiverDirection::kSendOnly;
}
base::Optional<webrtc::RtpTransceiverDirection>
RTCRtpSenderOnlyTransceiver::FiredDirection() const {
NOTIMPLEMENTED();
return webrtc::RtpTransceiverDirection::kSendOnly;
}
webrtc::RTCError RTCRtpSenderOnlyTransceiver::SetCodecPreferences(
Vector<webrtc::RtpCodecCapability>) {
NOTIMPLEMENTED();
return {};
}
} // namespace blink