This commit is contained in:
Ali 2020-06-02 11:01:57 +04:00
parent b71f748c48
commit 5f9565853d
9 changed files with 7309 additions and 6084 deletions

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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,11 +63,11 @@ class RtcEventLog;
// - Generating offers and answers based on the current state.
// - The ICE state machine.
// - Generating stats.
class TgPeerConnection : public PeerConnectionInternal,
public TgJsepTransportController::Observer,
public RtpSenderBase::SetStreamsObserver,
public rtc::MessageHandler,
public sigslot::has_slots<> {
class TgPeerConnection : public rtc::RefCountInterface,
public TgJsepTransportController::Observer,
public TgRtpSenderBase::SetStreamsObserver,
public rtc::MessageHandler,
public sigslot::has_slots<> {
public:
// A bit in the usage pattern is registered when its defining event occurs at
// least once.
@ -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.

View File

@ -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>

View File

@ -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_;

View 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

View 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_

View File

@ -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

View File

@ -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_