mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-02 00:17:02 +00:00
Temp
This commit is contained in:
parent
b71f748c48
commit
5f9565853d
@ -183,7 +183,7 @@ public:
|
||||
std::unique_ptr<rtc::Thread> _networkThread;
|
||||
std::unique_ptr<rtc::Thread> _workerThread;
|
||||
std::unique_ptr<rtc::Thread> _signalingThread;
|
||||
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> _nativeFactory;
|
||||
rtc::scoped_refptr<webrtc::TgPeerConnectionFactory> _nativeFactory;
|
||||
|
||||
std::unique_ptr<PeerConnectionObserverImpl> _observer;
|
||||
rtc::scoped_refptr<webrtc::PeerConnectionInterface> _peerConnection;
|
||||
@ -255,7 +255,7 @@ public:
|
||||
if (!result) {
|
||||
return nil;
|
||||
}
|
||||
_nativeFactory = webrtc::PeerConnectionFactoryProxy::Create(pc_factory->signaling_thread(), pc_factory);
|
||||
_nativeFactory = pc_factory;
|
||||
|
||||
webrtc::PeerConnectionInterface::RTCConfiguration config;
|
||||
config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;
|
||||
|
@ -65,6 +65,8 @@
|
||||
#include "tg_jsep_transport.h"
|
||||
#include "tg_jsep_transport_controller.h"
|
||||
|
||||
#include "tg_rtp_sender.h"
|
||||
|
||||
using cricket::ContentInfo;
|
||||
using cricket::ContentInfos;
|
||||
using cricket::MediaContentDescription;
|
||||
@ -138,7 +140,6 @@ enum {
|
||||
MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
|
||||
MSG_SET_SESSIONDESCRIPTION_FAILED,
|
||||
MSG_CREATE_SESSIONDESCRIPTION_FAILED,
|
||||
MSG_GETSTATS,
|
||||
MSG_REPORT_USAGE_PATTERN,
|
||||
};
|
||||
|
||||
@ -200,51 +201,6 @@ bool IsValidOfferToReceiveMedia(int value) {
|
||||
(value <= Options::kMaxOfferToReceiveMedia);
|
||||
}
|
||||
|
||||
// Add options to |[audio/video]_media_description_options| from |senders|.
|
||||
void AddPlanBRtpSenderOptions(
|
||||
const std::vector<rtc::scoped_refptr<
|
||||
RtpSenderProxyWithInternal<RtpSenderInternal>>>& senders,
|
||||
cricket::MediaDescriptionOptions* audio_media_description_options,
|
||||
cricket::MediaDescriptionOptions* video_media_description_options,
|
||||
int num_sim_layers) {
|
||||
for (const auto& sender : senders) {
|
||||
if (sender->media_type() == cricket::MEDIA_TYPE_AUDIO) {
|
||||
if (audio_media_description_options) {
|
||||
audio_media_description_options->AddAudioSender(
|
||||
sender->id(), sender->internal()->stream_ids());
|
||||
}
|
||||
} else {
|
||||
RTC_DCHECK(sender->media_type() == cricket::MEDIA_TYPE_VIDEO);
|
||||
if (video_media_description_options) {
|
||||
video_media_description_options->AddVideoSender(
|
||||
sender->id(), sender->internal()->stream_ids(), {},
|
||||
SimulcastLayerList(), num_sim_layers);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add options to |session_options| from |rtp_data_channels|.
|
||||
void AddRtpDataChannelOptions(
|
||||
const std::map<std::string, rtc::scoped_refptr<DataChannel>>&
|
||||
rtp_data_channels,
|
||||
cricket::MediaDescriptionOptions* data_media_description_options) {
|
||||
if (!data_media_description_options) {
|
||||
return;
|
||||
}
|
||||
// Check for data channels.
|
||||
for (const auto& kv : rtp_data_channels) {
|
||||
const DataChannel* channel = kv.second;
|
||||
if (channel->state() == DataChannel::kConnecting ||
|
||||
channel->state() == DataChannel::kOpen) {
|
||||
// Legacy RTP data channels are signaled with the track/stream ID set to
|
||||
// the data channel's label.
|
||||
data_media_description_options->AddRtpDataChannel(channel->label(),
|
||||
channel->label());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ConvertIceTransportTypeToCandidateFilter(
|
||||
PeerConnectionInterface::IceTransportsType type) {
|
||||
switch (type) {
|
||||
@ -1062,18 +1018,12 @@ TgPeerConnection::~TgPeerConnection() {
|
||||
weak_ptr_factory_.InvalidateWeakPtrs();
|
||||
|
||||
// Need to stop transceivers before destroying the stats collector because
|
||||
// AudioRtpSender has a reference to the StatsCollector it will update when
|
||||
// TgAudioRtpSender has a reference to the StatsCollector it will update when
|
||||
// stopping.
|
||||
for (const auto& transceiver : transceivers_) {
|
||||
transceiver->Stop();
|
||||
}
|
||||
|
||||
stats_.reset(nullptr);
|
||||
if (stats_collector_) {
|
||||
stats_collector_->WaitForPendingRequest();
|
||||
stats_collector_ = nullptr;
|
||||
}
|
||||
|
||||
// Don't destroy BaseChannels until after stats has been cleaned up so that
|
||||
// the last stats request can still read from the channels.
|
||||
DestroyAllChannels();
|
||||
@ -1343,9 +1293,6 @@ bool TgPeerConnection::Initialize(
|
||||
transport_controller_->SignalIceCandidatePairChanged.connect(
|
||||
this, &TgPeerConnection::OnTransportControllerCandidateChanged);
|
||||
|
||||
stats_.reset(new StatsCollector(this));
|
||||
stats_collector_ = RTCStatsCollector::Create(this);
|
||||
|
||||
configuration_ = configuration;
|
||||
|
||||
transport_controller_->SetIceConfig(ParseIceConfig(configuration));
|
||||
@ -1378,7 +1325,7 @@ bool TgPeerConnection::Initialize(
|
||||
dependencies.cert_generator.reset();
|
||||
}
|
||||
|
||||
webrtc_session_desc_factory_.reset(new WebRtcSessionDescriptionFactory(
|
||||
webrtc_session_desc_factory_.reset(new TgWebRtcSessionDescriptionFactory(
|
||||
signaling_thread(), channel_manager(), this, session_id(),
|
||||
std::move(dependencies.cert_generator), certificate, &ssrc_generator_));
|
||||
webrtc_session_desc_factory_->SignalCertificateReady.connect(
|
||||
@ -1417,9 +1364,9 @@ bool TgPeerConnection::Initialize(
|
||||
}
|
||||
|
||||
RTCError TgPeerConnection::ValidateConfiguration(
|
||||
const RTCConfiguration& config) const {
|
||||
const PeerConnectionInterface::RTCConfiguration& config) const {
|
||||
if (config.ice_regather_interval_range &&
|
||||
config.continual_gathering_policy == GATHER_ONCE) {
|
||||
config.continual_gathering_policy == PeerConnectionInterface::GATHER_ONCE) {
|
||||
return RTCError(RTCErrorType::INVALID_PARAMETER,
|
||||
"ice_regather_interval_range specified but continual "
|
||||
"gathering policy is GATHER_ONCE");
|
||||
@ -1476,7 +1423,6 @@ bool TgPeerConnection::AddStream(MediaStreamInterface* local_stream) {
|
||||
AddVideoTrack(track.get(), local_stream);
|
||||
}
|
||||
|
||||
stats_->AddStream(local_stream);
|
||||
UpdateNegotiationNeeded();
|
||||
return true;
|
||||
}
|
||||
@ -1532,58 +1478,13 @@ RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> TgPeerConnection::AddTrack(
|
||||
RTCErrorType::INVALID_PARAMETER,
|
||||
"Sender already exists for track " + track->id() + ".");
|
||||
}
|
||||
auto sender_or_error =
|
||||
(IsUnifiedPlan() ? AddTrackUnifiedPlan(track, stream_ids)
|
||||
: AddTrackPlanB(track, stream_ids));
|
||||
auto sender_or_error = AddTrackUnifiedPlan(track, stream_ids);
|
||||
if (sender_or_error.ok()) {
|
||||
UpdateNegotiationNeeded();
|
||||
stats_->AddTrack(track);
|
||||
}
|
||||
return sender_or_error;
|
||||
}
|
||||
|
||||
RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>
|
||||
TgPeerConnection::AddTrackPlanB(
|
||||
rtc::scoped_refptr<MediaStreamTrackInterface> track,
|
||||
const std::vector<std::string>& stream_ids) {
|
||||
if (stream_ids.size() > 1u) {
|
||||
LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION,
|
||||
"AddTrack with more than one stream is not "
|
||||
"supported with Plan B semantics.");
|
||||
}
|
||||
std::vector<std::string> adjusted_stream_ids = stream_ids;
|
||||
if (adjusted_stream_ids.empty()) {
|
||||
adjusted_stream_ids.push_back(rtc::CreateRandomUuid());
|
||||
}
|
||||
cricket::MediaType media_type =
|
||||
(track->kind() == MediaStreamTrackInterface::kAudioKind
|
||||
? cricket::MEDIA_TYPE_AUDIO
|
||||
: cricket::MEDIA_TYPE_VIDEO);
|
||||
auto new_sender =
|
||||
CreateSender(media_type, track->id(), track, adjusted_stream_ids, {});
|
||||
if (track->kind() == MediaStreamTrackInterface::kAudioKind) {
|
||||
new_sender->internal()->SetMediaChannel(voice_media_channel());
|
||||
GetAudioTransceiver()->internal()->AddSender(new_sender);
|
||||
const RtpSenderInfo* sender_info =
|
||||
FindSenderInfo(local_audio_sender_infos_,
|
||||
new_sender->internal()->stream_ids()[0], track->id());
|
||||
if (sender_info) {
|
||||
new_sender->internal()->SetSsrc(sender_info->first_ssrc);
|
||||
}
|
||||
} else {
|
||||
RTC_DCHECK_EQ(MediaStreamTrackInterface::kVideoKind, track->kind());
|
||||
new_sender->internal()->SetMediaChannel(video_media_channel());
|
||||
GetVideoTransceiver()->internal()->AddSender(new_sender);
|
||||
const RtpSenderInfo* sender_info =
|
||||
FindSenderInfo(local_video_sender_infos_,
|
||||
new_sender->internal()->stream_ids()[0], track->id());
|
||||
if (sender_info) {
|
||||
new_sender->internal()->SetSsrc(sender_info->first_ssrc);
|
||||
}
|
||||
}
|
||||
return rtc::scoped_refptr<RtpSenderInterface>(new_sender);
|
||||
}
|
||||
|
||||
RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>
|
||||
TgPeerConnection::AddTrackUnifiedPlan(
|
||||
rtc::scoped_refptr<MediaStreamTrackInterface> track,
|
||||
@ -1847,7 +1748,7 @@ TgPeerConnection::AddTransceiver(
|
||||
return rtc::scoped_refptr<RtpTransceiverInterface>(transceiver);
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>>
|
||||
TgPeerConnection::CreateSender(
|
||||
cricket::MediaType media_type,
|
||||
const std::string& id,
|
||||
@ -1855,20 +1756,20 @@ TgPeerConnection::CreateSender(
|
||||
const std::vector<std::string>& stream_ids,
|
||||
const std::vector<RtpEncodingParameters>& send_encodings) {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender;
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>> sender;
|
||||
if (media_type == cricket::MEDIA_TYPE_AUDIO) {
|
||||
RTC_DCHECK(!track ||
|
||||
(track->kind() == MediaStreamTrackInterface::kAudioKind));
|
||||
sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
|
||||
sender = RtpSenderProxyWithInternal<TgRtpSenderInternal>::Create(
|
||||
signaling_thread(),
|
||||
AudioRtpSender::Create(worker_thread(), id, stats_.get(), this));
|
||||
TgAudioRtpSender::Create(worker_thread(), id, stats_.get(), this));
|
||||
NoteUsageEvent(UsageEvent::AUDIO_ADDED);
|
||||
} else {
|
||||
RTC_DCHECK_EQ(media_type, cricket::MEDIA_TYPE_VIDEO);
|
||||
RTC_DCHECK(!track ||
|
||||
(track->kind() == MediaStreamTrackInterface::kVideoKind));
|
||||
sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
|
||||
signaling_thread(), VideoRtpSender::Create(worker_thread(), id, this));
|
||||
sender = RtpSenderProxyWithInternal<TgRtpSenderInternal>::Create(
|
||||
signaling_thread(), TgVideoRtpSender::Create(worker_thread(), id, this));
|
||||
NoteUsageEvent(UsageEvent::VIDEO_ADDED);
|
||||
}
|
||||
bool set_track_succeeded = sender->SetTrack(track);
|
||||
@ -1900,7 +1801,7 @@ TgPeerConnection::CreateReceiver(cricket::MediaType media_type,
|
||||
|
||||
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
|
||||
TgPeerConnection::CreateAndAddTransceiver(
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>> sender,
|
||||
rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
|
||||
receiver) {
|
||||
// Ensure that the new sender does not have an ID that is already in use by
|
||||
@ -1948,19 +1849,19 @@ rtc::scoped_refptr<RtpSenderInterface> TgPeerConnection::CreateSender(
|
||||
}
|
||||
|
||||
// TODO(steveanton): Move construction of the RtpSenders to RtpTransceiver.
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> new_sender;
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>> new_sender;
|
||||
if (kind == MediaStreamTrackInterface::kAudioKind) {
|
||||
auto audio_sender = AudioRtpSender::Create(
|
||||
auto audio_sender = TgAudioRtpSender::Create(
|
||||
worker_thread(), rtc::CreateRandomUuid(), stats_.get(), this);
|
||||
audio_sender->SetMediaChannel(voice_media_channel());
|
||||
new_sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
|
||||
new_sender = RtpSenderProxyWithInternal<TgRtpSenderInternal>::Create(
|
||||
signaling_thread(), audio_sender);
|
||||
GetAudioTransceiver()->internal()->AddSender(new_sender);
|
||||
} else if (kind == MediaStreamTrackInterface::kVideoKind) {
|
||||
auto video_sender =
|
||||
VideoRtpSender::Create(worker_thread(), rtc::CreateRandomUuid(), this);
|
||||
TgVideoRtpSender::Create(worker_thread(), rtc::CreateRandomUuid(), this);
|
||||
video_sender->SetMediaChannel(video_media_channel());
|
||||
new_sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
|
||||
new_sender = RtpSenderProxyWithInternal<TgRtpSenderInternal>::Create(
|
||||
signaling_thread(), video_sender);
|
||||
GetVideoTransceiver()->internal()->AddSender(new_sender);
|
||||
} else {
|
||||
@ -1982,9 +1883,9 @@ std::vector<rtc::scoped_refptr<RtpSenderInterface>> TgPeerConnection::GetSenders
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>>
|
||||
std::vector<rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>>>
|
||||
TgPeerConnection::GetSendersInternal() const {
|
||||
std::vector<rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>>
|
||||
std::vector<rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>>>
|
||||
all_senders;
|
||||
for (const auto& transceiver : transceivers_) {
|
||||
auto senders = transceiver->internal()->senders();
|
||||
@ -2017,6 +1918,12 @@ TgPeerConnection::GetReceiversInternal() const {
|
||||
return all_receivers;
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<DataChannelInterface> TgPeerConnection::CreateDataChannel(
|
||||
const std::string& label,
|
||||
const DataChannelInit* config) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>
|
||||
TgPeerConnection::GetTransceivers() const {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
@ -2029,95 +1936,6 @@ TgPeerConnection::GetTransceivers() const {
|
||||
return all_transceivers;
|
||||
}
|
||||
|
||||
bool TgPeerConnection::GetStats(StatsObserver* observer,
|
||||
MediaStreamTrackInterface* track,
|
||||
StatsOutputLevel level) {
|
||||
TRACE_EVENT0("webrtc", "TgPeerConnection::GetStats");
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
if (!observer) {
|
||||
RTC_LOG(LS_ERROR) << "GetStats - observer is NULL.";
|
||||
return false;
|
||||
}
|
||||
|
||||
stats_->UpdateStats(level);
|
||||
// The StatsCollector is used to tell if a track is valid because it may
|
||||
// remember tracks that the TgPeerConnection previously removed.
|
||||
if (track && !stats_->IsValidTrack(track->id())) {
|
||||
RTC_LOG(LS_WARNING) << "GetStats is called with an invalid track: "
|
||||
<< track->id();
|
||||
return false;
|
||||
}
|
||||
signaling_thread()->Post(RTC_FROM_HERE, this, MSG_GETSTATS,
|
||||
new GetStatsMsg(observer, track));
|
||||
return true;
|
||||
}
|
||||
|
||||
void TgPeerConnection::GetStats(RTCStatsCollectorCallback* callback) {
|
||||
TRACE_EVENT0("webrtc", "TgPeerConnection::GetStats");
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
RTC_DCHECK(stats_collector_);
|
||||
RTC_DCHECK(callback);
|
||||
stats_collector_->GetStatsReport(callback);
|
||||
}
|
||||
|
||||
void TgPeerConnection::GetStats(
|
||||
rtc::scoped_refptr<RtpSenderInterface> selector,
|
||||
rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {
|
||||
TRACE_EVENT0("webrtc", "TgPeerConnection::GetStats");
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
RTC_DCHECK(callback);
|
||||
RTC_DCHECK(stats_collector_);
|
||||
rtc::scoped_refptr<RtpSenderInternal> internal_sender;
|
||||
if (selector) {
|
||||
for (const auto& proxy_transceiver : transceivers_) {
|
||||
for (const auto& proxy_sender :
|
||||
proxy_transceiver->internal()->senders()) {
|
||||
if (proxy_sender == selector) {
|
||||
internal_sender = proxy_sender->internal();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (internal_sender)
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If there is no |internal_sender| then |selector| is either null or does not
|
||||
// belong to the TgPeerConnection (in Plan B, senders can be removed from the
|
||||
// TgPeerConnection). This means that "all the stats objects representing the
|
||||
// selector" is an empty set. Invoking GetStatsReport() with a null selector
|
||||
// produces an empty stats report.
|
||||
stats_collector_->GetStatsReport(internal_sender, callback);
|
||||
}
|
||||
|
||||
void TgPeerConnection::GetStats(
|
||||
rtc::scoped_refptr<RtpReceiverInterface> selector,
|
||||
rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {
|
||||
TRACE_EVENT0("webrtc", "TgPeerConnection::GetStats");
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
RTC_DCHECK(callback);
|
||||
RTC_DCHECK(stats_collector_);
|
||||
rtc::scoped_refptr<RtpReceiverInternal> internal_receiver;
|
||||
if (selector) {
|
||||
for (const auto& proxy_transceiver : transceivers_) {
|
||||
for (const auto& proxy_receiver :
|
||||
proxy_transceiver->internal()->receivers()) {
|
||||
if (proxy_receiver == selector) {
|
||||
internal_receiver = proxy_receiver->internal();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (internal_receiver)
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If there is no |internal_receiver| then |selector| is either null or does
|
||||
// not belong to the TgPeerConnection (in Plan B, receivers can be removed from
|
||||
// the TgPeerConnection). This means that "all the stats objects representing
|
||||
// the selector" is an empty set. Invoking GetStatsReport() with a null
|
||||
// selector produces an empty stats report.
|
||||
stats_collector_->GetStatsReport(internal_receiver, callback);
|
||||
}
|
||||
|
||||
PeerConnectionInterface::SignalingState TgPeerConnection::signaling_state() {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
return signaling_state_;
|
||||
@ -2155,7 +1973,7 @@ void TgPeerConnection::RestartIce() {
|
||||
}
|
||||
|
||||
void TgPeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
|
||||
const RTCOfferAnswerOptions& options) {
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions& options) {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
// Chain this operation. If asynchronous operations are pending on the chain,
|
||||
// this operation will be queued to be invoked, otherwise the contents of the
|
||||
@ -2184,7 +2002,7 @@ void TgPeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
|
||||
}
|
||||
|
||||
void TgPeerConnection::DoCreateOffer(
|
||||
const RTCOfferAnswerOptions& options,
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions& options,
|
||||
rtc::scoped_refptr<CreateSessionDescriptionObserver> observer) {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
TRACE_EVENT0("webrtc", "TgPeerConnection::DoCreateOffer");
|
||||
@ -2237,7 +2055,7 @@ void TgPeerConnection::DoCreateOffer(
|
||||
}
|
||||
|
||||
RTCError TgPeerConnection::HandleLegacyOfferOptions(
|
||||
const RTCOfferAnswerOptions& options) {
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions& options) {
|
||||
RTC_DCHECK(IsUnifiedPlan());
|
||||
|
||||
if (options.offer_to_receive_audio == 0) {
|
||||
@ -2311,7 +2129,7 @@ TgPeerConnection::GetReceivingTransceiversOfType(cricket::MediaType media_type)
|
||||
}
|
||||
|
||||
void TgPeerConnection::CreateAnswer(CreateSessionDescriptionObserver* observer,
|
||||
const RTCOfferAnswerOptions& options) {
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions& options) {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
// Chain this operation. If asynchronous operations are pending on the chain,
|
||||
// this operation will be queued to be invoked, otherwise the contents of the
|
||||
@ -2340,7 +2158,7 @@ void TgPeerConnection::CreateAnswer(CreateSessionDescriptionObserver* observer,
|
||||
}
|
||||
|
||||
void TgPeerConnection::DoCreateAnswer(
|
||||
const RTCOfferAnswerOptions& options,
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions& options,
|
||||
rtc::scoped_refptr<CreateSessionDescriptionObserver> observer) {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
TRACE_EVENT0("webrtc", "TgPeerConnection::DoCreateAnswer");
|
||||
@ -2360,8 +2178,8 @@ void TgPeerConnection::DoCreateAnswer(
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(signaling_state_ == kHaveRemoteOffer ||
|
||||
signaling_state_ == kHaveLocalPrAnswer)) {
|
||||
if (!(signaling_state_ == PeerConnectionInterface::kHaveRemoteOffer ||
|
||||
signaling_state_ == PeerConnectionInterface::kHaveLocalPrAnswer)) {
|
||||
std::string error =
|
||||
"TgPeerConnection cannot create an answer in a state other than "
|
||||
"have-remote-offer or have-local-pranswer.";
|
||||
@ -2375,12 +2193,12 @@ void TgPeerConnection::DoCreateAnswer(
|
||||
RTC_DCHECK(remote_description());
|
||||
|
||||
if (IsUnifiedPlan()) {
|
||||
if (options.offer_to_receive_audio != RTCOfferAnswerOptions::kUndefined) {
|
||||
if (options.offer_to_receive_audio != PeerConnectionInterface::RTCOfferAnswerOptions::kUndefined) {
|
||||
RTC_LOG(LS_WARNING) << "CreateAnswer: offer_to_receive_audio is not "
|
||||
"supported with Unified Plan semantics. Use the "
|
||||
"RtpTransceiver API instead.";
|
||||
}
|
||||
if (options.offer_to_receive_video != RTCOfferAnswerOptions::kUndefined) {
|
||||
if (options.offer_to_receive_video != PeerConnectionInterface::RTCOfferAnswerOptions::kUndefined) {
|
||||
RTC_LOG(LS_WARNING) << "CreateAnswer: offer_to_receive_video is not "
|
||||
"supported with Unified Plan semantics. Use the "
|
||||
"RtpTransceiver API instead.";
|
||||
@ -2463,7 +2281,7 @@ void TgPeerConnection::SetLocalDescription(
|
||||
// TODO(hbos): If [LastCreatedOffer] exists and still represents the
|
||||
// current state of the system, use that instead of creating another
|
||||
// offer.
|
||||
this_weak_ptr->DoCreateOffer(RTCOfferAnswerOptions(),
|
||||
this_weak_ptr->DoCreateOffer(PeerConnectionInterface::RTCOfferAnswerOptions(),
|
||||
create_sdp_observer);
|
||||
break;
|
||||
case PeerConnectionInterface::kHaveLocalPrAnswer:
|
||||
@ -2471,7 +2289,7 @@ void TgPeerConnection::SetLocalDescription(
|
||||
// TODO(hbos): If [LastCreatedAnswer] exists and still represents
|
||||
// the current state of the system, use that instead of creating
|
||||
// another answer.
|
||||
this_weak_ptr->DoCreateAnswer(RTCOfferAnswerOptions(),
|
||||
this_weak_ptr->DoCreateAnswer(PeerConnectionInterface::RTCOfferAnswerOptions(),
|
||||
create_sdp_observer);
|
||||
break;
|
||||
case PeerConnectionInterface::kClosed:
|
||||
@ -2582,7 +2400,7 @@ void TgPeerConnection::DoSetLocalDescription(
|
||||
if (IsUnifiedPlan()) {
|
||||
bool was_negotiation_needed = is_negotiation_needed_;
|
||||
UpdateNegotiationNeeded();
|
||||
if (signaling_state() == kStable && was_negotiation_needed &&
|
||||
if (signaling_state() == PeerConnectionInterface::kStable && was_negotiation_needed &&
|
||||
is_negotiation_needed_) {
|
||||
Observer()->OnRenegotiationNeeded();
|
||||
}
|
||||
@ -2596,10 +2414,6 @@ RTCError TgPeerConnection::ApplyLocalDescription(
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
RTC_DCHECK(desc);
|
||||
|
||||
// Update stats here so that we have the most recent stats for tracks and
|
||||
// streams that might be removed by updating the session description.
|
||||
stats_->UpdateStats(kStatsOutputLevelStandard);
|
||||
|
||||
// Take a reference to the old local description since it's used below to
|
||||
// compare against the new local description. When setting the new local
|
||||
// description, grab ownership of the replaced session description in case it
|
||||
@ -2643,8 +2457,7 @@ RTCError TgPeerConnection::ApplyLocalDescription(
|
||||
return error;
|
||||
}
|
||||
|
||||
if (IsUnifiedPlan()) {
|
||||
RTCError error = UpdateTransceiversAndDataChannels(
|
||||
error = UpdateTransceiversAndDataChannels(
|
||||
cricket::CS_LOCAL, *local_description(), old_local_description,
|
||||
remote_description());
|
||||
if (!error.ok()) {
|
||||
@ -2698,20 +2511,6 @@ RTCError TgPeerConnection::ApplyLocalDescription(
|
||||
for (const auto& stream : removed_streams) {
|
||||
observer->OnRemoveStream(stream);
|
||||
}
|
||||
} else {
|
||||
// Media channels will be created only when offer is set. These may use new
|
||||
// transports just created by PushdownTransportDescription.
|
||||
if (type == SdpType::kOffer) {
|
||||
// TODO(bugs.webrtc.org/4676) - Handle CreateChannel failure, as new local
|
||||
// description is applied. Restore back to old description.
|
||||
RTCError error = CreateChannels(*local_description()->description());
|
||||
if (!error.ok()) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
// Remove unused channels if MediaContentDescription is rejected.
|
||||
RemoveUnusedChannels(local_description()->description());
|
||||
}
|
||||
|
||||
error = UpdateSessionState(type, cricket::CS_LOCAL,
|
||||
local_description()->description());
|
||||
@ -2791,21 +2590,6 @@ RTCError TgPeerConnection::ApplyLocalDescription(
|
||||
return RTCError::OK();
|
||||
}
|
||||
|
||||
// The SDP parser used to populate these values by default for the 'content
|
||||
// name' if an a=mid line was absent.
|
||||
static absl::string_view GetDefaultMidForPlanB(cricket::MediaType media_type) {
|
||||
switch (media_type) {
|
||||
case cricket::MEDIA_TYPE_AUDIO:
|
||||
return cricket::CN_AUDIO;
|
||||
case cricket::MEDIA_TYPE_VIDEO:
|
||||
return cricket::CN_VIDEO;
|
||||
case cricket::MEDIA_TYPE_DATA:
|
||||
return cricket::CN_DATA;
|
||||
}
|
||||
RTC_NOTREACHED();
|
||||
return "";
|
||||
}
|
||||
|
||||
void TgPeerConnection::FillInMissingRemoteMids(
|
||||
cricket::SessionDescription* new_remote_description) {
|
||||
RTC_DCHECK(new_remote_description);
|
||||
@ -2823,7 +2607,7 @@ void TgPeerConnection::FillInMissingRemoteMids(
|
||||
}
|
||||
std::string new_mid;
|
||||
absl::string_view source_explanation;
|
||||
if (IsUnifiedPlan()) {
|
||||
|
||||
if (i < local_contents.size()) {
|
||||
new_mid = local_contents[i].name;
|
||||
source_explanation = "from the matching local media section";
|
||||
@ -2834,11 +2618,7 @@ void TgPeerConnection::FillInMissingRemoteMids(
|
||||
new_mid = mid_generator_();
|
||||
source_explanation = "generated just now";
|
||||
}
|
||||
} else {
|
||||
new_mid = std::string(
|
||||
GetDefaultMidForPlanB(content.media_description()->type()));
|
||||
source_explanation = "to match pre-existing behavior";
|
||||
}
|
||||
|
||||
RTC_DCHECK(!new_mid.empty());
|
||||
content.name = new_mid;
|
||||
new_remote_description->transport_infos()[i].content_name = new_mid;
|
||||
@ -2949,7 +2729,7 @@ void TgPeerConnection::DoSetRemoteDescription(
|
||||
if (IsUnifiedPlan()) {
|
||||
if (configuration_.enable_implicit_rollback) {
|
||||
if (desc->GetType() == SdpType::kOffer &&
|
||||
signaling_state() == kHaveLocalOffer) {
|
||||
signaling_state() == PeerConnectionInterface::kHaveLocalOffer) {
|
||||
Rollback(desc->GetType());
|
||||
}
|
||||
}
|
||||
@ -3017,7 +2797,7 @@ void TgPeerConnection::DoSetRemoteDescription(
|
||||
if (IsUnifiedPlan()) {
|
||||
bool was_negotiation_needed = is_negotiation_needed_;
|
||||
UpdateNegotiationNeeded();
|
||||
if (signaling_state() == kStable && was_negotiation_needed &&
|
||||
if (signaling_state() == PeerConnectionInterface::kStable && was_negotiation_needed &&
|
||||
is_negotiation_needed_) {
|
||||
Observer()->OnRenegotiationNeeded();
|
||||
}
|
||||
@ -3032,10 +2812,6 @@ RTCError TgPeerConnection::ApplyRemoteDescription(
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
RTC_DCHECK(desc);
|
||||
|
||||
// Update stats here so that we have the most recent stats for tracks and
|
||||
// streams that might be removed by updating the session description.
|
||||
stats_->UpdateStats(kStatsOutputLevelStandard);
|
||||
|
||||
// Take a reference to the old remote description since it's used below to
|
||||
// compare against the new remote description. When setting the new remote
|
||||
// description, grab ownership of the replaced session description in case it
|
||||
@ -3125,7 +2901,7 @@ RTCError TgPeerConnection::ApplyRemoteDescription(
|
||||
// description should only contain candidates from the last set remote
|
||||
// description plus any candidates added since then. We should remove
|
||||
// this once we're sure it won't break anything.
|
||||
WebRtcSessionDescriptionFactory::CopyCandidatesFromSessionDescription(
|
||||
TgWebRtcSessionDescriptionFactory::CopyCandidatesFromSessionDescription(
|
||||
old_remote_description, content.name, mutable_remote_description());
|
||||
}
|
||||
}
|
||||
@ -3245,7 +3021,6 @@ RTCError TgPeerConnection::ApplyRemoteDescription(
|
||||
// Once all processing has finished, fire off callbacks.
|
||||
auto observer = Observer();
|
||||
for (const auto& transceiver : now_receiving_transceivers) {
|
||||
stats_->AddTrack(transceiver->receiver()->track());
|
||||
observer->OnTrack(transceiver);
|
||||
observer->OnAddTrack(transceiver->receiver(),
|
||||
transceiver->receiver()->streams());
|
||||
@ -3325,7 +3100,6 @@ RTCError TgPeerConnection::ApplyRemoteDescription(
|
||||
auto observer = Observer();
|
||||
for (size_t i = 0; i < new_streams->count(); ++i) {
|
||||
MediaStreamInterface* new_stream = new_streams->at(i);
|
||||
stats_->AddStream(new_stream);
|
||||
observer->OnAddStream(
|
||||
rtc::scoped_refptr<MediaStreamInterface>(new_stream));
|
||||
}
|
||||
@ -3531,7 +3305,7 @@ static std::vector<RtpEncodingParameters> GetSendEncodingsFromRemoteDescription(
|
||||
|
||||
static RTCError UpdateSimulcastLayerStatusInSender(
|
||||
const std::vector<SimulcastLayer>& layers,
|
||||
rtc::scoped_refptr<RtpSenderInternal> sender) {
|
||||
rtc::scoped_refptr<TgRtpSenderInternal> sender) {
|
||||
RTC_DCHECK(sender);
|
||||
RtpParameters parameters = sender->GetParametersInternal();
|
||||
std::vector<std::string> disabled_layers;
|
||||
@ -3573,7 +3347,7 @@ static bool SimulcastIsRejected(
|
||||
}
|
||||
|
||||
static RTCError DisableSimulcastInSender(
|
||||
rtc::scoped_refptr<RtpSenderInternal> sender) {
|
||||
rtc::scoped_refptr<TgRtpSenderInternal> sender) {
|
||||
RTC_DCHECK(sender);
|
||||
RtpParameters parameters = sender->GetParametersInternal();
|
||||
if (parameters.encodings.size() <= 1) {
|
||||
@ -3672,12 +3446,12 @@ TgPeerConnection::AssociateTransceiver(cricket::ContentSource source,
|
||||
// This can happen when simulcast is not supported on the remote party.
|
||||
if (SimulcastIsRejected(old_local_content, *media_desc)) {
|
||||
RTC_HISTOGRAM_BOOLEAN(kSimulcastDisabled, true);
|
||||
RTCError error =
|
||||
/*RTCError error =
|
||||
DisableSimulcastInSender(transceiver->internal()->sender_internal());
|
||||
if (!error.ok()) {
|
||||
RTC_LOG(LS_ERROR) << "Failed to remove rejected simulcast.";
|
||||
return std::move(error);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
RTC_DCHECK(transceiver);
|
||||
@ -3786,7 +3560,7 @@ PeerConnectionInterface::RTCConfiguration TgPeerConnection::GetConfiguration() {
|
||||
}
|
||||
|
||||
RTCError TgPeerConnection::SetConfiguration(
|
||||
const RTCConfiguration& configuration) {
|
||||
const PeerConnectionInterface::RTCConfiguration& configuration) {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
TRACE_EVENT0("webrtc", "TgPeerConnection::SetConfiguration");
|
||||
if (IsClosed()) {
|
||||
@ -3867,7 +3641,7 @@ RTCError TgPeerConnection::SetConfiguration(
|
||||
*configuration.use_datagram_transport) ||
|
||||
(configuration.use_datagram_transport_for_data_channels &&
|
||||
*configuration.use_datagram_transport_for_data_channels)) {
|
||||
RTC_CHECK(configuration.bundle_policy == kBundlePolicyMaxBundle)
|
||||
RTC_CHECK(configuration.bundle_policy == PeerConnectionInterface::kBundlePolicyMaxBundle)
|
||||
<< "Media transport requires MaxBundle policy.";
|
||||
}
|
||||
|
||||
@ -3875,7 +3649,7 @@ RTCError TgPeerConnection::SetConfiguration(
|
||||
// modified in an invalid way is to copy each property we do support
|
||||
// modifying, then use operator==. There are far more properties we don't
|
||||
// support modifying than those we do, and more could be added.
|
||||
RTCConfiguration modified_config = configuration_;
|
||||
PeerConnectionInterface::RTCConfiguration modified_config = configuration_;
|
||||
modified_config.servers = configuration.servers;
|
||||
modified_config.type = configuration.type;
|
||||
modified_config.ice_candidate_pool_size =
|
||||
@ -4305,9 +4079,6 @@ const SessionDescriptionInterface* TgPeerConnection::pending_remote_description(
|
||||
void TgPeerConnection::Close() {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
TRACE_EVENT0("webrtc", "TgPeerConnection::Close");
|
||||
// Update stats here so that we have the most recent stats for tracks and
|
||||
// streams before the channels are closed.
|
||||
stats_->UpdateStats(kStatsOutputLevelStandard);
|
||||
|
||||
ChangeSignalingState(PeerConnectionInterface::kClosed);
|
||||
NoteUsageEvent(UsageEvent::CLOSE_CALLED);
|
||||
@ -4316,12 +4087,6 @@ void TgPeerConnection::Close() {
|
||||
transceiver->Stop();
|
||||
}
|
||||
|
||||
// Ensure that all asynchronous stats requests are completed before destroying
|
||||
// the transport controller below.
|
||||
if (stats_collector_) {
|
||||
stats_collector_->WaitForPendingRequest();
|
||||
}
|
||||
|
||||
// Don't destroy BaseChannels until after stats has been cleaned up so that
|
||||
// the last stats request can still read from the channels.
|
||||
DestroyAllChannels();
|
||||
@ -4374,14 +4139,6 @@ void TgPeerConnection::OnMessage(rtc::Message* msg) {
|
||||
delete param;
|
||||
break;
|
||||
}
|
||||
case MSG_GETSTATS: {
|
||||
GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
|
||||
StatsReports reports;
|
||||
stats_->GetStats(param->track, &reports);
|
||||
param->observer->OnComplete(reports);
|
||||
delete param;
|
||||
break;
|
||||
}
|
||||
case MSG_REPORT_USAGE_PATTERN: {
|
||||
ReportUsagePattern();
|
||||
break;
|
||||
@ -4558,7 +4315,7 @@ void TgPeerConnection::RemoveVideoTrack(VideoTrackInterface* track,
|
||||
GetVideoTransceiver()->internal()->RemoveSender(sender);
|
||||
}
|
||||
|
||||
void TgPeerConnection::SetIceConnectionState(IceConnectionState new_state) {
|
||||
void TgPeerConnection::SetIceConnectionState(PeerConnectionInterface::IceConnectionState new_state) {
|
||||
if (ice_connection_state_ == new_state) {
|
||||
return;
|
||||
}
|
||||
@ -4670,15 +4427,15 @@ void TgPeerConnection::ChangeSignalingState(
|
||||
<< " New state: "
|
||||
<< GetSignalingStateString(signaling_state);
|
||||
signaling_state_ = signaling_state;
|
||||
if (signaling_state == kClosed) {
|
||||
ice_connection_state_ = kIceConnectionClosed;
|
||||
if (signaling_state == PeerConnectionInterface::kClosed) {
|
||||
ice_connection_state_ = PeerConnectionInterface::kIceConnectionClosed;
|
||||
Observer()->OnIceConnectionChange(ice_connection_state_);
|
||||
standardized_ice_connection_state_ =
|
||||
PeerConnectionInterface::IceConnectionState::kIceConnectionClosed;
|
||||
connection_state_ = PeerConnectionInterface::PeerConnectionState::kClosed;
|
||||
Observer()->OnConnectionChange(connection_state_);
|
||||
if (ice_gathering_state_ != kIceGatheringComplete) {
|
||||
ice_gathering_state_ = kIceGatheringComplete;
|
||||
if (ice_gathering_state_ != PeerConnectionInterface::kIceGatheringComplete) {
|
||||
ice_gathering_state_ = PeerConnectionInterface::kIceGatheringComplete;
|
||||
Observer()->OnIceGatheringChange(ice_gathering_state_);
|
||||
}
|
||||
}
|
||||
@ -4753,11 +4510,7 @@ void TgPeerConnection::GetOptionsForOffer(
|
||||
cricket::MediaSessionOptions* session_options) {
|
||||
ExtractSharedMediaSessionOptions(offer_answer_options, session_options);
|
||||
|
||||
if (IsUnifiedPlan()) {
|
||||
GetOptionsForUnifiedPlanOffer(offer_answer_options, session_options);
|
||||
} else {
|
||||
GetOptionsForPlanBOffer(offer_answer_options, session_options);
|
||||
}
|
||||
|
||||
// Apply ICE restart flag and renomination flag.
|
||||
bool ice_restart = offer_answer_options.ice_restart ||
|
||||
@ -4804,83 +4557,6 @@ void TgPeerConnection::GetOptionsForOffer(
|
||||
offer_answer_options.use_obsolete_sctp_sdp;
|
||||
}
|
||||
|
||||
void TgPeerConnection::GetOptionsForPlanBOffer(
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions& offer_answer_options,
|
||||
cricket::MediaSessionOptions* session_options) {
|
||||
// Figure out transceiver directional preferences.
|
||||
bool send_audio = HasRtpSender(cricket::MEDIA_TYPE_AUDIO);
|
||||
bool send_video = HasRtpSender(cricket::MEDIA_TYPE_VIDEO);
|
||||
|
||||
// By default, generate sendrecv/recvonly m= sections.
|
||||
bool recv_audio = true;
|
||||
bool recv_video = true;
|
||||
|
||||
// By default, only offer a new m= section if we have media to send with it.
|
||||
bool offer_new_audio_description = send_audio;
|
||||
bool offer_new_video_description = send_video;
|
||||
bool offer_new_data_description = false;
|
||||
|
||||
// The "offer_to_receive_X" options allow those defaults to be overridden.
|
||||
if (offer_answer_options.offer_to_receive_audio !=
|
||||
RTCOfferAnswerOptions::kUndefined) {
|
||||
recv_audio = (offer_answer_options.offer_to_receive_audio > 0);
|
||||
offer_new_audio_description =
|
||||
offer_new_audio_description ||
|
||||
(offer_answer_options.offer_to_receive_audio > 0);
|
||||
}
|
||||
if (offer_answer_options.offer_to_receive_video !=
|
||||
RTCOfferAnswerOptions::kUndefined) {
|
||||
recv_video = (offer_answer_options.offer_to_receive_video > 0);
|
||||
offer_new_video_description =
|
||||
offer_new_video_description ||
|
||||
(offer_answer_options.offer_to_receive_video > 0);
|
||||
}
|
||||
|
||||
absl::optional<size_t> audio_index;
|
||||
absl::optional<size_t> video_index;
|
||||
absl::optional<size_t> data_index;
|
||||
// If a current description exists, generate m= sections in the same order,
|
||||
// using the first audio/video/data section that appears and rejecting
|
||||
// extraneous ones.
|
||||
if (local_description()) {
|
||||
GenerateMediaDescriptionOptions(
|
||||
local_description(),
|
||||
RtpTransceiverDirectionFromSendRecv(send_audio, recv_audio),
|
||||
RtpTransceiverDirectionFromSendRecv(send_video, recv_video),
|
||||
&audio_index, &video_index, &data_index, session_options);
|
||||
}
|
||||
|
||||
// Add audio/video/data m= sections to the end if needed.
|
||||
if (!audio_index && offer_new_audio_description) {
|
||||
session_options->media_description_options.push_back(
|
||||
cricket::MediaDescriptionOptions(
|
||||
cricket::MEDIA_TYPE_AUDIO, cricket::CN_AUDIO,
|
||||
RtpTransceiverDirectionFromSendRecv(send_audio, recv_audio),
|
||||
false));
|
||||
audio_index = session_options->media_description_options.size() - 1;
|
||||
}
|
||||
if (!video_index && offer_new_video_description) {
|
||||
session_options->media_description_options.push_back(
|
||||
cricket::MediaDescriptionOptions(
|
||||
cricket::MEDIA_TYPE_VIDEO, cricket::CN_VIDEO,
|
||||
RtpTransceiverDirectionFromSendRecv(send_video, recv_video),
|
||||
false));
|
||||
video_index = session_options->media_description_options.size() - 1;
|
||||
}
|
||||
|
||||
cricket::MediaDescriptionOptions* audio_media_description_options =
|
||||
!audio_index ? nullptr
|
||||
: &session_options->media_description_options[*audio_index];
|
||||
cricket::MediaDescriptionOptions* video_media_description_options =
|
||||
!video_index ? nullptr
|
||||
: &session_options->media_description_options[*video_index];
|
||||
|
||||
AddPlanBRtpSenderOptions(GetSendersInternal(),
|
||||
audio_media_description_options,
|
||||
video_media_description_options,
|
||||
offer_answer_options.num_simulcast_layers);
|
||||
}
|
||||
|
||||
static cricket::MediaDescriptionOptions
|
||||
GetMediaDescriptionOptionsForTransceiver(
|
||||
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
|
||||
@ -4952,7 +4628,7 @@ static const ContentInfo* GetContentByIndex(
|
||||
}
|
||||
|
||||
void TgPeerConnection::GetOptionsForUnifiedPlanOffer(
|
||||
const RTCOfferAnswerOptions& offer_answer_options,
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions& offer_answer_options,
|
||||
cricket::MediaSessionOptions* session_options) {
|
||||
// Rules for generating an offer are dictated by JSEP sections 5.2.1 (Initial
|
||||
// Offers) and 5.2.2 (Subsequent Offers).
|
||||
@ -5042,15 +4718,11 @@ void TgPeerConnection::GetOptionsForUnifiedPlanOffer(
|
||||
}
|
||||
|
||||
void TgPeerConnection::GetOptionsForAnswer(
|
||||
const RTCOfferAnswerOptions& offer_answer_options,
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions& offer_answer_options,
|
||||
cricket::MediaSessionOptions* session_options) {
|
||||
ExtractSharedMediaSessionOptions(offer_answer_options, session_options);
|
||||
|
||||
if (IsUnifiedPlan()) {
|
||||
GetOptionsForUnifiedPlanAnswer(offer_answer_options, session_options);
|
||||
} else {
|
||||
GetOptionsForPlanBAnswer(offer_answer_options, session_options);
|
||||
}
|
||||
|
||||
// Apply ICE renomination flag.
|
||||
for (auto& options : session_options->media_description_options) {
|
||||
@ -5086,54 +4758,6 @@ void TgPeerConnection::GetOptionsForAnswer(
|
||||
}
|
||||
}
|
||||
|
||||
void TgPeerConnection::GetOptionsForPlanBAnswer(
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions& offer_answer_options,
|
||||
cricket::MediaSessionOptions* session_options) {
|
||||
// Figure out transceiver directional preferences.
|
||||
bool send_audio = HasRtpSender(cricket::MEDIA_TYPE_AUDIO);
|
||||
bool send_video = HasRtpSender(cricket::MEDIA_TYPE_VIDEO);
|
||||
|
||||
// By default, generate sendrecv/recvonly m= sections. The direction is also
|
||||
// restricted by the direction in the offer.
|
||||
bool recv_audio = true;
|
||||
bool recv_video = true;
|
||||
|
||||
// The "offer_to_receive_X" options allow those defaults to be overridden.
|
||||
if (offer_answer_options.offer_to_receive_audio !=
|
||||
RTCOfferAnswerOptions::kUndefined) {
|
||||
recv_audio = (offer_answer_options.offer_to_receive_audio > 0);
|
||||
}
|
||||
if (offer_answer_options.offer_to_receive_video !=
|
||||
RTCOfferAnswerOptions::kUndefined) {
|
||||
recv_video = (offer_answer_options.offer_to_receive_video > 0);
|
||||
}
|
||||
|
||||
absl::optional<size_t> audio_index;
|
||||
absl::optional<size_t> video_index;
|
||||
absl::optional<size_t> data_index;
|
||||
|
||||
// Generate m= sections that match those in the offer.
|
||||
// Note that mediasession.cc will handle intersection our preferred
|
||||
// direction with the offered direction.
|
||||
GenerateMediaDescriptionOptions(
|
||||
remote_description(),
|
||||
RtpTransceiverDirectionFromSendRecv(send_audio, recv_audio),
|
||||
RtpTransceiverDirectionFromSendRecv(send_video, recv_video), &audio_index,
|
||||
&video_index, &data_index, session_options);
|
||||
|
||||
cricket::MediaDescriptionOptions* audio_media_description_options =
|
||||
!audio_index ? nullptr
|
||||
: &session_options->media_description_options[*audio_index];
|
||||
cricket::MediaDescriptionOptions* video_media_description_options =
|
||||
!video_index ? nullptr
|
||||
: &session_options->media_description_options[*video_index];
|
||||
|
||||
AddPlanBRtpSenderOptions(GetSendersInternal(),
|
||||
audio_media_description_options,
|
||||
video_media_description_options,
|
||||
offer_answer_options.num_simulcast_layers);
|
||||
}
|
||||
|
||||
void TgPeerConnection::GetOptionsForUnifiedPlanAnswer(
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions& offer_answer_options,
|
||||
cricket::MediaSessionOptions* session_options) {
|
||||
@ -5494,7 +5118,7 @@ bool TgPeerConnection::HasRtpSender(cricket::MediaType type) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>>
|
||||
TgPeerConnection::FindSenderForTrack(MediaStreamTrackInterface* track) const {
|
||||
for (const auto& transceiver : transceivers_) {
|
||||
for (auto sender : transceiver->internal()->senders()) {
|
||||
@ -5506,7 +5130,7 @@ TgPeerConnection::FindSenderForTrack(MediaStreamTrackInterface* track) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>>
|
||||
TgPeerConnection::FindSenderById(const std::string& sender_id) const {
|
||||
for (const auto& transceiver : transceivers_) {
|
||||
for (auto sender : transceiver->internal()->senders()) {
|
||||
@ -5564,7 +5188,7 @@ TgPeerConnection::InitializePortAllocatorResult
|
||||
TgPeerConnection::InitializePortAllocator_n(
|
||||
const cricket::ServerAddresses& stun_servers,
|
||||
const std::vector<cricket::RelayServerConfig>& turn_servers,
|
||||
const RTCConfiguration& configuration) {
|
||||
const PeerConnectionInterface::RTCConfiguration& configuration) {
|
||||
RTC_DCHECK_RUN_ON(network_thread());
|
||||
|
||||
port_allocator_->Initialize();
|
||||
@ -5588,13 +5212,13 @@ TgPeerConnection::InitializePortAllocator_n(
|
||||
RTC_LOG(LS_INFO) << "IPv6 candidates on Wi-Fi are disabled.";
|
||||
}
|
||||
|
||||
if (configuration.tcp_candidate_policy == kTcpCandidatePolicyDisabled) {
|
||||
if (configuration.tcp_candidate_policy == PeerConnectionInterface::kTcpCandidatePolicyDisabled) {
|
||||
port_allocator_flags |= cricket::PORTALLOCATOR_DISABLE_TCP;
|
||||
RTC_LOG(LS_INFO) << "TCP candidates are disabled.";
|
||||
}
|
||||
|
||||
if (configuration.candidate_network_policy ==
|
||||
kCandidateNetworkPolicyLowCost) {
|
||||
PeerConnectionInterface::kCandidateNetworkPolicyLowCost) {
|
||||
port_allocator_flags |= cricket::PORTALLOCATOR_DISABLE_COSTLY_NETWORKS;
|
||||
RTC_LOG(LS_INFO) << "Do not gather candidates on high-cost networks";
|
||||
}
|
||||
@ -5631,7 +5255,7 @@ TgPeerConnection::InitializePortAllocator_n(
|
||||
bool TgPeerConnection::ReconfigurePortAllocator_n(
|
||||
const cricket::ServerAddresses& stun_servers,
|
||||
const std::vector<cricket::RelayServerConfig>& turn_servers,
|
||||
IceTransportsType type,
|
||||
PeerConnectionInterface::IceTransportsType type,
|
||||
int candidate_pool_size,
|
||||
PortPrunePolicy turn_port_prune_policy,
|
||||
webrtc::TurnCustomizer* turn_customizer,
|
||||
@ -6582,8 +6206,6 @@ void TgPeerConnection::ReportSdpFormatReceived(
|
||||
SdpFormatReceived format = kSdpFormatReceivedNoTracks;
|
||||
if (num_audio_mlines > 1 || num_video_mlines > 1) {
|
||||
format = kSdpFormatReceivedComplexUnifiedPlan;
|
||||
} else if (num_audio_tracks > 1 || num_video_tracks > 1) {
|
||||
format = kSdpFormatReceivedComplexPlanB;
|
||||
} else if (num_audio_tracks > 0 || num_video_tracks > 0) {
|
||||
format = kSdpFormatReceivedSimple;
|
||||
}
|
||||
@ -6953,10 +6575,6 @@ CryptoOptions TgPeerConnection::GetCryptoOptions() {
|
||||
}
|
||||
|
||||
void TgPeerConnection::ClearStatsCache() {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
if (stats_collector_) {
|
||||
stats_collector_->ClearCachedStatsReport();
|
||||
}
|
||||
}
|
||||
|
||||
void TgPeerConnection::RequestUsagePatternReportForTesting() {
|
||||
@ -6976,7 +6594,7 @@ void TgPeerConnection::UpdateNegotiationNeeded() {
|
||||
return;
|
||||
|
||||
// If connection's signaling state is not "stable", abort these steps.
|
||||
if (signaling_state() != kStable)
|
||||
if (signaling_state() != PeerConnectionInterface::kStable)
|
||||
return;
|
||||
|
||||
// NOTE
|
||||
@ -7223,12 +6841,4 @@ RTCError TgPeerConnection::Rollback(SdpType sdp_type) {
|
||||
return RTCError::OK();
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<DataChannelInterface> TgPeerConnection::CreateDataChannel(const std::string& label, const DataChannelInit* config) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RTCError TgPeerConnection::UpdateDataChannel(cricket::ContentSource source, const cricket::ContentInfo& content, const cricket::ContentGroup* bundle_group) {
|
||||
return RTCError::OK();
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include "pc/sctp_transport.h"
|
||||
#include "pc/stats_collector.h"
|
||||
#include "pc/stream_collection.h"
|
||||
#include "pc/webrtc_session_description_factory.h"
|
||||
#include "tg_webrtc_session_description_factory.h"
|
||||
#include "rtc_base/experiments/field_trial_parser.h"
|
||||
#include "rtc_base/operations_chain.h"
|
||||
#include "rtc_base/race_checker.h"
|
||||
@ -40,6 +40,8 @@
|
||||
|
||||
#include "tg_jsep_transport_controller.h"
|
||||
#include "tg_peer_connection_factory.h"
|
||||
#include "tg_webrtc_session_description_factory.h"
|
||||
#include "tg_rtp_sender.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -61,9 +63,9 @@ class RtcEventLog;
|
||||
// - Generating offers and answers based on the current state.
|
||||
// - The ICE state machine.
|
||||
// - Generating stats.
|
||||
class TgPeerConnection : public PeerConnectionInternal,
|
||||
class TgPeerConnection : public rtc::RefCountInterface,
|
||||
public TgJsepTransportController::Observer,
|
||||
public RtpSenderBase::SetStreamsObserver,
|
||||
public TgRtpSenderBase::SetStreamsObserver,
|
||||
public rtc::MessageHandler,
|
||||
public sigslot::has_slots<> {
|
||||
public:
|
||||
@ -122,28 +124,28 @@ class TgPeerConnection : public PeerConnectionInternal,
|
||||
const PeerConnectionInterface::RTCConfiguration& configuration,
|
||||
PeerConnectionDependencies dependencies);
|
||||
|
||||
rtc::scoped_refptr<StreamCollectionInterface> local_streams() override;
|
||||
rtc::scoped_refptr<StreamCollectionInterface> remote_streams() override;
|
||||
bool AddStream(MediaStreamInterface* local_stream) override;
|
||||
void RemoveStream(MediaStreamInterface* local_stream) override;
|
||||
rtc::scoped_refptr<StreamCollectionInterface> local_streams();
|
||||
rtc::scoped_refptr<StreamCollectionInterface> remote_streams();
|
||||
bool AddStream(MediaStreamInterface* local_stream);
|
||||
void RemoveStream(MediaStreamInterface* local_stream);
|
||||
|
||||
RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> AddTrack(
|
||||
rtc::scoped_refptr<MediaStreamTrackInterface> track,
|
||||
const std::vector<std::string>& stream_ids) override;
|
||||
bool RemoveTrack(RtpSenderInterface* sender) override;
|
||||
const std::vector<std::string>& stream_ids);
|
||||
bool RemoveTrack(RtpSenderInterface* sender);
|
||||
RTCError RemoveTrackNew(
|
||||
rtc::scoped_refptr<RtpSenderInterface> sender) override;
|
||||
rtc::scoped_refptr<RtpSenderInterface> sender);
|
||||
|
||||
RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> AddTransceiver(
|
||||
rtc::scoped_refptr<MediaStreamTrackInterface> track) override;
|
||||
rtc::scoped_refptr<MediaStreamTrackInterface> track);
|
||||
RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> AddTransceiver(
|
||||
rtc::scoped_refptr<MediaStreamTrackInterface> track,
|
||||
const RtpTransceiverInit& init) override;
|
||||
const RtpTransceiverInit& init);
|
||||
RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> AddTransceiver(
|
||||
cricket::MediaType media_type) override;
|
||||
cricket::MediaType media_type);
|
||||
RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> AddTransceiver(
|
||||
cricket::MediaType media_type,
|
||||
const RtpTransceiverInit& init) override;
|
||||
const RtpTransceiverInit& init);
|
||||
|
||||
// Gets the DTLS SSL certificate associated with the audio transport on the
|
||||
// remote side. This will become populated once the DTLS connection with the
|
||||
@ -159,154 +161,153 @@ class TgPeerConnection : public PeerConnectionInternal,
|
||||
|
||||
rtc::scoped_refptr<RtpSenderInterface> CreateSender(
|
||||
const std::string& kind,
|
||||
const std::string& stream_id) override;
|
||||
const std::string& stream_id);
|
||||
|
||||
std::vector<rtc::scoped_refptr<RtpSenderInterface>> GetSenders()
|
||||
const override;
|
||||
const;
|
||||
std::vector<rtc::scoped_refptr<RtpReceiverInterface>> GetReceivers()
|
||||
const override;
|
||||
const;
|
||||
std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> GetTransceivers()
|
||||
const override;
|
||||
const;
|
||||
|
||||
rtc::scoped_refptr<DataChannelInterface> CreateDataChannel(
|
||||
const std::string& label,
|
||||
const DataChannelInit* config) override;
|
||||
const DataChannelInit* config);
|
||||
// WARNING: LEGACY. See peerconnectioninterface.h
|
||||
bool GetStats(StatsObserver* observer,
|
||||
webrtc::MediaStreamTrackInterface* track,
|
||||
StatsOutputLevel level) override;
|
||||
PeerConnectionInterface::StatsOutputLevel level);
|
||||
// Spec-complaint GetStats(). See peerconnectioninterface.h
|
||||
void GetStats(RTCStatsCollectorCallback* callback) override;
|
||||
void GetStats(RTCStatsCollectorCallback* callback);
|
||||
void GetStats(
|
||||
rtc::scoped_refptr<RtpSenderInterface> selector,
|
||||
rtc::scoped_refptr<RTCStatsCollectorCallback> callback) override;
|
||||
rtc::scoped_refptr<RTCStatsCollectorCallback> callback);
|
||||
void GetStats(
|
||||
rtc::scoped_refptr<RtpReceiverInterface> selector,
|
||||
rtc::scoped_refptr<RTCStatsCollectorCallback> callback) override;
|
||||
void ClearStatsCache() override;
|
||||
rtc::scoped_refptr<RTCStatsCollectorCallback> callback);
|
||||
void ClearStatsCache();
|
||||
|
||||
SignalingState signaling_state() override;
|
||||
PeerConnectionInterface::SignalingState signaling_state();
|
||||
|
||||
IceConnectionState ice_connection_state() override;
|
||||
IceConnectionState standardized_ice_connection_state() override;
|
||||
PeerConnectionState peer_connection_state() override;
|
||||
IceGatheringState ice_gathering_state() override;
|
||||
PeerConnectionInterface::IceConnectionState ice_connection_state();
|
||||
PeerConnectionInterface::IceConnectionState standardized_ice_connection_state();
|
||||
PeerConnectionInterface::PeerConnectionState peer_connection_state();
|
||||
PeerConnectionInterface::IceGatheringState ice_gathering_state();
|
||||
|
||||
const SessionDescriptionInterface* local_description() const override;
|
||||
const SessionDescriptionInterface* remote_description() const override;
|
||||
const SessionDescriptionInterface* current_local_description() const override;
|
||||
const SessionDescriptionInterface* local_description() const;
|
||||
const SessionDescriptionInterface* remote_description() const;
|
||||
const SessionDescriptionInterface* current_local_description() const;
|
||||
const SessionDescriptionInterface* current_remote_description()
|
||||
const override;
|
||||
const SessionDescriptionInterface* pending_local_description() const override;
|
||||
const;
|
||||
const SessionDescriptionInterface* pending_local_description() const;
|
||||
const SessionDescriptionInterface* pending_remote_description()
|
||||
const override;
|
||||
const;
|
||||
|
||||
void RestartIce() override;
|
||||
void RestartIce();
|
||||
|
||||
// JSEP01
|
||||
void CreateOffer(CreateSessionDescriptionObserver* observer,
|
||||
const RTCOfferAnswerOptions& options) override;
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions& options);
|
||||
void CreateAnswer(CreateSessionDescriptionObserver* observer,
|
||||
const RTCOfferAnswerOptions& options) override;
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions& options);
|
||||
void SetLocalDescription(SetSessionDescriptionObserver* observer,
|
||||
SessionDescriptionInterface* desc) override;
|
||||
void SetLocalDescription(SetSessionDescriptionObserver* observer) override;
|
||||
SessionDescriptionInterface* desc);
|
||||
void SetLocalDescription(SetSessionDescriptionObserver* observer);
|
||||
void SetRemoteDescription(SetSessionDescriptionObserver* observer,
|
||||
SessionDescriptionInterface* desc) override;
|
||||
SessionDescriptionInterface* desc);
|
||||
void SetRemoteDescription(
|
||||
std::unique_ptr<SessionDescriptionInterface> desc,
|
||||
rtc::scoped_refptr<SetRemoteDescriptionObserverInterface> observer)
|
||||
override;
|
||||
PeerConnectionInterface::RTCConfiguration GetConfiguration() override;
|
||||
rtc::scoped_refptr<SetRemoteDescriptionObserverInterface> observer);
|
||||
PeerConnectionInterface::RTCConfiguration GetConfiguration();
|
||||
RTCError SetConfiguration(
|
||||
const PeerConnectionInterface::RTCConfiguration& configuration) override;
|
||||
bool AddIceCandidate(const IceCandidateInterface* candidate) override;
|
||||
const PeerConnectionInterface::RTCConfiguration& configuration);
|
||||
bool AddIceCandidate(const IceCandidateInterface* candidate);
|
||||
void AddIceCandidate(std::unique_ptr<IceCandidateInterface> candidate,
|
||||
std::function<void(RTCError)> callback) override;
|
||||
std::function<void(RTCError)> callback);
|
||||
bool RemoveIceCandidates(
|
||||
const std::vector<cricket::Candidate>& candidates) override;
|
||||
const std::vector<cricket::Candidate>& candidates);
|
||||
|
||||
RTCError SetBitrate(const BitrateSettings& bitrate) override;
|
||||
RTCError SetBitrate(const BitrateSettings& bitrate);
|
||||
|
||||
void SetAudioPlayout(bool playout) override;
|
||||
void SetAudioRecording(bool recording) override;
|
||||
void SetAudioPlayout(bool playout);
|
||||
void SetAudioRecording(bool recording);
|
||||
|
||||
rtc::scoped_refptr<DtlsTransportInterface> LookupDtlsTransportByMid(
|
||||
const std::string& mid) override;
|
||||
const std::string& mid);
|
||||
rtc::scoped_refptr<DtlsTransport> LookupDtlsTransportByMidInternal(
|
||||
const std::string& mid);
|
||||
|
||||
rtc::scoped_refptr<SctpTransportInterface> GetSctpTransport() const override;
|
||||
rtc::scoped_refptr<SctpTransportInterface> GetSctpTransport() const;
|
||||
|
||||
bool StartRtcEventLog(std::unique_ptr<RtcEventLogOutput> output,
|
||||
int64_t output_period_ms) override;
|
||||
bool StartRtcEventLog(std::unique_ptr<RtcEventLogOutput> output) override;
|
||||
void StopRtcEventLog() override;
|
||||
int64_t output_period_ms);
|
||||
bool StartRtcEventLog(std::unique_ptr<RtcEventLogOutput> output);
|
||||
void StopRtcEventLog();
|
||||
|
||||
void Close() override;
|
||||
void Close();
|
||||
|
||||
// PeerConnectionInternal implementation.
|
||||
rtc::Thread* network_thread() const final {
|
||||
rtc::Thread* network_thread() const {
|
||||
return factory_->network_thread();
|
||||
}
|
||||
rtc::Thread* worker_thread() const final { return factory_->worker_thread(); }
|
||||
rtc::Thread* signaling_thread() const final {
|
||||
rtc::Thread* worker_thread() const { return factory_->worker_thread(); }
|
||||
rtc::Thread* signaling_thread() const {
|
||||
return factory_->signaling_thread();
|
||||
}
|
||||
|
||||
std::string session_id() const override {
|
||||
std::string session_id() const {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
return session_id_;
|
||||
}
|
||||
|
||||
bool initial_offerer() const override {
|
||||
bool initial_offerer() const {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
return transport_controller_ && transport_controller_->initial_offerer();
|
||||
}
|
||||
|
||||
std::vector<
|
||||
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>>
|
||||
GetTransceiversInternal() const override {
|
||||
GetTransceiversInternal() const {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
return transceivers_;
|
||||
}
|
||||
|
||||
sigslot::signal1<DataChannel*>& SignalDataChannelCreated() override {
|
||||
sigslot::signal1<DataChannel*>& SignalDataChannelCreated() {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
return SignalDataChannelCreated_;
|
||||
}
|
||||
|
||||
cricket::RtpDataChannel* rtp_data_channel() const override {
|
||||
cricket::RtpDataChannel* rtp_data_channel() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<rtc::scoped_refptr<DataChannel>> sctp_data_channels()
|
||||
const override {
|
||||
const {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
return std::vector<rtc::scoped_refptr<DataChannel>>();
|
||||
}
|
||||
|
||||
absl::optional<std::string> sctp_content_name() const override {
|
||||
absl::optional<std::string> sctp_content_name() const {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
return sctp_mid_;
|
||||
}
|
||||
|
||||
absl::optional<std::string> sctp_transport_name() const override;
|
||||
absl::optional<std::string> sctp_transport_name() const;
|
||||
|
||||
cricket::CandidateStatsList GetPooledCandidateStats() const override;
|
||||
std::map<std::string, std::string> GetTransportNamesByMid() const override;
|
||||
cricket::CandidateStatsList GetPooledCandidateStats() const;
|
||||
std::map<std::string, std::string> GetTransportNamesByMid() const;
|
||||
std::map<std::string, cricket::TransportStats> GetTransportStatsByNames(
|
||||
const std::set<std::string>& transport_names) override;
|
||||
Call::Stats GetCallStats() override;
|
||||
const std::set<std::string>& transport_names);
|
||||
Call::Stats GetCallStats();
|
||||
|
||||
bool GetLocalCertificate(
|
||||
const std::string& transport_name,
|
||||
rtc::scoped_refptr<rtc::RTCCertificate>* certificate) override;
|
||||
rtc::scoped_refptr<rtc::RTCCertificate>* certificate);
|
||||
std::unique_ptr<rtc::SSLCertChain> GetRemoteSSLCertChain(
|
||||
const std::string& transport_name) override;
|
||||
bool IceRestartPending(const std::string& content_name) const override;
|
||||
bool NeedsIceRestart(const std::string& content_name) const override;
|
||||
bool GetSslRole(const std::string& content_name, rtc::SSLRole* role) override;
|
||||
const std::string& transport_name);
|
||||
bool IceRestartPending(const std::string& content_name) const;
|
||||
bool NeedsIceRestart(const std::string& content_name) const;
|
||||
bool GetSslRole(const std::string& content_name, rtc::SSLRole* role);
|
||||
|
||||
// Functions needed by DataChannelController
|
||||
void NoteDataAddedEvent() { NoteUsageEvent(UsageEvent::DATA_ADDED); }
|
||||
@ -457,7 +458,7 @@ class TgPeerConnection : public PeerConnectionInternal,
|
||||
cricket::VideoMediaChannel* video_media_channel() const
|
||||
RTC_RUN_ON(signaling_thread());
|
||||
|
||||
std::vector<rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>>
|
||||
std::vector<rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>>>
|
||||
GetSendersInternal() const RTC_RUN_ON(signaling_thread());
|
||||
std::vector<
|
||||
rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>>
|
||||
@ -475,10 +476,10 @@ class TgPeerConnection : public PeerConnectionInternal,
|
||||
// onto the |operations_chain_| when the public CreateOffer(), CreateAnswer(),
|
||||
// SetLocalDescription() and SetRemoteDescription() methods are invoked.
|
||||
void DoCreateOffer(
|
||||
const RTCOfferAnswerOptions& options,
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions& options,
|
||||
rtc::scoped_refptr<CreateSessionDescriptionObserver> observer);
|
||||
void DoCreateAnswer(
|
||||
const RTCOfferAnswerOptions& options,
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions& options,
|
||||
rtc::scoped_refptr<CreateSessionDescriptionObserver> observer);
|
||||
void DoSetLocalDescription(
|
||||
std::unique_ptr<SessionDescriptionInterface> desc,
|
||||
@ -540,7 +541,7 @@ class TgPeerConnection : public PeerConnectionInternal,
|
||||
const RtpTransceiverInit& init,
|
||||
bool fire_callback = true) RTC_RUN_ON(signaling_thread());
|
||||
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>>
|
||||
CreateSender(cricket::MediaType media_type,
|
||||
const std::string& id,
|
||||
rtc::scoped_refptr<MediaStreamTrackInterface> track,
|
||||
@ -554,11 +555,11 @@ class TgPeerConnection : public PeerConnectionInternal,
|
||||
// transceivers.
|
||||
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
|
||||
CreateAndAddTransceiver(
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>> sender,
|
||||
rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
|
||||
receiver) RTC_RUN_ON(signaling_thread());
|
||||
|
||||
void SetIceConnectionState(IceConnectionState new_state)
|
||||
void SetIceConnectionState(PeerConnectionInterface::IceConnectionState new_state)
|
||||
RTC_RUN_ON(signaling_thread());
|
||||
void SetStandardizedIceConnectionState(
|
||||
PeerConnectionInterface::IceConnectionState new_state)
|
||||
@ -568,7 +569,7 @@ class TgPeerConnection : public PeerConnectionInternal,
|
||||
RTC_RUN_ON(signaling_thread());
|
||||
|
||||
// Called any time the IceGatheringState changes.
|
||||
void OnIceGatheringChange(IceGatheringState new_state)
|
||||
void OnIceGatheringChange(PeerConnectionInterface::IceGatheringState new_state)
|
||||
RTC_RUN_ON(signaling_thread());
|
||||
// New ICE candidate has been gathered.
|
||||
void OnIceCandidate(std::unique_ptr<IceCandidateInterface> candidate)
|
||||
@ -589,7 +590,7 @@ class TgPeerConnection : public PeerConnectionInternal,
|
||||
RTC_RUN_ON(signaling_thread());
|
||||
|
||||
// Update the state, signaling if necessary.
|
||||
void ChangeSignalingState(SignalingState signaling_state)
|
||||
void ChangeSignalingState(PeerConnectionInterface::SignalingState signaling_state)
|
||||
RTC_RUN_ON(signaling_thread());
|
||||
|
||||
// Signals from MediaStreamObserver.
|
||||
@ -732,7 +733,7 @@ class TgPeerConnection : public PeerConnectionInternal,
|
||||
cricket::MediaSessionOptions* session_options)
|
||||
RTC_RUN_ON(signaling_thread());
|
||||
|
||||
RTCError HandleLegacyOfferOptions(const RTCOfferAnswerOptions& options)
|
||||
RTCError HandleLegacyOfferOptions(const PeerConnectionInterface::RTCOfferAnswerOptions& options)
|
||||
RTC_RUN_ON(signaling_thread());
|
||||
void RemoveRecvDirectionFromReceivingTransceiversOfType(
|
||||
cricket::MediaType media_type) RTC_RUN_ON(signaling_thread());
|
||||
@ -744,7 +745,7 @@ class TgPeerConnection : public PeerConnectionInternal,
|
||||
|
||||
// Returns a MediaSessionOptions struct with options decided by
|
||||
// |constraints|, the local MediaStreams and DataChannels.
|
||||
void GetOptionsForAnswer(const RTCOfferAnswerOptions& offer_answer_options,
|
||||
void GetOptionsForAnswer(const PeerConnectionInterface::RTCOfferAnswerOptions& offer_answer_options,
|
||||
cricket::MediaSessionOptions* session_options)
|
||||
RTC_RUN_ON(signaling_thread());
|
||||
void GetOptionsForPlanBAnswer(
|
||||
@ -854,12 +855,12 @@ class TgPeerConnection : public PeerConnectionInternal,
|
||||
RTC_RUN_ON(signaling_thread());
|
||||
|
||||
// Return the RtpSender with the given track attached.
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>>
|
||||
FindSenderForTrack(MediaStreamTrackInterface* track) const
|
||||
RTC_RUN_ON(signaling_thread());
|
||||
|
||||
// Return the RtpSender with the given id, or null if none exists.
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
|
||||
rtc::scoped_refptr<RtpSenderProxyWithInternal<TgRtpSenderInternal>>
|
||||
FindSenderById(const std::string& sender_id) const
|
||||
RTC_RUN_ON(signaling_thread());
|
||||
|
||||
@ -888,13 +889,13 @@ class TgPeerConnection : public PeerConnectionInternal,
|
||||
InitializePortAllocatorResult InitializePortAllocator_n(
|
||||
const cricket::ServerAddresses& stun_servers,
|
||||
const std::vector<cricket::RelayServerConfig>& turn_servers,
|
||||
const RTCConfiguration& configuration);
|
||||
const PeerConnectionInterface::RTCConfiguration& configuration);
|
||||
// Called when SetConfiguration is called to apply the supported subset
|
||||
// of the configuration on the network thread.
|
||||
bool ReconfigurePortAllocator_n(
|
||||
const cricket::ServerAddresses& stun_servers,
|
||||
const std::vector<cricket::RelayServerConfig>& turn_servers,
|
||||
IceTransportsType type,
|
||||
PeerConnectionInterface::IceTransportsType type,
|
||||
int candidate_pool_size,
|
||||
PortPrunePolicy turn_port_prune_policy,
|
||||
webrtc::TurnCustomizer* turn_customizer,
|
||||
@ -914,7 +915,7 @@ class TgPeerConnection : public PeerConnectionInternal,
|
||||
// or values that conflict with other parameters.
|
||||
//
|
||||
// Returns RTCError::OK() if there are no issues.
|
||||
RTCError ValidateConfiguration(const RTCConfiguration& config) const;
|
||||
RTCError ValidateConfiguration(const PeerConnectionInterface::RTCConfiguration& config) const;
|
||||
|
||||
cricket::ChannelManager* channel_manager() const;
|
||||
|
||||
@ -1138,7 +1139,7 @@ class TgPeerConnection : public PeerConnectionInternal,
|
||||
rtc::scoped_refptr<DtlsTransport> dtls_transport,
|
||||
DataChannelTransportInterface* data_channel_transport) override;
|
||||
|
||||
// RtpSenderBase::SetStreamsObserver override.
|
||||
// TgRtpSenderBase::SetStreamsObserver override.
|
||||
void OnSetStreams() override;
|
||||
|
||||
// Returns the CryptoOptions for this TgPeerConnection. This will always
|
||||
@ -1185,16 +1186,16 @@ class TgPeerConnection : public PeerConnectionInternal,
|
||||
rtc::scoped_refptr<rtc::OperationsChain> operations_chain_
|
||||
RTC_GUARDED_BY(signaling_thread());
|
||||
|
||||
SignalingState signaling_state_ RTC_GUARDED_BY(signaling_thread()) = kStable;
|
||||
IceConnectionState ice_connection_state_ RTC_GUARDED_BY(signaling_thread()) =
|
||||
kIceConnectionNew;
|
||||
PeerConnectionInterface::SignalingState signaling_state_ RTC_GUARDED_BY(signaling_thread()) = PeerConnectionInterface::kStable;
|
||||
PeerConnectionInterface::IceConnectionState ice_connection_state_ RTC_GUARDED_BY(signaling_thread()) =
|
||||
PeerConnectionInterface::kIceConnectionNew;
|
||||
PeerConnectionInterface::IceConnectionState standardized_ice_connection_state_
|
||||
RTC_GUARDED_BY(signaling_thread()) = kIceConnectionNew;
|
||||
RTC_GUARDED_BY(signaling_thread()) = PeerConnectionInterface::kIceConnectionNew;
|
||||
PeerConnectionInterface::PeerConnectionState connection_state_
|
||||
RTC_GUARDED_BY(signaling_thread()) = PeerConnectionState::kNew;
|
||||
RTC_GUARDED_BY(signaling_thread()) = PeerConnectionInterface::PeerConnectionState::kNew;
|
||||
|
||||
IceGatheringState ice_gathering_state_ RTC_GUARDED_BY(signaling_thread()) =
|
||||
kIceGatheringNew;
|
||||
PeerConnectionInterface::IceGatheringState ice_gathering_state_ RTC_GUARDED_BY(signaling_thread()) =
|
||||
PeerConnectionInterface::kIceGatheringNew;
|
||||
PeerConnectionInterface::RTCConfiguration configuration_
|
||||
RTC_GUARDED_BY(signaling_thread());
|
||||
|
||||
@ -1270,10 +1271,6 @@ class TgPeerConnection : public PeerConnectionInternal,
|
||||
// pointer from any thread.
|
||||
Call* const call_ptr_;
|
||||
|
||||
std::unique_ptr<StatsCollector> stats_
|
||||
RTC_GUARDED_BY(signaling_thread()); // A pointer is passed to senders_
|
||||
rtc::scoped_refptr<RTCStatsCollector> stats_collector_
|
||||
RTC_GUARDED_BY(signaling_thread());
|
||||
// Holds changes made to transceivers during applying descriptors for
|
||||
// potential rollback. Gets cleared once signaling state goes to stable.
|
||||
std::map<rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>,
|
||||
@ -1338,7 +1335,7 @@ class TgPeerConnection : public PeerConnectionInternal,
|
||||
std::set<std::string> pending_ice_restarts_
|
||||
RTC_GUARDED_BY(signaling_thread());
|
||||
|
||||
std::unique_ptr<WebRtcSessionDescriptionFactory> webrtc_session_desc_factory_
|
||||
std::unique_ptr<TgWebRtcSessionDescriptionFactory> webrtc_session_desc_factory_
|
||||
RTC_GUARDED_BY(signaling_thread());
|
||||
|
||||
// Member variables for caching global options.
|
||||
|
@ -48,25 +48,6 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
rtc::scoped_refptr<PeerConnectionFactoryInterface>
|
||||
CreateModularPeerConnectionFactory(
|
||||
PeerConnectionFactoryDependencies dependencies) {
|
||||
rtc::scoped_refptr<TgPeerConnectionFactory> pc_factory(
|
||||
new rtc::RefCountedObject<TgPeerConnectionFactory>(
|
||||
std::move(dependencies)));
|
||||
// Call Initialize synchronously but make sure it is executed on
|
||||
// |signaling_thread|.
|
||||
MethodCall<TgPeerConnectionFactory, bool> call(
|
||||
pc_factory.get(), &TgPeerConnectionFactory::Initialize);
|
||||
bool result = call.Marshal(RTC_FROM_HERE, pc_factory->signaling_thread());
|
||||
|
||||
if (!result) {
|
||||
return nullptr;
|
||||
}
|
||||
return PeerConnectionFactoryProxy::Create(pc_factory->signaling_thread(),
|
||||
pc_factory);
|
||||
}
|
||||
|
||||
TgPeerConnectionFactory::TgPeerConnectionFactory(
|
||||
PeerConnectionFactoryDependencies dependencies)
|
||||
: wraps_current_thread_(false),
|
||||
@ -153,7 +134,7 @@ bool TgPeerConnectionFactory::Initialize() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void TgPeerConnectionFactory::SetOptions(const Options& options) {
|
||||
void TgPeerConnectionFactory::SetOptions(const PeerConnectionFactory::Options& options) {
|
||||
options_ = options;
|
||||
}
|
||||
|
||||
@ -229,7 +210,7 @@ void TgPeerConnectionFactory::StopAecDump() {
|
||||
channel_manager_->StopAecDump();
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<PeerConnectionInterface>
|
||||
rtc::scoped_refptr<TgPeerConnection>
|
||||
TgPeerConnectionFactory::CreatePeerConnection(
|
||||
const PeerConnectionInterface::RTCConfiguration& configuration,
|
||||
std::unique_ptr<cricket::PortAllocator> allocator,
|
||||
@ -243,7 +224,7 @@ TgPeerConnectionFactory::CreatePeerConnection(
|
||||
return CreatePeerConnection(configuration, std::move(dependencies));
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<PeerConnectionInterface>
|
||||
rtc::scoped_refptr<TgPeerConnection>
|
||||
TgPeerConnectionFactory::CreatePeerConnection(
|
||||
const PeerConnectionInterface::RTCConfiguration& configuration,
|
||||
PeerConnectionDependencies dependencies) {
|
||||
@ -300,11 +281,10 @@ TgPeerConnectionFactory::CreatePeerConnection(
|
||||
rtc::scoped_refptr<TgPeerConnection> pc(
|
||||
new rtc::RefCountedObject<TgPeerConnection>(this, std::move(event_log),
|
||||
std::move(call)));
|
||||
ActionsBeforeInitializeForTesting(pc);
|
||||
if (!pc->Initialize(configuration, std::move(dependencies))) {
|
||||
return nullptr;
|
||||
}
|
||||
return PeerConnectionProxy::Create(signaling_thread(), pc);
|
||||
return pc;
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<MediaStreamInterface>
|
||||
|
@ -32,45 +32,46 @@ class BasicPacketSocketFactory;
|
||||
namespace webrtc {
|
||||
|
||||
class RtcEventLog;
|
||||
class TgPeerConnection;
|
||||
|
||||
class TgPeerConnectionFactory : public PeerConnectionFactoryInterface {
|
||||
class TgPeerConnectionFactory: public rtc::RefCountInterface {
|
||||
public:
|
||||
void SetOptions(const Options& options) override;
|
||||
void SetOptions(const PeerConnectionFactoryInterface::Options& options);
|
||||
|
||||
rtc::scoped_refptr<PeerConnectionInterface> CreatePeerConnection(
|
||||
rtc::scoped_refptr<TgPeerConnection> CreatePeerConnection(
|
||||
const PeerConnectionInterface::RTCConfiguration& configuration,
|
||||
std::unique_ptr<cricket::PortAllocator> allocator,
|
||||
std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator,
|
||||
PeerConnectionObserver* observer) override;
|
||||
PeerConnectionObserver* observer);
|
||||
|
||||
rtc::scoped_refptr<PeerConnectionInterface> CreatePeerConnection(
|
||||
rtc::scoped_refptr<TgPeerConnection> CreatePeerConnection(
|
||||
const PeerConnectionInterface::RTCConfiguration& configuration,
|
||||
PeerConnectionDependencies dependencies) override;
|
||||
PeerConnectionDependencies dependencies);
|
||||
|
||||
bool Initialize();
|
||||
|
||||
RtpCapabilities GetRtpSenderCapabilities(
|
||||
cricket::MediaType kind) const override;
|
||||
cricket::MediaType kind) const;
|
||||
|
||||
RtpCapabilities GetRtpReceiverCapabilities(
|
||||
cricket::MediaType kind) const override;
|
||||
cricket::MediaType kind) const;
|
||||
|
||||
rtc::scoped_refptr<MediaStreamInterface> CreateLocalMediaStream(
|
||||
const std::string& stream_id) override;
|
||||
const std::string& stream_id);
|
||||
|
||||
rtc::scoped_refptr<AudioSourceInterface> CreateAudioSource(
|
||||
const cricket::AudioOptions& options) override;
|
||||
const cricket::AudioOptions& options);
|
||||
|
||||
rtc::scoped_refptr<VideoTrackInterface> CreateVideoTrack(
|
||||
const std::string& id,
|
||||
VideoTrackSourceInterface* video_source) override;
|
||||
VideoTrackSourceInterface* video_source);
|
||||
|
||||
rtc::scoped_refptr<AudioTrackInterface> CreateAudioTrack(
|
||||
const std::string& id,
|
||||
AudioSourceInterface* audio_source) override;
|
||||
AudioSourceInterface* audio_source);
|
||||
|
||||
bool StartAecDump(FILE* file, int64_t max_size_bytes) override;
|
||||
void StopAecDump() override;
|
||||
bool StartAecDump(FILE* file, int64_t max_size_bytes);
|
||||
void StopAecDump();
|
||||
|
||||
virtual std::unique_ptr<cricket::SctpTransportInternalFactory>
|
||||
CreateSctpTransportInternalFactory();
|
||||
@ -85,7 +86,7 @@ class TgPeerConnectionFactory : public PeerConnectionFactoryInterface {
|
||||
rtc::Thread* worker_thread() { return worker_thread_; }
|
||||
rtc::Thread* network_thread() { return network_thread_; }
|
||||
|
||||
const Options& options() const { return options_; }
|
||||
const PeerConnectionFactoryInterface::Options& options() const { return options_; }
|
||||
|
||||
MediaTransportFactory* media_transport_factory() {
|
||||
return media_transport_factory_.get();
|
||||
@ -116,7 +117,7 @@ class TgPeerConnectionFactory : public PeerConnectionFactoryInterface {
|
||||
std::unique_ptr<rtc::Thread> owned_network_thread_;
|
||||
std::unique_ptr<rtc::Thread> owned_worker_thread_;
|
||||
const std::unique_ptr<TaskQueueFactory> task_queue_factory_;
|
||||
Options options_;
|
||||
PeerConnectionFactoryInterface::Options options_;
|
||||
std::unique_ptr<cricket::ChannelManager> channel_manager_;
|
||||
std::unique_ptr<rtc::BasicNetworkManager> default_network_manager_;
|
||||
std::unique_ptr<rtc::BasicPacketSocketFactory> default_socket_factory_;
|
||||
|
625
submodules/TgVoipWebrtcCustom/Sources/tg_rtp_sender.cpp
Normal file
625
submodules/TgVoipWebrtcCustom/Sources/tg_rtp_sender.cpp
Normal file
@ -0,0 +1,625 @@
|
||||
/*
|
||||
* Copyright 2015 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 "tg_rtp_sender.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "api/audio_options.h"
|
||||
#include "api/media_stream_interface.h"
|
||||
#include "media/base/media_engine.h"
|
||||
#include "pc/peer_connection.h"
|
||||
#include "pc/stats_collector.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/helpers.h"
|
||||
#include "rtc_base/location.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/trace_event.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
// This function is only expected to be called on the signaling thread.
|
||||
// On the other hand, some test or even production setups may use
|
||||
// several signaling threads.
|
||||
int GenerateUniqueId() {
|
||||
static std::atomic<int> g_unique_id{0};
|
||||
|
||||
return ++g_unique_id;
|
||||
}
|
||||
|
||||
// Returns true if a "per-sender" encoding parameter contains a value that isn't
|
||||
// its default. Currently max_bitrate_bps and bitrate_priority both are
|
||||
// implemented "per-sender," meaning that these encoding parameters
|
||||
// are used for the RtpSender as a whole, not for a specific encoding layer.
|
||||
// This is done by setting these encoding parameters at index 0 of
|
||||
// RtpParameters.encodings. This function can be used to check if these
|
||||
// parameters are set at any index other than 0 of RtpParameters.encodings,
|
||||
// because they are currently unimplemented to be used for a specific encoding
|
||||
// layer.
|
||||
bool PerSenderRtpEncodingParameterHasValue(
|
||||
const RtpEncodingParameters& encoding_params) {
|
||||
if (encoding_params.bitrate_priority != kDefaultBitratePriority ||
|
||||
encoding_params.network_priority != kDefaultBitratePriority) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RemoveEncodingLayers(const std::vector<std::string>& rids,
|
||||
std::vector<RtpEncodingParameters>* encodings) {
|
||||
RTC_DCHECK(encodings);
|
||||
encodings->erase(
|
||||
std::remove_if(encodings->begin(), encodings->end(),
|
||||
[&rids](const RtpEncodingParameters& encoding) {
|
||||
return absl::c_linear_search(rids, encoding.rid);
|
||||
}),
|
||||
encodings->end());
|
||||
}
|
||||
|
||||
RtpParameters RestoreEncodingLayers(
|
||||
const RtpParameters& parameters,
|
||||
const std::vector<std::string>& removed_rids,
|
||||
const std::vector<RtpEncodingParameters>& all_layers) {
|
||||
RTC_DCHECK_EQ(parameters.encodings.size() + removed_rids.size(),
|
||||
all_layers.size());
|
||||
RtpParameters result(parameters);
|
||||
result.encodings.clear();
|
||||
size_t index = 0;
|
||||
for (const RtpEncodingParameters& encoding : all_layers) {
|
||||
if (absl::c_linear_search(removed_rids, encoding.rid)) {
|
||||
result.encodings.push_back(encoding);
|
||||
continue;
|
||||
}
|
||||
result.encodings.push_back(parameters.encodings[index++]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Returns true if any RtpParameters member that isn't implemented contains a
|
||||
// value.
|
||||
bool UnimplementedRtpParameterHasValue(const RtpParameters& parameters) {
|
||||
if (!parameters.mid.empty()) {
|
||||
return true;
|
||||
}
|
||||
for (size_t i = 0; i < parameters.encodings.size(); ++i) {
|
||||
// Encoding parameters that are per-sender should only contain value at
|
||||
// index 0.
|
||||
if (i != 0 &&
|
||||
PerSenderRtpEncodingParameterHasValue(parameters.encodings[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TgRtpSenderBase::TgRtpSenderBase(rtc::Thread* worker_thread,
|
||||
const std::string& id,
|
||||
SetStreamsObserver* set_streams_observer)
|
||||
: worker_thread_(worker_thread),
|
||||
id_(id),
|
||||
set_streams_observer_(set_streams_observer) {
|
||||
RTC_DCHECK(worker_thread);
|
||||
init_parameters_.encodings.emplace_back();
|
||||
}
|
||||
|
||||
void TgRtpSenderBase::SetFrameEncryptor(
|
||||
rtc::scoped_refptr<FrameEncryptorInterface> frame_encryptor) {
|
||||
frame_encryptor_ = std::move(frame_encryptor);
|
||||
// Special Case: Set the frame encryptor to any value on any existing channel.
|
||||
if (media_channel_ && ssrc_ && !stopped_) {
|
||||
worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
|
||||
media_channel_->SetFrameEncryptor(ssrc_, frame_encryptor_);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void TgRtpSenderBase::SetMediaChannel(cricket::MediaChannel* media_channel) {
|
||||
RTC_DCHECK(media_channel == nullptr ||
|
||||
media_channel->media_type() == media_type());
|
||||
media_channel_ = media_channel;
|
||||
}
|
||||
|
||||
RtpParameters TgRtpSenderBase::GetParametersInternal() const {
|
||||
if (stopped_) {
|
||||
return RtpParameters();
|
||||
}
|
||||
if (!media_channel_ || !ssrc_) {
|
||||
return init_parameters_;
|
||||
}
|
||||
return worker_thread_->Invoke<RtpParameters>(RTC_FROM_HERE, [&] {
|
||||
RtpParameters result = media_channel_->GetRtpSendParameters(ssrc_);
|
||||
RemoveEncodingLayers(disabled_rids_, &result.encodings);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
RtpParameters TgRtpSenderBase::GetParameters() const {
|
||||
RtpParameters result = GetParametersInternal();
|
||||
last_transaction_id_ = rtc::CreateRandomUuid();
|
||||
result.transaction_id = last_transaction_id_.value();
|
||||
return result;
|
||||
}
|
||||
|
||||
RTCError TgRtpSenderBase::SetParametersInternal(const RtpParameters& parameters) {
|
||||
RTC_DCHECK(!stopped_);
|
||||
|
||||
if (UnimplementedRtpParameterHasValue(parameters)) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::UNSUPPORTED_PARAMETER,
|
||||
"Attempted to set an unimplemented parameter of RtpParameters.");
|
||||
}
|
||||
if (!media_channel_ || !ssrc_) {
|
||||
auto result = cricket::CheckRtpParametersInvalidModificationAndValues(
|
||||
init_parameters_, parameters);
|
||||
if (result.ok()) {
|
||||
init_parameters_ = parameters;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return worker_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
|
||||
RtpParameters rtp_parameters = parameters;
|
||||
if (!disabled_rids_.empty()) {
|
||||
// Need to add the inactive layers.
|
||||
RtpParameters old_parameters =
|
||||
media_channel_->GetRtpSendParameters(ssrc_);
|
||||
rtp_parameters = RestoreEncodingLayers(parameters, disabled_rids_,
|
||||
old_parameters.encodings);
|
||||
}
|
||||
return media_channel_->SetRtpSendParameters(ssrc_, rtp_parameters);
|
||||
});
|
||||
}
|
||||
|
||||
RTCError TgRtpSenderBase::SetParameters(const RtpParameters& parameters) {
|
||||
TRACE_EVENT0("webrtc", "TgRtpSenderBase::SetParameters");
|
||||
if (stopped_) {
|
||||
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
|
||||
"Cannot set parameters on a stopped sender.");
|
||||
}
|
||||
if (!last_transaction_id_) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::INVALID_STATE,
|
||||
"Failed to set parameters since getParameters() has never been called"
|
||||
" on this sender");
|
||||
}
|
||||
if (last_transaction_id_ != parameters.transaction_id) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::INVALID_MODIFICATION,
|
||||
"Failed to set parameters since the transaction_id doesn't match"
|
||||
" the last value returned from getParameters()");
|
||||
}
|
||||
|
||||
RTCError result = SetParametersInternal(parameters);
|
||||
last_transaction_id_.reset();
|
||||
return result;
|
||||
}
|
||||
|
||||
void TgRtpSenderBase::SetStreams(const std::vector<std::string>& stream_ids) {
|
||||
set_stream_ids(stream_ids);
|
||||
if (set_streams_observer_)
|
||||
set_streams_observer_->OnSetStreams();
|
||||
}
|
||||
|
||||
bool TgRtpSenderBase::SetTrack(MediaStreamTrackInterface* track) {
|
||||
TRACE_EVENT0("webrtc", "TgRtpSenderBase::SetTrack");
|
||||
if (stopped_) {
|
||||
RTC_LOG(LS_ERROR) << "SetTrack can't be called on a stopped RtpSender.";
|
||||
return false;
|
||||
}
|
||||
if (track && track->kind() != track_kind()) {
|
||||
RTC_LOG(LS_ERROR) << "SetTrack with " << track->kind()
|
||||
<< " called on RtpSender with " << track_kind()
|
||||
<< " track.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Detach from old track.
|
||||
if (track_) {
|
||||
DetachTrack();
|
||||
track_->UnregisterObserver(this);
|
||||
RemoveTrackFromStats();
|
||||
}
|
||||
|
||||
// Attach to new track.
|
||||
bool prev_can_send_track = can_send_track();
|
||||
// Keep a reference to the old track to keep it alive until we call SetSend.
|
||||
rtc::scoped_refptr<MediaStreamTrackInterface> old_track = track_;
|
||||
track_ = track;
|
||||
if (track_) {
|
||||
track_->RegisterObserver(this);
|
||||
AttachTrack();
|
||||
}
|
||||
|
||||
// Update channel.
|
||||
if (can_send_track()) {
|
||||
SetSend();
|
||||
AddTrackToStats();
|
||||
} else if (prev_can_send_track) {
|
||||
ClearSend();
|
||||
}
|
||||
attachment_id_ = (track_ ? GenerateUniqueId() : 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TgRtpSenderBase::SetSsrc(uint32_t ssrc) {
|
||||
TRACE_EVENT0("webrtc", "TgRtpSenderBase::SetSsrc");
|
||||
if (stopped_ || ssrc == ssrc_) {
|
||||
return;
|
||||
}
|
||||
// If we are already sending with a particular SSRC, stop sending.
|
||||
if (can_send_track()) {
|
||||
ClearSend();
|
||||
RemoveTrackFromStats();
|
||||
}
|
||||
ssrc_ = ssrc;
|
||||
if (can_send_track()) {
|
||||
SetSend();
|
||||
AddTrackToStats();
|
||||
}
|
||||
if (!init_parameters_.encodings.empty()) {
|
||||
worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
|
||||
RTC_DCHECK(media_channel_);
|
||||
// Get the current parameters, which are constructed from the SDP.
|
||||
// The number of layers in the SDP is currently authoritative to support
|
||||
// SDP munging for Plan-B simulcast with "a=ssrc-group:SIM <ssrc-id>..."
|
||||
// lines as described in RFC 5576.
|
||||
// All fields should be default constructed and the SSRC field set, which
|
||||
// we need to copy.
|
||||
RtpParameters current_parameters =
|
||||
media_channel_->GetRtpSendParameters(ssrc_);
|
||||
RTC_DCHECK_GE(current_parameters.encodings.size(),
|
||||
init_parameters_.encodings.size());
|
||||
for (size_t i = 0; i < init_parameters_.encodings.size(); ++i) {
|
||||
init_parameters_.encodings[i].ssrc =
|
||||
current_parameters.encodings[i].ssrc;
|
||||
init_parameters_.encodings[i].rid = current_parameters.encodings[i].rid;
|
||||
current_parameters.encodings[i] = init_parameters_.encodings[i];
|
||||
}
|
||||
current_parameters.degradation_preference =
|
||||
init_parameters_.degradation_preference;
|
||||
media_channel_->SetRtpSendParameters(ssrc_, current_parameters);
|
||||
init_parameters_.encodings.clear();
|
||||
});
|
||||
}
|
||||
// Attempt to attach the frame decryptor to the current media channel.
|
||||
if (frame_encryptor_) {
|
||||
SetFrameEncryptor(frame_encryptor_);
|
||||
}
|
||||
}
|
||||
|
||||
void TgRtpSenderBase::Stop() {
|
||||
TRACE_EVENT0("webrtc", "TgRtpSenderBase::Stop");
|
||||
// TODO(deadbeef): Need to do more here to fully stop sending packets.
|
||||
if (stopped_) {
|
||||
return;
|
||||
}
|
||||
if (track_) {
|
||||
DetachTrack();
|
||||
track_->UnregisterObserver(this);
|
||||
}
|
||||
if (can_send_track()) {
|
||||
ClearSend();
|
||||
RemoveTrackFromStats();
|
||||
}
|
||||
media_channel_ = nullptr;
|
||||
set_streams_observer_ = nullptr;
|
||||
stopped_ = true;
|
||||
}
|
||||
|
||||
RTCError TgRtpSenderBase::DisableEncodingLayers(
|
||||
const std::vector<std::string>& rids) {
|
||||
if (stopped_) {
|
||||
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
|
||||
"Cannot disable encodings on a stopped sender.");
|
||||
}
|
||||
|
||||
if (rids.empty()) {
|
||||
return RTCError::OK();
|
||||
}
|
||||
|
||||
// Check that all the specified layers exist and disable them in the channel.
|
||||
RtpParameters parameters = GetParametersInternal();
|
||||
for (const std::string& rid : rids) {
|
||||
if (absl::c_none_of(parameters.encodings,
|
||||
[&rid](const RtpEncodingParameters& encoding) {
|
||||
return encoding.rid == rid;
|
||||
})) {
|
||||
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
|
||||
"RID: " + rid + " does not refer to a valid layer.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!media_channel_ || !ssrc_) {
|
||||
RemoveEncodingLayers(rids, &init_parameters_.encodings);
|
||||
// Invalidate any transaction upon success.
|
||||
last_transaction_id_.reset();
|
||||
return RTCError::OK();
|
||||
}
|
||||
|
||||
for (RtpEncodingParameters& encoding : parameters.encodings) {
|
||||
// Remain active if not in the disable list.
|
||||
encoding.active &= absl::c_none_of(
|
||||
rids,
|
||||
[&encoding](const std::string& rid) { return encoding.rid == rid; });
|
||||
}
|
||||
|
||||
RTCError result = SetParametersInternal(parameters);
|
||||
if (result.ok()) {
|
||||
disabled_rids_.insert(disabled_rids_.end(), rids.begin(), rids.end());
|
||||
// Invalidate any transaction upon success.
|
||||
last_transaction_id_.reset();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
TgLocalAudioSinkAdapter::TgLocalAudioSinkAdapter() : sink_(nullptr) {}
|
||||
|
||||
TgLocalAudioSinkAdapter::~TgLocalAudioSinkAdapter() {
|
||||
rtc::CritScope lock(&lock_);
|
||||
if (sink_)
|
||||
sink_->OnClose();
|
||||
}
|
||||
|
||||
void TgLocalAudioSinkAdapter::OnData(const void* audio_data,
|
||||
int bits_per_sample,
|
||||
int sample_rate,
|
||||
size_t number_of_channels,
|
||||
size_t number_of_frames) {
|
||||
rtc::CritScope lock(&lock_);
|
||||
if (sink_) {
|
||||
sink_->OnData(audio_data, bits_per_sample, sample_rate, number_of_channels,
|
||||
number_of_frames);
|
||||
}
|
||||
}
|
||||
|
||||
void TgLocalAudioSinkAdapter::SetSink(cricket::AudioSource::Sink* sink) {
|
||||
rtc::CritScope lock(&lock_);
|
||||
RTC_DCHECK(!sink || !sink_);
|
||||
sink_ = sink;
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<TgAudioRtpSender> TgAudioRtpSender::Create(
|
||||
rtc::Thread* worker_thread,
|
||||
const std::string& id,
|
||||
StatsCollector* stats,
|
||||
SetStreamsObserver* set_streams_observer) {
|
||||
return rtc::scoped_refptr<TgAudioRtpSender>(
|
||||
new rtc::RefCountedObject<TgAudioRtpSender>(worker_thread, id, stats,
|
||||
set_streams_observer));
|
||||
}
|
||||
|
||||
TgAudioRtpSender::TgAudioRtpSender(rtc::Thread* worker_thread,
|
||||
const std::string& id,
|
||||
StatsCollector* stats,
|
||||
SetStreamsObserver* set_streams_observer)
|
||||
: TgRtpSenderBase(worker_thread, id, set_streams_observer),
|
||||
stats_(stats),
|
||||
dtmf_sender_proxy_(DtmfSenderProxy::Create(
|
||||
rtc::Thread::Current(),
|
||||
DtmfSender::Create(rtc::Thread::Current(), this))),
|
||||
sink_adapter_(new TgLocalAudioSinkAdapter()) {}
|
||||
|
||||
TgAudioRtpSender::~TgAudioRtpSender() {
|
||||
// For DtmfSender.
|
||||
SignalDestroyed();
|
||||
Stop();
|
||||
}
|
||||
|
||||
bool TgAudioRtpSender::CanInsertDtmf() {
|
||||
if (!media_channel_) {
|
||||
RTC_LOG(LS_ERROR) << "CanInsertDtmf: No audio channel exists.";
|
||||
return false;
|
||||
}
|
||||
// Check that this RTP sender is active (description has been applied that
|
||||
// matches an SSRC to its ID).
|
||||
if (!ssrc_) {
|
||||
RTC_LOG(LS_ERROR) << "CanInsertDtmf: Sender does not have SSRC.";
|
||||
return false;
|
||||
}
|
||||
return worker_thread_->Invoke<bool>(
|
||||
RTC_FROM_HERE, [&] { return voice_media_channel()->CanInsertDtmf(); });
|
||||
}
|
||||
|
||||
bool TgAudioRtpSender::InsertDtmf(int code, int duration) {
|
||||
if (!media_channel_) {
|
||||
RTC_LOG(LS_ERROR) << "InsertDtmf: No audio channel exists.";
|
||||
return false;
|
||||
}
|
||||
if (!ssrc_) {
|
||||
RTC_LOG(LS_ERROR) << "InsertDtmf: Sender does not have SSRC.";
|
||||
return false;
|
||||
}
|
||||
bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
|
||||
return voice_media_channel()->InsertDtmf(ssrc_, code, duration);
|
||||
});
|
||||
if (!success) {
|
||||
RTC_LOG(LS_ERROR) << "Failed to insert DTMF to channel.";
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
sigslot::signal0<>* TgAudioRtpSender::GetOnDestroyedSignal() {
|
||||
return &SignalDestroyed;
|
||||
}
|
||||
|
||||
void TgAudioRtpSender::OnChanged() {
|
||||
TRACE_EVENT0("webrtc", "TgAudioRtpSender::OnChanged");
|
||||
RTC_DCHECK(!stopped_);
|
||||
if (cached_track_enabled_ != track_->enabled()) {
|
||||
cached_track_enabled_ = track_->enabled();
|
||||
if (can_send_track()) {
|
||||
SetSend();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TgAudioRtpSender::DetachTrack() {
|
||||
RTC_DCHECK(track_);
|
||||
audio_track()->RemoveSink(sink_adapter_.get());
|
||||
}
|
||||
|
||||
void TgAudioRtpSender::AttachTrack() {
|
||||
RTC_DCHECK(track_);
|
||||
cached_track_enabled_ = track_->enabled();
|
||||
audio_track()->AddSink(sink_adapter_.get());
|
||||
}
|
||||
|
||||
void TgAudioRtpSender::AddTrackToStats() {
|
||||
if (can_send_track() && stats_) {
|
||||
stats_->AddLocalAudioTrack(audio_track().get(), ssrc_);
|
||||
}
|
||||
}
|
||||
|
||||
void TgAudioRtpSender::RemoveTrackFromStats() {
|
||||
if (can_send_track() && stats_) {
|
||||
stats_->RemoveLocalAudioTrack(audio_track().get(), ssrc_);
|
||||
}
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<DtmfSenderInterface> TgAudioRtpSender::GetDtmfSender() const {
|
||||
return dtmf_sender_proxy_;
|
||||
}
|
||||
|
||||
void TgAudioRtpSender::SetSend() {
|
||||
RTC_DCHECK(!stopped_);
|
||||
RTC_DCHECK(can_send_track());
|
||||
if (!media_channel_) {
|
||||
RTC_LOG(LS_ERROR) << "SetAudioSend: No audio channel exists.";
|
||||
return;
|
||||
}
|
||||
cricket::AudioOptions options;
|
||||
#if !defined(WEBRTC_CHROMIUM_BUILD) && !defined(WEBRTC_WEBKIT_BUILD)
|
||||
// TODO(tommi): Remove this hack when we move CreateAudioSource out of
|
||||
// PeerConnection. This is a bit of a strange way to apply local audio
|
||||
// options since it is also applied to all streams/channels, local or remote.
|
||||
if (track_->enabled() && audio_track()->GetSource() &&
|
||||
!audio_track()->GetSource()->remote()) {
|
||||
options = audio_track()->GetSource()->options();
|
||||
}
|
||||
#endif
|
||||
|
||||
// |track_->enabled()| hops to the signaling thread, so call it before we hop
|
||||
// to the worker thread or else it will deadlock.
|
||||
bool track_enabled = track_->enabled();
|
||||
bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
|
||||
return voice_media_channel()->SetAudioSend(ssrc_, track_enabled, &options,
|
||||
sink_adapter_.get());
|
||||
});
|
||||
if (!success) {
|
||||
RTC_LOG(LS_ERROR) << "SetAudioSend: ssrc is incorrect: " << ssrc_;
|
||||
}
|
||||
}
|
||||
|
||||
void TgAudioRtpSender::ClearSend() {
|
||||
RTC_DCHECK(ssrc_ != 0);
|
||||
RTC_DCHECK(!stopped_);
|
||||
if (!media_channel_) {
|
||||
RTC_LOG(LS_WARNING) << "ClearAudioSend: No audio channel exists.";
|
||||
return;
|
||||
}
|
||||
cricket::AudioOptions options;
|
||||
bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
|
||||
return voice_media_channel()->SetAudioSend(ssrc_, false, &options, nullptr);
|
||||
});
|
||||
if (!success) {
|
||||
RTC_LOG(LS_WARNING) << "ClearAudioSend: ssrc is incorrect: " << ssrc_;
|
||||
}
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<TgVideoRtpSender> TgVideoRtpSender::Create(
|
||||
rtc::Thread* worker_thread,
|
||||
const std::string& id,
|
||||
SetStreamsObserver* set_streams_observer) {
|
||||
return rtc::scoped_refptr<TgVideoRtpSender>(
|
||||
new rtc::RefCountedObject<TgVideoRtpSender>(worker_thread, id,
|
||||
set_streams_observer));
|
||||
}
|
||||
|
||||
TgVideoRtpSender::TgVideoRtpSender(rtc::Thread* worker_thread,
|
||||
const std::string& id,
|
||||
SetStreamsObserver* set_streams_observer)
|
||||
: TgRtpSenderBase(worker_thread, id, set_streams_observer) {}
|
||||
|
||||
TgVideoRtpSender::~TgVideoRtpSender() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
void TgVideoRtpSender::OnChanged() {
|
||||
TRACE_EVENT0("webrtc", "TgVideoRtpSender::OnChanged");
|
||||
RTC_DCHECK(!stopped_);
|
||||
if (cached_track_content_hint_ != video_track()->content_hint()) {
|
||||
cached_track_content_hint_ = video_track()->content_hint();
|
||||
if (can_send_track()) {
|
||||
SetSend();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TgVideoRtpSender::AttachTrack() {
|
||||
RTC_DCHECK(track_);
|
||||
cached_track_content_hint_ = video_track()->content_hint();
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<DtmfSenderInterface> TgVideoRtpSender::GetDtmfSender() const {
|
||||
RTC_LOG(LS_ERROR) << "Tried to get DTMF sender from video sender.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void TgVideoRtpSender::SetSend() {
|
||||
RTC_DCHECK(!stopped_);
|
||||
RTC_DCHECK(can_send_track());
|
||||
if (!media_channel_) {
|
||||
RTC_LOG(LS_ERROR) << "SetVideoSend: No video channel exists.";
|
||||
return;
|
||||
}
|
||||
cricket::VideoOptions options;
|
||||
VideoTrackSourceInterface* source = video_track()->GetSource();
|
||||
if (source) {
|
||||
options.is_screencast = source->is_screencast();
|
||||
options.video_noise_reduction = source->needs_denoising();
|
||||
}
|
||||
switch (cached_track_content_hint_) {
|
||||
case VideoTrackInterface::ContentHint::kNone:
|
||||
break;
|
||||
case VideoTrackInterface::ContentHint::kFluid:
|
||||
options.is_screencast = false;
|
||||
break;
|
||||
case VideoTrackInterface::ContentHint::kDetailed:
|
||||
case VideoTrackInterface::ContentHint::kText:
|
||||
options.is_screencast = true;
|
||||
break;
|
||||
}
|
||||
bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
|
||||
return video_media_channel()->SetVideoSend(ssrc_, &options, video_track());
|
||||
});
|
||||
RTC_DCHECK(success);
|
||||
}
|
||||
|
||||
void TgVideoRtpSender::ClearSend() {
|
||||
RTC_DCHECK(ssrc_ != 0);
|
||||
RTC_DCHECK(!stopped_);
|
||||
if (!media_channel_) {
|
||||
RTC_LOG(LS_WARNING) << "SetVideoSend: No video channel exists.";
|
||||
return;
|
||||
}
|
||||
// Allow SetVideoSend to fail since |enable| is false and |source| is null.
|
||||
// This the normal case when the underlying media channel has already been
|
||||
// deleted.
|
||||
worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
|
||||
return video_media_channel()->SetVideoSend(ssrc_, nullptr, nullptr);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
344
submodules/TgVoipWebrtcCustom/Sources/tg_rtp_sender.h
Normal file
344
submodules/TgVoipWebrtcCustom/Sources/tg_rtp_sender.h
Normal file
@ -0,0 +1,344 @@
|
||||
/*
|
||||
* Copyright 2015 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.
|
||||
*/
|
||||
|
||||
// This file contains classes that implement RtpSenderInterface.
|
||||
// An RtpSender associates a MediaStreamTrackInterface with an underlying
|
||||
// transport (provided by AudioProviderInterface/VideoProviderInterface)
|
||||
|
||||
#ifndef TG_PC_RTP_SENDER_H_
|
||||
#define TG_PC_RTP_SENDER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "api/media_stream_interface.h"
|
||||
#include "api/rtp_sender_interface.h"
|
||||
#include "media/base/audio_source.h"
|
||||
#include "media/base/media_channel.h"
|
||||
#include "pc/dtmf_sender.h"
|
||||
#include "rtc_base/critical_section.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class StatsCollector;
|
||||
|
||||
bool UnimplementedRtpParameterHasValue(const RtpParameters& parameters);
|
||||
|
||||
// Internal interface used by PeerConnection.
|
||||
class TgRtpSenderInternal : public RtpSenderInterface {
|
||||
public:
|
||||
// Sets the underlying MediaEngine channel associated with this RtpSender.
|
||||
// A VoiceMediaChannel should be used for audio RtpSenders and
|
||||
// a VideoMediaChannel should be used for video RtpSenders.
|
||||
// Must call SetMediaChannel(nullptr) before the media channel is destroyed.
|
||||
virtual void SetMediaChannel(cricket::MediaChannel* media_channel) = 0;
|
||||
|
||||
// Used to set the SSRC of the sender, once a local description has been set.
|
||||
// If |ssrc| is 0, this indiates that the sender should disconnect from the
|
||||
// underlying transport (this occurs if the sender isn't seen in a local
|
||||
// description).
|
||||
virtual void SetSsrc(uint32_t ssrc) = 0;
|
||||
|
||||
virtual void set_stream_ids(const std::vector<std::string>& stream_ids) = 0;
|
||||
virtual void set_init_send_encodings(
|
||||
const std::vector<RtpEncodingParameters>& init_send_encodings) = 0;
|
||||
virtual void set_transport(
|
||||
rtc::scoped_refptr<DtlsTransportInterface> dtls_transport) = 0;
|
||||
|
||||
virtual void Stop() = 0;
|
||||
|
||||
// |GetParameters| and |SetParameters| operate with a transactional model.
|
||||
// Allow access to get/set parameters without invalidating transaction id.
|
||||
virtual RtpParameters GetParametersInternal() const = 0;
|
||||
virtual RTCError SetParametersInternal(const RtpParameters& parameters) = 0;
|
||||
|
||||
// Returns an ID that changes every time SetTrack() is called, but
|
||||
// otherwise remains constant. Used to generate IDs for stats.
|
||||
// The special value zero means that no track is attached.
|
||||
virtual int AttachmentId() const = 0;
|
||||
|
||||
// Disables the layers identified by the specified RIDs.
|
||||
// If the specified list is empty, this is a no-op.
|
||||
virtual RTCError DisableEncodingLayers(
|
||||
const std::vector<std::string>& rid) = 0;
|
||||
};
|
||||
|
||||
// Shared implementation for RtpSenderInternal interface.
|
||||
class TgRtpSenderBase : public TgRtpSenderInternal, public ObserverInterface {
|
||||
public:
|
||||
class SetStreamsObserver {
|
||||
public:
|
||||
virtual ~SetStreamsObserver() = default;
|
||||
virtual void OnSetStreams() = 0;
|
||||
};
|
||||
|
||||
// Sets the underlying MediaEngine channel associated with this RtpSender.
|
||||
// A VoiceMediaChannel should be used for audio RtpSenders and
|
||||
// a VideoMediaChannel should be used for video RtpSenders.
|
||||
// Must call SetMediaChannel(nullptr) before the media channel is destroyed.
|
||||
void SetMediaChannel(cricket::MediaChannel* media_channel) override;
|
||||
|
||||
bool SetTrack(MediaStreamTrackInterface* track) override;
|
||||
rtc::scoped_refptr<MediaStreamTrackInterface> track() const override {
|
||||
return track_;
|
||||
}
|
||||
|
||||
RtpParameters GetParameters() const override;
|
||||
RTCError SetParameters(const RtpParameters& parameters) override;
|
||||
|
||||
// |GetParameters| and |SetParameters| operate with a transactional model.
|
||||
// Allow access to get/set parameters without invalidating transaction id.
|
||||
RtpParameters GetParametersInternal() const override;
|
||||
RTCError SetParametersInternal(const RtpParameters& parameters) override;
|
||||
|
||||
// Used to set the SSRC of the sender, once a local description has been set.
|
||||
// If |ssrc| is 0, this indiates that the sender should disconnect from the
|
||||
// underlying transport (this occurs if the sender isn't seen in a local
|
||||
// description).
|
||||
void SetSsrc(uint32_t ssrc) override;
|
||||
uint32_t ssrc() const override { return ssrc_; }
|
||||
|
||||
std::vector<std::string> stream_ids() const override { return stream_ids_; }
|
||||
void set_stream_ids(const std::vector<std::string>& stream_ids) override {
|
||||
stream_ids_ = stream_ids;
|
||||
}
|
||||
void SetStreams(const std::vector<std::string>& stream_ids) override;
|
||||
|
||||
std::string id() const override { return id_; }
|
||||
|
||||
void set_init_send_encodings(
|
||||
const std::vector<RtpEncodingParameters>& init_send_encodings) override {
|
||||
init_parameters_.encodings = init_send_encodings;
|
||||
}
|
||||
std::vector<RtpEncodingParameters> init_send_encodings() const override {
|
||||
return init_parameters_.encodings;
|
||||
}
|
||||
|
||||
void set_transport(
|
||||
rtc::scoped_refptr<DtlsTransportInterface> dtls_transport) override {
|
||||
dtls_transport_ = dtls_transport;
|
||||
}
|
||||
rtc::scoped_refptr<DtlsTransportInterface> dtls_transport() const override {
|
||||
return dtls_transport_;
|
||||
}
|
||||
|
||||
void SetFrameEncryptor(
|
||||
rtc::scoped_refptr<FrameEncryptorInterface> frame_encryptor) override;
|
||||
|
||||
rtc::scoped_refptr<FrameEncryptorInterface> GetFrameEncryptor()
|
||||
const override {
|
||||
return frame_encryptor_;
|
||||
}
|
||||
|
||||
void Stop() override;
|
||||
|
||||
// Returns an ID that changes every time SetTrack() is called, but
|
||||
// otherwise remains constant. Used to generate IDs for stats.
|
||||
// The special value zero means that no track is attached.
|
||||
int AttachmentId() const override { return attachment_id_; }
|
||||
|
||||
// Disables the layers identified by the specified RIDs.
|
||||
// If the specified list is empty, this is a no-op.
|
||||
RTCError DisableEncodingLayers(const std::vector<std::string>& rid) override;
|
||||
|
||||
protected:
|
||||
// If |set_streams_observer| is not null, it is invoked when SetStreams()
|
||||
// is called. |set_streams_observer| is not owned by this object. If not
|
||||
// null, it must be valid at least until this sender becomes stopped.
|
||||
TgRtpSenderBase(rtc::Thread* worker_thread,
|
||||
const std::string& id,
|
||||
SetStreamsObserver* set_streams_observer);
|
||||
// TODO(nisse): Since SSRC == 0 is technically valid, figure out
|
||||
// some other way to test if we have a valid SSRC.
|
||||
bool can_send_track() const { return track_ && ssrc_; }
|
||||
|
||||
virtual std::string track_kind() const = 0;
|
||||
|
||||
// Enable sending on the media channel.
|
||||
virtual void SetSend() = 0;
|
||||
// Disable sending on the media channel.
|
||||
virtual void ClearSend() = 0;
|
||||
|
||||
// Template method pattern to allow subclasses to add custom behavior for
|
||||
// when tracks are attached, detached, and for adding tracks to statistics.
|
||||
virtual void AttachTrack() {}
|
||||
virtual void DetachTrack() {}
|
||||
virtual void AddTrackToStats() {}
|
||||
virtual void RemoveTrackFromStats() {}
|
||||
|
||||
rtc::Thread* worker_thread_;
|
||||
uint32_t ssrc_ = 0;
|
||||
bool stopped_ = false;
|
||||
int attachment_id_ = 0;
|
||||
const std::string id_;
|
||||
|
||||
std::vector<std::string> stream_ids_;
|
||||
RtpParameters init_parameters_;
|
||||
|
||||
cricket::MediaChannel* media_channel_ = nullptr;
|
||||
rtc::scoped_refptr<MediaStreamTrackInterface> track_;
|
||||
|
||||
rtc::scoped_refptr<DtlsTransportInterface> dtls_transport_;
|
||||
rtc::scoped_refptr<FrameEncryptorInterface> frame_encryptor_;
|
||||
// |last_transaction_id_| is used to verify that |SetParameters| is receiving
|
||||
// the parameters object that was last returned from |GetParameters|.
|
||||
// As such, it is used for internal verification and is not observable by the
|
||||
// the client. It is marked as mutable to enable |GetParameters| to be a
|
||||
// const method.
|
||||
mutable absl::optional<std::string> last_transaction_id_;
|
||||
std::vector<std::string> disabled_rids_;
|
||||
|
||||
SetStreamsObserver* set_streams_observer_ = nullptr;
|
||||
};
|
||||
|
||||
// TgLocalAudioSinkAdapter receives data callback as a sink to the local
|
||||
// AudioTrack, and passes the data to the sink of AudioSource.
|
||||
class TgLocalAudioSinkAdapter : public AudioTrackSinkInterface,
|
||||
public cricket::AudioSource {
|
||||
public:
|
||||
TgLocalAudioSinkAdapter();
|
||||
virtual ~TgLocalAudioSinkAdapter();
|
||||
|
||||
private:
|
||||
// AudioSinkInterface implementation.
|
||||
void OnData(const void* audio_data,
|
||||
int bits_per_sample,
|
||||
int sample_rate,
|
||||
size_t number_of_channels,
|
||||
size_t number_of_frames) override;
|
||||
|
||||
// cricket::AudioSource implementation.
|
||||
void SetSink(cricket::AudioSource::Sink* sink) override;
|
||||
|
||||
cricket::AudioSource::Sink* sink_;
|
||||
// Critical section protecting |sink_|.
|
||||
rtc::CriticalSection lock_;
|
||||
};
|
||||
|
||||
class TgAudioRtpSender : public DtmfProviderInterface, public TgRtpSenderBase {
|
||||
public:
|
||||
// Construct an RtpSender for audio with the given sender ID.
|
||||
// The sender is initialized with no track to send and no associated streams.
|
||||
// StatsCollector provided so that Add/RemoveLocalAudioTrack can be called
|
||||
// at the appropriate times.
|
||||
// If |set_streams_observer| is not null, it is invoked when SetStreams()
|
||||
// is called. |set_streams_observer| is not owned by this object. If not
|
||||
// null, it must be valid at least until this sender becomes stopped.
|
||||
static rtc::scoped_refptr<TgAudioRtpSender> Create(
|
||||
rtc::Thread* worker_thread,
|
||||
const std::string& id,
|
||||
StatsCollector* stats,
|
||||
SetStreamsObserver* set_streams_observer);
|
||||
virtual ~TgAudioRtpSender();
|
||||
|
||||
// DtmfSenderProvider implementation.
|
||||
bool CanInsertDtmf() override;
|
||||
bool InsertDtmf(int code, int duration) override;
|
||||
sigslot::signal0<>* GetOnDestroyedSignal() override;
|
||||
|
||||
// ObserverInterface implementation.
|
||||
void OnChanged() override;
|
||||
|
||||
cricket::MediaType media_type() const override {
|
||||
return cricket::MEDIA_TYPE_AUDIO;
|
||||
}
|
||||
std::string track_kind() const override {
|
||||
return MediaStreamTrackInterface::kAudioKind;
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<DtmfSenderInterface> GetDtmfSender() const override;
|
||||
|
||||
protected:
|
||||
TgAudioRtpSender(rtc::Thread* worker_thread,
|
||||
const std::string& id,
|
||||
StatsCollector* stats,
|
||||
SetStreamsObserver* set_streams_observer);
|
||||
|
||||
void SetSend() override;
|
||||
void ClearSend() override;
|
||||
|
||||
// Hooks to allow custom logic when tracks are attached and detached.
|
||||
void AttachTrack() override;
|
||||
void DetachTrack() override;
|
||||
void AddTrackToStats() override;
|
||||
void RemoveTrackFromStats() override;
|
||||
|
||||
private:
|
||||
cricket::VoiceMediaChannel* voice_media_channel() {
|
||||
return static_cast<cricket::VoiceMediaChannel*>(media_channel_);
|
||||
}
|
||||
rtc::scoped_refptr<AudioTrackInterface> audio_track() const {
|
||||
return rtc::scoped_refptr<AudioTrackInterface>(
|
||||
static_cast<AudioTrackInterface*>(track_.get()));
|
||||
}
|
||||
sigslot::signal0<> SignalDestroyed;
|
||||
|
||||
StatsCollector* stats_ = nullptr;
|
||||
rtc::scoped_refptr<DtmfSenderInterface> dtmf_sender_proxy_;
|
||||
bool cached_track_enabled_ = false;
|
||||
|
||||
// Used to pass the data callback from the |track_| to the other end of
|
||||
// cricket::AudioSource.
|
||||
std::unique_ptr<TgLocalAudioSinkAdapter> sink_adapter_;
|
||||
};
|
||||
|
||||
class TgVideoRtpSender : public TgRtpSenderBase {
|
||||
public:
|
||||
// Construct an RtpSender for video with the given sender ID.
|
||||
// The sender is initialized with no track to send and no associated streams.
|
||||
// If |set_streams_observer| is not null, it is invoked when SetStreams()
|
||||
// is called. |set_streams_observer| is not owned by this object. If not
|
||||
// null, it must be valid at least until this sender becomes stopped.
|
||||
static rtc::scoped_refptr<TgVideoRtpSender> Create(
|
||||
rtc::Thread* worker_thread,
|
||||
const std::string& id,
|
||||
SetStreamsObserver* set_streams_observer);
|
||||
virtual ~TgVideoRtpSender();
|
||||
|
||||
// ObserverInterface implementation
|
||||
void OnChanged() override;
|
||||
|
||||
cricket::MediaType media_type() const override {
|
||||
return cricket::MEDIA_TYPE_VIDEO;
|
||||
}
|
||||
std::string track_kind() const override {
|
||||
return MediaStreamTrackInterface::kVideoKind;
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<DtmfSenderInterface> GetDtmfSender() const override;
|
||||
|
||||
protected:
|
||||
TgVideoRtpSender(rtc::Thread* worker_thread,
|
||||
const std::string& id,
|
||||
SetStreamsObserver* set_streams_observer);
|
||||
|
||||
void SetSend() override;
|
||||
void ClearSend() override;
|
||||
|
||||
// Hook to allow custom logic when tracks are attached.
|
||||
void AttachTrack() override;
|
||||
|
||||
private:
|
||||
cricket::VideoMediaChannel* video_media_channel() {
|
||||
return static_cast<cricket::VideoMediaChannel*>(media_channel_);
|
||||
}
|
||||
rtc::scoped_refptr<VideoTrackInterface> video_track() const {
|
||||
return rtc::scoped_refptr<VideoTrackInterface>(
|
||||
static_cast<VideoTrackInterface*>(track_.get()));
|
||||
}
|
||||
|
||||
VideoTrackInterface::ContentHint cached_track_content_hint_ =
|
||||
VideoTrackInterface::ContentHint::kNone;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // PC_RTP_SENDER_H_
|
@ -0,0 +1,501 @@
|
||||
/*
|
||||
* Copyright 2013 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 "tg_webrtc_session_description_factory.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/algorithm/container.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/jsep.h"
|
||||
#include "api/jsep_session_description.h"
|
||||
#include "api/rtc_error.h"
|
||||
#include "pc/session_description.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/location.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/ref_counted_object.h"
|
||||
#include "rtc_base/ssl_identity.h"
|
||||
#include "rtc_base/ssl_stream_adapter.h"
|
||||
#include "rtc_base/string_encode.h"
|
||||
|
||||
#include "tg_peer_connection.h"
|
||||
|
||||
using cricket::MediaSessionOptions;
|
||||
using rtc::UniqueRandomIdGenerator;
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
static const char kFailedDueToIdentityFailed[] =
|
||||
" failed because DTLS identity request failed";
|
||||
static const char kFailedDueToSessionShutdown[] =
|
||||
" failed because the session was shut down";
|
||||
|
||||
static const uint64_t kInitSessionVersion = 2;
|
||||
|
||||
// Check that each sender has a unique ID.
|
||||
static bool ValidMediaSessionOptions(
|
||||
const cricket::MediaSessionOptions& session_options) {
|
||||
std::vector<cricket::SenderOptions> sorted_senders;
|
||||
for (const cricket::MediaDescriptionOptions& media_description_options :
|
||||
session_options.media_description_options) {
|
||||
sorted_senders.insert(sorted_senders.end(),
|
||||
media_description_options.sender_options.begin(),
|
||||
media_description_options.sender_options.end());
|
||||
}
|
||||
absl::c_sort(sorted_senders, [](const cricket::SenderOptions& sender1,
|
||||
const cricket::SenderOptions& sender2) {
|
||||
return sender1.track_id < sender2.track_id;
|
||||
});
|
||||
return absl::c_adjacent_find(sorted_senders,
|
||||
[](const cricket::SenderOptions& sender1,
|
||||
const cricket::SenderOptions& sender2) {
|
||||
return sender1.track_id == sender2.track_id;
|
||||
}) == sorted_senders.end();
|
||||
}
|
||||
|
||||
enum {
|
||||
MSG_CREATE_SESSIONDESCRIPTION_SUCCESS,
|
||||
MSG_CREATE_SESSIONDESCRIPTION_FAILED,
|
||||
MSG_USE_CONSTRUCTOR_CERTIFICATE
|
||||
};
|
||||
|
||||
struct CreateSessionDescriptionMsg : public rtc::MessageData {
|
||||
explicit CreateSessionDescriptionMsg(
|
||||
webrtc::CreateSessionDescriptionObserver* observer,
|
||||
RTCError error_in)
|
||||
: observer(observer), error(std::move(error_in)) {}
|
||||
|
||||
rtc::scoped_refptr<webrtc::CreateSessionDescriptionObserver> observer;
|
||||
RTCError error;
|
||||
std::unique_ptr<webrtc::SessionDescriptionInterface> description;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void TgWebRtcCertificateGeneratorCallback::OnFailure() {
|
||||
SignalRequestFailed();
|
||||
}
|
||||
|
||||
void TgWebRtcCertificateGeneratorCallback::OnSuccess(
|
||||
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
|
||||
SignalCertificateReady(certificate);
|
||||
}
|
||||
|
||||
// static
|
||||
void TgWebRtcSessionDescriptionFactory::CopyCandidatesFromSessionDescription(
|
||||
const SessionDescriptionInterface* source_desc,
|
||||
const std::string& content_name,
|
||||
SessionDescriptionInterface* dest_desc) {
|
||||
if (!source_desc) {
|
||||
return;
|
||||
}
|
||||
const cricket::ContentInfos& contents =
|
||||
source_desc->description()->contents();
|
||||
const cricket::ContentInfo* cinfo =
|
||||
source_desc->description()->GetContentByName(content_name);
|
||||
if (!cinfo) {
|
||||
return;
|
||||
}
|
||||
size_t mediasection_index = static_cast<int>(cinfo - &contents[0]);
|
||||
const IceCandidateCollection* source_candidates =
|
||||
source_desc->candidates(mediasection_index);
|
||||
const IceCandidateCollection* dest_candidates =
|
||||
dest_desc->candidates(mediasection_index);
|
||||
if (!source_candidates || !dest_candidates) {
|
||||
return;
|
||||
}
|
||||
for (size_t n = 0; n < source_candidates->count(); ++n) {
|
||||
const IceCandidateInterface* new_candidate = source_candidates->at(n);
|
||||
if (!dest_candidates->HasCandidate(new_candidate)) {
|
||||
dest_desc->AddCandidate(source_candidates->at(n));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TgWebRtcSessionDescriptionFactory::TgWebRtcSessionDescriptionFactory(
|
||||
rtc::Thread* signaling_thread,
|
||||
cricket::ChannelManager* channel_manager,
|
||||
TgPeerConnection* pc,
|
||||
const std::string& session_id,
|
||||
std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator,
|
||||
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate,
|
||||
UniqueRandomIdGenerator* ssrc_generator)
|
||||
: signaling_thread_(signaling_thread),
|
||||
session_desc_factory_(channel_manager,
|
||||
&transport_desc_factory_,
|
||||
ssrc_generator),
|
||||
// RFC 4566 suggested a Network Time Protocol (NTP) format timestamp
|
||||
// as the session id and session version. To simplify, it should be fine
|
||||
// to just use a random number as session id and start version from
|
||||
// |kInitSessionVersion|.
|
||||
session_version_(kInitSessionVersion),
|
||||
cert_generator_(std::move(cert_generator)),
|
||||
pc_(pc),
|
||||
session_id_(session_id),
|
||||
certificate_request_state_(CERTIFICATE_NOT_NEEDED) {
|
||||
RTC_DCHECK(signaling_thread_);
|
||||
RTC_DCHECK(!(cert_generator_ && certificate));
|
||||
bool dtls_enabled = cert_generator_ || certificate;
|
||||
// SRTP-SDES is disabled if DTLS is on.
|
||||
SetSdesPolicy(dtls_enabled ? cricket::SEC_DISABLED : cricket::SEC_REQUIRED);
|
||||
if (!dtls_enabled) {
|
||||
RTC_LOG(LS_VERBOSE) << "DTLS-SRTP disabled.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (certificate) {
|
||||
// Use |certificate|.
|
||||
certificate_request_state_ = CERTIFICATE_WAITING;
|
||||
|
||||
RTC_LOG(LS_VERBOSE) << "DTLS-SRTP enabled; has certificate parameter.";
|
||||
// We already have a certificate but we wait to do |SetIdentity|; if we do
|
||||
// it in the constructor then the caller has not had a chance to connect to
|
||||
// |SignalCertificateReady|.
|
||||
signaling_thread_->Post(
|
||||
RTC_FROM_HERE, this, MSG_USE_CONSTRUCTOR_CERTIFICATE,
|
||||
new rtc::ScopedRefMessageData<rtc::RTCCertificate>(certificate));
|
||||
} else {
|
||||
// Generate certificate.
|
||||
certificate_request_state_ = CERTIFICATE_WAITING;
|
||||
|
||||
rtc::scoped_refptr<TgWebRtcCertificateGeneratorCallback> callback(
|
||||
new rtc::RefCountedObject<TgWebRtcCertificateGeneratorCallback>());
|
||||
callback->SignalRequestFailed.connect(
|
||||
this, &TgWebRtcSessionDescriptionFactory::OnCertificateRequestFailed);
|
||||
callback->SignalCertificateReady.connect(
|
||||
this, &TgWebRtcSessionDescriptionFactory::SetCertificate);
|
||||
|
||||
rtc::KeyParams key_params = rtc::KeyParams();
|
||||
RTC_LOG(LS_VERBOSE)
|
||||
<< "DTLS-SRTP enabled; sending DTLS identity request (key type: "
|
||||
<< key_params.type() << ").";
|
||||
|
||||
// Request certificate. This happens asynchronously, so that the caller gets
|
||||
// a chance to connect to |SignalCertificateReady|.
|
||||
cert_generator_->GenerateCertificateAsync(key_params, absl::nullopt,
|
||||
callback);
|
||||
}
|
||||
}
|
||||
|
||||
TgWebRtcSessionDescriptionFactory::~TgWebRtcSessionDescriptionFactory() {
|
||||
RTC_DCHECK(signaling_thread_->IsCurrent());
|
||||
|
||||
// Fail any requests that were asked for before identity generation completed.
|
||||
FailPendingRequests(kFailedDueToSessionShutdown);
|
||||
|
||||
// Process all pending notifications in the message queue. If we don't do
|
||||
// this, requests will linger and not know they succeeded or failed.
|
||||
rtc::MessageList list;
|
||||
signaling_thread_->Clear(this, rtc::MQID_ANY, &list);
|
||||
for (auto& msg : list) {
|
||||
if (msg.message_id != MSG_USE_CONSTRUCTOR_CERTIFICATE) {
|
||||
OnMessage(&msg);
|
||||
} else {
|
||||
// Skip MSG_USE_CONSTRUCTOR_CERTIFICATE because we don't want to trigger
|
||||
// SetIdentity-related callbacks in the destructor. This can be a problem
|
||||
// when WebRtcSession listens to the callback but it was the WebRtcSession
|
||||
// destructor that caused TgWebRtcSessionDescriptionFactory's destruction.
|
||||
// The callback is then ignored, leaking memory allocated by OnMessage for
|
||||
// MSG_USE_CONSTRUCTOR_CERTIFICATE.
|
||||
delete msg.pdata;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TgWebRtcSessionDescriptionFactory::CreateOffer(
|
||||
CreateSessionDescriptionObserver* observer,
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions& options,
|
||||
const cricket::MediaSessionOptions& session_options) {
|
||||
std::string error = "CreateOffer";
|
||||
if (certificate_request_state_ == CERTIFICATE_FAILED) {
|
||||
error += kFailedDueToIdentityFailed;
|
||||
RTC_LOG(LS_ERROR) << error;
|
||||
PostCreateSessionDescriptionFailed(observer, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidMediaSessionOptions(session_options)) {
|
||||
error += " called with invalid session options";
|
||||
RTC_LOG(LS_ERROR) << error;
|
||||
PostCreateSessionDescriptionFailed(observer, error);
|
||||
return;
|
||||
}
|
||||
|
||||
TgCreateSessionDescriptionRequest request(
|
||||
TgCreateSessionDescriptionRequest::kOffer, observer, session_options);
|
||||
if (certificate_request_state_ == CERTIFICATE_WAITING) {
|
||||
create_session_description_requests_.push(request);
|
||||
} else {
|
||||
RTC_DCHECK(certificate_request_state_ == CERTIFICATE_SUCCEEDED ||
|
||||
certificate_request_state_ == CERTIFICATE_NOT_NEEDED);
|
||||
InternalCreateOffer(request);
|
||||
}
|
||||
}
|
||||
|
||||
void TgWebRtcSessionDescriptionFactory::CreateAnswer(
|
||||
CreateSessionDescriptionObserver* observer,
|
||||
const cricket::MediaSessionOptions& session_options) {
|
||||
std::string error = "CreateAnswer";
|
||||
if (certificate_request_state_ == CERTIFICATE_FAILED) {
|
||||
error += kFailedDueToIdentityFailed;
|
||||
RTC_LOG(LS_ERROR) << error;
|
||||
PostCreateSessionDescriptionFailed(observer, error);
|
||||
return;
|
||||
}
|
||||
if (!pc_->remote_description()) {
|
||||
error += " can't be called before SetRemoteDescription.";
|
||||
RTC_LOG(LS_ERROR) << error;
|
||||
PostCreateSessionDescriptionFailed(observer, error);
|
||||
return;
|
||||
}
|
||||
if (pc_->remote_description()->GetType() != SdpType::kOffer) {
|
||||
error += " failed because remote_description is not an offer.";
|
||||
RTC_LOG(LS_ERROR) << error;
|
||||
PostCreateSessionDescriptionFailed(observer, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidMediaSessionOptions(session_options)) {
|
||||
error += " called with invalid session options.";
|
||||
RTC_LOG(LS_ERROR) << error;
|
||||
PostCreateSessionDescriptionFailed(observer, error);
|
||||
return;
|
||||
}
|
||||
|
||||
TgCreateSessionDescriptionRequest request(
|
||||
TgCreateSessionDescriptionRequest::kAnswer, observer, session_options);
|
||||
if (certificate_request_state_ == CERTIFICATE_WAITING) {
|
||||
create_session_description_requests_.push(request);
|
||||
} else {
|
||||
RTC_DCHECK(certificate_request_state_ == CERTIFICATE_SUCCEEDED ||
|
||||
certificate_request_state_ == CERTIFICATE_NOT_NEEDED);
|
||||
InternalCreateAnswer(request);
|
||||
}
|
||||
}
|
||||
|
||||
void TgWebRtcSessionDescriptionFactory::SetSdesPolicy(
|
||||
cricket::SecurePolicy secure_policy) {
|
||||
session_desc_factory_.set_secure(secure_policy);
|
||||
}
|
||||
|
||||
cricket::SecurePolicy TgWebRtcSessionDescriptionFactory::SdesPolicy() const {
|
||||
return session_desc_factory_.secure();
|
||||
}
|
||||
|
||||
void TgWebRtcSessionDescriptionFactory::OnMessage(rtc::Message* msg) {
|
||||
switch (msg->message_id) {
|
||||
case MSG_CREATE_SESSIONDESCRIPTION_SUCCESS: {
|
||||
CreateSessionDescriptionMsg* param =
|
||||
static_cast<CreateSessionDescriptionMsg*>(msg->pdata);
|
||||
param->observer->OnSuccess(param->description.release());
|
||||
delete param;
|
||||
break;
|
||||
}
|
||||
case MSG_CREATE_SESSIONDESCRIPTION_FAILED: {
|
||||
CreateSessionDescriptionMsg* param =
|
||||
static_cast<CreateSessionDescriptionMsg*>(msg->pdata);
|
||||
param->observer->OnFailure(std::move(param->error));
|
||||
delete param;
|
||||
break;
|
||||
}
|
||||
case MSG_USE_CONSTRUCTOR_CERTIFICATE: {
|
||||
rtc::ScopedRefMessageData<rtc::RTCCertificate>* param =
|
||||
static_cast<rtc::ScopedRefMessageData<rtc::RTCCertificate>*>(
|
||||
msg->pdata);
|
||||
RTC_LOG(LS_INFO) << "Using certificate supplied to the constructor.";
|
||||
SetCertificate(param->data());
|
||||
delete param;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
RTC_NOTREACHED();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TgWebRtcSessionDescriptionFactory::InternalCreateOffer(
|
||||
TgCreateSessionDescriptionRequest request) {
|
||||
if (pc_->local_description()) {
|
||||
// If the needs-ice-restart flag is set as described by JSEP, we should
|
||||
// generate an offer with a new ufrag/password to trigger an ICE restart.
|
||||
for (cricket::MediaDescriptionOptions& options :
|
||||
request.options.media_description_options) {
|
||||
if (pc_->NeedsIceRestart(options.mid)) {
|
||||
options.transport_options.ice_restart = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<cricket::SessionDescription> desc =
|
||||
session_desc_factory_.CreateOffer(
|
||||
request.options, pc_->local_description()
|
||||
? pc_->local_description()->description()
|
||||
: nullptr);
|
||||
if (!desc) {
|
||||
PostCreateSessionDescriptionFailed(request.observer,
|
||||
"Failed to initialize the offer.");
|
||||
return;
|
||||
}
|
||||
|
||||
// RFC 3264
|
||||
// When issuing an offer that modifies the session,
|
||||
// the "o=" line of the new SDP MUST be identical to that in the
|
||||
// previous SDP, except that the version in the origin field MUST
|
||||
// increment by one from the previous SDP.
|
||||
|
||||
// Just increase the version number by one each time when a new offer
|
||||
// is created regardless if it's identical to the previous one or not.
|
||||
// The |session_version_| is a uint64_t, the wrap around should not happen.
|
||||
RTC_DCHECK(session_version_ + 1 > session_version_);
|
||||
auto offer = std::make_unique<JsepSessionDescription>(
|
||||
SdpType::kOffer, std::move(desc), session_id_,
|
||||
rtc::ToString(session_version_++));
|
||||
if (pc_->local_description()) {
|
||||
for (const cricket::MediaDescriptionOptions& options :
|
||||
request.options.media_description_options) {
|
||||
if (!options.transport_options.ice_restart) {
|
||||
CopyCandidatesFromSessionDescription(pc_->local_description(),
|
||||
options.mid, offer.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
PostCreateSessionDescriptionSucceeded(request.observer, std::move(offer));
|
||||
}
|
||||
|
||||
void TgWebRtcSessionDescriptionFactory::InternalCreateAnswer(
|
||||
TgCreateSessionDescriptionRequest request) {
|
||||
if (pc_->remote_description()) {
|
||||
for (cricket::MediaDescriptionOptions& options :
|
||||
request.options.media_description_options) {
|
||||
// According to http://tools.ietf.org/html/rfc5245#section-9.2.1.1
|
||||
// an answer should also contain new ICE ufrag and password if an offer
|
||||
// has been received with new ufrag and password.
|
||||
options.transport_options.ice_restart =
|
||||
pc_->IceRestartPending(options.mid);
|
||||
// We should pass the current SSL role to the transport description
|
||||
// factory, if there is already an existing ongoing session.
|
||||
rtc::SSLRole ssl_role;
|
||||
if (pc_->GetSslRole(options.mid, &ssl_role)) {
|
||||
options.transport_options.prefer_passive_role =
|
||||
(rtc::SSL_SERVER == ssl_role);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<cricket::SessionDescription> desc =
|
||||
session_desc_factory_.CreateAnswer(
|
||||
pc_->remote_description() ? pc_->remote_description()->description()
|
||||
: nullptr,
|
||||
request.options,
|
||||
pc_->local_description() ? pc_->local_description()->description()
|
||||
: nullptr);
|
||||
if (!desc) {
|
||||
PostCreateSessionDescriptionFailed(request.observer,
|
||||
"Failed to initialize the answer.");
|
||||
return;
|
||||
}
|
||||
|
||||
// RFC 3264
|
||||
// If the answer is different from the offer in any way (different IP
|
||||
// addresses, ports, etc.), the origin line MUST be different in the answer.
|
||||
// In that case, the version number in the "o=" line of the answer is
|
||||
// unrelated to the version number in the o line of the offer.
|
||||
// Get a new version number by increasing the |session_version_answer_|.
|
||||
// The |session_version_| is a uint64_t, the wrap around should not happen.
|
||||
RTC_DCHECK(session_version_ + 1 > session_version_);
|
||||
auto answer = std::make_unique<JsepSessionDescription>(
|
||||
SdpType::kAnswer, std::move(desc), session_id_,
|
||||
rtc::ToString(session_version_++));
|
||||
if (pc_->local_description()) {
|
||||
// Include all local ICE candidates in the SessionDescription unless
|
||||
// the remote peer has requested an ICE restart.
|
||||
for (const cricket::MediaDescriptionOptions& options :
|
||||
request.options.media_description_options) {
|
||||
if (!options.transport_options.ice_restart) {
|
||||
CopyCandidatesFromSessionDescription(pc_->local_description(),
|
||||
options.mid, answer.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
PostCreateSessionDescriptionSucceeded(request.observer, std::move(answer));
|
||||
}
|
||||
|
||||
void TgWebRtcSessionDescriptionFactory::FailPendingRequests(
|
||||
const std::string& reason) {
|
||||
RTC_DCHECK(signaling_thread_->IsCurrent());
|
||||
while (!create_session_description_requests_.empty()) {
|
||||
const TgCreateSessionDescriptionRequest& request =
|
||||
create_session_description_requests_.front();
|
||||
PostCreateSessionDescriptionFailed(
|
||||
request.observer,
|
||||
((request.type == TgCreateSessionDescriptionRequest::kOffer)
|
||||
? "CreateOffer"
|
||||
: "CreateAnswer") +
|
||||
reason);
|
||||
create_session_description_requests_.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void TgWebRtcSessionDescriptionFactory::PostCreateSessionDescriptionFailed(
|
||||
CreateSessionDescriptionObserver* observer,
|
||||
const std::string& error) {
|
||||
CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(
|
||||
observer, RTCError(RTCErrorType::INTERNAL_ERROR, std::string(error)));
|
||||
signaling_thread_->Post(RTC_FROM_HERE, this,
|
||||
MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg);
|
||||
RTC_LOG(LS_ERROR) << "Create SDP failed: " << error;
|
||||
}
|
||||
|
||||
void TgWebRtcSessionDescriptionFactory::PostCreateSessionDescriptionSucceeded(
|
||||
CreateSessionDescriptionObserver* observer,
|
||||
std::unique_ptr<SessionDescriptionInterface> description) {
|
||||
CreateSessionDescriptionMsg* msg =
|
||||
new CreateSessionDescriptionMsg(observer, RTCError::OK());
|
||||
msg->description = std::move(description);
|
||||
signaling_thread_->Post(RTC_FROM_HERE, this,
|
||||
MSG_CREATE_SESSIONDESCRIPTION_SUCCESS, msg);
|
||||
}
|
||||
|
||||
void TgWebRtcSessionDescriptionFactory::OnCertificateRequestFailed() {
|
||||
RTC_DCHECK(signaling_thread_->IsCurrent());
|
||||
|
||||
RTC_LOG(LS_ERROR) << "Asynchronous certificate generation request failed.";
|
||||
certificate_request_state_ = CERTIFICATE_FAILED;
|
||||
|
||||
FailPendingRequests(kFailedDueToIdentityFailed);
|
||||
}
|
||||
|
||||
void TgWebRtcSessionDescriptionFactory::SetCertificate(
|
||||
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
|
||||
RTC_DCHECK(certificate);
|
||||
RTC_LOG(LS_VERBOSE) << "Setting new certificate.";
|
||||
|
||||
certificate_request_state_ = CERTIFICATE_SUCCEEDED;
|
||||
SignalCertificateReady(certificate);
|
||||
|
||||
transport_desc_factory_.set_certificate(certificate);
|
||||
transport_desc_factory_.set_secure(cricket::SEC_ENABLED);
|
||||
|
||||
while (!create_session_description_requests_.empty()) {
|
||||
if (create_session_description_requests_.front().type ==
|
||||
TgCreateSessionDescriptionRequest::kOffer) {
|
||||
InternalCreateOffer(create_session_description_requests_.front());
|
||||
} else {
|
||||
InternalCreateAnswer(create_session_description_requests_.front());
|
||||
}
|
||||
create_session_description_requests_.pop();
|
||||
}
|
||||
}
|
||||
} // namespace webrtc
|
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright 2013 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 TG_PC_WEBRTC_SESSION_DESCRIPTION_FACTORY_H_
|
||||
#define TG_PC_WEBRTC_SESSION_DESCRIPTION_FACTORY_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
|
||||
#include "api/jsep.h"
|
||||
#include "api/peer_connection_interface.h"
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "p2p/base/transport_description.h"
|
||||
#include "p2p/base/transport_description_factory.h"
|
||||
#include "pc/media_session.h"
|
||||
#include "pc/peer_connection_internal.h"
|
||||
#include "rtc_base/constructor_magic.h"
|
||||
#include "rtc_base/message_handler.h"
|
||||
#include "rtc_base/message_queue.h"
|
||||
#include "rtc_base/rtc_certificate.h"
|
||||
#include "rtc_base/rtc_certificate_generator.h"
|
||||
#include "rtc_base/third_party/sigslot/sigslot.h"
|
||||
#include "rtc_base/thread.h"
|
||||
#include "rtc_base/unique_id_generator.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class TgPeerConnection;
|
||||
|
||||
// DTLS certificate request callback class.
|
||||
class TgWebRtcCertificateGeneratorCallback
|
||||
: public rtc::RTCCertificateGeneratorCallback,
|
||||
public sigslot::has_slots<> {
|
||||
public:
|
||||
// |rtc::RTCCertificateGeneratorCallback| overrides.
|
||||
void OnSuccess(
|
||||
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) override;
|
||||
void OnFailure() override;
|
||||
|
||||
sigslot::signal0<> SignalRequestFailed;
|
||||
sigslot::signal1<const rtc::scoped_refptr<rtc::RTCCertificate>&>
|
||||
SignalCertificateReady;
|
||||
};
|
||||
|
||||
struct TgCreateSessionDescriptionRequest {
|
||||
enum Type {
|
||||
kOffer,
|
||||
kAnswer,
|
||||
};
|
||||
|
||||
TgCreateSessionDescriptionRequest(Type type,
|
||||
CreateSessionDescriptionObserver* observer,
|
||||
const cricket::MediaSessionOptions& options)
|
||||
: type(type), observer(observer), options(options) {}
|
||||
|
||||
Type type;
|
||||
rtc::scoped_refptr<CreateSessionDescriptionObserver> observer;
|
||||
cricket::MediaSessionOptions options;
|
||||
};
|
||||
|
||||
// This class is used to create offer/answer session description. Certificates
|
||||
// for WebRtcSession/DTLS are either supplied at construction or generated
|
||||
// asynchronously. It queues the create offer/answer request until the
|
||||
// certificate generation has completed, i.e. when OnCertificateRequestFailed or
|
||||
// OnCertificateReady is called.
|
||||
class TgWebRtcSessionDescriptionFactory : public rtc::MessageHandler,
|
||||
public sigslot::has_slots<> {
|
||||
public:
|
||||
// Can specify either a |cert_generator| or |certificate| to enable DTLS. If
|
||||
// a certificate generator is given, starts generating the certificate
|
||||
// asynchronously. If a certificate is given, will use that for identifying
|
||||
// over DTLS. If neither is specified, DTLS is disabled.
|
||||
TgWebRtcSessionDescriptionFactory(
|
||||
rtc::Thread* signaling_thread,
|
||||
cricket::ChannelManager* channel_manager,
|
||||
TgPeerConnection* pc,
|
||||
const std::string& session_id,
|
||||
std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator,
|
||||
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate,
|
||||
rtc::UniqueRandomIdGenerator* ssrc_generator);
|
||||
virtual ~TgWebRtcSessionDescriptionFactory();
|
||||
|
||||
static void CopyCandidatesFromSessionDescription(
|
||||
const SessionDescriptionInterface* source_desc,
|
||||
const std::string& content_name,
|
||||
SessionDescriptionInterface* dest_desc);
|
||||
|
||||
void CreateOffer(
|
||||
CreateSessionDescriptionObserver* observer,
|
||||
const PeerConnectionInterface::RTCOfferAnswerOptions& options,
|
||||
const cricket::MediaSessionOptions& session_options);
|
||||
void CreateAnswer(CreateSessionDescriptionObserver* observer,
|
||||
const cricket::MediaSessionOptions& session_options);
|
||||
|
||||
void SetSdesPolicy(cricket::SecurePolicy secure_policy);
|
||||
cricket::SecurePolicy SdesPolicy() const;
|
||||
|
||||
void set_enable_encrypted_rtp_header_extensions(bool enable) {
|
||||
session_desc_factory_.set_enable_encrypted_rtp_header_extensions(enable);
|
||||
}
|
||||
|
||||
void set_is_unified_plan(bool is_unified_plan) {
|
||||
session_desc_factory_.set_is_unified_plan(is_unified_plan);
|
||||
}
|
||||
|
||||
sigslot::signal1<const rtc::scoped_refptr<rtc::RTCCertificate>&>
|
||||
SignalCertificateReady;
|
||||
|
||||
// For testing.
|
||||
bool waiting_for_certificate_for_testing() const {
|
||||
return certificate_request_state_ == CERTIFICATE_WAITING;
|
||||
}
|
||||
|
||||
private:
|
||||
enum CertificateRequestState {
|
||||
CERTIFICATE_NOT_NEEDED,
|
||||
CERTIFICATE_WAITING,
|
||||
CERTIFICATE_SUCCEEDED,
|
||||
CERTIFICATE_FAILED,
|
||||
};
|
||||
|
||||
// MessageHandler implementation.
|
||||
virtual void OnMessage(rtc::Message* msg);
|
||||
|
||||
void InternalCreateOffer(TgCreateSessionDescriptionRequest request);
|
||||
void InternalCreateAnswer(TgCreateSessionDescriptionRequest request);
|
||||
// Posts failure notifications for all pending session description requests.
|
||||
void FailPendingRequests(const std::string& reason);
|
||||
void PostCreateSessionDescriptionFailed(
|
||||
CreateSessionDescriptionObserver* observer,
|
||||
const std::string& error);
|
||||
void PostCreateSessionDescriptionSucceeded(
|
||||
CreateSessionDescriptionObserver* observer,
|
||||
std::unique_ptr<SessionDescriptionInterface> description);
|
||||
|
||||
void OnCertificateRequestFailed();
|
||||
void SetCertificate(
|
||||
const rtc::scoped_refptr<rtc::RTCCertificate>& certificate);
|
||||
|
||||
std::queue<TgCreateSessionDescriptionRequest>
|
||||
create_session_description_requests_;
|
||||
rtc::Thread* const signaling_thread_;
|
||||
cricket::TransportDescriptionFactory transport_desc_factory_;
|
||||
cricket::MediaSessionDescriptionFactory session_desc_factory_;
|
||||
uint64_t session_version_;
|
||||
const std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator_;
|
||||
// TODO(jiayl): remove the dependency on peer connection once bug 2264 is
|
||||
// fixed.
|
||||
TgPeerConnection* const pc_;
|
||||
const std::string session_id_;
|
||||
CertificateRequestState certificate_request_state_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(TgWebRtcSessionDescriptionFactory);
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // PC_WEBRTC_SESSION_DESCRIPTION_FACTORY_H_
|
Loading…
x
Reference in New Issue
Block a user