Files
platform-external-webrtc/webrtc/video/call.cc
pbos@webrtc.org f577ae9eac Remove internal codecs from VideoSendStream.
Replaces VideoCodec in VideoSendStream::Config with an EncoderSettings
struct. The EncoderSettings struct uses an external encoder for all
codecs. This means that external users, such as libjingle, will provide
the encoders themselves, removing the previous distinction of internal
and external codecs.

For now VideoSendStream translates to VideoCodec internally. In the
interrim (before the corresponding change is implemented in
VideoReceiveStream) tests convert EncoderSettings to VideoCodecs.

Removes Call::GetVideoCodecs().

Disables RampUpTest.WithPacingAndRtx as its further exposed with changes
to bitrates used in tests.

BUG=2854,2992
R=mflodman@webrtc.org, stefan@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/7919004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5722 4adac7df-926f-26a2-2b94-8c16560cd09d
2014-03-19 08:43:57 +00:00

413 lines
12 KiB
C++

/*
* 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 <assert.h>
#include <string.h>
#include <map>
#include <vector>
#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<CriticalSectionWrapper> 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<uint32_t, VideoReceiveStream*> receive_ssrcs_;
scoped_ptr<RWLockWrapper> receive_lock_;
std::map<uint32_t, VideoSendStream*> send_ssrcs_;
scoped_ptr<RWLockWrapper> send_lock_;
scoped_ptr<RtpHeaderParser> rtp_header_parser_;
scoped_ptr<CpuOveruseObserverProxy> 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
class TraceDispatcher : public TraceCallback {
public:
TraceDispatcher()
: lock_(CriticalSectionWrapper::CreateCriticalSection()),
filter_(kTraceNone) {
Trace::CreateTrace();
VideoEngine::SetTraceCallback(this);
VideoEngine::SetTraceFilter(kTraceNone);
}
~TraceDispatcher() {
Trace::ReturnTrace();
VideoEngine::SetTraceCallback(NULL);
}
virtual void Print(TraceLevel level,
const char* message,
int length) OVERRIDE {
CriticalSectionScoped crit(lock_.get());
for (std::map<Call*, Call::Config*>::iterator it = callbacks_.begin();
it != callbacks_.end();
++it) {
if ((level & it->second->trace_filter) != kTraceNone)
it->second->trace_callback->Print(level, message, length);
}
}
void RegisterCallback(Call* call, Call::Config* config) {
if (config->trace_callback == NULL)
return;
CriticalSectionScoped crit(lock_.get());
callbacks_[call] = config;
filter_ |= config->trace_filter;
VideoEngine::SetTraceFilter(filter_);
}
void DeregisterCallback(Call* call) {
CriticalSectionScoped crit(lock_.get());
callbacks_.erase(call);
filter_ = kTraceNone;
for (std::map<Call*, Call::Config*>::iterator it = callbacks_.begin();
it != callbacks_.end();
++it) {
filter_ |= it->second->trace_filter;
}
VideoEngine::SetTraceFilter(filter_);
}
private:
scoped_ptr<CriticalSectionWrapper> lock_;
unsigned int filter_;
std::map<Call*, Call::Config*> callbacks_;
};
namespace internal {
TraceDispatcher* global_trace_dispatcher = NULL;
} // internal
void CreateTraceDispatcher() {
if (internal::global_trace_dispatcher == NULL) {
TraceDispatcher* dispatcher = new TraceDispatcher();
// TODO(pbos): Atomic compare and exchange.
if (internal::global_trace_dispatcher == NULL) {
internal::global_trace_dispatcher = dispatcher;
} else {
delete dispatcher;
}
}
}
Call* Call::Create(const Call::Config& config) {
CreateTraceDispatcher();
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));
}
global_trace_dispatcher->RegisterCallback(this, &config_);
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() {
global_trace_dispatcher->DeregisterCallback(this);
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<uint32_t, VideoSendStream*>::iterator it =
send_ssrcs_.begin();
it != send_ssrcs_.end();
++it) {
if (it->second == static_cast<VideoSendStream*>(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<uint32_t, VideoReceiveStream*>::iterator it =
receive_ssrcs_.begin();
while (it != receive_ssrcs_.end()) {
if (it->second == static_cast<VideoReceiveStream*>(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<uint32_t, VideoReceiveStream*>::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<uint32_t, VideoSendStream*>::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<uint32_t, VideoReceiveStream*>::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<const uint8_t*>(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<int>(length)))
return DeliverRtcp(packet, length);
RTPHeader rtp_header;
if (!rtp_header_parser_->Parse(packet, static_cast<int>(length), &rtp_header))
return false;
return DeliverRtp(rtp_header, packet, length);
}
} // namespace internal
} // namespace webrtc