757 lines
21 KiB
C++
757 lines
21 KiB
C++
|
|
|
|
#include "talk/app/videomediaengine.h"
|
|
|
|
#include <iostream>
|
|
|
|
#ifdef PLATFORM_CHROMIUM
|
|
#include "content/renderer/video_capture_chrome.h"
|
|
#endif
|
|
#include "talk/base/buffer.h"
|
|
#include "talk/base/byteorder.h"
|
|
#include "talk/base/logging.h"
|
|
#include "talk/base/stringutils.h"
|
|
#include "talk/app/voicemediaengine.h"
|
|
|
|
#include "modules/video_capture/main/interface/video_capture.h"
|
|
|
|
#ifndef ARRAYSIZE
|
|
#define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0]))
|
|
#endif
|
|
|
|
namespace webrtc {
|
|
|
|
static const int kDefaultLogSeverity = 3;
|
|
static const int kStartVideoBitrate = 300;
|
|
static const int kMaxVideoBitrate = 1000;
|
|
|
|
const RtcVideoEngine::VideoCodecPref RtcVideoEngine::kVideoCodecPrefs[] = {
|
|
{"VP8", 104, 0},
|
|
{"H264", 105, 1}
|
|
};
|
|
|
|
RtcVideoEngine::RtcVideoEngine()
|
|
: video_engine_(new VideoEngineWrapper()),
|
|
capture_(NULL),
|
|
capture_id_(-1),
|
|
voice_engine_(NULL),
|
|
initialized_(false),
|
|
log_level_(kDefaultLogSeverity),
|
|
capture_started_(false){
|
|
}
|
|
|
|
RtcVideoEngine::RtcVideoEngine(RtcVoiceEngine* voice_engine)
|
|
: video_engine_(new VideoEngineWrapper()),
|
|
capture_(NULL),
|
|
capture_id_(-1),
|
|
voice_engine_(voice_engine),
|
|
initialized_(false),
|
|
log_level_(kDefaultLogSeverity),
|
|
capture_started_(false){
|
|
}
|
|
|
|
RtcVideoEngine::~RtcVideoEngine() {
|
|
LOG(LS_VERBOSE) << " RtcVideoEngine::~RtcVideoEngine";
|
|
video_engine_->engine()->SetTraceCallback(NULL);
|
|
Terminate();
|
|
}
|
|
|
|
bool RtcVideoEngine::Init() {
|
|
LOG(LS_VERBOSE) << "RtcVideoEngine::Init";
|
|
ApplyLogging();
|
|
if (video_engine_->engine()->SetTraceCallback(this) != 0) {
|
|
LOG(LS_ERROR) << "SetTraceCallback error";
|
|
}
|
|
|
|
bool result = InitVideoEngine(voice_engine_);
|
|
if (result) {
|
|
LOG(LS_INFO) << "VideoEngine Init done";
|
|
} else {
|
|
LOG(LS_ERROR) << "VideoEngine Init failed, releasing";
|
|
Terminate();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool RtcVideoEngine::InitVideoEngine(RtcVoiceEngine* voice_engine) {
|
|
LOG(LS_VERBOSE) << "RtcVideoEngine::InitVideoEngine";
|
|
|
|
bool ret = true;
|
|
if (video_engine_->base()->Init() != 0) {
|
|
LOG(LS_ERROR) << "VideoEngine Init method failed";
|
|
ret = false;
|
|
}
|
|
|
|
if (!voice_engine) {
|
|
LOG(LS_WARNING) << "NULL voice engine";
|
|
} else if ((video_engine_->base()->SetVoiceEngine(
|
|
voice_engine->webrtc()->engine())) != 0) {
|
|
LOG(LS_WARNING) << "Failed to SetVoiceEngine";
|
|
}
|
|
|
|
if ((video_engine_->base()->RegisterObserver(*this)) != 0) {
|
|
LOG(LS_WARNING) << "Failed to register observer";
|
|
}
|
|
|
|
int ncodecs = video_engine_->codec()->NumberOfCodecs();
|
|
for (int i = 0; i < ncodecs - 2; ++i) {
|
|
VideoCodec wcodec;
|
|
if ((video_engine_->codec()->GetCodec(i, wcodec) == 0) &&
|
|
(strncmp(wcodec.plName, "I420", 4) != 0)) { //ignore I420
|
|
cricket::VideoCodec codec(wcodec.plType, wcodec.plName, wcodec.width,
|
|
wcodec.height, wcodec.maxFramerate, i);
|
|
LOG(LS_INFO) << codec.ToString();
|
|
video_codecs_.push_back(codec);
|
|
}
|
|
}
|
|
|
|
std::sort(video_codecs_.begin(), video_codecs_.end(),
|
|
&cricket::VideoCodec::Preferable);
|
|
return ret;
|
|
}
|
|
|
|
void RtcVideoEngine::PerformanceAlarm(const unsigned int cpuLoad) {
|
|
return;
|
|
}
|
|
|
|
void RtcVideoEngine::Print(const TraceLevel level, const char *traceString,
|
|
const int length) {
|
|
return;
|
|
}
|
|
|
|
int RtcVideoEngine::GetCodecPreference(const char* name) {
|
|
for (size_t i = 0; i < ARRAY_SIZE(kVideoCodecPrefs); ++i) {
|
|
if (strcmp(kVideoCodecPrefs[i].payload_name, name) == 0) {
|
|
return kVideoCodecPrefs[i].pref;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void RtcVideoEngine::ApplyLogging() {
|
|
int filter = 0;
|
|
switch(log_level_) {
|
|
case talk_base::LS_VERBOSE: filter |= kTraceAll;
|
|
case talk_base::LS_INFO: filter |= kTraceStateInfo;
|
|
case talk_base::LS_WARNING: filter |= kTraceWarning;
|
|
case talk_base::LS_ERROR: filter |= kTraceError | kTraceCritical;
|
|
}
|
|
}
|
|
|
|
void RtcVideoEngine::Terminate() {
|
|
LOG(LS_INFO) << "RtcVideoEngine::Terminate";
|
|
ReleaseCaptureDevice();
|
|
}
|
|
|
|
int RtcVideoEngine::GetCapabilities() {
|
|
return cricket::MediaEngine::VIDEO_RECV | cricket::MediaEngine::VIDEO_SEND;
|
|
}
|
|
|
|
bool RtcVideoEngine::SetOptions(int options) {
|
|
return true;
|
|
}
|
|
|
|
bool RtcVideoEngine::ReleaseCaptureDevice() {
|
|
if (capture_) {
|
|
// Stop capture
|
|
SetCapture(false);
|
|
// DisconnectCaptureDevice
|
|
RtcVideoMediaChannel* channel;
|
|
for (VideoChannels::const_iterator it = channels_.begin();
|
|
it != channels_.end(); ++it) {
|
|
ASSERT(*it != NULL);
|
|
channel = *it;
|
|
video_engine_->capture()->DisconnectCaptureDevice(channel->video_channel());
|
|
}
|
|
// ReleaseCaptureDevice
|
|
video_engine_->capture()->ReleaseCaptureDevice(capture_id_);
|
|
capture_id_ = -1;
|
|
#ifdef PLATFORM_CHROMIUM
|
|
VideoCaptureChrome::DestroyVideoCapture(
|
|
static_cast<VideoCaptureChrome*>(capture_));
|
|
#else
|
|
webrtc::VideoCaptureModule::Destroy(capture_);
|
|
#endif
|
|
capture_ = NULL;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool RtcVideoEngine::SetCaptureDevice(const cricket::Device* cam) {
|
|
ASSERT(video_engine_.get());
|
|
ASSERT(cam != NULL);
|
|
|
|
ReleaseCaptureDevice();
|
|
|
|
#ifdef PLATFORM_CHROMIUM
|
|
int cam_id = atol(cam->id.c_str());
|
|
if (cam_id == -1)
|
|
return false;
|
|
unsigned char uniqueId[16];
|
|
capture_ = VideoCaptureChrome::CreateVideoCapture(cam_id, uniqueId);
|
|
#else
|
|
WebRtc_UWord8 device_name[128];
|
|
WebRtc_UWord8 device_id[260];
|
|
VideoCaptureModule::DeviceInfo* device_info =
|
|
VideoCaptureModule::CreateDeviceInfo(0);
|
|
for (WebRtc_UWord32 i = 0; i < device_info->NumberOfDevices(); ++i) {
|
|
if (device_info->GetDeviceName(i, device_name, ARRAYSIZE(device_name),
|
|
device_id, ARRAYSIZE(device_id)) == 0) {
|
|
if ((cam->name.compare("") == 0) ||
|
|
(cam->id.compare((char*) device_id) == 0)) {
|
|
capture_ = VideoCaptureModule::Create(1234, device_id);
|
|
if (capture_) {
|
|
LOG(INFO) << "Found video capture device: " << device_name;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
VideoCaptureModule::DestroyDeviceInfo(device_info);
|
|
#endif
|
|
|
|
if (!capture_)
|
|
return false;
|
|
|
|
ViECapture* vie_capture = video_engine_->capture();
|
|
if (vie_capture->AllocateCaptureDevice(*capture_, capture_id_) == 0) {
|
|
// Connect to all the channels
|
|
RtcVideoMediaChannel* channel;
|
|
for (VideoChannels::const_iterator it = channels_.begin();
|
|
it != channels_.end(); ++it) {
|
|
ASSERT(*it != NULL);
|
|
channel = *it;
|
|
vie_capture->ConnectCaptureDevice(capture_id_, channel->video_channel());
|
|
}
|
|
SetCapture(true);
|
|
} else {
|
|
ASSERT(capture_id_ == -1);
|
|
}
|
|
|
|
return (capture_id_ != -1);
|
|
}
|
|
|
|
bool RtcVideoEngine::SetVideoRenderer(int channel_id,
|
|
void* window,
|
|
unsigned int zOrder,
|
|
float left,
|
|
float top,
|
|
float right,
|
|
float bottom) {
|
|
int ret;
|
|
if (channel_id == -1)
|
|
channel_id = capture_id_;
|
|
ret = video_engine_->render()->AddRenderer(
|
|
channel_id, window, zOrder, left, top, right, bottom);
|
|
if (ret !=0 )
|
|
return false;
|
|
ret = video_engine_->render()->StartRender(channel_id);
|
|
if (ret !=0 )
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool RtcVideoEngine::SetLocalRenderer(cricket::VideoRenderer* renderer) {
|
|
LOG(LS_WARNING) << "Not required call SetLocalRenderer for webrtc";
|
|
return false;
|
|
}
|
|
|
|
cricket::CaptureResult RtcVideoEngine::SetCapture(bool capture) {
|
|
if (capture_started_ == capture)
|
|
return cricket::CR_SUCCESS;
|
|
|
|
if (capture_id_ != -1) {
|
|
int ret;
|
|
if (capture)
|
|
ret = video_engine_->capture()->StartCapture(capture_id_);
|
|
else
|
|
ret = video_engine_->capture()->StopCapture(capture_id_);
|
|
if (ret == 0) {
|
|
capture_started_ = capture;
|
|
return cricket::CR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return cricket::CR_NO_DEVICE;
|
|
}
|
|
|
|
const std::vector<cricket::VideoCodec>& RtcVideoEngine::codecs() const {
|
|
return video_codecs_;
|
|
}
|
|
|
|
void RtcVideoEngine::SetLogging(int min_sev, const char* filter) {
|
|
log_level_ = min_sev;
|
|
ApplyLogging();
|
|
}
|
|
|
|
bool RtcVideoEngine::SetDefaultEncoderConfig(
|
|
const cricket::VideoEncoderConfig& config) {
|
|
bool ret = SetDefaultCodec(config.max_codec);
|
|
if (ret) {
|
|
default_encoder_config_ = config;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool RtcVideoEngine::SetDefaultCodec(const cricket::VideoCodec& codec) {
|
|
default_codec_ = codec;
|
|
return true;
|
|
}
|
|
|
|
RtcVideoMediaChannel* RtcVideoEngine::CreateChannel(
|
|
cricket::VoiceMediaChannel* voice_channel) {
|
|
RtcVideoMediaChannel* channel =
|
|
new RtcVideoMediaChannel(this, voice_channel);
|
|
if (channel) {
|
|
if (!channel->Init()) {
|
|
delete channel;
|
|
channel = NULL;
|
|
}
|
|
}
|
|
return channel;
|
|
}
|
|
|
|
bool RtcVideoEngine::FindCodec(const cricket::VideoCodec& codec) {
|
|
for (size_t i = 0; i < video_codecs_.size(); ++i) {
|
|
if (video_codecs_[i].Matches(codec)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void RtcVideoEngine::ConvertToCricketVideoCodec(
|
|
const VideoCodec& in_codec, cricket::VideoCodec& out_codec) {
|
|
out_codec.id = in_codec.plType;
|
|
out_codec.name = in_codec.plName;
|
|
out_codec.width = in_codec.width;
|
|
out_codec.height = in_codec.height;
|
|
out_codec.framerate = in_codec.maxFramerate;
|
|
}
|
|
|
|
void RtcVideoEngine::ConvertFromCricketVideoCodec(
|
|
const cricket::VideoCodec& in_codec, VideoCodec& out_codec) {
|
|
out_codec.plType = in_codec.id;
|
|
strcpy(out_codec.plName, in_codec.name.c_str());
|
|
out_codec.width = 352; //in_codec.width;
|
|
out_codec.height = 288; //in_codec.height;
|
|
out_codec.maxFramerate = 30; //in_codec.framerate;
|
|
|
|
if (strncmp(out_codec.plName, "VP8", 3) == 0) {
|
|
out_codec.codecType = kVideoCodecVP8;
|
|
} else if (strncmp(out_codec.plName, "H263", 4) == 0) {
|
|
out_codec.codecType = kVideoCodecH263;
|
|
} else if (strncmp(out_codec.plName, "H264", 4) == 0) {
|
|
out_codec.codecType = kVideoCodecH264;
|
|
} else if (strncmp(out_codec.plName, "I420", 4) == 0) {
|
|
out_codec.codecType = kVideoCodecI420;
|
|
} else {
|
|
LOG(LS_INFO) << "invalid codec type";
|
|
}
|
|
|
|
out_codec.maxBitrate = kMaxVideoBitrate;
|
|
out_codec.startBitrate = kStartVideoBitrate;
|
|
out_codec.minBitrate = kStartVideoBitrate;
|
|
}
|
|
|
|
int RtcVideoEngine::GetLastVideoEngineError() {
|
|
return video_engine_->base()->LastError();
|
|
}
|
|
|
|
void RtcVideoEngine::RegisterChannel(RtcVideoMediaChannel *channel) {
|
|
talk_base::CritScope lock(&channels_cs_);
|
|
channels_.push_back(channel);
|
|
}
|
|
|
|
void RtcVideoEngine::UnregisterChannel(RtcVideoMediaChannel *channel) {
|
|
talk_base::CritScope lock(&channels_cs_);
|
|
VideoChannels::iterator i = std::find(channels_.begin(),
|
|
channels_.end(),
|
|
channel);
|
|
if (i != channels_.end()) {
|
|
channels_.erase(i);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// RtcVideoMediaChannel
|
|
|
|
RtcVideoMediaChannel::RtcVideoMediaChannel(
|
|
RtcVideoEngine* engine, cricket::VoiceMediaChannel* channel)
|
|
: engine_(engine),
|
|
voice_channel_(channel),
|
|
video_channel_(-1),
|
|
sending_(false),
|
|
render_started_(false) {
|
|
engine->RegisterChannel(this);
|
|
}
|
|
|
|
bool RtcVideoMediaChannel::Init() {
|
|
bool ret = true;
|
|
if (engine_->video_engine()->base()->CreateChannel(video_channel_) != 0) {
|
|
LOG(LS_ERROR) << "ViE CreateChannel Failed!!";
|
|
ret = false;
|
|
}
|
|
|
|
LOG(LS_INFO) << "RtcVideoMediaChannel::Init "
|
|
<< "video_channel " << video_channel_ << " created";
|
|
//connect audio channel
|
|
if (voice_channel_) {
|
|
RtcVoiceMediaChannel* channel =
|
|
static_cast<RtcVoiceMediaChannel*> (voice_channel_);
|
|
if (engine_->video_engine()->base()->ConnectAudioChannel(
|
|
video_channel_, channel->audio_channel()) != 0) {
|
|
LOG(LS_WARNING) << "ViE ConnectAudioChannel failed"
|
|
<< "A/V not synchronized";
|
|
// Don't set ret to false;
|
|
}
|
|
}
|
|
|
|
//Register external transport
|
|
if (engine_->video_engine()->network()->RegisterSendTransport(
|
|
video_channel_, *this) != 0) {
|
|
ret = false;
|
|
} else {
|
|
EnableRtcp();
|
|
EnablePLI();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
RtcVideoMediaChannel::~RtcVideoMediaChannel() {
|
|
// Stop and remote renderer
|
|
SetRender(false);
|
|
if (engine()->video_engine()->render()->RemoveRenderer(video_channel_) == -1) {
|
|
LOG(LS_ERROR) << "Video RemoveRenderer failed for channel "
|
|
<< video_channel_;
|
|
}
|
|
|
|
// DeRegister external transport
|
|
if (engine()->video_engine()->network()->DeregisterSendTransport(
|
|
video_channel_) == -1) {
|
|
LOG(LS_ERROR) << "DeRegisterSendTransport failed for channel id "
|
|
<< video_channel_;
|
|
}
|
|
|
|
// Unregister RtcChannel with the engine.
|
|
engine()->UnregisterChannel(this);
|
|
|
|
// Delete VideoChannel
|
|
if (engine()->video_engine()->base()->DeleteChannel(video_channel_) == -1) {
|
|
LOG(LS_ERROR) << "Video DeleteChannel failed for channel "
|
|
<< video_channel_;
|
|
}
|
|
}
|
|
|
|
bool RtcVideoMediaChannel::SetRecvCodecs(
|
|
const std::vector<cricket::VideoCodec>& codecs) {
|
|
bool ret = true;
|
|
for (std::vector<cricket::VideoCodec>::const_iterator iter = codecs.begin();
|
|
iter != codecs.end(); ++iter) {
|
|
if (engine()->FindCodec(*iter)) {
|
|
VideoCodec wcodec;
|
|
engine()->ConvertFromCricketVideoCodec(*iter, wcodec);
|
|
if (engine()->video_engine()->codec()->SetReceiveCodec(
|
|
video_channel_, wcodec) != 0) {
|
|
LOG(LS_ERROR) << "ViE SetReceiveCodec failed"
|
|
<< " VideoChannel : " << video_channel_ << " Error: "
|
|
<< engine()->video_engine()->base()->LastError()
|
|
<< "wcodec " << wcodec.plName;
|
|
ret = false;
|
|
}
|
|
} else {
|
|
LOG(LS_INFO) << "Unknown codec" << iter->name;
|
|
ret = false;
|
|
}
|
|
}
|
|
|
|
// make channel ready to receive packets
|
|
if (ret) {
|
|
if (engine()->video_engine()->base()->StartReceive(video_channel_) != 0) {
|
|
LOG(LS_ERROR) << "ViE StartReceive failure";
|
|
ret = false;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool RtcVideoMediaChannel::SetSendCodecs(
|
|
const std::vector<cricket::VideoCodec>& codecs) {
|
|
if (sending_) {
|
|
LOG(LS_ERROR) << "channel is alredy sending";
|
|
return false;
|
|
}
|
|
|
|
//match with local video codec list
|
|
std::vector<VideoCodec> send_codecs;
|
|
for (std::vector<cricket::VideoCodec>::const_iterator iter = codecs.begin();
|
|
iter != codecs.end(); ++iter) {
|
|
if (engine()->FindCodec(*iter)) {
|
|
VideoCodec wcodec;
|
|
engine()->ConvertFromCricketVideoCodec(*iter, wcodec);
|
|
send_codecs.push_back(wcodec);
|
|
}
|
|
}
|
|
|
|
// if none matches, return with set
|
|
if (send_codecs.empty()) {
|
|
LOG(LS_ERROR) << "No matching codecs avilable";
|
|
return false;
|
|
}
|
|
|
|
//select the first matched codec
|
|
const VideoCodec& codec(send_codecs[0]);
|
|
send_codec_ = codec;
|
|
if (engine()->video_engine()->codec()->SetSendCodec(
|
|
video_channel_, codec) != 0) {
|
|
LOG(LS_ERROR) << "ViE SetSendCodec failed";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool RtcVideoMediaChannel::SetRender(bool render) {
|
|
if (video_channel_ != -1) {
|
|
int ret = -1;
|
|
if (render == render_started_)
|
|
return true;
|
|
|
|
if (render) {
|
|
ret = engine()->video_engine()->render()->StartRender(video_channel_);
|
|
} else {
|
|
ret = engine()->video_engine()->render()->StopRender(video_channel_);
|
|
}
|
|
|
|
if (ret == 0) {
|
|
render_started_ = render;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool RtcVideoMediaChannel::SetSend(bool send) {
|
|
if (send == sending()) {
|
|
return true; // no action required
|
|
}
|
|
|
|
bool ret = true;
|
|
if (send) { //enable
|
|
if (engine()->video_engine()->base()->StartSend(video_channel_) != 0) {
|
|
LOG(LS_ERROR) << "ViE StartSend failed";
|
|
ret = false;
|
|
}
|
|
} else { // disable
|
|
if (engine()->video_engine()->base()->StopSend(video_channel_) != 0) {
|
|
LOG(LS_ERROR) << "ViE StopSend failed";
|
|
ret = false;
|
|
}
|
|
}
|
|
if (ret)
|
|
sending_ = send;
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool RtcVideoMediaChannel::AddStream(uint32 ssrc, uint32 voice_ssrc) {
|
|
return false;
|
|
}
|
|
|
|
bool RtcVideoMediaChannel::RemoveStream(uint32 ssrc) {
|
|
return false;
|
|
}
|
|
|
|
bool RtcVideoMediaChannel::SetRenderer(
|
|
uint32 ssrc, cricket::VideoRenderer* renderer) {
|
|
return false;
|
|
}
|
|
|
|
bool RtcVideoMediaChannel::SetExternalRenderer(uint32 ssrc, void* renderer)
|
|
{
|
|
int ret;
|
|
ret = engine_->video_engine()->render()->AddRenderer(
|
|
video_channel_,
|
|
kVideoI420,
|
|
static_cast<ExternalRenderer*>(renderer));
|
|
if (ret !=0 )
|
|
return false;
|
|
ret = engine_->video_engine()->render()->StartRender(video_channel_);
|
|
if (ret !=0 )
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool RtcVideoMediaChannel::GetStats(cricket::VideoMediaInfo* info) {
|
|
cricket::VideoSenderInfo sinfo;
|
|
memset(&sinfo, 0, sizeof(sinfo));
|
|
|
|
unsigned int ssrc;
|
|
if (engine_->video_engine()->rtp()->GetLocalSSRC(video_channel_,
|
|
ssrc) != 0) {
|
|
LOG(LS_ERROR) << "ViE GetLocalSSRC failed";
|
|
return false;
|
|
}
|
|
sinfo.ssrc = ssrc;
|
|
|
|
unsigned int cumulative_lost, extended_max, jitter;
|
|
int rtt_ms;
|
|
unsigned short fraction_lost;
|
|
|
|
if (engine_->video_engine()->rtp()->GetSentRTCPStatistics(video_channel_,
|
|
fraction_lost, cumulative_lost, extended_max, jitter, rtt_ms) != 0) {
|
|
LOG(LS_ERROR) << "ViE GetLocalSSRC failed";
|
|
return false;
|
|
}
|
|
|
|
sinfo.fraction_lost = fraction_lost;
|
|
sinfo.rtt_ms = rtt_ms;
|
|
|
|
unsigned int bytes_sent, packets_sent, bytes_recv, packets_recv;
|
|
if (engine_->video_engine()->rtp()->GetRTPStatistics(video_channel_,
|
|
bytes_sent, packets_sent, bytes_recv, packets_recv) != 0) {
|
|
LOG(LS_ERROR) << "ViE GetRTPStatistics";
|
|
return false;
|
|
}
|
|
sinfo.packets_sent = packets_sent;
|
|
sinfo.bytes_sent = bytes_sent;
|
|
sinfo.packets_lost = -1;
|
|
sinfo.packets_cached = -1;
|
|
|
|
info->senders.push_back(sinfo);
|
|
|
|
//build receiver info.
|
|
// reusing the above local variables
|
|
cricket::VideoReceiverInfo rinfo;
|
|
memset(&rinfo, 0, sizeof(rinfo));
|
|
if (engine_->video_engine()->rtp()->GetReceivedRTCPStatistics(video_channel_,
|
|
fraction_lost, cumulative_lost, extended_max, jitter, rtt_ms) != 0) {
|
|
LOG(LS_ERROR) << "ViE GetReceivedRTPStatistics Failed";
|
|
return false;
|
|
}
|
|
rinfo.bytes_rcvd = bytes_recv;
|
|
rinfo.packets_rcvd = packets_recv;
|
|
rinfo.fraction_lost = fraction_lost;
|
|
|
|
if (engine_->video_engine()->rtp()->GetRemoteSSRC(video_channel_,
|
|
ssrc) != 0) {
|
|
return false;
|
|
}
|
|
rinfo.ssrc = ssrc;
|
|
|
|
//Get codec for wxh
|
|
info->receivers.push_back(rinfo);
|
|
return true;
|
|
}
|
|
|
|
bool RtcVideoMediaChannel::SendIntraFrame() {
|
|
bool ret = true;
|
|
if (engine()->video_engine()->codec()->SendKeyFrame(video_channel_) != 0) {
|
|
LOG(LS_ERROR) << "ViE SendKeyFrame failed";
|
|
ret = false;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool RtcVideoMediaChannel::RequestIntraFrame() {
|
|
//There is no API exposed to application to request a key frame
|
|
// ViE does this internally when there are errors from decoder
|
|
return true;
|
|
}
|
|
|
|
void RtcVideoMediaChannel::OnPacketReceived(talk_base::Buffer* packet) {
|
|
engine()->video_engine()->network()->ReceivedRTPPacket(video_channel_,
|
|
packet->data(),
|
|
packet->length());
|
|
|
|
}
|
|
|
|
void RtcVideoMediaChannel::OnRtcpReceived(talk_base::Buffer* packet) {
|
|
engine_->video_engine()->network()->ReceivedRTCPPacket(video_channel_,
|
|
packet->data(),
|
|
packet->length());
|
|
|
|
}
|
|
|
|
void RtcVideoMediaChannel::SetSendSsrc(uint32 id) {
|
|
if (!sending_){
|
|
if (engine()->video_engine()->rtp()->SetLocalSSRC(video_channel_, id) != 0) {
|
|
LOG(LS_ERROR) << "ViE SetLocalSSRC failed";
|
|
}
|
|
} else {
|
|
LOG(LS_ERROR) << "Channel already in send state";
|
|
}
|
|
}
|
|
|
|
bool RtcVideoMediaChannel::SetRtcpCName(const std::string& cname) {
|
|
if (engine()->video_engine()->rtp()->SetRTCPCName(video_channel_,
|
|
cname.c_str()) != 0) {
|
|
LOG(LS_ERROR) << "ViE SetRTCPCName failed";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool RtcVideoMediaChannel::Mute(bool on) {
|
|
// stop send??
|
|
return false;
|
|
}
|
|
|
|
bool RtcVideoMediaChannel::SetSendBandwidth(bool autobw, int bps) {
|
|
LOG(LS_VERBOSE) << "RtcVideoMediaChanne::SetSendBandwidth";
|
|
|
|
VideoCodec current = send_codec_;
|
|
send_codec_.startBitrate = bps;
|
|
|
|
if (engine()->video_engine()->codec()->SetSendCodec(video_channel_,
|
|
send_codec_) != 0) {
|
|
LOG(LS_ERROR) << "ViE SetSendCodec failed";
|
|
if (engine()->video_engine()->codec()->SetSendCodec(video_channel_,
|
|
current) != 0) {
|
|
// should call be ended in this case?
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool RtcVideoMediaChannel::SetOptions(int options) {
|
|
return true;
|
|
}
|
|
|
|
void RtcVideoMediaChannel::EnableRtcp() {
|
|
engine()->video_engine()->rtp()->SetRTCPStatus(
|
|
video_channel_, kRtcpCompound_RFC4585);
|
|
}
|
|
|
|
void RtcVideoMediaChannel::EnablePLI() {
|
|
engine_->video_engine()->rtp()->SetKeyFrameRequestMethod(
|
|
video_channel_, kViEKeyFrameRequestPliRtcp);
|
|
}
|
|
|
|
void RtcVideoMediaChannel::EnableTMMBR() {
|
|
engine_->video_engine()->rtp()->SetTMMBRStatus(video_channel_, true);
|
|
}
|
|
|
|
int RtcVideoMediaChannel::SendPacket(int channel, const void* data, int len) {
|
|
if (!network_interface_) {
|
|
return -1;
|
|
}
|
|
talk_base::Buffer packet(data, len, cricket::kMaxRtpPacketLen);
|
|
return network_interface_->SendPacket(&packet) ? len : -1;
|
|
}
|
|
|
|
int RtcVideoMediaChannel::SendRTCPPacket(int channel,
|
|
const void* data,
|
|
int len) {
|
|
if (!network_interface_) {
|
|
return -1;
|
|
}
|
|
talk_base::Buffer packet(data, len, cricket::kMaxRtpPacketLen);
|
|
return network_interface_->SendRtcp(&packet) ? len : -1;
|
|
}
|
|
|
|
} // namespace webrtc
|