blob: 16cb2485d08500f944dc6f53845fc55f9f7d6d24 [file] [log] [blame]
/*
* Copyright 2017 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 "ortc/ortcrtpreceiveradapter.h"
#include <utility>
#include "media/base/mediaconstants.h"
#include "ortc/rtptransportadapter.h"
#include "rtc_base/checks.h"
#include "rtc_base/helpers.h" // For "CreateRandomX".
namespace {
void FillAudioReceiverParameters(webrtc::RtpParameters* parameters) {
for (webrtc::RtpCodecParameters& codec : parameters->codecs) {
if (!codec.num_channels) {
codec.num_channels = 1;
}
}
}
void FillVideoReceiverParameters(webrtc::RtpParameters* parameters) {
for (webrtc::RtpCodecParameters& codec : parameters->codecs) {
if (!codec.clock_rate) {
codec.clock_rate = cricket::kVideoCodecClockrate;
}
}
}
} // namespace
namespace webrtc {
BEGIN_OWNED_PROXY_MAP(OrtcRtpReceiver)
PROXY_SIGNALING_THREAD_DESTRUCTOR()
PROXY_CONSTMETHOD0(rtc::scoped_refptr<MediaStreamTrackInterface>, GetTrack)
PROXY_METHOD1(RTCError, SetTransport, RtpTransportInterface*)
PROXY_CONSTMETHOD0(RtpTransportInterface*, GetTransport)
PROXY_METHOD1(RTCError, Receive, const RtpParameters&)
PROXY_CONSTMETHOD0(RtpParameters, GetParameters)
PROXY_CONSTMETHOD0(cricket::MediaType, GetKind)
END_PROXY_MAP()
// static
std::unique_ptr<OrtcRtpReceiverInterface> OrtcRtpReceiverAdapter::CreateProxy(
std::unique_ptr<OrtcRtpReceiverAdapter> wrapped_receiver) {
RTC_DCHECK(wrapped_receiver);
rtc::Thread* signaling =
wrapped_receiver->rtp_transport_controller_->signaling_thread();
rtc::Thread* worker =
wrapped_receiver->rtp_transport_controller_->worker_thread();
return OrtcRtpReceiverProxy::Create(signaling, worker,
std::move(wrapped_receiver));
}
OrtcRtpReceiverAdapter::~OrtcRtpReceiverAdapter() {
internal_receiver_ = nullptr;
SignalDestroyed();
}
rtc::scoped_refptr<MediaStreamTrackInterface> OrtcRtpReceiverAdapter::GetTrack()
const {
return internal_receiver_ ? internal_receiver_->track() : nullptr;
}
RTCError OrtcRtpReceiverAdapter::SetTransport(
RtpTransportInterface* transport) {
LOG_AND_RETURN_ERROR(
RTCErrorType::UNSUPPORTED_OPERATION,
"Changing the transport of an RtpReceiver is not yet supported.");
}
RtpTransportInterface* OrtcRtpReceiverAdapter::GetTransport() const {
return transport_;
}
RTCError OrtcRtpReceiverAdapter::Receive(const RtpParameters& parameters) {
RtpParameters filled_parameters = parameters;
RTCError err;
switch (kind_) {
case cricket::MEDIA_TYPE_AUDIO:
FillAudioReceiverParameters(&filled_parameters);
err = rtp_transport_controller_->ValidateAndApplyAudioReceiverParameters(
filled_parameters);
if (!err.ok()) {
return err;
}
break;
case cricket::MEDIA_TYPE_VIDEO:
FillVideoReceiverParameters(&filled_parameters);
err = rtp_transport_controller_->ValidateAndApplyVideoReceiverParameters(
filled_parameters);
if (!err.ok()) {
return err;
}
break;
case cricket::MEDIA_TYPE_DATA:
RTC_NOTREACHED();
return webrtc::RTCError(webrtc::RTCErrorType::INTERNAL_ERROR);
}
last_applied_parameters_ = filled_parameters;
// Now that parameters were applied, can create (or recreate) the internal
// receiver.
//
// This is analogous to a PeerConnection creating a receiver after
// SetRemoteDescription is successful.
MaybeRecreateInternalReceiver();
return RTCError::OK();
}
RtpParameters OrtcRtpReceiverAdapter::GetParameters() const {
return last_applied_parameters_;
}
cricket::MediaType OrtcRtpReceiverAdapter::GetKind() const {
return kind_;
}
OrtcRtpReceiverAdapter::OrtcRtpReceiverAdapter(
cricket::MediaType kind,
RtpTransportInterface* transport,
RtpTransportControllerAdapter* rtp_transport_controller)
: kind_(kind),
transport_(transport),
rtp_transport_controller_(rtp_transport_controller) {}
void OrtcRtpReceiverAdapter::MaybeRecreateInternalReceiver() {
if (last_applied_parameters_.encodings.empty()) {
internal_receiver_ = nullptr;
return;
}
// An SSRC of 0 is valid; this is used to identify "the default SSRC" (which
// is the first one seen by the underlying media engine).
uint32_t ssrc = 0;
if (last_applied_parameters_.encodings[0].ssrc) {
ssrc = *last_applied_parameters_.encodings[0].ssrc;
}
if (internal_receiver_ && ssrc == internal_receiver_->ssrc()) {
// SSRC not changing; nothing to do.
return;
}
internal_receiver_ = nullptr;
switch (kind_) {
case cricket::MEDIA_TYPE_AUDIO: {
auto* audio_receiver =
new AudioRtpReceiver(rtp_transport_controller_->worker_thread(),
rtc::CreateRandomUuid(), {});
auto* voice_channel = rtp_transport_controller_->voice_channel();
RTC_DCHECK(voice_channel);
audio_receiver->SetMediaChannel(voice_channel->media_channel());
internal_receiver_ = audio_receiver;
break;
}
case cricket::MEDIA_TYPE_VIDEO: {
auto* video_receiver =
new VideoRtpReceiver(rtp_transport_controller_->worker_thread(),
rtc::CreateRandomUuid(), {});
auto* video_channel = rtp_transport_controller_->video_channel();
RTC_DCHECK(video_channel);
video_receiver->SetMediaChannel(video_channel->media_channel());
internal_receiver_ = video_receiver;
break;
}
case cricket::MEDIA_TYPE_DATA:
RTC_NOTREACHED();
}
internal_receiver_->SetupMediaChannel(ssrc);
}
} // namespace webrtc