/* * Copyright (c) 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 #include #include #include #include "webrtc/call.h" #include "webrtc/common.h" #include "webrtc/config.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h" #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" #include "webrtc/system_wrappers/interface/rw_lock_wrapper.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h" #include "webrtc/system_wrappers/interface/trace.h" #include "webrtc/video/video_receive_stream.h" #include "webrtc/video/video_send_stream.h" #include "webrtc/video_engine/include/vie_base.h" #include "webrtc/video_engine/include/vie_codec.h" #include "webrtc/video_engine/include/vie_rtp_rtcp.h" namespace webrtc { const char* RtpExtension::kTOffset = "urn:ietf:params:rtp-hdrext:toffset"; const char* RtpExtension::kAbsSendTime = "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time"; namespace internal { class CpuOveruseObserverProxy : public webrtc::CpuOveruseObserver { public: CpuOveruseObserverProxy(OveruseCallback* overuse_callback) : crit_(CriticalSectionWrapper::CreateCriticalSection()), overuse_callback_(overuse_callback) { assert(overuse_callback != NULL); } virtual ~CpuOveruseObserverProxy() {} virtual void OveruseDetected() OVERRIDE { CriticalSectionScoped cs(crit_.get()); overuse_callback_->OnOveruse(); } virtual void NormalUsage() OVERRIDE { CriticalSectionScoped cs(crit_.get()); overuse_callback_->OnNormalUse(); } private: scoped_ptr crit_; OveruseCallback* overuse_callback_; }; class Call : public webrtc::Call, public PacketReceiver { public: Call(webrtc::VideoEngine* video_engine, const Call::Config& config); virtual ~Call(); virtual PacketReceiver* Receiver() OVERRIDE; virtual VideoSendStream::Config GetDefaultSendConfig() OVERRIDE; virtual VideoSendStream* CreateVideoSendStream( const VideoSendStream::Config& config) OVERRIDE; virtual void DestroyVideoSendStream(webrtc::VideoSendStream* send_stream) OVERRIDE; virtual VideoReceiveStream::Config GetDefaultReceiveConfig() OVERRIDE; virtual VideoReceiveStream* CreateVideoReceiveStream( const VideoReceiveStream::Config& config) OVERRIDE; virtual void DestroyVideoReceiveStream( webrtc::VideoReceiveStream* receive_stream) OVERRIDE; virtual uint32_t SendBitrateEstimate() OVERRIDE; virtual uint32_t ReceiveBitrateEstimate() OVERRIDE; virtual bool DeliverPacket(const uint8_t* packet, size_t length) OVERRIDE; private: bool DeliverRtcp(const uint8_t* packet, size_t length); bool DeliverRtp(const RTPHeader& header, const uint8_t* packet, size_t length); Call::Config config_; std::map receive_ssrcs_; scoped_ptr receive_lock_; std::map send_ssrcs_; scoped_ptr send_lock_; scoped_ptr rtp_header_parser_; scoped_ptr overuse_observer_proxy_; VideoEngine* video_engine_; ViERTP_RTCP* rtp_rtcp_; ViECodec* codec_; ViEBase* base_; int base_channel_id_; DISALLOW_COPY_AND_ASSIGN(Call); }; } // namespace internal Call* Call::Create(const Call::Config& config) { VideoEngine* video_engine = config.webrtc_config != NULL ? VideoEngine::Create(*config.webrtc_config) : VideoEngine::Create(); assert(video_engine != NULL); return new internal::Call(video_engine, config); } namespace internal { Call::Call(webrtc::VideoEngine* video_engine, const Call::Config& config) : config_(config), receive_lock_(RWLockWrapper::CreateRWLock()), send_lock_(RWLockWrapper::CreateRWLock()), rtp_header_parser_(RtpHeaderParser::Create()), video_engine_(video_engine), base_channel_id_(-1) { assert(video_engine != NULL); assert(config.send_transport != NULL); if (config.overuse_callback) { overuse_observer_proxy_.reset( new CpuOveruseObserverProxy(config.overuse_callback)); } rtp_rtcp_ = ViERTP_RTCP::GetInterface(video_engine_); assert(rtp_rtcp_ != NULL); codec_ = ViECodec::GetInterface(video_engine_); assert(codec_ != NULL); // As a workaround for non-existing calls in the old API, create a base // channel used as default channel when creating send and receive streams. base_ = ViEBase::GetInterface(video_engine_); assert(base_ != NULL); base_->CreateChannel(base_channel_id_); assert(base_channel_id_ != -1); } Call::~Call() { base_->DeleteChannel(base_channel_id_); base_->Release(); codec_->Release(); rtp_rtcp_->Release(); webrtc::VideoEngine::Delete(video_engine_); } PacketReceiver* Call::Receiver() { return this; } VideoSendStream::Config Call::GetDefaultSendConfig() { VideoSendStream::Config config; return config; } VideoSendStream* Call::CreateVideoSendStream( const VideoSendStream::Config& config) { assert(config.rtp.ssrcs.size() > 0); VideoSendStream* send_stream = new VideoSendStream( config_.send_transport, overuse_observer_proxy_.get(), video_engine_, config, base_channel_id_); WriteLockScoped write_lock(*send_lock_); for (size_t i = 0; i < config.rtp.ssrcs.size(); ++i) { assert(send_ssrcs_.find(config.rtp.ssrcs[i]) == send_ssrcs_.end()); send_ssrcs_[config.rtp.ssrcs[i]] = send_stream; } return send_stream; } void Call::DestroyVideoSendStream(webrtc::VideoSendStream* send_stream) { assert(send_stream != NULL); VideoSendStream* send_stream_impl = NULL; { WriteLockScoped write_lock(*send_lock_); for (std::map::iterator it = send_ssrcs_.begin(); it != send_ssrcs_.end(); ++it) { if (it->second == static_cast(send_stream)) { send_stream_impl = it->second; send_ssrcs_.erase(it); break; } } } assert(send_stream_impl != NULL); delete send_stream_impl; } VideoReceiveStream::Config Call::GetDefaultReceiveConfig() { VideoReceiveStream::Config config; config.rtp.remb = true; return config; } VideoReceiveStream* Call::CreateVideoReceiveStream( const VideoReceiveStream::Config& config) { VideoReceiveStream* receive_stream = new VideoReceiveStream(video_engine_, config, config_.send_transport, config_.voice_engine, base_channel_id_); WriteLockScoped write_lock(*receive_lock_); assert(receive_ssrcs_.find(config.rtp.remote_ssrc) == receive_ssrcs_.end()); receive_ssrcs_[config.rtp.remote_ssrc] = receive_stream; // TODO(pbos): Configure different RTX payloads per receive payload. VideoReceiveStream::Config::Rtp::RtxMap::const_iterator it = config.rtp.rtx.begin(); if (it != config.rtp.rtx.end()) receive_ssrcs_[it->second.ssrc] = receive_stream; return receive_stream; } void Call::DestroyVideoReceiveStream( webrtc::VideoReceiveStream* receive_stream) { assert(receive_stream != NULL); VideoReceiveStream* receive_stream_impl = NULL; { WriteLockScoped write_lock(*receive_lock_); // Remove all ssrcs pointing to a receive stream. As RTX retransmits on a // separate SSRC there can be either one or two. std::map::iterator it = receive_ssrcs_.begin(); while (it != receive_ssrcs_.end()) { if (it->second == static_cast(receive_stream)) { assert(receive_stream_impl == NULL || receive_stream_impl == it->second); receive_stream_impl = it->second; receive_ssrcs_.erase(it++); } else { ++it; } } } assert(receive_stream_impl != NULL); delete receive_stream_impl; } uint32_t Call::SendBitrateEstimate() { // TODO(pbos): Return send-bitrate estimate return 0; } uint32_t Call::ReceiveBitrateEstimate() { // TODO(pbos): Return receive-bitrate estimate return 0; } bool Call::DeliverRtcp(const uint8_t* packet, size_t length) { // TODO(pbos): Figure out what channel needs it actually. // Do NOT broadcast! Also make sure it's a valid packet. bool rtcp_delivered = false; { ReadLockScoped read_lock(*receive_lock_); for (std::map::iterator it = receive_ssrcs_.begin(); it != receive_ssrcs_.end(); ++it) { if (it->second->DeliverRtcp(packet, length)) rtcp_delivered = true; } } { ReadLockScoped read_lock(*send_lock_); for (std::map::iterator it = send_ssrcs_.begin(); it != send_ssrcs_.end(); ++it) { if (it->second->DeliverRtcp(packet, length)) rtcp_delivered = true; } } return rtcp_delivered; } bool Call::DeliverRtp(const RTPHeader& header, const uint8_t* packet, size_t length) { ReadLockScoped read_lock(*receive_lock_); std::map::iterator it = receive_ssrcs_.find(header.ssrc); if (it == receive_ssrcs_.end()) { // TODO(pbos): Log some warning, SSRC without receiver. return false; } return it->second->DeliverRtp(static_cast(packet), length); } bool Call::DeliverPacket(const uint8_t* packet, size_t length) { // TODO(pbos): ExtensionMap if there are extensions. if (RtpHeaderParser::IsRtcp(packet, static_cast(length))) return DeliverRtcp(packet, length); RTPHeader rtp_header; if (!rtp_header_parser_->Parse(packet, static_cast(length), &rtp_header)) return false; return DeliverRtp(rtp_header, packet, length); } } // namespace internal } // namespace webrtc