blob: f2827db026c912650e8e42cbf445e01f90f9b5f4 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2004 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#ifdef HAVE_WEBRTC_VIDEO
29#include "talk/media/webrtc/webrtcvideoengine.h"
30
31#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34
35#include <math.h>
36#include <set>
37
38#include "talk/base/basictypes.h"
39#include "talk/base/buffer.h"
40#include "talk/base/byteorder.h"
41#include "talk/base/common.h"
42#include "talk/base/cpumonitor.h"
43#include "talk/base/logging.h"
44#include "talk/base/stringutils.h"
45#include "talk/base/thread.h"
46#include "talk/base/timeutils.h"
47#include "talk/media/base/constants.h"
48#include "talk/media/base/rtputils.h"
49#include "talk/media/base/streamparams.h"
50#include "talk/media/base/videoadapter.h"
51#include "talk/media/base/videocapturer.h"
52#include "talk/media/base/videorenderer.h"
53#include "talk/media/devices/filevideocapturer.h"
wu@webrtc.org9dba5252013-08-05 20:36:57 +000054#include "talk/media/webrtc/webrtcpassthroughrender.h"
55#include "talk/media/webrtc/webrtctexturevideoframe.h"
56#include "talk/media/webrtc/webrtcvideocapturer.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000057#include "talk/media/webrtc/webrtcvideodecoderfactory.h"
58#include "talk/media/webrtc/webrtcvideoencoderfactory.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000059#include "talk/media/webrtc/webrtcvideoframe.h"
60#include "talk/media/webrtc/webrtcvie.h"
61#include "talk/media/webrtc/webrtcvoe.h"
62#include "talk/media/webrtc/webrtcvoiceengine.h"
63
64#if !defined(LIBPEERCONNECTION_LIB)
65#ifndef HAVE_WEBRTC_VIDEO
66#error Need webrtc video
67#endif
68#include "talk/media/webrtc/webrtcmediaengine.h"
69
70WRME_EXPORT
71cricket::MediaEngineInterface* CreateWebRtcMediaEngine(
72 webrtc::AudioDeviceModule* adm, webrtc::AudioDeviceModule* adm_sc,
73 cricket::WebRtcVideoEncoderFactory* encoder_factory,
74 cricket::WebRtcVideoDecoderFactory* decoder_factory) {
75 return new cricket::WebRtcMediaEngine(adm, adm_sc, encoder_factory,
76 decoder_factory);
77}
78
79WRME_EXPORT
80void DestroyWebRtcMediaEngine(cricket::MediaEngineInterface* media_engine) {
81 delete static_cast<cricket::WebRtcMediaEngine*>(media_engine);
82}
83#endif
84
85
86namespace cricket {
87
88
89static const int kDefaultLogSeverity = talk_base::LS_WARNING;
90
91static const int kMinVideoBitrate = 50;
92static const int kStartVideoBitrate = 300;
93static const int kMaxVideoBitrate = 2000;
94static const int kDefaultConferenceModeMaxVideoBitrate = 500;
95
wu@webrtc.orgcecfd182013-10-30 05:18:12 +000096// Controlled by exp, try a super low minimum bitrate for poor connections.
97static const int kLowerMinBitrate = 30;
98
henrike@webrtc.org28e20752013-07-10 00:45:36 +000099static const int kVideoMtu = 1200;
100
101static const int kVideoRtpBufferSize = 65536;
102
103static const char kVp8PayloadName[] = "VP8";
104static const char kRedPayloadName[] = "red";
105static const char kFecPayloadName[] = "ulpfec";
106
107static const int kDefaultNumberOfTemporalLayers = 1; // 1:1
108
109static const int kTimestampDeltaInSecondsForWarning = 2;
110
111static const int kMaxExternalVideoCodecs = 8;
112static const int kExternalVideoPayloadTypeBase = 120;
113
114// Static allocation of payload type values for external video codec.
115static int GetExternalVideoPayloadType(int index) {
116 ASSERT(index >= 0 && index < kMaxExternalVideoCodecs);
117 return kExternalVideoPayloadTypeBase + index;
118}
119
120static void LogMultiline(talk_base::LoggingSeverity sev, char* text) {
121 const char* delim = "\r\n";
122 // TODO(fbarchard): Fix strtok lint warning.
123 for (char* tok = strtok(text, delim); tok; tok = strtok(NULL, delim)) {
124 LOG_V(sev) << tok;
125 }
126}
127
128// Severity is an integer because it comes is assumed to be from command line.
129static int SeverityToFilter(int severity) {
130 int filter = webrtc::kTraceNone;
131 switch (severity) {
132 case talk_base::LS_VERBOSE:
133 filter |= webrtc::kTraceAll;
134 case talk_base::LS_INFO:
135 filter |= (webrtc::kTraceStateInfo | webrtc::kTraceInfo);
136 case talk_base::LS_WARNING:
137 filter |= (webrtc::kTraceTerseInfo | webrtc::kTraceWarning);
138 case talk_base::LS_ERROR:
139 filter |= (webrtc::kTraceError | webrtc::kTraceCritical);
140 }
141 return filter;
142}
143
144static const int kCpuMonitorPeriodMs = 2000; // 2 seconds.
145
146static const bool kNotSending = false;
147
148// Extension header for RTP timestamp offset, see RFC 5450 for details:
149// http://tools.ietf.org/html/rfc5450
150static const char kRtpTimestampOffsetHeaderExtension[] =
151 "urn:ietf:params:rtp-hdrext:toffset";
152static const int kRtpTimeOffsetExtensionId = 2;
153
154// Extension header for absolute send time, see url for details:
155// http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
156static const char kRtpAbsoluteSendTimeHeaderExtension[] =
157 "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time";
158static const int kRtpAbsoluteSendTimeExtensionId = 3;
159
160static bool IsNackEnabled(const VideoCodec& codec) {
161 return codec.HasFeedbackParam(FeedbackParam(kRtcpFbParamNack,
162 kParamValueEmpty));
163}
164
165// Returns true if Receiver Estimated Max Bitrate is enabled.
166static bool IsRembEnabled(const VideoCodec& codec) {
167 return codec.HasFeedbackParam(FeedbackParam(kRtcpFbParamRemb,
168 kParamValueEmpty));
169}
170
171struct FlushBlackFrameData : public talk_base::MessageData {
172 FlushBlackFrameData(uint32 s, int64 t) : ssrc(s), timestamp(t) {
173 }
174 uint32 ssrc;
175 int64 timestamp;
176};
177
178class WebRtcRenderAdapter : public webrtc::ExternalRenderer {
179 public:
180 explicit WebRtcRenderAdapter(VideoRenderer* renderer)
181 : renderer_(renderer), width_(0), height_(0), watermark_enabled_(false) {
182 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000183
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000184 virtual ~WebRtcRenderAdapter() {
185 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000186
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000187 void set_watermark_enabled(bool enable) {
188 talk_base::CritScope cs(&crit_);
189 watermark_enabled_ = enable;
190 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000191
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000192 void SetRenderer(VideoRenderer* renderer) {
193 talk_base::CritScope cs(&crit_);
194 renderer_ = renderer;
195 // FrameSizeChange may have already been called when renderer was not set.
196 // If so we should call SetSize here.
197 // TODO(ronghuawu): Add unit test for this case. Didn't do it now
198 // because the WebRtcRenderAdapter is currently hiding in cc file. No
199 // good way to get access to it from the unit test.
200 if (width_ > 0 && height_ > 0 && renderer_ != NULL) {
201 if (!renderer_->SetSize(width_, height_, 0)) {
202 LOG(LS_ERROR)
203 << "WebRtcRenderAdapter SetRenderer failed to SetSize to: "
204 << width_ << "x" << height_;
205 }
206 }
207 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000208
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000209 // Implementation of webrtc::ExternalRenderer.
210 virtual int FrameSizeChange(unsigned int width, unsigned int height,
211 unsigned int /*number_of_streams*/) {
212 talk_base::CritScope cs(&crit_);
213 width_ = width;
214 height_ = height;
215 LOG(LS_INFO) << "WebRtcRenderAdapter frame size changed to: "
216 << width << "x" << height;
217 if (renderer_ == NULL) {
218 LOG(LS_VERBOSE) << "WebRtcRenderAdapter the renderer has not been set. "
219 << "SetSize will be called later in SetRenderer.";
220 return 0;
221 }
222 return renderer_->SetSize(width_, height_, 0) ? 0 : -1;
223 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000224
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000225 virtual int DeliverFrame(unsigned char* buffer, int buffer_size,
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000226 uint32_t time_stamp, int64_t render_time
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000227 , void* handle
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000228 ) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000229 talk_base::CritScope cs(&crit_);
230 frame_rate_tracker_.Update(1);
231 if (renderer_ == NULL) {
232 return 0;
233 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000234 // Convert 90K rtp timestamp to ns timestamp.
235 int64 rtp_time_stamp_in_ns = (time_stamp / 90) *
236 talk_base::kNumNanosecsPerMillisec;
237 // Convert milisecond render time to ns timestamp.
238 int64 render_time_stamp_in_ns = render_time *
239 talk_base::kNumNanosecsPerMillisec;
240 // Send the rtp timestamp to renderer as the VideoFrame timestamp.
241 // and the render timestamp as the VideoFrame elapsed_time.
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000242 if (handle == NULL) {
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000243 return DeliverBufferFrame(buffer, buffer_size, render_time_stamp_in_ns,
244 rtp_time_stamp_in_ns);
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000245 } else {
246 return DeliverTextureFrame(handle, render_time_stamp_in_ns,
247 rtp_time_stamp_in_ns);
248 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000249 }
250
251 virtual bool IsTextureSupported() { return true; }
252
253 int DeliverBufferFrame(unsigned char* buffer, int buffer_size,
254 int64 elapsed_time, int64 time_stamp) {
255 WebRtcVideoFrame video_frame;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000256 video_frame.Attach(buffer, buffer_size, width_, height_,
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000257 1, 1, elapsed_time, time_stamp, 0);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000258
259
260 // Sanity check on decoded frame size.
261 if (buffer_size != static_cast<int>(VideoFrame::SizeOf(width_, height_))) {
262 LOG(LS_WARNING) << "WebRtcRenderAdapter received a strange frame size: "
263 << buffer_size;
264 }
265
266 int ret = renderer_->RenderFrame(&video_frame) ? 0 : -1;
267 uint8* buffer_temp;
268 size_t buffer_size_temp;
269 video_frame.Detach(&buffer_temp, &buffer_size_temp);
270 return ret;
271 }
272
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000273 int DeliverTextureFrame(void* handle, int64 elapsed_time, int64 time_stamp) {
274 WebRtcTextureVideoFrame video_frame(
275 static_cast<webrtc::NativeHandle*>(handle), width_, height_,
276 elapsed_time, time_stamp);
277 return renderer_->RenderFrame(&video_frame);
278 }
279
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000280 unsigned int width() {
281 talk_base::CritScope cs(&crit_);
282 return width_;
283 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000284
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000285 unsigned int height() {
286 talk_base::CritScope cs(&crit_);
287 return height_;
288 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000289
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000290 int framerate() {
291 talk_base::CritScope cs(&crit_);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000292 return static_cast<int>(frame_rate_tracker_.units_second());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000293 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +0000294
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000295 VideoRenderer* renderer() {
296 talk_base::CritScope cs(&crit_);
297 return renderer_;
298 }
299
300 private:
301 talk_base::CriticalSection crit_;
302 VideoRenderer* renderer_;
303 unsigned int width_;
304 unsigned int height_;
305 talk_base::RateTracker frame_rate_tracker_;
306 bool watermark_enabled_;
307};
308
309class WebRtcDecoderObserver : public webrtc::ViEDecoderObserver {
310 public:
311 explicit WebRtcDecoderObserver(int video_channel)
312 : video_channel_(video_channel),
313 framerate_(0),
314 bitrate_(0),
wu@webrtc.org97077a32013-10-25 21:18:33 +0000315 decode_ms_(0),
316 max_decode_ms_(0),
317 current_delay_ms_(0),
318 target_delay_ms_(0),
319 jitter_buffer_ms_(0),
320 min_playout_delay_ms_(0),
321 render_delay_ms_(0),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000322 firs_requested_(0) {
323 }
324
325 // virtual functions from VieDecoderObserver.
326 virtual void IncomingCodecChanged(const int videoChannel,
327 const webrtc::VideoCodec& videoCodec) {}
328 virtual void IncomingRate(const int videoChannel,
329 const unsigned int framerate,
330 const unsigned int bitrate) {
wu@webrtc.org78187522013-10-07 23:32:02 +0000331 talk_base::CritScope cs(&crit_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000332 ASSERT(video_channel_ == videoChannel);
333 framerate_ = framerate;
334 bitrate_ = bitrate;
335 }
wu@webrtc.org97077a32013-10-25 21:18:33 +0000336
337 virtual void DecoderTiming(int decode_ms,
338 int max_decode_ms,
339 int current_delay_ms,
340 int target_delay_ms,
341 int jitter_buffer_ms,
342 int min_playout_delay_ms,
343 int render_delay_ms) {
344 talk_base::CritScope cs(&crit_);
345 decode_ms_ = decode_ms;
346 max_decode_ms_ = max_decode_ms;
347 current_delay_ms_ = current_delay_ms;
348 target_delay_ms_ = target_delay_ms;
349 jitter_buffer_ms_ = jitter_buffer_ms;
350 min_playout_delay_ms_ = min_playout_delay_ms;
351 render_delay_ms_ = render_delay_ms;
352 }
353
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000354 virtual void RequestNewKeyFrame(const int videoChannel) {
wu@webrtc.org78187522013-10-07 23:32:02 +0000355 talk_base::CritScope cs(&crit_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000356 ASSERT(video_channel_ == videoChannel);
357 ++firs_requested_;
358 }
359
wu@webrtc.org97077a32013-10-25 21:18:33 +0000360 // Populate |rinfo| based on previously-set data in |*this|.
361 void ExportTo(VideoReceiverInfo* rinfo) {
wu@webrtc.org78187522013-10-07 23:32:02 +0000362 talk_base::CritScope cs(&crit_);
wu@webrtc.org97077a32013-10-25 21:18:33 +0000363 rinfo->firs_sent = firs_requested_;
364 rinfo->framerate_rcvd = framerate_;
365 rinfo->decode_ms = decode_ms_;
366 rinfo->max_decode_ms = max_decode_ms_;
367 rinfo->current_delay_ms = current_delay_ms_;
368 rinfo->target_delay_ms = target_delay_ms_;
369 rinfo->jitter_buffer_ms = jitter_buffer_ms_;
370 rinfo->min_playout_delay_ms = min_playout_delay_ms_;
371 rinfo->render_delay_ms = render_delay_ms_;
wu@webrtc.org78187522013-10-07 23:32:02 +0000372 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000373
374 private:
wu@webrtc.org78187522013-10-07 23:32:02 +0000375 mutable talk_base::CriticalSection crit_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000376 int video_channel_;
377 int framerate_;
378 int bitrate_;
wu@webrtc.org97077a32013-10-25 21:18:33 +0000379 int decode_ms_;
380 int max_decode_ms_;
381 int current_delay_ms_;
382 int target_delay_ms_;
383 int jitter_buffer_ms_;
384 int min_playout_delay_ms_;
385 int render_delay_ms_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000386 int firs_requested_;
387};
388
389class WebRtcEncoderObserver : public webrtc::ViEEncoderObserver {
390 public:
391 explicit WebRtcEncoderObserver(int video_channel)
392 : video_channel_(video_channel),
393 framerate_(0),
394 bitrate_(0) {
395 }
396
397 // virtual functions from VieEncoderObserver.
398 virtual void OutgoingRate(const int videoChannel,
399 const unsigned int framerate,
400 const unsigned int bitrate) {
wu@webrtc.org78187522013-10-07 23:32:02 +0000401 talk_base::CritScope cs(&crit_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000402 ASSERT(video_channel_ == videoChannel);
403 framerate_ = framerate;
404 bitrate_ = bitrate;
405 }
406
wu@webrtc.org78187522013-10-07 23:32:02 +0000407 int framerate() const {
408 talk_base::CritScope cs(&crit_);
409 return framerate_;
410 }
411 int bitrate() const {
412 talk_base::CritScope cs(&crit_);
413 return bitrate_;
414 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000415
416 private:
wu@webrtc.org78187522013-10-07 23:32:02 +0000417 mutable talk_base::CriticalSection crit_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000418 int video_channel_;
419 int framerate_;
420 int bitrate_;
421};
422
423class WebRtcLocalStreamInfo {
424 public:
425 WebRtcLocalStreamInfo()
426 : width_(0), height_(0), elapsed_time_(-1), time_stamp_(-1) {}
427 size_t width() const {
428 talk_base::CritScope cs(&crit_);
429 return width_;
430 }
431 size_t height() const {
432 talk_base::CritScope cs(&crit_);
433 return height_;
434 }
435 int64 elapsed_time() const {
436 talk_base::CritScope cs(&crit_);
437 return elapsed_time_;
438 }
439 int64 time_stamp() const {
440 talk_base::CritScope cs(&crit_);
441 return time_stamp_;
442 }
443 int framerate() {
444 talk_base::CritScope cs(&crit_);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000445 return static_cast<int>(rate_tracker_.units_second());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000446 }
447 void GetLastFrameInfo(
448 size_t* width, size_t* height, int64* elapsed_time) const {
449 talk_base::CritScope cs(&crit_);
450 *width = width_;
451 *height = height_;
452 *elapsed_time = elapsed_time_;
453 }
454
455 void UpdateFrame(const VideoFrame* frame) {
456 talk_base::CritScope cs(&crit_);
457
458 width_ = frame->GetWidth();
459 height_ = frame->GetHeight();
460 elapsed_time_ = frame->GetElapsedTime();
461 time_stamp_ = frame->GetTimeStamp();
462
463 rate_tracker_.Update(1);
464 }
465
466 private:
467 mutable talk_base::CriticalSection crit_;
468 size_t width_;
469 size_t height_;
470 int64 elapsed_time_;
471 int64 time_stamp_;
472 talk_base::RateTracker rate_tracker_;
473
474 DISALLOW_COPY_AND_ASSIGN(WebRtcLocalStreamInfo);
475};
476
477// WebRtcVideoChannelRecvInfo is a container class with members such as renderer
478// and a decoder observer that is used by receive channels.
479// It must exist as long as the receive channel is connected to renderer or a
480// decoder observer in this class and methods in the class should only be called
481// from the worker thread.
482class WebRtcVideoChannelRecvInfo {
483 public:
484 typedef std::map<int, webrtc::VideoDecoder*> DecoderMap; // key: payload type
485 explicit WebRtcVideoChannelRecvInfo(int channel_id)
486 : channel_id_(channel_id),
487 render_adapter_(NULL),
488 decoder_observer_(channel_id) {
489 }
490 int channel_id() { return channel_id_; }
491 void SetRenderer(VideoRenderer* renderer) {
492 render_adapter_.SetRenderer(renderer);
493 }
494 WebRtcRenderAdapter* render_adapter() { return &render_adapter_; }
495 WebRtcDecoderObserver* decoder_observer() { return &decoder_observer_; }
496 void RegisterDecoder(int pl_type, webrtc::VideoDecoder* decoder) {
497 ASSERT(!IsDecoderRegistered(pl_type));
498 registered_decoders_[pl_type] = decoder;
499 }
500 bool IsDecoderRegistered(int pl_type) {
501 return registered_decoders_.count(pl_type) != 0;
502 }
503 const DecoderMap& registered_decoders() {
504 return registered_decoders_;
505 }
506 void ClearRegisteredDecoders() {
507 registered_decoders_.clear();
508 }
509
510 private:
511 int channel_id_; // Webrtc video channel number.
512 // Renderer for this channel.
513 WebRtcRenderAdapter render_adapter_;
514 WebRtcDecoderObserver decoder_observer_;
515 DecoderMap registered_decoders_;
516};
517
wu@webrtc.orgcadf9042013-08-30 21:24:16 +0000518class WebRtcOveruseObserver : public webrtc::CpuOveruseObserver {
519 public:
520 explicit WebRtcOveruseObserver(CoordinatedVideoAdapter* video_adapter)
521 : video_adapter_(video_adapter),
522 enabled_(false) {
523 }
524
525 // TODO(mflodman): Consider sending resolution as part of event, to let
526 // adapter know what resolution the request is based on. Helps eliminate stale
527 // data, race conditions.
528 virtual void OveruseDetected() OVERRIDE {
529 talk_base::CritScope cs(&crit_);
530 if (!enabled_) {
531 return;
532 }
533
534 video_adapter_->OnCpuResolutionRequest(CoordinatedVideoAdapter::DOWNGRADE);
535 }
536
537 virtual void NormalUsage() OVERRIDE {
538 talk_base::CritScope cs(&crit_);
539 if (!enabled_) {
540 return;
541 }
542
543 video_adapter_->OnCpuResolutionRequest(CoordinatedVideoAdapter::UPGRADE);
544 }
545
546 void Enable(bool enable) {
547 talk_base::CritScope cs(&crit_);
548 enabled_ = enable;
549 }
550
551 private:
552 CoordinatedVideoAdapter* video_adapter_;
553 bool enabled_;
554 talk_base::CriticalSection crit_;
555};
556
wu@webrtc.orgcadf9042013-08-30 21:24:16 +0000557
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000558class WebRtcVideoChannelSendInfo : public sigslot::has_slots<> {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000559 public:
560 typedef std::map<int, webrtc::VideoEncoder*> EncoderMap; // key: payload type
561 WebRtcVideoChannelSendInfo(int channel_id, int capture_id,
562 webrtc::ViEExternalCapture* external_capture,
563 talk_base::CpuMonitor* cpu_monitor)
564 : channel_id_(channel_id),
565 capture_id_(capture_id),
566 sending_(false),
567 muted_(false),
568 video_capturer_(NULL),
569 encoder_observer_(channel_id),
570 external_capture_(external_capture),
571 capturer_updated_(false),
572 interval_(0),
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000573 video_adapter_(new CoordinatedVideoAdapter),
574 cpu_monitor_(cpu_monitor) {
wu@webrtc.orgcadf9042013-08-30 21:24:16 +0000575 overuse_observer_.reset(new WebRtcOveruseObserver(video_adapter_.get()));
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000576 SignalCpuAdaptationUnable.repeat(video_adapter_->SignalCpuAdaptationUnable);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000577 if (cpu_monitor) {
578 cpu_monitor->SignalUpdate.connect(
579 video_adapter_.get(), &CoordinatedVideoAdapter::OnCpuLoadUpdated);
580 }
581 }
582
583 int channel_id() const { return channel_id_; }
584 int capture_id() const { return capture_id_; }
585 void set_sending(bool sending) { sending_ = sending; }
586 bool sending() const { return sending_; }
587 void set_muted(bool on) {
588 // TODO(asapersson): add support.
589 // video_adapter_->SetBlackOutput(on);
590 muted_ = on;
591 }
592 bool muted() {return muted_; }
593
594 WebRtcEncoderObserver* encoder_observer() { return &encoder_observer_; }
595 webrtc::ViEExternalCapture* external_capture() { return external_capture_; }
596 const VideoFormat& video_format() const {
597 return video_format_;
598 }
599 void set_video_format(const VideoFormat& video_format) {
600 video_format_ = video_format;
601 if (video_format_ != cricket::VideoFormat()) {
602 interval_ = video_format_.interval;
603 }
604 video_adapter_->OnOutputFormatRequest(video_format_);
605 }
606 void set_interval(int64 interval) {
607 if (video_format() == cricket::VideoFormat()) {
608 interval_ = interval;
609 }
610 }
611 int64 interval() { return interval_; }
612
613 void InitializeAdapterOutputFormat(const webrtc::VideoCodec& codec) {
614 VideoFormat format(codec.width, codec.height,
615 VideoFormat::FpsToInterval(codec.maxFramerate),
616 FOURCC_I420);
617 if (video_adapter_->output_format().IsSize0x0()) {
618 video_adapter_->SetOutputFormat(format);
619 }
620 }
621
622 bool AdaptFrame(const VideoFrame* in_frame, const VideoFrame** out_frame) {
623 *out_frame = NULL;
624 return video_adapter_->AdaptFrame(in_frame, out_frame);
625 }
626 int CurrentAdaptReason() const {
627 return video_adapter_->adapt_reason();
628 }
wu@webrtc.orgcadf9042013-08-30 21:24:16 +0000629 webrtc::CpuOveruseObserver* overuse_observer() {
630 return overuse_observer_.get();
631 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000632
633 StreamParams* stream_params() { return stream_params_.get(); }
634 void set_stream_params(const StreamParams& sp) {
635 stream_params_.reset(new StreamParams(sp));
636 }
637 void ClearStreamParams() { stream_params_.reset(); }
638 bool has_ssrc(uint32 local_ssrc) const {
639 return !stream_params_ ? false :
640 stream_params_->has_ssrc(local_ssrc);
641 }
642 WebRtcLocalStreamInfo* local_stream_info() {
643 return &local_stream_info_;
644 }
645 VideoCapturer* video_capturer() {
646 return video_capturer_;
647 }
648 void set_video_capturer(VideoCapturer* video_capturer) {
649 if (video_capturer == video_capturer_) {
650 return;
651 }
652 capturer_updated_ = true;
653 video_capturer_ = video_capturer;
654 if (video_capturer && !video_capturer->IsScreencast()) {
655 const VideoFormat* capture_format = video_capturer->GetCaptureFormat();
656 if (capture_format) {
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000657 // TODO(thorcarpenter): This is broken. Video capturer doesn't have
658 // a capture format until the capturer is started. So, if
659 // the capturer is started immediately after calling set_video_capturer
660 // video adapter may not have the input format set, the interval may
661 // be zero, and all frames may be dropped.
662 // Consider fixing this by having video_adapter keep a pointer to the
663 // video capturer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000664 video_adapter_->SetInputFormat(*capture_format);
665 }
666 }
667 }
668
669 void ApplyCpuOptions(const VideoOptions& options) {
wu@webrtc.orgcadf9042013-08-30 21:24:16 +0000670 bool cpu_adapt, cpu_smoothing, adapt_third;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000671 float low, med, high;
672 if (options.adapt_input_to_cpu_usage.Get(&cpu_adapt)) {
673 video_adapter_->set_cpu_adaptation(cpu_adapt);
674 }
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000675 if (options.adapt_cpu_with_smoothing.Get(&cpu_smoothing)) {
676 video_adapter_->set_cpu_smoothing(cpu_smoothing);
677 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000678 if (options.process_adaptation_threshhold.Get(&med)) {
679 video_adapter_->set_process_threshold(med);
680 }
681 if (options.system_low_adaptation_threshhold.Get(&low)) {
682 video_adapter_->set_low_system_threshold(low);
683 }
684 if (options.system_high_adaptation_threshhold.Get(&high)) {
685 video_adapter_->set_high_system_threshold(high);
686 }
wu@webrtc.orgcadf9042013-08-30 21:24:16 +0000687 if (options.video_adapt_third.Get(&adapt_third)) {
688 video_adapter_->set_scale_third(adapt_third);
689 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000690 }
wu@webrtc.orgcadf9042013-08-30 21:24:16 +0000691
692 void SetCpuOveruseDetection(bool enable) {
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000693 if (cpu_monitor_ && enable) {
694 cpu_monitor_->SignalUpdate.disconnect(video_adapter_.get());
695 }
wu@webrtc.orgcadf9042013-08-30 21:24:16 +0000696 overuse_observer_->Enable(enable);
697 video_adapter_->set_cpu_adaptation(enable);
wu@webrtc.orgcadf9042013-08-30 21:24:16 +0000698 }
699
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000700 void ProcessFrame(const VideoFrame& original_frame, bool mute,
701 VideoFrame** processed_frame) {
702 if (!mute) {
703 *processed_frame = original_frame.Copy();
704 } else {
705 WebRtcVideoFrame* black_frame = new WebRtcVideoFrame();
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000706 black_frame->InitToBlack(static_cast<int>(original_frame.GetWidth()),
707 static_cast<int>(original_frame.GetHeight()),
708 1, 1,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000709 original_frame.GetElapsedTime(),
710 original_frame.GetTimeStamp());
711 *processed_frame = black_frame;
712 }
713 local_stream_info_.UpdateFrame(*processed_frame);
714 }
715 void RegisterEncoder(int pl_type, webrtc::VideoEncoder* encoder) {
716 ASSERT(!IsEncoderRegistered(pl_type));
717 registered_encoders_[pl_type] = encoder;
718 }
719 bool IsEncoderRegistered(int pl_type) {
720 return registered_encoders_.count(pl_type) != 0;
721 }
722 const EncoderMap& registered_encoders() {
723 return registered_encoders_;
724 }
725 void ClearRegisteredEncoders() {
726 registered_encoders_.clear();
727 }
728
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000729 sigslot::repeater0<> SignalCpuAdaptationUnable;
730
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000731 private:
732 int channel_id_;
733 int capture_id_;
734 bool sending_;
735 bool muted_;
736 VideoCapturer* video_capturer_;
737 WebRtcEncoderObserver encoder_observer_;
738 webrtc::ViEExternalCapture* external_capture_;
739 EncoderMap registered_encoders_;
740
741 VideoFormat video_format_;
742
743 talk_base::scoped_ptr<StreamParams> stream_params_;
744
745 WebRtcLocalStreamInfo local_stream_info_;
746
747 bool capturer_updated_;
748
749 int64 interval_;
750
751 talk_base::scoped_ptr<CoordinatedVideoAdapter> video_adapter_;
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000752 talk_base::CpuMonitor* cpu_monitor_;
wu@webrtc.orgcadf9042013-08-30 21:24:16 +0000753 talk_base::scoped_ptr<WebRtcOveruseObserver> overuse_observer_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000754};
755
756const WebRtcVideoEngine::VideoCodecPref
757 WebRtcVideoEngine::kVideoCodecPrefs[] = {
758 {kVp8PayloadName, 100, 0},
759 {kRedPayloadName, 116, 1},
760 {kFecPayloadName, 117, 2},
761};
762
763// The formats are sorted by the descending order of width. We use the order to
764// find the next format for CPU and bandwidth adaptation.
765const VideoFormatPod WebRtcVideoEngine::kVideoFormats[] = {
766 {1280, 800, FPS_TO_INTERVAL(30), FOURCC_ANY},
767 {1280, 720, FPS_TO_INTERVAL(30), FOURCC_ANY},
768 {960, 600, FPS_TO_INTERVAL(30), FOURCC_ANY},
769 {960, 540, FPS_TO_INTERVAL(30), FOURCC_ANY},
770 {640, 400, FPS_TO_INTERVAL(30), FOURCC_ANY},
771 {640, 360, FPS_TO_INTERVAL(30), FOURCC_ANY},
772 {640, 480, FPS_TO_INTERVAL(30), FOURCC_ANY},
773 {480, 300, FPS_TO_INTERVAL(30), FOURCC_ANY},
774 {480, 270, FPS_TO_INTERVAL(30), FOURCC_ANY},
775 {480, 360, FPS_TO_INTERVAL(30), FOURCC_ANY},
776 {320, 200, FPS_TO_INTERVAL(30), FOURCC_ANY},
777 {320, 180, FPS_TO_INTERVAL(30), FOURCC_ANY},
778 {320, 240, FPS_TO_INTERVAL(30), FOURCC_ANY},
779 {240, 150, FPS_TO_INTERVAL(30), FOURCC_ANY},
780 {240, 135, FPS_TO_INTERVAL(30), FOURCC_ANY},
781 {240, 180, FPS_TO_INTERVAL(30), FOURCC_ANY},
782 {160, 100, FPS_TO_INTERVAL(30), FOURCC_ANY},
783 {160, 90, FPS_TO_INTERVAL(30), FOURCC_ANY},
784 {160, 120, FPS_TO_INTERVAL(30), FOURCC_ANY},
785};
786
787const VideoFormatPod WebRtcVideoEngine::kDefaultVideoFormat =
788 {640, 400, FPS_TO_INTERVAL(30), FOURCC_ANY};
789
790static void UpdateVideoCodec(const cricket::VideoFormat& video_format,
791 webrtc::VideoCodec* target_codec) {
792 if ((target_codec == NULL) || (video_format == cricket::VideoFormat())) {
793 return;
794 }
795 target_codec->width = video_format.width;
796 target_codec->height = video_format.height;
797 target_codec->maxFramerate = cricket::VideoFormat::IntervalToFps(
798 video_format.interval);
799}
800
801WebRtcVideoEngine::WebRtcVideoEngine() {
802 Construct(new ViEWrapper(), new ViETraceWrapper(), NULL,
803 new talk_base::CpuMonitor(NULL));
804}
805
806WebRtcVideoEngine::WebRtcVideoEngine(WebRtcVoiceEngine* voice_engine,
807 ViEWrapper* vie_wrapper,
808 talk_base::CpuMonitor* cpu_monitor) {
809 Construct(vie_wrapper, new ViETraceWrapper(), voice_engine, cpu_monitor);
810}
811
812WebRtcVideoEngine::WebRtcVideoEngine(WebRtcVoiceEngine* voice_engine,
813 ViEWrapper* vie_wrapper,
814 ViETraceWrapper* tracing,
815 talk_base::CpuMonitor* cpu_monitor) {
816 Construct(vie_wrapper, tracing, voice_engine, cpu_monitor);
817}
818
819void WebRtcVideoEngine::Construct(ViEWrapper* vie_wrapper,
820 ViETraceWrapper* tracing,
821 WebRtcVoiceEngine* voice_engine,
822 talk_base::CpuMonitor* cpu_monitor) {
823 LOG(LS_INFO) << "WebRtcVideoEngine::WebRtcVideoEngine";
824 worker_thread_ = NULL;
825 vie_wrapper_.reset(vie_wrapper);
826 vie_wrapper_base_initialized_ = false;
827 tracing_.reset(tracing);
828 voice_engine_ = voice_engine;
829 initialized_ = false;
830 SetTraceFilter(SeverityToFilter(kDefaultLogSeverity));
831 render_module_.reset(new WebRtcPassthroughRender());
832 local_renderer_w_ = local_renderer_h_ = 0;
833 local_renderer_ = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000834 capture_started_ = false;
835 decoder_factory_ = NULL;
836 encoder_factory_ = NULL;
837 cpu_monitor_.reset(cpu_monitor);
838
839 SetTraceOptions("");
840 if (tracing_->SetTraceCallback(this) != 0) {
841 LOG_RTCERR1(SetTraceCallback, this);
842 }
843
844 // Set default quality levels for our supported codecs. We override them here
845 // if we know your cpu performance is low, and they can be updated explicitly
846 // by calling SetDefaultCodec. For example by a flute preference setting, or
847 // by the server with a jec in response to our reported system info.
848 VideoCodec max_codec(kVideoCodecPrefs[0].payload_type,
849 kVideoCodecPrefs[0].name,
850 kDefaultVideoFormat.width,
851 kDefaultVideoFormat.height,
852 VideoFormat::IntervalToFps(kDefaultVideoFormat.interval),
853 0);
854 if (!SetDefaultCodec(max_codec)) {
855 LOG(LS_ERROR) << "Failed to initialize list of supported codec types";
856 }
857
858
859 // Load our RTP Header extensions.
860 rtp_header_extensions_.push_back(
861 RtpHeaderExtension(kRtpTimestampOffsetHeaderExtension,
862 kRtpTimeOffsetExtensionId));
863 rtp_header_extensions_.push_back(
864 RtpHeaderExtension(kRtpAbsoluteSendTimeHeaderExtension,
865 kRtpAbsoluteSendTimeExtensionId));
866}
867
868WebRtcVideoEngine::~WebRtcVideoEngine() {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000869 LOG(LS_INFO) << "WebRtcVideoEngine::~WebRtcVideoEngine";
870 if (initialized_) {
871 Terminate();
872 }
873 if (encoder_factory_) {
874 encoder_factory_->RemoveObserver(this);
875 }
876 tracing_->SetTraceCallback(NULL);
877 // Test to see if the media processor was deregistered properly.
878 ASSERT(SignalMediaFrame.is_empty());
879}
880
881bool WebRtcVideoEngine::Init(talk_base::Thread* worker_thread) {
882 LOG(LS_INFO) << "WebRtcVideoEngine::Init";
883 worker_thread_ = worker_thread;
884 ASSERT(worker_thread_ != NULL);
885
886 cpu_monitor_->set_thread(worker_thread_);
887 if (!cpu_monitor_->Start(kCpuMonitorPeriodMs)) {
888 LOG(LS_ERROR) << "Failed to start CPU monitor.";
889 cpu_monitor_.reset();
890 }
891
892 bool result = InitVideoEngine();
893 if (result) {
894 LOG(LS_INFO) << "VideoEngine Init done";
895 } else {
896 LOG(LS_ERROR) << "VideoEngine Init failed, releasing";
897 Terminate();
898 }
899 return result;
900}
901
902bool WebRtcVideoEngine::InitVideoEngine() {
903 LOG(LS_INFO) << "WebRtcVideoEngine::InitVideoEngine";
904
905 // Init WebRTC VideoEngine.
906 if (!vie_wrapper_base_initialized_) {
907 if (vie_wrapper_->base()->Init() != 0) {
908 LOG_RTCERR0(Init);
909 return false;
910 }
911 vie_wrapper_base_initialized_ = true;
912 }
913
914 // Log the VoiceEngine version info.
915 char buffer[1024] = "";
916 if (vie_wrapper_->base()->GetVersion(buffer) != 0) {
917 LOG_RTCERR0(GetVersion);
918 return false;
919 }
920
921 LOG(LS_INFO) << "WebRtc VideoEngine Version:";
922 LogMultiline(talk_base::LS_INFO, buffer);
923
924 // Hook up to VoiceEngine for sync purposes, if supplied.
925 if (!voice_engine_) {
926 LOG(LS_WARNING) << "NULL voice engine";
927 } else if ((vie_wrapper_->base()->SetVoiceEngine(
928 voice_engine_->voe()->engine())) != 0) {
929 LOG_RTCERR0(SetVoiceEngine);
930 return false;
931 }
932
933 // Register our custom render module.
934 if (vie_wrapper_->render()->RegisterVideoRenderModule(
935 *render_module_.get()) != 0) {
936 LOG_RTCERR0(RegisterVideoRenderModule);
937 return false;
938 }
939
940 initialized_ = true;
941 return true;
942}
943
944void WebRtcVideoEngine::Terminate() {
945 LOG(LS_INFO) << "WebRtcVideoEngine::Terminate";
946 initialized_ = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000947
948 if (vie_wrapper_->render()->DeRegisterVideoRenderModule(
949 *render_module_.get()) != 0) {
950 LOG_RTCERR0(DeRegisterVideoRenderModule);
951 }
952
953 if (vie_wrapper_->base()->SetVoiceEngine(NULL) != 0) {
954 LOG_RTCERR0(SetVoiceEngine);
955 }
956
957 cpu_monitor_->Stop();
958}
959
960int WebRtcVideoEngine::GetCapabilities() {
961 return VIDEO_RECV | VIDEO_SEND;
962}
963
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +0000964bool WebRtcVideoEngine::SetOptions(const VideoOptions &options) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000965 return true;
966}
967
968bool WebRtcVideoEngine::SetDefaultEncoderConfig(
969 const VideoEncoderConfig& config) {
970 return SetDefaultCodec(config.max_codec);
971}
972
wu@webrtc.org78187522013-10-07 23:32:02 +0000973VideoEncoderConfig WebRtcVideoEngine::GetDefaultEncoderConfig() const {
974 ASSERT(!video_codecs_.empty());
975 VideoCodec max_codec(kVideoCodecPrefs[0].payload_type,
976 kVideoCodecPrefs[0].name,
977 video_codecs_[0].width,
978 video_codecs_[0].height,
979 video_codecs_[0].framerate,
980 0);
981 return VideoEncoderConfig(max_codec);
982}
983
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000984// SetDefaultCodec may be called while the capturer is running. For example, a
985// test call is started in a page with QVGA default codec, and then a real call
986// is started in another page with VGA default codec. This is the corner case
987// and happens only when a session is started. We ignore this case currently.
988bool WebRtcVideoEngine::SetDefaultCodec(const VideoCodec& codec) {
989 if (!RebuildCodecList(codec)) {
990 LOG(LS_WARNING) << "Failed to RebuildCodecList";
991 return false;
992 }
993
wu@webrtc.org78187522013-10-07 23:32:02 +0000994 ASSERT(!video_codecs_.empty());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000995 default_codec_format_ = VideoFormat(
996 video_codecs_[0].width,
997 video_codecs_[0].height,
998 VideoFormat::FpsToInterval(video_codecs_[0].framerate),
999 FOURCC_ANY);
1000 return true;
1001}
1002
1003WebRtcVideoMediaChannel* WebRtcVideoEngine::CreateChannel(
1004 VoiceMediaChannel* voice_channel) {
1005 WebRtcVideoMediaChannel* channel =
1006 new WebRtcVideoMediaChannel(this, voice_channel);
1007 if (!channel->Init()) {
1008 delete channel;
1009 channel = NULL;
1010 }
1011 return channel;
1012}
1013
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001014bool WebRtcVideoEngine::SetLocalRenderer(VideoRenderer* renderer) {
1015 local_renderer_w_ = local_renderer_h_ = 0;
1016 local_renderer_ = renderer;
1017 return true;
1018}
1019
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001020const std::vector<VideoCodec>& WebRtcVideoEngine::codecs() const {
1021 return video_codecs_;
1022}
1023
1024const std::vector<RtpHeaderExtension>&
1025WebRtcVideoEngine::rtp_header_extensions() const {
1026 return rtp_header_extensions_;
1027}
1028
1029void WebRtcVideoEngine::SetLogging(int min_sev, const char* filter) {
1030 // if min_sev == -1, we keep the current log level.
1031 if (min_sev >= 0) {
1032 SetTraceFilter(SeverityToFilter(min_sev));
1033 }
1034 SetTraceOptions(filter);
1035}
1036
1037int WebRtcVideoEngine::GetLastEngineError() {
1038 return vie_wrapper_->error();
1039}
1040
1041// Checks to see whether we comprehend and could receive a particular codec
1042bool WebRtcVideoEngine::FindCodec(const VideoCodec& in) {
1043 for (int i = 0; i < ARRAY_SIZE(kVideoFormats); ++i) {
1044 const VideoFormat fmt(kVideoFormats[i]);
1045 if ((in.width == 0 && in.height == 0) ||
1046 (fmt.width == in.width && fmt.height == in.height)) {
1047 if (encoder_factory_) {
1048 const std::vector<WebRtcVideoEncoderFactory::VideoCodec>& codecs =
1049 encoder_factory_->codecs();
1050 for (size_t j = 0; j < codecs.size(); ++j) {
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00001051 VideoCodec codec(GetExternalVideoPayloadType(static_cast<int>(j)),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001052 codecs[j].name, 0, 0, 0, 0);
1053 if (codec.Matches(in))
1054 return true;
1055 }
1056 }
1057 for (size_t j = 0; j < ARRAY_SIZE(kVideoCodecPrefs); ++j) {
1058 VideoCodec codec(kVideoCodecPrefs[j].payload_type,
1059 kVideoCodecPrefs[j].name, 0, 0, 0, 0);
1060 if (codec.Matches(in)) {
1061 return true;
1062 }
1063 }
1064 }
1065 }
1066 return false;
1067}
1068
1069// Given the requested codec, returns true if we can send that codec type and
1070// updates out with the best quality we could send for that codec. If current is
1071// not empty, we constrain out so that its aspect ratio matches current's.
1072bool WebRtcVideoEngine::CanSendCodec(const VideoCodec& requested,
1073 const VideoCodec& current,
1074 VideoCodec* out) {
1075 if (!out) {
1076 return false;
1077 }
1078
1079 std::vector<VideoCodec>::const_iterator local_max;
1080 for (local_max = video_codecs_.begin();
1081 local_max < video_codecs_.end();
1082 ++local_max) {
1083 // First match codecs by payload type
1084 if (!requested.Matches(*local_max)) {
1085 continue;
1086 }
1087
1088 out->id = requested.id;
1089 out->name = requested.name;
1090 out->preference = requested.preference;
1091 out->params = requested.params;
1092 out->framerate = talk_base::_min(requested.framerate, local_max->framerate);
1093 out->width = 0;
1094 out->height = 0;
1095 out->params = requested.params;
1096 out->feedback_params = requested.feedback_params;
1097
1098 if (0 == requested.width && 0 == requested.height) {
1099 // Special case with resolution 0. The channel should not send frames.
1100 return true;
1101 } else if (0 == requested.width || 0 == requested.height) {
1102 // 0xn and nx0 are invalid resolutions.
1103 return false;
1104 }
1105
1106 // Pick the best quality that is within their and our bounds and has the
1107 // correct aspect ratio.
1108 for (int j = 0; j < ARRAY_SIZE(kVideoFormats); ++j) {
1109 const VideoFormat format(kVideoFormats[j]);
1110
1111 // Skip any format that is larger than the local or remote maximums, or
1112 // smaller than the current best match
1113 if (format.width > requested.width || format.height > requested.height ||
1114 format.width > local_max->width ||
1115 (format.width < out->width && format.height < out->height)) {
1116 continue;
1117 }
1118
1119 bool better = false;
1120
1121 // Check any further constraints on this prospective format
1122 if (!out->width || !out->height) {
1123 // If we don't have any matches yet, this is the best so far.
1124 better = true;
1125 } else if (current.width && current.height) {
1126 // current is set so format must match its ratio exactly.
1127 better =
1128 (format.width * current.height == format.height * current.width);
1129 } else {
1130 // Prefer closer aspect ratios i.e
1131 // format.aspect - requested.aspect < out.aspect - requested.aspect
1132 better = abs(format.width * requested.height * out->height -
1133 requested.width * format.height * out->height) <
1134 abs(out->width * format.height * requested.height -
1135 requested.width * format.height * out->height);
1136 }
1137
1138 if (better) {
1139 out->width = format.width;
1140 out->height = format.height;
1141 }
1142 }
1143 if (out->width > 0) {
1144 return true;
1145 }
1146 }
1147 return false;
1148}
1149
1150static void ConvertToCricketVideoCodec(
1151 const webrtc::VideoCodec& in_codec, VideoCodec* out_codec) {
1152 out_codec->id = in_codec.plType;
1153 out_codec->name = in_codec.plName;
1154 out_codec->width = in_codec.width;
1155 out_codec->height = in_codec.height;
1156 out_codec->framerate = in_codec.maxFramerate;
1157 out_codec->SetParam(kCodecParamMinBitrate, in_codec.minBitrate);
1158 out_codec->SetParam(kCodecParamMaxBitrate, in_codec.maxBitrate);
1159 if (in_codec.qpMax) {
1160 out_codec->SetParam(kCodecParamMaxQuantization, in_codec.qpMax);
1161 }
1162}
1163
1164bool WebRtcVideoEngine::ConvertFromCricketVideoCodec(
1165 const VideoCodec& in_codec, webrtc::VideoCodec* out_codec) {
1166 bool found = false;
1167 int ncodecs = vie_wrapper_->codec()->NumberOfCodecs();
1168 for (int i = 0; i < ncodecs; ++i) {
1169 if (vie_wrapper_->codec()->GetCodec(i, *out_codec) == 0 &&
1170 _stricmp(in_codec.name.c_str(), out_codec->plName) == 0) {
1171 found = true;
1172 break;
1173 }
1174 }
1175
1176 // If not found, check if this is supported by external encoder factory.
1177 if (!found && encoder_factory_) {
1178 const std::vector<WebRtcVideoEncoderFactory::VideoCodec>& codecs =
1179 encoder_factory_->codecs();
1180 for (size_t i = 0; i < codecs.size(); ++i) {
1181 if (_stricmp(in_codec.name.c_str(), codecs[i].name.c_str()) == 0) {
1182 out_codec->codecType = codecs[i].type;
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00001183 out_codec->plType = GetExternalVideoPayloadType(static_cast<int>(i));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001184 talk_base::strcpyn(out_codec->plName, sizeof(out_codec->plName),
1185 codecs[i].name.c_str(), codecs[i].name.length());
1186 found = true;
1187 break;
1188 }
1189 }
1190 }
1191
1192 if (!found) {
1193 LOG(LS_ERROR) << "invalid codec type";
1194 return false;
1195 }
1196
1197 if (in_codec.id != 0)
1198 out_codec->plType = in_codec.id;
1199
1200 if (in_codec.width != 0)
1201 out_codec->width = in_codec.width;
1202
1203 if (in_codec.height != 0)
1204 out_codec->height = in_codec.height;
1205
1206 if (in_codec.framerate != 0)
1207 out_codec->maxFramerate = in_codec.framerate;
1208
1209 // Convert bitrate parameters.
1210 int max_bitrate = kMaxVideoBitrate;
1211 int min_bitrate = kMinVideoBitrate;
1212 int start_bitrate = kStartVideoBitrate;
1213
1214 in_codec.GetParam(kCodecParamMinBitrate, &min_bitrate);
1215 in_codec.GetParam(kCodecParamMaxBitrate, &max_bitrate);
1216
1217 if (max_bitrate < min_bitrate) {
1218 return false;
1219 }
1220 start_bitrate = talk_base::_max(start_bitrate, min_bitrate);
1221 start_bitrate = talk_base::_min(start_bitrate, max_bitrate);
1222
1223 out_codec->minBitrate = min_bitrate;
1224 out_codec->startBitrate = start_bitrate;
1225 out_codec->maxBitrate = max_bitrate;
1226
1227 // Convert general codec parameters.
1228 int max_quantization = 0;
1229 if (in_codec.GetParam(kCodecParamMaxQuantization, &max_quantization)) {
1230 if (max_quantization < 0) {
1231 return false;
1232 }
1233 out_codec->qpMax = max_quantization;
1234 }
1235 return true;
1236}
1237
1238void WebRtcVideoEngine::RegisterChannel(WebRtcVideoMediaChannel *channel) {
1239 talk_base::CritScope cs(&channels_crit_);
1240 channels_.push_back(channel);
1241}
1242
1243void WebRtcVideoEngine::UnregisterChannel(WebRtcVideoMediaChannel *channel) {
1244 talk_base::CritScope cs(&channels_crit_);
1245 channels_.erase(std::remove(channels_.begin(), channels_.end(), channel),
1246 channels_.end());
1247}
1248
1249bool WebRtcVideoEngine::SetVoiceEngine(WebRtcVoiceEngine* voice_engine) {
1250 if (initialized_) {
1251 LOG(LS_WARNING) << "SetVoiceEngine can not be called after Init";
1252 return false;
1253 }
1254 voice_engine_ = voice_engine;
1255 return true;
1256}
1257
1258bool WebRtcVideoEngine::EnableTimedRender() {
1259 if (initialized_) {
1260 LOG(LS_WARNING) << "EnableTimedRender can not be called after Init";
1261 return false;
1262 }
1263 render_module_.reset(webrtc::VideoRender::CreateVideoRender(0, NULL,
1264 false, webrtc::kRenderExternal));
1265 return true;
1266}
1267
1268void WebRtcVideoEngine::SetTraceFilter(int filter) {
1269 tracing_->SetTraceFilter(filter);
1270}
1271
1272// See https://sites.google.com/a/google.com/wavelet/
1273// Home/Magic-Flute--RTC-Engine-/Magic-Flute-Command-Line-Parameters
1274// for all supported command line setttings.
1275void WebRtcVideoEngine::SetTraceOptions(const std::string& options) {
1276 // Set WebRTC trace file.
1277 std::vector<std::string> opts;
1278 talk_base::tokenize(options, ' ', '"', '"', &opts);
1279 std::vector<std::string>::iterator tracefile =
1280 std::find(opts.begin(), opts.end(), "tracefile");
1281 if (tracefile != opts.end() && ++tracefile != opts.end()) {
1282 // Write WebRTC debug output (at same loglevel) to file
1283 if (tracing_->SetTraceFile(tracefile->c_str()) == -1) {
1284 LOG_RTCERR1(SetTraceFile, *tracefile);
1285 }
1286 }
1287}
1288
1289static void AddDefaultFeedbackParams(VideoCodec* codec) {
1290 const FeedbackParam kFir(kRtcpFbParamCcm, kRtcpFbCcmParamFir);
1291 codec->AddFeedbackParam(kFir);
1292 const FeedbackParam kNack(kRtcpFbParamNack, kParamValueEmpty);
1293 codec->AddFeedbackParam(kNack);
1294 const FeedbackParam kRemb(kRtcpFbParamRemb, kParamValueEmpty);
1295 codec->AddFeedbackParam(kRemb);
1296}
1297
1298// Rebuilds the codec list to be only those that are less intensive
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +00001299// than the specified codec. Prefers internal codec over external with
1300// higher preference field.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001301bool WebRtcVideoEngine::RebuildCodecList(const VideoCodec& in_codec) {
1302 if (!FindCodec(in_codec))
1303 return false;
1304
1305 video_codecs_.clear();
1306
1307 bool found = false;
mallinath@webrtc.org1112c302013-09-23 20:34:45 +00001308 std::set<std::string> internal_codec_names;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001309 for (size_t i = 0; i < ARRAY_SIZE(kVideoCodecPrefs); ++i) {
1310 const VideoCodecPref& pref(kVideoCodecPrefs[i]);
1311 if (!found)
1312 found = (in_codec.name == pref.name);
mallinath@webrtc.org1112c302013-09-23 20:34:45 +00001313 if (found) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001314 VideoCodec codec(pref.payload_type, pref.name,
1315 in_codec.width, in_codec.height, in_codec.framerate,
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00001316 static_cast<int>(ARRAY_SIZE(kVideoCodecPrefs) - i));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001317 if (_stricmp(kVp8PayloadName, codec.name.c_str()) == 0) {
1318 AddDefaultFeedbackParams(&codec);
1319 }
1320 video_codecs_.push_back(codec);
mallinath@webrtc.org1112c302013-09-23 20:34:45 +00001321 internal_codec_names.insert(codec.name);
1322 }
1323 }
1324 if (encoder_factory_) {
1325 const std::vector<WebRtcVideoEncoderFactory::VideoCodec>& codecs =
1326 encoder_factory_->codecs();
1327 for (size_t i = 0; i < codecs.size(); ++i) {
1328 bool is_internal_codec = internal_codec_names.find(codecs[i].name) !=
1329 internal_codec_names.end();
1330 if (!is_internal_codec) {
1331 if (!found)
1332 found = (in_codec.name == codecs[i].name);
1333 VideoCodec codec(
1334 GetExternalVideoPayloadType(static_cast<int>(i)),
1335 codecs[i].name,
1336 codecs[i].max_width,
1337 codecs[i].max_height,
1338 codecs[i].max_fps,
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +00001339 // Use negative preference on external codec to ensure the internal
1340 // codec is preferred.
1341 static_cast<int>(0 - i));
mallinath@webrtc.org1112c302013-09-23 20:34:45 +00001342 AddDefaultFeedbackParams(&codec);
1343 video_codecs_.push_back(codec);
1344 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001345 }
1346 }
1347 ASSERT(found);
1348 return true;
1349}
1350
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001351// Ignore spammy trace messages, mostly from the stats API when we haven't
1352// gotten RTCP info yet from the remote side.
1353bool WebRtcVideoEngine::ShouldIgnoreTrace(const std::string& trace) {
1354 static const char* const kTracesToIgnore[] = {
1355 NULL
1356 };
1357 for (const char* const* p = kTracesToIgnore; *p; ++p) {
1358 if (trace.find(*p) == 0) {
1359 return true;
1360 }
1361 }
1362 return false;
1363}
1364
1365int WebRtcVideoEngine::GetNumOfChannels() {
1366 talk_base::CritScope cs(&channels_crit_);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00001367 return static_cast<int>(channels_.size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001368}
1369
1370void WebRtcVideoEngine::Print(webrtc::TraceLevel level, const char* trace,
1371 int length) {
1372 talk_base::LoggingSeverity sev = talk_base::LS_VERBOSE;
1373 if (level == webrtc::kTraceError || level == webrtc::kTraceCritical)
1374 sev = talk_base::LS_ERROR;
1375 else if (level == webrtc::kTraceWarning)
1376 sev = talk_base::LS_WARNING;
1377 else if (level == webrtc::kTraceStateInfo || level == webrtc::kTraceInfo)
1378 sev = talk_base::LS_INFO;
1379 else if (level == webrtc::kTraceTerseInfo)
1380 sev = talk_base::LS_INFO;
1381
1382 // Skip past boilerplate prefix text
1383 if (length < 72) {
1384 std::string msg(trace, length);
1385 LOG(LS_ERROR) << "Malformed webrtc log message: ";
1386 LOG_V(sev) << msg;
1387 } else {
1388 std::string msg(trace + 71, length - 72);
1389 if (!ShouldIgnoreTrace(msg) &&
1390 (!voice_engine_ || !voice_engine_->ShouldIgnoreTrace(msg))) {
1391 LOG_V(sev) << "webrtc: " << msg;
1392 }
1393 }
1394}
1395
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001396webrtc::VideoDecoder* WebRtcVideoEngine::CreateExternalDecoder(
1397 webrtc::VideoCodecType type) {
1398 if (decoder_factory_ == NULL) {
1399 return NULL;
1400 }
1401 return decoder_factory_->CreateVideoDecoder(type);
1402}
1403
1404void WebRtcVideoEngine::DestroyExternalDecoder(webrtc::VideoDecoder* decoder) {
1405 ASSERT(decoder_factory_ != NULL);
1406 if (decoder_factory_ == NULL)
1407 return;
1408 decoder_factory_->DestroyVideoDecoder(decoder);
1409}
1410
1411webrtc::VideoEncoder* WebRtcVideoEngine::CreateExternalEncoder(
1412 webrtc::VideoCodecType type) {
1413 if (encoder_factory_ == NULL) {
1414 return NULL;
1415 }
1416 return encoder_factory_->CreateVideoEncoder(type);
1417}
1418
1419void WebRtcVideoEngine::DestroyExternalEncoder(webrtc::VideoEncoder* encoder) {
1420 ASSERT(encoder_factory_ != NULL);
1421 if (encoder_factory_ == NULL)
1422 return;
1423 encoder_factory_->DestroyVideoEncoder(encoder);
1424}
1425
1426bool WebRtcVideoEngine::IsExternalEncoderCodecType(
1427 webrtc::VideoCodecType type) const {
1428 if (!encoder_factory_)
1429 return false;
1430 const std::vector<WebRtcVideoEncoderFactory::VideoCodec>& codecs =
1431 encoder_factory_->codecs();
1432 std::vector<WebRtcVideoEncoderFactory::VideoCodec>::const_iterator it;
1433 for (it = codecs.begin(); it != codecs.end(); ++it) {
1434 if (it->type == type)
1435 return true;
1436 }
1437 return false;
1438}
1439
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001440void WebRtcVideoEngine::SetExternalDecoderFactory(
1441 WebRtcVideoDecoderFactory* decoder_factory) {
1442 decoder_factory_ = decoder_factory;
1443}
1444
1445void WebRtcVideoEngine::SetExternalEncoderFactory(
1446 WebRtcVideoEncoderFactory* encoder_factory) {
1447 if (encoder_factory_ == encoder_factory)
1448 return;
1449
1450 if (encoder_factory_) {
1451 encoder_factory_->RemoveObserver(this);
1452 }
1453 encoder_factory_ = encoder_factory;
1454 if (encoder_factory_) {
1455 encoder_factory_->AddObserver(this);
1456 }
1457
1458 // Invoke OnCodecAvailable() here in case the list of codecs is already
1459 // available when the encoder factory is installed. If not the encoder
1460 // factory will invoke the callback later when the codecs become available.
1461 OnCodecsAvailable();
1462}
1463
1464void WebRtcVideoEngine::OnCodecsAvailable() {
1465 // Rebuild codec list while reapplying the current default codec format.
1466 VideoCodec max_codec(kVideoCodecPrefs[0].payload_type,
1467 kVideoCodecPrefs[0].name,
1468 video_codecs_[0].width,
1469 video_codecs_[0].height,
1470 video_codecs_[0].framerate,
1471 0);
1472 if (!RebuildCodecList(max_codec)) {
1473 LOG(LS_ERROR) << "Failed to initialize list of supported codec types";
1474 }
1475}
1476
1477// WebRtcVideoMediaChannel
1478
1479WebRtcVideoMediaChannel::WebRtcVideoMediaChannel(
1480 WebRtcVideoEngine* engine,
1481 VoiceMediaChannel* channel)
1482 : engine_(engine),
1483 voice_channel_(channel),
1484 vie_channel_(-1),
1485 nack_enabled_(true),
1486 remb_enabled_(false),
1487 render_started_(false),
1488 first_receive_ssrc_(0),
1489 send_red_type_(-1),
1490 send_fec_type_(-1),
1491 send_min_bitrate_(kMinVideoBitrate),
1492 send_start_bitrate_(kStartVideoBitrate),
1493 send_max_bitrate_(kMaxVideoBitrate),
1494 sending_(false),
1495 ratio_w_(0),
1496 ratio_h_(0) {
1497 engine->RegisterChannel(this);
1498}
1499
1500bool WebRtcVideoMediaChannel::Init() {
1501 const uint32 ssrc_key = 0;
1502 return CreateChannel(ssrc_key, MD_SENDRECV, &vie_channel_);
1503}
1504
1505WebRtcVideoMediaChannel::~WebRtcVideoMediaChannel() {
1506 const bool send = false;
1507 SetSend(send);
1508 const bool render = false;
1509 SetRender(render);
1510
1511 while (!send_channels_.empty()) {
1512 if (!DeleteSendChannel(send_channels_.begin()->first)) {
1513 LOG(LS_ERROR) << "Unable to delete channel with ssrc key "
1514 << send_channels_.begin()->first;
1515 ASSERT(false);
1516 break;
1517 }
1518 }
1519
1520 // Remove all receive streams and the default channel.
1521 while (!recv_channels_.empty()) {
1522 RemoveRecvStream(recv_channels_.begin()->first);
1523 }
1524
1525 // Unregister the channel from the engine.
1526 engine()->UnregisterChannel(this);
1527 if (worker_thread()) {
1528 worker_thread()->Clear(this);
1529 }
1530}
1531
1532bool WebRtcVideoMediaChannel::SetRecvCodecs(
1533 const std::vector<VideoCodec>& codecs) {
1534 receive_codecs_.clear();
1535 for (std::vector<VideoCodec>::const_iterator iter = codecs.begin();
1536 iter != codecs.end(); ++iter) {
1537 if (engine()->FindCodec(*iter)) {
1538 webrtc::VideoCodec wcodec;
1539 if (engine()->ConvertFromCricketVideoCodec(*iter, &wcodec)) {
1540 receive_codecs_.push_back(wcodec);
1541 }
1542 } else {
1543 LOG(LS_INFO) << "Unknown codec " << iter->name;
1544 return false;
1545 }
1546 }
1547
1548 for (RecvChannelMap::iterator it = recv_channels_.begin();
1549 it != recv_channels_.end(); ++it) {
1550 if (!SetReceiveCodecs(it->second))
1551 return false;
1552 }
1553 return true;
1554}
1555
1556bool WebRtcVideoMediaChannel::SetSendCodecs(
1557 const std::vector<VideoCodec>& codecs) {
1558 // Match with local video codec list.
1559 std::vector<webrtc::VideoCodec> send_codecs;
1560 VideoCodec checked_codec;
1561 VideoCodec current; // defaults to 0x0
1562 if (sending_) {
1563 ConvertToCricketVideoCodec(*send_codec_, &current);
1564 }
1565 for (std::vector<VideoCodec>::const_iterator iter = codecs.begin();
1566 iter != codecs.end(); ++iter) {
1567 if (_stricmp(iter->name.c_str(), kRedPayloadName) == 0) {
1568 send_red_type_ = iter->id;
1569 } else if (_stricmp(iter->name.c_str(), kFecPayloadName) == 0) {
1570 send_fec_type_ = iter->id;
1571 } else if (engine()->CanSendCodec(*iter, current, &checked_codec)) {
1572 webrtc::VideoCodec wcodec;
1573 if (engine()->ConvertFromCricketVideoCodec(checked_codec, &wcodec)) {
1574 if (send_codecs.empty()) {
1575 nack_enabled_ = IsNackEnabled(checked_codec);
1576 remb_enabled_ = IsRembEnabled(checked_codec);
1577 }
1578 send_codecs.push_back(wcodec);
1579 }
1580 } else {
1581 LOG(LS_WARNING) << "Unknown codec " << iter->name;
1582 }
1583 }
1584
1585 // Fail if we don't have a match.
1586 if (send_codecs.empty()) {
1587 LOG(LS_WARNING) << "No matching codecs available";
1588 return false;
1589 }
1590
1591 // Recv protection.
1592 for (RecvChannelMap::iterator it = recv_channels_.begin();
1593 it != recv_channels_.end(); ++it) {
1594 int channel_id = it->second->channel_id();
1595 if (!SetNackFec(channel_id, send_red_type_, send_fec_type_,
1596 nack_enabled_)) {
1597 return false;
1598 }
1599 if (engine_->vie()->rtp()->SetRembStatus(channel_id,
1600 kNotSending,
1601 remb_enabled_) != 0) {
1602 LOG_RTCERR3(SetRembStatus, channel_id, kNotSending, remb_enabled_);
1603 return false;
1604 }
1605 }
1606
1607 // Send settings.
1608 for (SendChannelMap::iterator iter = send_channels_.begin();
1609 iter != send_channels_.end(); ++iter) {
1610 int channel_id = iter->second->channel_id();
1611 if (!SetNackFec(channel_id, send_red_type_, send_fec_type_,
1612 nack_enabled_)) {
1613 return false;
1614 }
1615 if (engine_->vie()->rtp()->SetRembStatus(channel_id,
1616 remb_enabled_,
1617 remb_enabled_) != 0) {
1618 LOG_RTCERR3(SetRembStatus, channel_id, remb_enabled_, remb_enabled_);
1619 return false;
1620 }
1621 }
1622
1623 // Select the first matched codec.
1624 webrtc::VideoCodec& codec(send_codecs[0]);
1625
1626 if (!SetSendCodec(
1627 codec, codec.minBitrate, codec.startBitrate, codec.maxBitrate)) {
1628 return false;
1629 }
1630
1631 for (SendChannelMap::iterator iter = send_channels_.begin();
1632 iter != send_channels_.end(); ++iter) {
1633 WebRtcVideoChannelSendInfo* send_channel = iter->second;
1634 send_channel->InitializeAdapterOutputFormat(codec);
1635 }
1636
1637 LogSendCodecChange("SetSendCodecs()");
1638
1639 return true;
1640}
1641
1642bool WebRtcVideoMediaChannel::GetSendCodec(VideoCodec* send_codec) {
1643 if (!send_codec_) {
1644 return false;
1645 }
1646 ConvertToCricketVideoCodec(*send_codec_, send_codec);
1647 return true;
1648}
1649
1650bool WebRtcVideoMediaChannel::SetSendStreamFormat(uint32 ssrc,
1651 const VideoFormat& format) {
1652 if (!send_codec_) {
1653 LOG(LS_ERROR) << "The send codec has not been set yet.";
1654 return false;
1655 }
1656 WebRtcVideoChannelSendInfo* send_channel = GetSendChannel(ssrc);
1657 if (!send_channel) {
1658 LOG(LS_ERROR) << "The specified ssrc " << ssrc << " is not in use.";
1659 return false;
1660 }
1661 send_channel->set_video_format(format);
1662 return true;
1663}
1664
1665bool WebRtcVideoMediaChannel::SetRender(bool render) {
1666 if (render == render_started_) {
1667 return true; // no action required
1668 }
1669
1670 bool ret = true;
1671 for (RecvChannelMap::iterator it = recv_channels_.begin();
1672 it != recv_channels_.end(); ++it) {
1673 if (render) {
1674 if (engine()->vie()->render()->StartRender(
1675 it->second->channel_id()) != 0) {
1676 LOG_RTCERR1(StartRender, it->second->channel_id());
1677 ret = false;
1678 }
1679 } else {
1680 if (engine()->vie()->render()->StopRender(
1681 it->second->channel_id()) != 0) {
1682 LOG_RTCERR1(StopRender, it->second->channel_id());
1683 ret = false;
1684 }
1685 }
1686 }
1687 if (ret) {
1688 render_started_ = render;
1689 }
1690
1691 return ret;
1692}
1693
1694bool WebRtcVideoMediaChannel::SetSend(bool send) {
1695 if (!HasReadySendChannels() && send) {
1696 LOG(LS_ERROR) << "No stream added";
1697 return false;
1698 }
1699 if (send == sending()) {
1700 return true; // No action required.
1701 }
1702
1703 if (send) {
1704 // We've been asked to start sending.
1705 // SetSendCodecs must have been called already.
1706 if (!send_codec_) {
1707 return false;
1708 }
1709 // Start send now.
1710 if (!StartSend()) {
1711 return false;
1712 }
1713 } else {
1714 // We've been asked to stop sending.
1715 if (!StopSend()) {
1716 return false;
1717 }
1718 }
1719 sending_ = send;
1720
1721 return true;
1722}
1723
1724bool WebRtcVideoMediaChannel::AddSendStream(const StreamParams& sp) {
1725 LOG(LS_INFO) << "AddSendStream " << sp.ToString();
1726
1727 if (!IsOneSsrcStream(sp)) {
1728 LOG(LS_ERROR) << "AddSendStream: bad local stream parameters";
1729 return false;
1730 }
1731
1732 uint32 ssrc_key;
1733 if (!CreateSendChannelKey(sp.first_ssrc(), &ssrc_key)) {
1734 LOG(LS_ERROR) << "Trying to register duplicate ssrc: " << sp.first_ssrc();
1735 return false;
1736 }
1737 // If the default channel is already used for sending create a new channel
1738 // otherwise use the default channel for sending.
1739 int channel_id = -1;
1740 if (send_channels_[0]->stream_params() == NULL) {
1741 channel_id = vie_channel_;
1742 } else {
1743 if (!CreateChannel(ssrc_key, MD_SEND, &channel_id)) {
1744 LOG(LS_ERROR) << "AddSendStream: unable to create channel";
1745 return false;
1746 }
1747 }
1748 WebRtcVideoChannelSendInfo* send_channel = send_channels_[ssrc_key];
1749 // Set the send (local) SSRC.
1750 // If there are multiple send SSRCs, we can only set the first one here, and
1751 // the rest of the SSRC(s) need to be set after SetSendCodec has been called
1752 // (with a codec requires multiple SSRC(s)).
1753 if (engine()->vie()->rtp()->SetLocalSSRC(channel_id,
1754 sp.first_ssrc()) != 0) {
1755 LOG_RTCERR2(SetLocalSSRC, channel_id, sp.first_ssrc());
1756 return false;
1757 }
1758
1759 // Set RTCP CName.
1760 if (engine()->vie()->rtp()->SetRTCPCName(channel_id,
1761 sp.cname.c_str()) != 0) {
1762 LOG_RTCERR2(SetRTCPCName, channel_id, sp.cname.c_str());
1763 return false;
1764 }
1765
1766 // At this point the channel's local SSRC has been updated. If the channel is
1767 // the default channel make sure that all the receive channels are updated as
1768 // well. Receive channels have to have the same SSRC as the default channel in
1769 // order to send receiver reports with this SSRC.
1770 if (IsDefaultChannel(channel_id)) {
1771 for (RecvChannelMap::const_iterator it = recv_channels_.begin();
1772 it != recv_channels_.end(); ++it) {
1773 WebRtcVideoChannelRecvInfo* info = it->second;
1774 int channel_id = info->channel_id();
1775 if (engine()->vie()->rtp()->SetLocalSSRC(channel_id,
1776 sp.first_ssrc()) != 0) {
1777 LOG_RTCERR1(SetLocalSSRC, it->first);
1778 return false;
1779 }
1780 }
1781 }
1782
1783 send_channel->set_stream_params(sp);
1784
1785 // Reset send codec after stream parameters changed.
1786 if (send_codec_) {
1787 if (!SetSendCodec(send_channel, *send_codec_, send_min_bitrate_,
1788 send_start_bitrate_, send_max_bitrate_)) {
1789 return false;
1790 }
1791 LogSendCodecChange("SetSendStreamFormat()");
1792 }
1793
1794 if (sending_) {
1795 return StartSend(send_channel);
1796 }
1797 return true;
1798}
1799
1800bool WebRtcVideoMediaChannel::RemoveSendStream(uint32 ssrc) {
1801 uint32 ssrc_key;
1802 if (!GetSendChannelKey(ssrc, &ssrc_key)) {
1803 LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc
1804 << " which doesn't exist.";
1805 return false;
1806 }
1807 WebRtcVideoChannelSendInfo* send_channel = send_channels_[ssrc_key];
1808 int channel_id = send_channel->channel_id();
1809 if (IsDefaultChannel(channel_id) && (send_channel->stream_params() == NULL)) {
1810 // Default channel will still exist. However, if stream_params() is NULL
1811 // there is no stream to remove.
1812 return false;
1813 }
1814 if (sending_) {
1815 StopSend(send_channel);
1816 }
1817
1818 const WebRtcVideoChannelSendInfo::EncoderMap& encoder_map =
1819 send_channel->registered_encoders();
1820 for (WebRtcVideoChannelSendInfo::EncoderMap::const_iterator it =
1821 encoder_map.begin(); it != encoder_map.end(); ++it) {
1822 if (engine()->vie()->ext_codec()->DeRegisterExternalSendCodec(
1823 channel_id, it->first) != 0) {
1824 LOG_RTCERR1(DeregisterEncoderObserver, channel_id);
1825 }
1826 engine()->DestroyExternalEncoder(it->second);
1827 }
1828 send_channel->ClearRegisteredEncoders();
1829
1830 // The receive channels depend on the default channel, recycle it instead.
1831 if (IsDefaultChannel(channel_id)) {
1832 SetCapturer(GetDefaultChannelSsrc(), NULL);
1833 send_channel->ClearStreamParams();
1834 } else {
1835 return DeleteSendChannel(ssrc_key);
1836 }
1837 return true;
1838}
1839
1840bool WebRtcVideoMediaChannel::AddRecvStream(const StreamParams& sp) {
1841 // TODO(zhurunz) Remove this once BWE works properly across different send
1842 // and receive channels.
1843 // Reuse default channel for recv stream in 1:1 call.
1844 if (!InConferenceMode() && first_receive_ssrc_ == 0) {
1845 LOG(LS_INFO) << "Recv stream " << sp.first_ssrc()
1846 << " reuse default channel #"
1847 << vie_channel_;
1848 first_receive_ssrc_ = sp.first_ssrc();
1849 if (render_started_) {
1850 if (engine()->vie()->render()->StartRender(vie_channel_) !=0) {
1851 LOG_RTCERR1(StartRender, vie_channel_);
1852 }
1853 }
1854 return true;
1855 }
1856
1857 if (recv_channels_.find(sp.first_ssrc()) != recv_channels_.end() ||
1858 first_receive_ssrc_ == sp.first_ssrc()) {
1859 LOG(LS_ERROR) << "Stream already exists";
1860 return false;
1861 }
1862
1863 // TODO(perkj): Implement recv media from multiple SSRCs per stream.
1864 if (sp.ssrcs.size() != 1) {
1865 LOG(LS_ERROR) << "WebRtcVideoMediaChannel supports one receiving SSRC per"
1866 << " stream";
1867 return false;
1868 }
1869
1870 // Create a new channel for receiving video data.
1871 // In order to get the bandwidth estimation work fine for
1872 // receive only channels, we connect all receiving channels
1873 // to our master send channel.
1874 int channel_id = -1;
1875 if (!CreateChannel(sp.first_ssrc(), MD_RECV, &channel_id)) {
1876 return false;
1877 }
1878
1879 // Get the default renderer.
1880 VideoRenderer* default_renderer = NULL;
1881 if (InConferenceMode()) {
1882 // The recv_channels_ size start out being 1, so if it is two here this
1883 // is the first receive channel created (vie_channel_ is not used for
1884 // receiving in a conference call). This means that the renderer stored
1885 // inside vie_channel_ should be used for the just created channel.
1886 if (recv_channels_.size() == 2 &&
1887 recv_channels_.find(0) != recv_channels_.end()) {
1888 GetRenderer(0, &default_renderer);
1889 }
1890 }
1891
1892 // The first recv stream reuses the default renderer (if a default renderer
1893 // has been set).
1894 if (default_renderer) {
1895 SetRenderer(sp.first_ssrc(), default_renderer);
1896 }
1897
1898 LOG(LS_INFO) << "New video stream " << sp.first_ssrc()
1899 << " registered to VideoEngine channel #"
1900 << channel_id << " and connected to channel #" << vie_channel_;
1901
1902 return true;
1903}
1904
1905bool WebRtcVideoMediaChannel::RemoveRecvStream(uint32 ssrc) {
1906 RecvChannelMap::iterator it = recv_channels_.find(ssrc);
1907
1908 if (it == recv_channels_.end()) {
1909 // TODO(perkj): Remove this once BWE works properly across different send
1910 // and receive channels.
1911 // The default channel is reused for recv stream in 1:1 call.
1912 if (first_receive_ssrc_ == ssrc) {
1913 first_receive_ssrc_ = 0;
1914 // Need to stop the renderer and remove it since the render window can be
1915 // deleted after this.
1916 if (render_started_) {
1917 if (engine()->vie()->render()->StopRender(vie_channel_) !=0) {
1918 LOG_RTCERR1(StopRender, it->second->channel_id());
1919 }
1920 }
1921 recv_channels_[0]->SetRenderer(NULL);
1922 return true;
1923 }
1924 return false;
1925 }
1926 WebRtcVideoChannelRecvInfo* info = it->second;
1927 int channel_id = info->channel_id();
1928 if (engine()->vie()->render()->RemoveRenderer(channel_id) != 0) {
1929 LOG_RTCERR1(RemoveRenderer, channel_id);
1930 }
1931
1932 if (engine()->vie()->network()->DeregisterSendTransport(channel_id) !=0) {
1933 LOG_RTCERR1(DeRegisterSendTransport, channel_id);
1934 }
1935
1936 if (engine()->vie()->codec()->DeregisterDecoderObserver(
1937 channel_id) != 0) {
1938 LOG_RTCERR1(DeregisterDecoderObserver, channel_id);
1939 }
1940
1941 const WebRtcVideoChannelRecvInfo::DecoderMap& decoder_map =
1942 info->registered_decoders();
1943 for (WebRtcVideoChannelRecvInfo::DecoderMap::const_iterator it =
1944 decoder_map.begin(); it != decoder_map.end(); ++it) {
1945 if (engine()->vie()->ext_codec()->DeRegisterExternalReceiveCodec(
1946 channel_id, it->first) != 0) {
1947 LOG_RTCERR1(DeregisterDecoderObserver, channel_id);
1948 }
1949 engine()->DestroyExternalDecoder(it->second);
1950 }
1951 info->ClearRegisteredDecoders();
1952
1953 LOG(LS_INFO) << "Removing video stream " << ssrc
1954 << " with VideoEngine channel #"
1955 << channel_id;
1956 if (engine()->vie()->base()->DeleteChannel(channel_id) == -1) {
1957 LOG_RTCERR1(DeleteChannel, channel_id);
1958 // Leak the WebRtcVideoChannelRecvInfo owned by |it| but remove the channel
1959 // from recv_channels_.
1960 recv_channels_.erase(it);
1961 return false;
1962 }
1963 // Delete the WebRtcVideoChannelRecvInfo pointed to by it->second.
1964 delete info;
1965 recv_channels_.erase(it);
1966 return true;
1967}
1968
1969bool WebRtcVideoMediaChannel::StartSend() {
1970 bool success = true;
1971 for (SendChannelMap::iterator iter = send_channels_.begin();
1972 iter != send_channels_.end(); ++iter) {
1973 WebRtcVideoChannelSendInfo* send_channel = iter->second;
1974 if (!StartSend(send_channel)) {
1975 success = false;
1976 }
1977 }
1978 return success;
1979}
1980
1981bool WebRtcVideoMediaChannel::StartSend(
1982 WebRtcVideoChannelSendInfo* send_channel) {
1983 const int channel_id = send_channel->channel_id();
1984 if (engine()->vie()->base()->StartSend(channel_id) != 0) {
1985 LOG_RTCERR1(StartSend, channel_id);
1986 return false;
1987 }
1988
1989 send_channel->set_sending(true);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001990 return true;
1991}
1992
1993bool WebRtcVideoMediaChannel::StopSend() {
1994 bool success = true;
1995 for (SendChannelMap::iterator iter = send_channels_.begin();
1996 iter != send_channels_.end(); ++iter) {
1997 WebRtcVideoChannelSendInfo* send_channel = iter->second;
1998 if (!StopSend(send_channel)) {
1999 success = false;
2000 }
2001 }
2002 return success;
2003}
2004
2005bool WebRtcVideoMediaChannel::StopSend(
2006 WebRtcVideoChannelSendInfo* send_channel) {
2007 const int channel_id = send_channel->channel_id();
2008 if (engine()->vie()->base()->StopSend(channel_id) != 0) {
2009 LOG_RTCERR1(StopSend, channel_id);
2010 return false;
2011 }
2012 send_channel->set_sending(false);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002013 return true;
2014}
2015
2016bool WebRtcVideoMediaChannel::SendIntraFrame() {
2017 bool success = true;
2018 for (SendChannelMap::iterator iter = send_channels_.begin();
2019 iter != send_channels_.end();
2020 ++iter) {
2021 WebRtcVideoChannelSendInfo* send_channel = iter->second;
2022 const int channel_id = send_channel->channel_id();
2023 if (engine()->vie()->codec()->SendKeyFrame(channel_id) != 0) {
2024 LOG_RTCERR1(SendKeyFrame, channel_id);
2025 success = false;
2026 }
2027 }
2028 return success;
2029}
2030
2031bool WebRtcVideoMediaChannel::IsOneSsrcStream(const StreamParams& sp) {
2032 return (sp.ssrcs.size() == 1 && sp.ssrc_groups.size() == 0);
2033}
2034
2035bool WebRtcVideoMediaChannel::HasReadySendChannels() {
2036 return !send_channels_.empty() &&
2037 ((send_channels_.size() > 1) ||
2038 (send_channels_[0]->stream_params() != NULL));
2039}
2040
2041bool WebRtcVideoMediaChannel::GetSendChannelKey(uint32 local_ssrc,
2042 uint32* key) {
2043 *key = 0;
2044 // If a send channel is not ready to send it will not have local_ssrc
2045 // registered to it.
2046 if (!HasReadySendChannels()) {
2047 return false;
2048 }
2049 // The default channel is stored with key 0. The key therefore does not match
2050 // the SSRC associated with the default channel. Check if the SSRC provided
2051 // corresponds to the default channel's SSRC.
2052 if (local_ssrc == GetDefaultChannelSsrc()) {
2053 return true;
2054 }
2055 if (send_channels_.find(local_ssrc) == send_channels_.end()) {
2056 for (SendChannelMap::iterator iter = send_channels_.begin();
2057 iter != send_channels_.end(); ++iter) {
2058 WebRtcVideoChannelSendInfo* send_channel = iter->second;
2059 if (send_channel->has_ssrc(local_ssrc)) {
2060 *key = iter->first;
2061 return true;
2062 }
2063 }
2064 return false;
2065 }
2066 // The key was found in the above std::map::find call. This means that the
2067 // ssrc is the key.
2068 *key = local_ssrc;
2069 return true;
2070}
2071
2072WebRtcVideoChannelSendInfo* WebRtcVideoMediaChannel::GetSendChannel(
2073 VideoCapturer* video_capturer) {
2074 for (SendChannelMap::iterator iter = send_channels_.begin();
2075 iter != send_channels_.end(); ++iter) {
2076 WebRtcVideoChannelSendInfo* send_channel = iter->second;
2077 if (send_channel->video_capturer() == video_capturer) {
2078 return send_channel;
2079 }
2080 }
2081 return NULL;
2082}
2083
2084WebRtcVideoChannelSendInfo* WebRtcVideoMediaChannel::GetSendChannel(
2085 uint32 local_ssrc) {
2086 uint32 key;
2087 if (!GetSendChannelKey(local_ssrc, &key)) {
2088 return NULL;
2089 }
2090 return send_channels_[key];
2091}
2092
2093bool WebRtcVideoMediaChannel::CreateSendChannelKey(uint32 local_ssrc,
2094 uint32* key) {
2095 if (GetSendChannelKey(local_ssrc, key)) {
2096 // If there is a key corresponding to |local_ssrc|, the SSRC is already in
2097 // use. SSRCs need to be unique in a session and at this point a duplicate
2098 // SSRC has been detected.
2099 return false;
2100 }
2101 if (send_channels_[0]->stream_params() == NULL) {
2102 // key should be 0 here as the default channel should be re-used whenever it
2103 // is not used.
2104 *key = 0;
2105 return true;
2106 }
2107 // SSRC is currently not in use and the default channel is already in use. Use
2108 // the SSRC as key since it is supposed to be unique in a session.
2109 *key = local_ssrc;
2110 return true;
2111}
2112
2113uint32 WebRtcVideoMediaChannel::GetDefaultChannelSsrc() {
2114 WebRtcVideoChannelSendInfo* send_channel = send_channels_[0];
2115 const StreamParams* sp = send_channel->stream_params();
2116 if (sp == NULL) {
2117 // This happens if no send stream is currently registered.
2118 return 0;
2119 }
2120 return sp->first_ssrc();
2121}
2122
2123bool WebRtcVideoMediaChannel::DeleteSendChannel(uint32 ssrc_key) {
2124 if (send_channels_.find(ssrc_key) == send_channels_.end()) {
2125 return false;
2126 }
2127 WebRtcVideoChannelSendInfo* send_channel = send_channels_[ssrc_key];
2128 VideoCapturer* capturer = send_channel->video_capturer();
2129 if (capturer != NULL) {
2130 capturer->SignalVideoFrame.disconnect(this);
2131 send_channel->set_video_capturer(NULL);
2132 }
2133
2134 int channel_id = send_channel->channel_id();
2135 int capture_id = send_channel->capture_id();
2136 if (engine()->vie()->codec()->DeregisterEncoderObserver(
2137 channel_id) != 0) {
2138 LOG_RTCERR1(DeregisterEncoderObserver, channel_id);
2139 }
2140
2141 // Destroy the external capture interface.
2142 if (engine()->vie()->capture()->DisconnectCaptureDevice(
2143 channel_id) != 0) {
2144 LOG_RTCERR1(DisconnectCaptureDevice, channel_id);
2145 }
2146 if (engine()->vie()->capture()->ReleaseCaptureDevice(
2147 capture_id) != 0) {
2148 LOG_RTCERR1(ReleaseCaptureDevice, capture_id);
2149 }
2150
2151 // The default channel is stored in both |send_channels_| and
2152 // |recv_channels_|. To make sure it is only deleted once from vie let the
2153 // delete call happen when tearing down |recv_channels_| and not here.
2154 if (!IsDefaultChannel(channel_id)) {
2155 engine_->vie()->base()->DeleteChannel(channel_id);
2156 }
2157 delete send_channel;
2158 send_channels_.erase(ssrc_key);
2159 return true;
2160}
2161
2162bool WebRtcVideoMediaChannel::RemoveCapturer(uint32 ssrc) {
2163 WebRtcVideoChannelSendInfo* send_channel = GetSendChannel(ssrc);
2164 if (!send_channel) {
2165 return false;
2166 }
2167 VideoCapturer* capturer = send_channel->video_capturer();
2168 if (capturer == NULL) {
2169 return false;
2170 }
2171 capturer->SignalVideoFrame.disconnect(this);
2172 send_channel->set_video_capturer(NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002173 const int64 timestamp = send_channel->local_stream_info()->time_stamp();
2174 if (send_codec_) {
2175 QueueBlackFrame(ssrc, timestamp, send_codec_->maxFramerate);
2176 }
2177 return true;
2178}
2179
2180bool WebRtcVideoMediaChannel::SetRenderer(uint32 ssrc,
2181 VideoRenderer* renderer) {
2182 if (recv_channels_.find(ssrc) == recv_channels_.end()) {
2183 // TODO(perkj): Remove this once BWE works properly across different send
2184 // and receive channels.
2185 // The default channel is reused for recv stream in 1:1 call.
2186 if (first_receive_ssrc_ == ssrc &&
2187 recv_channels_.find(0) != recv_channels_.end()) {
2188 LOG(LS_INFO) << "SetRenderer " << ssrc
2189 << " reuse default channel #"
2190 << vie_channel_;
2191 recv_channels_[0]->SetRenderer(renderer);
2192 return true;
2193 }
2194 return false;
2195 }
2196
2197 recv_channels_[ssrc]->SetRenderer(renderer);
2198 return true;
2199}
2200
2201bool WebRtcVideoMediaChannel::GetStats(VideoMediaInfo* info) {
2202 // Get sender statistics and build VideoSenderInfo.
2203 unsigned int total_bitrate_sent = 0;
2204 unsigned int video_bitrate_sent = 0;
2205 unsigned int fec_bitrate_sent = 0;
2206 unsigned int nack_bitrate_sent = 0;
2207 unsigned int estimated_send_bandwidth = 0;
2208 unsigned int target_enc_bitrate = 0;
2209 if (send_codec_) {
2210 for (SendChannelMap::const_iterator iter = send_channels_.begin();
2211 iter != send_channels_.end(); ++iter) {
2212 WebRtcVideoChannelSendInfo* send_channel = iter->second;
2213 const int channel_id = send_channel->channel_id();
2214 VideoSenderInfo sinfo;
2215 const StreamParams* send_params = send_channel->stream_params();
2216 if (send_params == NULL) {
2217 // This should only happen if the default vie channel is not in use.
2218 // This can happen if no streams have ever been added or the stream
2219 // corresponding to the default channel has been removed. Note that
2220 // there may be non-default vie channels in use when this happen so
2221 // asserting send_channels_.size() == 1 is not correct and neither is
2222 // breaking out of the loop.
2223 ASSERT(channel_id == vie_channel_);
2224 continue;
2225 }
2226 unsigned int bytes_sent, packets_sent, bytes_recv, packets_recv;
2227 if (engine_->vie()->rtp()->GetRTPStatistics(channel_id, bytes_sent,
2228 packets_sent, bytes_recv,
2229 packets_recv) != 0) {
2230 LOG_RTCERR1(GetRTPStatistics, vie_channel_);
2231 continue;
2232 }
2233 WebRtcLocalStreamInfo* channel_stream_info =
2234 send_channel->local_stream_info();
2235
2236 sinfo.ssrcs = send_params->ssrcs;
2237 sinfo.codec_name = send_codec_->plName;
2238 sinfo.bytes_sent = bytes_sent;
2239 sinfo.packets_sent = packets_sent;
2240 sinfo.packets_cached = -1;
2241 sinfo.packets_lost = -1;
2242 sinfo.fraction_lost = -1;
2243 sinfo.firs_rcvd = -1;
2244 sinfo.nacks_rcvd = -1;
2245 sinfo.rtt_ms = -1;
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002246 sinfo.frame_width = static_cast<int>(channel_stream_info->width());
2247 sinfo.frame_height = static_cast<int>(channel_stream_info->height());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002248 sinfo.framerate_input = channel_stream_info->framerate();
2249 sinfo.framerate_sent = send_channel->encoder_observer()->framerate();
2250 sinfo.nominal_bitrate = send_channel->encoder_observer()->bitrate();
2251 sinfo.preferred_bitrate = send_max_bitrate_;
2252 sinfo.adapt_reason = send_channel->CurrentAdaptReason();
2253
2254 // Get received RTCP statistics for the sender, if available.
2255 // It's not a fatal error if we can't, since RTCP may not have arrived
2256 // yet.
2257 uint16 r_fraction_lost;
2258 unsigned int r_cumulative_lost;
2259 unsigned int r_extended_max;
2260 unsigned int r_jitter;
2261 int r_rtt_ms;
2262
2263 if (engine_->vie()->rtp()->GetSentRTCPStatistics(
2264 channel_id,
2265 r_fraction_lost,
2266 r_cumulative_lost,
2267 r_extended_max,
2268 r_jitter, r_rtt_ms) == 0) {
2269 // Convert Q8 to float.
2270 sinfo.packets_lost = r_cumulative_lost;
2271 sinfo.fraction_lost = static_cast<float>(r_fraction_lost) / (1 << 8);
2272 sinfo.rtt_ms = r_rtt_ms;
2273 }
2274 info->senders.push_back(sinfo);
2275
2276 unsigned int channel_total_bitrate_sent = 0;
2277 unsigned int channel_video_bitrate_sent = 0;
2278 unsigned int channel_fec_bitrate_sent = 0;
2279 unsigned int channel_nack_bitrate_sent = 0;
2280 if (engine_->vie()->rtp()->GetBandwidthUsage(
2281 channel_id, channel_total_bitrate_sent, channel_video_bitrate_sent,
2282 channel_fec_bitrate_sent, channel_nack_bitrate_sent) == 0) {
2283 total_bitrate_sent += channel_total_bitrate_sent;
2284 video_bitrate_sent += channel_video_bitrate_sent;
2285 fec_bitrate_sent += channel_fec_bitrate_sent;
2286 nack_bitrate_sent += channel_nack_bitrate_sent;
2287 } else {
2288 LOG_RTCERR1(GetBandwidthUsage, channel_id);
2289 }
2290
2291 unsigned int estimated_stream_send_bandwidth = 0;
2292 if (engine_->vie()->rtp()->GetEstimatedSendBandwidth(
2293 channel_id, &estimated_stream_send_bandwidth) == 0) {
2294 estimated_send_bandwidth += estimated_stream_send_bandwidth;
2295 } else {
2296 LOG_RTCERR1(GetEstimatedSendBandwidth, channel_id);
2297 }
2298 unsigned int target_enc_stream_bitrate = 0;
2299 if (engine_->vie()->codec()->GetCodecTargetBitrate(
2300 channel_id, &target_enc_stream_bitrate) == 0) {
2301 target_enc_bitrate += target_enc_stream_bitrate;
2302 } else {
2303 LOG_RTCERR1(GetCodecTargetBitrate, channel_id);
2304 }
2305 }
2306 } else {
2307 LOG(LS_WARNING) << "GetStats: sender information not ready.";
2308 }
2309
2310 // Get the SSRC and stats for each receiver, based on our own calculations.
2311 unsigned int estimated_recv_bandwidth = 0;
2312 for (RecvChannelMap::const_iterator it = recv_channels_.begin();
2313 it != recv_channels_.end(); ++it) {
2314 // Don't report receive statistics from the default channel if we have
2315 // specified receive channels.
2316 if (it->first == 0 && recv_channels_.size() > 1)
2317 continue;
2318 WebRtcVideoChannelRecvInfo* channel = it->second;
2319
2320 unsigned int ssrc;
2321 // Get receiver statistics and build VideoReceiverInfo, if we have data.
sergeyu@chromium.orga59696b2013-09-13 23:48:58 +00002322 // Skip the default channel (ssrc == 0).
2323 if (engine_->vie()->rtp()->GetRemoteSSRC(
2324 channel->channel_id(), ssrc) != 0 ||
2325 ssrc == 0)
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002326 continue;
2327
2328 unsigned int bytes_sent, packets_sent, bytes_recv, packets_recv;
2329 if (engine_->vie()->rtp()->GetRTPStatistics(
2330 channel->channel_id(), bytes_sent, packets_sent, bytes_recv,
2331 packets_recv) != 0) {
2332 LOG_RTCERR1(GetRTPStatistics, channel->channel_id());
2333 return false;
2334 }
2335 VideoReceiverInfo rinfo;
2336 rinfo.ssrcs.push_back(ssrc);
2337 rinfo.bytes_rcvd = bytes_recv;
2338 rinfo.packets_rcvd = packets_recv;
2339 rinfo.packets_lost = -1;
2340 rinfo.packets_concealed = -1;
2341 rinfo.fraction_lost = -1; // from SentRTCP
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002342 rinfo.nacks_sent = -1;
2343 rinfo.frame_width = channel->render_adapter()->width();
2344 rinfo.frame_height = channel->render_adapter()->height();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002345 int fps = channel->render_adapter()->framerate();
2346 rinfo.framerate_decoded = fps;
2347 rinfo.framerate_output = fps;
wu@webrtc.org97077a32013-10-25 21:18:33 +00002348 channel->decoder_observer()->ExportTo(&rinfo);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002349
2350 // Get sent RTCP statistics.
2351 uint16 s_fraction_lost;
2352 unsigned int s_cumulative_lost;
2353 unsigned int s_extended_max;
2354 unsigned int s_jitter;
2355 int s_rtt_ms;
2356 if (engine_->vie()->rtp()->GetReceivedRTCPStatistics(channel->channel_id(),
2357 s_fraction_lost, s_cumulative_lost, s_extended_max,
2358 s_jitter, s_rtt_ms) == 0) {
2359 // Convert Q8 to float.
2360 rinfo.packets_lost = s_cumulative_lost;
2361 rinfo.fraction_lost = static_cast<float>(s_fraction_lost) / (1 << 8);
2362 }
2363 info->receivers.push_back(rinfo);
2364
2365 unsigned int estimated_recv_stream_bandwidth = 0;
2366 if (engine_->vie()->rtp()->GetEstimatedReceiveBandwidth(
2367 channel->channel_id(), &estimated_recv_stream_bandwidth) == 0) {
2368 estimated_recv_bandwidth += estimated_recv_stream_bandwidth;
2369 } else {
2370 LOG_RTCERR1(GetEstimatedReceiveBandwidth, channel->channel_id());
2371 }
2372 }
2373
2374 // Build BandwidthEstimationInfo.
2375 // TODO(zhurunz): Add real unittest for this.
2376 BandwidthEstimationInfo bwe;
2377
2378 // Calculations done above per send/receive stream.
2379 bwe.actual_enc_bitrate = video_bitrate_sent;
2380 bwe.transmit_bitrate = total_bitrate_sent;
2381 bwe.retransmit_bitrate = nack_bitrate_sent;
2382 bwe.available_send_bandwidth = estimated_send_bandwidth;
2383 bwe.available_recv_bandwidth = estimated_recv_bandwidth;
2384 bwe.target_enc_bitrate = target_enc_bitrate;
2385
2386 info->bw_estimations.push_back(bwe);
2387
2388 return true;
2389}
2390
2391bool WebRtcVideoMediaChannel::SetCapturer(uint32 ssrc,
2392 VideoCapturer* capturer) {
2393 ASSERT(ssrc != 0);
2394 if (!capturer) {
2395 return RemoveCapturer(ssrc);
2396 }
2397 WebRtcVideoChannelSendInfo* send_channel = GetSendChannel(ssrc);
2398 if (!send_channel) {
2399 return false;
2400 }
2401 VideoCapturer* old_capturer = send_channel->video_capturer();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002402 if (old_capturer) {
2403 old_capturer->SignalVideoFrame.disconnect(this);
2404 }
2405
2406 send_channel->set_video_capturer(capturer);
2407 capturer->SignalVideoFrame.connect(
2408 this,
2409 &WebRtcVideoMediaChannel::AdaptAndSendFrame);
2410 if (!capturer->IsScreencast() && ratio_w_ != 0 && ratio_h_ != 0) {
2411 capturer->UpdateAspectRatio(ratio_w_, ratio_h_);
2412 }
2413 const int64 timestamp = send_channel->local_stream_info()->time_stamp();
2414 if (send_codec_) {
2415 QueueBlackFrame(ssrc, timestamp, send_codec_->maxFramerate);
2416 }
2417 return true;
2418}
2419
2420bool WebRtcVideoMediaChannel::RequestIntraFrame() {
2421 // There is no API exposed to application to request a key frame
2422 // ViE does this internally when there are errors from decoder
2423 return false;
2424}
2425
2426void WebRtcVideoMediaChannel::OnPacketReceived(talk_base::Buffer* packet) {
2427 // Pick which channel to send this packet to. If this packet doesn't match
2428 // any multiplexed streams, just send it to the default channel. Otherwise,
2429 // send it to the specific decoder instance for that stream.
2430 uint32 ssrc = 0;
2431 if (!GetRtpSsrc(packet->data(), packet->length(), &ssrc))
2432 return;
2433 int which_channel = GetRecvChannelNum(ssrc);
2434 if (which_channel == -1) {
2435 which_channel = video_channel();
2436 }
2437
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002438 engine()->vie()->network()->ReceivedRTPPacket(
2439 which_channel,
2440 packet->data(),
2441 static_cast<int>(packet->length()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002442}
2443
2444void WebRtcVideoMediaChannel::OnRtcpReceived(talk_base::Buffer* packet) {
2445// Sending channels need all RTCP packets with feedback information.
2446// Even sender reports can contain attached report blocks.
2447// Receiving channels need sender reports in order to create
2448// correct receiver reports.
2449
2450 uint32 ssrc = 0;
2451 if (!GetRtcpSsrc(packet->data(), packet->length(), &ssrc)) {
2452 LOG(LS_WARNING) << "Failed to parse SSRC from received RTCP packet";
2453 return;
2454 }
2455 int type = 0;
2456 if (!GetRtcpType(packet->data(), packet->length(), &type)) {
2457 LOG(LS_WARNING) << "Failed to parse type from received RTCP packet";
2458 return;
2459 }
2460
2461 // If it is a sender report, find the channel that is listening.
2462 if (type == kRtcpTypeSR) {
2463 int which_channel = GetRecvChannelNum(ssrc);
2464 if (which_channel != -1 && !IsDefaultChannel(which_channel)) {
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002465 engine_->vie()->network()->ReceivedRTCPPacket(
2466 which_channel,
2467 packet->data(),
2468 static_cast<int>(packet->length()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002469 }
2470 }
2471 // SR may continue RR and any RR entry may correspond to any one of the send
2472 // channels. So all RTCP packets must be forwarded all send channels. ViE
2473 // will filter out RR internally.
2474 for (SendChannelMap::iterator iter = send_channels_.begin();
2475 iter != send_channels_.end(); ++iter) {
2476 WebRtcVideoChannelSendInfo* send_channel = iter->second;
2477 int channel_id = send_channel->channel_id();
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002478 engine_->vie()->network()->ReceivedRTCPPacket(
2479 channel_id,
2480 packet->data(),
2481 static_cast<int>(packet->length()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002482 }
2483}
2484
2485void WebRtcVideoMediaChannel::OnReadyToSend(bool ready) {
2486 SetNetworkTransmissionState(ready);
2487}
2488
2489bool WebRtcVideoMediaChannel::MuteStream(uint32 ssrc, bool muted) {
2490 WebRtcVideoChannelSendInfo* send_channel = GetSendChannel(ssrc);
2491 if (!send_channel) {
2492 LOG(LS_ERROR) << "The specified ssrc " << ssrc << " is not in use.";
2493 return false;
2494 }
2495 send_channel->set_muted(muted);
2496 return true;
2497}
2498
2499bool WebRtcVideoMediaChannel::SetRecvRtpHeaderExtensions(
2500 const std::vector<RtpHeaderExtension>& extensions) {
2501 if (receive_extensions_ == extensions) {
2502 return true;
2503 }
2504 receive_extensions_ = extensions;
2505
2506 const RtpHeaderExtension* offset_extension =
2507 FindHeaderExtension(extensions, kRtpTimestampOffsetHeaderExtension);
2508 const RtpHeaderExtension* send_time_extension =
2509 FindHeaderExtension(extensions, kRtpAbsoluteSendTimeHeaderExtension);
2510
2511 // Loop through all receive channels and enable/disable the extensions.
2512 for (RecvChannelMap::iterator channel_it = recv_channels_.begin();
2513 channel_it != recv_channels_.end(); ++channel_it) {
2514 int channel_id = channel_it->second->channel_id();
2515 if (!SetHeaderExtension(
2516 &webrtc::ViERTP_RTCP::SetReceiveTimestampOffsetStatus, channel_id,
2517 offset_extension)) {
2518 return false;
2519 }
2520 if (!SetHeaderExtension(
2521 &webrtc::ViERTP_RTCP::SetReceiveAbsoluteSendTimeStatus, channel_id,
2522 send_time_extension)) {
2523 return false;
2524 }
2525 }
2526 return true;
2527}
2528
2529bool WebRtcVideoMediaChannel::SetSendRtpHeaderExtensions(
2530 const std::vector<RtpHeaderExtension>& extensions) {
2531 send_extensions_ = extensions;
2532
2533 const RtpHeaderExtension* offset_extension =
2534 FindHeaderExtension(extensions, kRtpTimestampOffsetHeaderExtension);
2535 const RtpHeaderExtension* send_time_extension =
2536 FindHeaderExtension(extensions, kRtpAbsoluteSendTimeHeaderExtension);
2537
2538 // Loop through all send channels and enable/disable the extensions.
2539 for (SendChannelMap::iterator channel_it = send_channels_.begin();
2540 channel_it != send_channels_.end(); ++channel_it) {
2541 int channel_id = channel_it->second->channel_id();
2542 if (!SetHeaderExtension(
2543 &webrtc::ViERTP_RTCP::SetSendTimestampOffsetStatus, channel_id,
2544 offset_extension)) {
2545 return false;
2546 }
2547 if (!SetHeaderExtension(
2548 &webrtc::ViERTP_RTCP::SetSendAbsoluteSendTimeStatus, channel_id,
2549 send_time_extension)) {
2550 return false;
2551 }
2552 }
2553 return true;
2554}
2555
2556bool WebRtcVideoMediaChannel::SetSendBandwidth(bool autobw, int bps) {
2557 LOG(LS_INFO) << "WebRtcVideoMediaChanne::SetSendBandwidth";
2558
2559 if (InConferenceMode()) {
2560 LOG(LS_INFO) << "Conference mode ignores SetSendBandWidth";
2561 return true;
2562 }
2563
2564 if (!send_codec_) {
2565 LOG(LS_INFO) << "The send codec has not been set up yet";
2566 return true;
2567 }
2568
2569 int min_bitrate;
2570 int start_bitrate;
2571 int max_bitrate;
2572 if (autobw) {
2573 // Use the default values for min bitrate.
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002574 min_bitrate = send_min_bitrate_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002575 // Use the default value or the bps for the max
2576 max_bitrate = (bps <= 0) ? send_max_bitrate_ : (bps / 1000);
2577 // Maximum start bitrate can be kStartVideoBitrate.
2578 start_bitrate = talk_base::_min(kStartVideoBitrate, max_bitrate);
2579 } else {
2580 // Use the default start or the bps as the target bitrate.
2581 int target_bitrate = (bps <= 0) ? kStartVideoBitrate : (bps / 1000);
2582 min_bitrate = target_bitrate;
2583 start_bitrate = target_bitrate;
2584 max_bitrate = target_bitrate;
2585 }
2586
2587 if (!SetSendCodec(*send_codec_, min_bitrate, start_bitrate, max_bitrate)) {
2588 return false;
2589 }
2590 LogSendCodecChange("SetSendBandwidth()");
2591
2592 return true;
2593}
2594
2595bool WebRtcVideoMediaChannel::SetOptions(const VideoOptions &options) {
2596 // Always accept options that are unchanged.
2597 if (options_ == options) {
2598 return true;
2599 }
2600
2601 // Trigger SetSendCodec to set correct noise reduction state if the option has
2602 // changed.
2603 bool denoiser_changed = options.video_noise_reduction.IsSet() &&
2604 (options_.video_noise_reduction != options.video_noise_reduction);
2605
2606 bool leaky_bucket_changed = options.video_leaky_bucket.IsSet() &&
2607 (options_.video_leaky_bucket != options.video_leaky_bucket);
2608
2609 bool buffer_latency_changed = options.buffered_mode_latency.IsSet() &&
2610 (options_.buffered_mode_latency != options.buffered_mode_latency);
2611
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00002612 bool cpu_overuse_detection_changed = options.cpu_overuse_detection.IsSet() &&
2613 (options_.cpu_overuse_detection != options.cpu_overuse_detection);
2614
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002615 bool conference_mode_turned_off = false;
2616 if (options_.conference_mode.IsSet() && options.conference_mode.IsSet() &&
2617 options_.conference_mode.GetWithDefaultIfUnset(false) &&
2618 !options.conference_mode.GetWithDefaultIfUnset(false)) {
2619 conference_mode_turned_off = true;
2620 }
2621
2622 // Save the options, to be interpreted where appropriate.
2623 // Use options_.SetAll() instead of assignment so that unset value in options
2624 // will not overwrite the previous option value.
2625 options_.SetAll(options);
2626
2627 // Set CPU options for all send channels.
2628 for (SendChannelMap::iterator iter = send_channels_.begin();
2629 iter != send_channels_.end(); ++iter) {
2630 WebRtcVideoChannelSendInfo* send_channel = iter->second;
2631 send_channel->ApplyCpuOptions(options_);
2632 }
2633
2634 // Adjust send codec bitrate if needed.
2635 int conf_max_bitrate = kDefaultConferenceModeMaxVideoBitrate;
2636
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002637 // Save altered min_bitrate level and apply if necessary.
2638 bool adjusted_min_bitrate = false;
2639 if (options.lower_min_bitrate.IsSet()) {
2640 bool lower;
2641 options.lower_min_bitrate.Get(&lower);
2642
2643 int new_send_min_bitrate = lower ? kLowerMinBitrate : kMinVideoBitrate;
2644 adjusted_min_bitrate = (new_send_min_bitrate != send_min_bitrate_);
2645 send_min_bitrate_ = new_send_min_bitrate;
2646 }
2647
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002648 int expected_bitrate = send_max_bitrate_;
2649 if (InConferenceMode()) {
2650 expected_bitrate = conf_max_bitrate;
2651 } else if (conference_mode_turned_off) {
2652 // This is a special case for turning conference mode off.
2653 // Max bitrate should go back to the default maximum value instead
2654 // of the current maximum.
2655 expected_bitrate = kMaxVideoBitrate;
2656 }
2657
2658 if (send_codec_ &&
wu@webrtc.orgcecfd182013-10-30 05:18:12 +00002659 (send_max_bitrate_ != expected_bitrate || denoiser_changed ||
2660 adjusted_min_bitrate)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002661 // On success, SetSendCodec() will reset send_max_bitrate_ to
2662 // expected_bitrate.
2663 if (!SetSendCodec(*send_codec_,
2664 send_min_bitrate_,
2665 send_start_bitrate_,
2666 expected_bitrate)) {
2667 return false;
2668 }
2669 LogSendCodecChange("SetOptions()");
2670 }
2671 if (leaky_bucket_changed) {
2672 bool enable_leaky_bucket =
2673 options_.video_leaky_bucket.GetWithDefaultIfUnset(false);
2674 for (SendChannelMap::iterator it = send_channels_.begin();
2675 it != send_channels_.end(); ++it) {
2676 if (engine()->vie()->rtp()->SetTransmissionSmoothingStatus(
2677 it->second->channel_id(), enable_leaky_bucket) != 0) {
2678 LOG_RTCERR2(SetTransmissionSmoothingStatus, it->second->channel_id(),
2679 enable_leaky_bucket);
2680 }
2681 }
2682 }
2683 if (buffer_latency_changed) {
2684 int buffer_latency =
2685 options_.buffered_mode_latency.GetWithDefaultIfUnset(
2686 cricket::kBufferedModeDisabled);
2687 for (SendChannelMap::iterator it = send_channels_.begin();
2688 it != send_channels_.end(); ++it) {
2689 if (engine()->vie()->rtp()->SetSenderBufferingMode(
2690 it->second->channel_id(), buffer_latency) != 0) {
2691 LOG_RTCERR2(SetSenderBufferingMode, it->second->channel_id(),
2692 buffer_latency);
2693 }
2694 }
2695 for (RecvChannelMap::iterator it = recv_channels_.begin();
2696 it != recv_channels_.end(); ++it) {
2697 if (engine()->vie()->rtp()->SetReceiverBufferingMode(
2698 it->second->channel_id(), buffer_latency) != 0) {
2699 LOG_RTCERR2(SetReceiverBufferingMode, it->second->channel_id(),
2700 buffer_latency);
2701 }
2702 }
2703 }
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00002704 if (cpu_overuse_detection_changed) {
2705 bool cpu_overuse_detection =
2706 options_.cpu_overuse_detection.GetWithDefaultIfUnset(false);
2707 for (SendChannelMap::iterator iter = send_channels_.begin();
2708 iter != send_channels_.end(); ++iter) {
2709 WebRtcVideoChannelSendInfo* send_channel = iter->second;
2710 send_channel->SetCpuOveruseDetection(cpu_overuse_detection);
2711 }
2712 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002713 return true;
2714}
2715
2716void WebRtcVideoMediaChannel::SetInterface(NetworkInterface* iface) {
2717 MediaChannel::SetInterface(iface);
2718 // Set the RTP recv/send buffer to a bigger size
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00002719 MediaChannel::SetOption(NetworkInterface::ST_RTP,
2720 talk_base::Socket::OPT_RCVBUF,
2721 kVideoRtpBufferSize);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002722
2723 // TODO(sriniv): Remove or re-enable this.
2724 // As part of b/8030474, send-buffer is size now controlled through
2725 // portallocator flags.
2726 // network_interface_->SetOption(NetworkInterface::ST_RTP,
2727 // talk_base::Socket::OPT_SNDBUF,
2728 // kVideoRtpBufferSize);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002729}
2730
2731void WebRtcVideoMediaChannel::UpdateAspectRatio(int ratio_w, int ratio_h) {
2732 ASSERT(ratio_w != 0);
2733 ASSERT(ratio_h != 0);
2734 ratio_w_ = ratio_w;
2735 ratio_h_ = ratio_h;
2736 // For now assume that all streams want the same aspect ratio.
2737 // TODO(hellner): remove the need for this assumption.
2738 for (SendChannelMap::iterator iter = send_channels_.begin();
2739 iter != send_channels_.end(); ++iter) {
2740 WebRtcVideoChannelSendInfo* send_channel = iter->second;
2741 VideoCapturer* capturer = send_channel->video_capturer();
2742 if (capturer) {
2743 capturer->UpdateAspectRatio(ratio_w, ratio_h);
2744 }
2745 }
2746}
2747
2748bool WebRtcVideoMediaChannel::GetRenderer(uint32 ssrc,
2749 VideoRenderer** renderer) {
2750 RecvChannelMap::const_iterator it = recv_channels_.find(ssrc);
2751 if (it == recv_channels_.end()) {
2752 if (first_receive_ssrc_ == ssrc &&
2753 recv_channels_.find(0) != recv_channels_.end()) {
2754 LOG(LS_INFO) << " GetRenderer " << ssrc
2755 << " reuse default renderer #"
2756 << vie_channel_;
2757 *renderer = recv_channels_[0]->render_adapter()->renderer();
2758 return true;
2759 }
2760 return false;
2761 }
2762
2763 *renderer = it->second->render_adapter()->renderer();
2764 return true;
2765}
2766
2767void WebRtcVideoMediaChannel::AdaptAndSendFrame(VideoCapturer* capturer,
2768 const VideoFrame* frame) {
2769 if (capturer->IsScreencast()) {
2770 // Do not adapt frames that are screencast.
2771 SendFrame(capturer, frame);
2772 return;
2773 }
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002774 // TODO(thorcarpenter): This is broken. One capturer registered on two ssrc
2775 // will not send any video to the second ssrc send channel. We should remove
2776 // GetSendChannel(capturer) and pass in an ssrc here.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002777 WebRtcVideoChannelSendInfo* send_channel = GetSendChannel(capturer);
2778 if (!send_channel) {
2779 SendFrame(capturer, frame);
2780 return;
2781 }
2782 const VideoFrame* output_frame = NULL;
2783 send_channel->AdaptFrame(frame, &output_frame);
2784 if (output_frame) {
2785 SendFrame(send_channel, output_frame, capturer->IsScreencast());
2786 }
2787}
2788
2789// TODO(zhurunz): Add unittests to test this function.
2790void WebRtcVideoMediaChannel::SendFrame(VideoCapturer* capturer,
2791 const VideoFrame* frame) {
2792 // If there's send channel registers to the |capturer|, then only send the
2793 // frame to that channel and return. Otherwise send the frame to the default
2794 // channel, which currently taking frames from the engine.
2795 WebRtcVideoChannelSendInfo* send_channel = GetSendChannel(capturer);
2796 if (send_channel) {
2797 SendFrame(send_channel, frame, capturer->IsScreencast());
2798 return;
2799 }
2800 // TODO(hellner): Remove below for loop once the captured frame no longer
2801 // come from the engine, i.e. the engine no longer owns a capturer.
2802 for (SendChannelMap::iterator iter = send_channels_.begin();
2803 iter != send_channels_.end(); ++iter) {
2804 WebRtcVideoChannelSendInfo* send_channel = iter->second;
2805 if (send_channel->video_capturer() == NULL) {
2806 SendFrame(send_channel, frame, capturer->IsScreencast());
2807 }
2808 }
2809}
2810
2811bool WebRtcVideoMediaChannel::SendFrame(
2812 WebRtcVideoChannelSendInfo* send_channel,
2813 const VideoFrame* frame,
2814 bool is_screencast) {
2815 if (!send_channel) {
2816 return false;
2817 }
2818 if (!send_codec_) {
2819 // Send codec has not been set. No reason to process the frame any further.
2820 return false;
2821 }
2822 const VideoFormat& video_format = send_channel->video_format();
2823 // If the frame should be dropped.
2824 const bool video_format_set = video_format != cricket::VideoFormat();
2825 if (video_format_set &&
2826 (video_format.width == 0 && video_format.height == 0)) {
2827 return true;
2828 }
2829
2830 // Checks if we need to reset vie send codec.
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002831 if (!MaybeResetVieSendCodec(send_channel,
2832 static_cast<int>(frame->GetWidth()),
2833 static_cast<int>(frame->GetHeight()),
2834 is_screencast, NULL)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002835 LOG(LS_ERROR) << "MaybeResetVieSendCodec failed with "
2836 << frame->GetWidth() << "x" << frame->GetHeight();
2837 return false;
2838 }
2839 const VideoFrame* frame_out = frame;
2840 talk_base::scoped_ptr<VideoFrame> processed_frame;
2841 // Disable muting for screencast.
2842 const bool mute = (send_channel->muted() && !is_screencast);
2843 send_channel->ProcessFrame(*frame_out, mute, processed_frame.use());
2844 if (processed_frame) {
2845 frame_out = processed_frame.get();
2846 }
2847
2848 webrtc::ViEVideoFrameI420 frame_i420;
2849 // TODO(ronghuawu): Update the webrtc::ViEVideoFrameI420
2850 // to use const unsigned char*
2851 frame_i420.y_plane = const_cast<unsigned char*>(frame_out->GetYPlane());
2852 frame_i420.u_plane = const_cast<unsigned char*>(frame_out->GetUPlane());
2853 frame_i420.v_plane = const_cast<unsigned char*>(frame_out->GetVPlane());
2854 frame_i420.y_pitch = frame_out->GetYPitch();
2855 frame_i420.u_pitch = frame_out->GetUPitch();
2856 frame_i420.v_pitch = frame_out->GetVPitch();
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00002857 frame_i420.width = static_cast<uint16>(frame_out->GetWidth());
2858 frame_i420.height = static_cast<uint16>(frame_out->GetHeight());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002859
2860 int64 timestamp_ntp_ms = 0;
2861 // TODO(justinlin): Reenable after Windows issues with clock drift are fixed.
2862 // Currently reverted to old behavior of discarding capture timestamp.
2863#if 0
2864 // If the frame timestamp is 0, we will use the deliver time.
2865 const int64 frame_timestamp = frame->GetTimeStamp();
2866 if (frame_timestamp != 0) {
2867 if (abs(time(NULL) - frame_timestamp / talk_base::kNumNanosecsPerSec) >
2868 kTimestampDeltaInSecondsForWarning) {
2869 LOG(LS_WARNING) << "Frame timestamp differs by more than "
2870 << kTimestampDeltaInSecondsForWarning << " seconds from "
2871 << "current Unix timestamp.";
2872 }
2873
2874 timestamp_ntp_ms =
2875 talk_base::UnixTimestampNanosecsToNtpMillisecs(frame_timestamp);
2876 }
2877#endif
2878
2879 return send_channel->external_capture()->IncomingFrameI420(
2880 frame_i420, timestamp_ntp_ms) == 0;
2881}
2882
2883bool WebRtcVideoMediaChannel::CreateChannel(uint32 ssrc_key,
2884 MediaDirection direction,
2885 int* channel_id) {
2886 // There are 3 types of channels. Sending only, receiving only and
2887 // sending and receiving. The sending and receiving channel is the
2888 // default channel and there is only one. All other channels that are created
2889 // are associated with the default channel which must exist. The default
2890 // channel id is stored in |vie_channel_|. All channels need to know about
2891 // the default channel to properly handle remb which is why there are
2892 // different ViE create channel calls.
2893 // For this channel the local and remote ssrc key is 0. However, it may
2894 // have a non-zero local and/or remote ssrc depending on if it is currently
2895 // sending and/or receiving.
2896 if ((vie_channel_ == -1 || direction == MD_SENDRECV) &&
2897 (!send_channels_.empty() || !recv_channels_.empty())) {
2898 ASSERT(false);
2899 return false;
2900 }
2901
2902 *channel_id = -1;
2903 if (direction == MD_RECV) {
2904 // All rec channels are associated with the default channel |vie_channel_|
2905 if (engine_->vie()->base()->CreateReceiveChannel(*channel_id,
2906 vie_channel_) != 0) {
2907 LOG_RTCERR2(CreateReceiveChannel, *channel_id, vie_channel_);
2908 return false;
2909 }
2910 } else if (direction == MD_SEND) {
2911 if (engine_->vie()->base()->CreateChannel(*channel_id,
2912 vie_channel_) != 0) {
2913 LOG_RTCERR2(CreateChannel, *channel_id, vie_channel_);
2914 return false;
2915 }
2916 } else {
2917 ASSERT(direction == MD_SENDRECV);
2918 if (engine_->vie()->base()->CreateChannel(*channel_id) != 0) {
2919 LOG_RTCERR1(CreateChannel, *channel_id);
2920 return false;
2921 }
2922 }
2923 if (!ConfigureChannel(*channel_id, direction, ssrc_key)) {
2924 engine_->vie()->base()->DeleteChannel(*channel_id);
2925 *channel_id = -1;
2926 return false;
2927 }
2928
2929 return true;
2930}
2931
2932bool WebRtcVideoMediaChannel::ConfigureChannel(int channel_id,
2933 MediaDirection direction,
2934 uint32 ssrc_key) {
2935 const bool receiving = (direction == MD_RECV) || (direction == MD_SENDRECV);
2936 const bool sending = (direction == MD_SEND) || (direction == MD_SENDRECV);
2937 // Register external transport.
2938 if (engine_->vie()->network()->RegisterSendTransport(
2939 channel_id, *this) != 0) {
2940 LOG_RTCERR1(RegisterSendTransport, channel_id);
2941 return false;
2942 }
2943
2944 // Set MTU.
2945 if (engine_->vie()->network()->SetMTU(channel_id, kVideoMtu) != 0) {
2946 LOG_RTCERR2(SetMTU, channel_id, kVideoMtu);
2947 return false;
2948 }
2949 // Turn on RTCP and loss feedback reporting.
2950 if (engine()->vie()->rtp()->SetRTCPStatus(
2951 channel_id, webrtc::kRtcpCompound_RFC4585) != 0) {
2952 LOG_RTCERR2(SetRTCPStatus, channel_id, webrtc::kRtcpCompound_RFC4585);
2953 return false;
2954 }
2955 // Enable pli as key frame request method.
2956 if (engine_->vie()->rtp()->SetKeyFrameRequestMethod(
2957 channel_id, webrtc::kViEKeyFrameRequestPliRtcp) != 0) {
2958 LOG_RTCERR2(SetKeyFrameRequestMethod,
2959 channel_id, webrtc::kViEKeyFrameRequestPliRtcp);
2960 return false;
2961 }
2962 if (!SetNackFec(channel_id, send_red_type_, send_fec_type_, nack_enabled_)) {
2963 // Logged in SetNackFec. Don't spam the logs.
2964 return false;
2965 }
2966 // Note that receiving must always be configured before sending to ensure
2967 // that send and receive channel is configured correctly (ConfigureReceiving
2968 // assumes no sending).
2969 if (receiving) {
2970 if (!ConfigureReceiving(channel_id, ssrc_key)) {
2971 return false;
2972 }
2973 }
2974 if (sending) {
2975 if (!ConfigureSending(channel_id, ssrc_key)) {
2976 return false;
2977 }
2978 }
2979
2980 return true;
2981}
2982
2983bool WebRtcVideoMediaChannel::ConfigureReceiving(int channel_id,
2984 uint32 remote_ssrc_key) {
2985 // Make sure that an SSRC/key isn't registered more than once.
2986 if (recv_channels_.find(remote_ssrc_key) != recv_channels_.end()) {
2987 return false;
2988 }
2989 // Connect the voice channel, if there is one.
2990 // TODO(perkj): The A/V is synched by the receiving channel. So we need to
2991 // know the SSRC of the remote audio channel in order to fetch the correct
2992 // webrtc VoiceEngine channel. For now- only sync the default channel used
2993 // in 1-1 calls.
2994 if (remote_ssrc_key == 0 && voice_channel_) {
2995 WebRtcVoiceMediaChannel* voice_channel =
2996 static_cast<WebRtcVoiceMediaChannel*>(voice_channel_);
2997 if (engine_->vie()->base()->ConnectAudioChannel(
2998 vie_channel_, voice_channel->voe_channel()) != 0) {
2999 LOG_RTCERR2(ConnectAudioChannel, channel_id,
3000 voice_channel->voe_channel());
3001 LOG(LS_WARNING) << "A/V not synchronized";
3002 // Not a fatal error.
3003 }
3004 }
3005
3006 talk_base::scoped_ptr<WebRtcVideoChannelRecvInfo> channel_info(
3007 new WebRtcVideoChannelRecvInfo(channel_id));
3008
3009 // Install a render adapter.
3010 if (engine_->vie()->render()->AddRenderer(channel_id,
3011 webrtc::kVideoI420, channel_info->render_adapter()) != 0) {
3012 LOG_RTCERR3(AddRenderer, channel_id, webrtc::kVideoI420,
3013 channel_info->render_adapter());
3014 return false;
3015 }
3016
3017
3018 if (engine_->vie()->rtp()->SetRembStatus(channel_id,
3019 kNotSending,
3020 remb_enabled_) != 0) {
3021 LOG_RTCERR3(SetRembStatus, channel_id, kNotSending, remb_enabled_);
3022 return false;
3023 }
3024
3025 if (!SetHeaderExtension(&webrtc::ViERTP_RTCP::SetReceiveTimestampOffsetStatus,
3026 channel_id, receive_extensions_, kRtpTimestampOffsetHeaderExtension)) {
3027 return false;
3028 }
3029
3030 if (!SetHeaderExtension(
3031 &webrtc::ViERTP_RTCP::SetReceiveAbsoluteSendTimeStatus, channel_id,
3032 receive_extensions_, kRtpAbsoluteSendTimeHeaderExtension)) {
3033 return false;
3034 }
3035
3036 if (remote_ssrc_key != 0) {
3037 // Use the same SSRC as our default channel
3038 // (so the RTCP reports are correct).
3039 unsigned int send_ssrc = 0;
3040 webrtc::ViERTP_RTCP* rtp = engine()->vie()->rtp();
3041 if (rtp->GetLocalSSRC(vie_channel_, send_ssrc) == -1) {
3042 LOG_RTCERR2(GetLocalSSRC, vie_channel_, send_ssrc);
3043 return false;
3044 }
3045 if (rtp->SetLocalSSRC(channel_id, send_ssrc) == -1) {
3046 LOG_RTCERR2(SetLocalSSRC, channel_id, send_ssrc);
3047 return false;
3048 }
3049 } // Else this is the the default channel and we don't change the SSRC.
3050
3051 // Disable color enhancement since it is a bit too aggressive.
3052 if (engine()->vie()->image()->EnableColorEnhancement(channel_id,
3053 false) != 0) {
3054 LOG_RTCERR1(EnableColorEnhancement, channel_id);
3055 return false;
3056 }
3057
3058 if (!SetReceiveCodecs(channel_info.get())) {
3059 return false;
3060 }
3061
3062 int buffer_latency =
3063 options_.buffered_mode_latency.GetWithDefaultIfUnset(
3064 cricket::kBufferedModeDisabled);
3065 if (buffer_latency != cricket::kBufferedModeDisabled) {
3066 if (engine()->vie()->rtp()->SetReceiverBufferingMode(
3067 channel_id, buffer_latency) != 0) {
3068 LOG_RTCERR2(SetReceiverBufferingMode, channel_id, buffer_latency);
3069 }
3070 }
3071
3072 if (render_started_) {
3073 if (engine_->vie()->render()->StartRender(channel_id) != 0) {
3074 LOG_RTCERR1(StartRender, channel_id);
3075 return false;
3076 }
3077 }
3078
3079 // Register decoder observer for incoming framerate and bitrate.
3080 if (engine()->vie()->codec()->RegisterDecoderObserver(
3081 channel_id, *channel_info->decoder_observer()) != 0) {
3082 LOG_RTCERR1(RegisterDecoderObserver, channel_info->decoder_observer());
3083 return false;
3084 }
3085
3086 recv_channels_[remote_ssrc_key] = channel_info.release();
3087 return true;
3088}
3089
3090bool WebRtcVideoMediaChannel::ConfigureSending(int channel_id,
3091 uint32 local_ssrc_key) {
3092 // The ssrc key can be zero or correspond to an SSRC.
3093 // Make sure the default channel isn't configured more than once.
3094 if (local_ssrc_key == 0 && send_channels_.find(0) != send_channels_.end()) {
3095 return false;
3096 }
3097 // Make sure that the SSRC is not already in use.
3098 uint32 dummy_key;
3099 if (GetSendChannelKey(local_ssrc_key, &dummy_key)) {
3100 return false;
3101 }
3102 int vie_capture = 0;
3103 webrtc::ViEExternalCapture* external_capture = NULL;
3104 // Register external capture.
3105 if (engine()->vie()->capture()->AllocateExternalCaptureDevice(
3106 vie_capture, external_capture) != 0) {
3107 LOG_RTCERR0(AllocateExternalCaptureDevice);
3108 return false;
3109 }
3110
3111 // Connect external capture.
3112 if (engine()->vie()->capture()->ConnectCaptureDevice(
3113 vie_capture, channel_id) != 0) {
3114 LOG_RTCERR2(ConnectCaptureDevice, vie_capture, channel_id);
3115 return false;
3116 }
3117 talk_base::scoped_ptr<WebRtcVideoChannelSendInfo> send_channel(
3118 new WebRtcVideoChannelSendInfo(channel_id, vie_capture,
3119 external_capture,
3120 engine()->cpu_monitor()));
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00003121 if (engine()->vie()->base()->RegisterCpuOveruseObserver(
3122 channel_id, send_channel->overuse_observer())) {
3123 LOG_RTCERR1(RegisterCpuOveruseObserver, channel_id);
3124 return false;
3125 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003126 send_channel->ApplyCpuOptions(options_);
wu@webrtc.orgd64719d2013-08-01 00:00:07 +00003127 send_channel->SignalCpuAdaptationUnable.connect(this,
3128 &WebRtcVideoMediaChannel::OnCpuAdaptationUnable);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003129
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00003130 if (options_.cpu_overuse_detection.GetWithDefaultIfUnset(false)) {
3131 send_channel->SetCpuOveruseDetection(true);
3132 }
3133
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003134 // Register encoder observer for outgoing framerate and bitrate.
3135 if (engine()->vie()->codec()->RegisterEncoderObserver(
3136 channel_id, *send_channel->encoder_observer()) != 0) {
3137 LOG_RTCERR1(RegisterEncoderObserver, send_channel->encoder_observer());
3138 return false;
3139 }
3140
3141 if (!SetHeaderExtension(&webrtc::ViERTP_RTCP::SetSendTimestampOffsetStatus,
3142 channel_id, send_extensions_, kRtpTimestampOffsetHeaderExtension)) {
3143 return false;
3144 }
3145
3146 if (!SetHeaderExtension(&webrtc::ViERTP_RTCP::SetSendAbsoluteSendTimeStatus,
3147 channel_id, send_extensions_, kRtpAbsoluteSendTimeHeaderExtension)) {
3148 return false;
3149 }
3150
3151 if (options_.video_leaky_bucket.GetWithDefaultIfUnset(false)) {
3152 if (engine()->vie()->rtp()->SetTransmissionSmoothingStatus(channel_id,
3153 true) != 0) {
3154 LOG_RTCERR2(SetTransmissionSmoothingStatus, channel_id, true);
3155 return false;
3156 }
3157 }
3158
3159 int buffer_latency =
3160 options_.buffered_mode_latency.GetWithDefaultIfUnset(
3161 cricket::kBufferedModeDisabled);
3162 if (buffer_latency != cricket::kBufferedModeDisabled) {
3163 if (engine()->vie()->rtp()->SetSenderBufferingMode(
3164 channel_id, buffer_latency) != 0) {
3165 LOG_RTCERR2(SetSenderBufferingMode, channel_id, buffer_latency);
3166 }
3167 }
3168 // The remb status direction correspond to the RTP stream (and not the RTCP
3169 // stream). I.e. if send remb is enabled it means it is receiving remote
3170 // rembs and should use them to estimate bandwidth. Receive remb mean that
3171 // remb packets will be generated and that the channel should be included in
3172 // it. If remb is enabled all channels are allowed to contribute to the remb
3173 // but only receive channels will ever end up actually contributing. This
3174 // keeps the logic simple.
3175 if (engine_->vie()->rtp()->SetRembStatus(channel_id,
3176 remb_enabled_,
3177 remb_enabled_) != 0) {
3178 LOG_RTCERR3(SetRembStatus, channel_id, remb_enabled_, remb_enabled_);
3179 return false;
3180 }
3181 if (!SetNackFec(channel_id, send_red_type_, send_fec_type_, nack_enabled_)) {
3182 // Logged in SetNackFec. Don't spam the logs.
3183 return false;
3184 }
3185
3186 send_channels_[local_ssrc_key] = send_channel.release();
3187
3188 return true;
3189}
3190
3191bool WebRtcVideoMediaChannel::SetNackFec(int channel_id,
3192 int red_payload_type,
3193 int fec_payload_type,
3194 bool nack_enabled) {
3195 bool enable = (red_payload_type != -1 && fec_payload_type != -1 &&
3196 !InConferenceMode());
3197 if (enable) {
3198 if (engine_->vie()->rtp()->SetHybridNACKFECStatus(
3199 channel_id, nack_enabled, red_payload_type, fec_payload_type) != 0) {
3200 LOG_RTCERR4(SetHybridNACKFECStatus,
3201 channel_id, nack_enabled, red_payload_type, fec_payload_type);
3202 return false;
3203 }
3204 LOG(LS_INFO) << "Hybrid NACK/FEC enabled for channel " << channel_id;
3205 } else {
3206 if (engine_->vie()->rtp()->SetNACKStatus(channel_id, nack_enabled) != 0) {
3207 LOG_RTCERR1(SetNACKStatus, channel_id);
3208 return false;
3209 }
3210 LOG(LS_INFO) << "NACK enabled for channel " << channel_id;
3211 }
3212 return true;
3213}
3214
3215bool WebRtcVideoMediaChannel::SetSendCodec(const webrtc::VideoCodec& codec,
3216 int min_bitrate,
3217 int start_bitrate,
3218 int max_bitrate) {
3219 bool ret_val = true;
3220 for (SendChannelMap::iterator iter = send_channels_.begin();
3221 iter != send_channels_.end(); ++iter) {
3222 WebRtcVideoChannelSendInfo* send_channel = iter->second;
3223 ret_val = SetSendCodec(send_channel, codec, min_bitrate, start_bitrate,
3224 max_bitrate) && ret_val;
3225 }
3226 if (ret_val) {
3227 // All SetSendCodec calls were successful. Update the global state
3228 // accordingly.
3229 send_codec_.reset(new webrtc::VideoCodec(codec));
3230 send_min_bitrate_ = min_bitrate;
3231 send_start_bitrate_ = start_bitrate;
3232 send_max_bitrate_ = max_bitrate;
3233 } else {
3234 // At least one SetSendCodec call failed, rollback.
3235 for (SendChannelMap::iterator iter = send_channels_.begin();
3236 iter != send_channels_.end(); ++iter) {
3237 WebRtcVideoChannelSendInfo* send_channel = iter->second;
3238 if (send_codec_) {
3239 SetSendCodec(send_channel, *send_codec_.get(), send_min_bitrate_,
3240 send_start_bitrate_, send_max_bitrate_);
3241 }
3242 }
3243 }
3244 return ret_val;
3245}
3246
3247bool WebRtcVideoMediaChannel::SetSendCodec(
3248 WebRtcVideoChannelSendInfo* send_channel,
3249 const webrtc::VideoCodec& codec,
3250 int min_bitrate,
3251 int start_bitrate,
3252 int max_bitrate) {
3253 if (!send_channel) {
3254 return false;
3255 }
3256 const int channel_id = send_channel->channel_id();
3257 // Make a copy of the codec
3258 webrtc::VideoCodec target_codec = codec;
3259 target_codec.startBitrate = start_bitrate;
3260 target_codec.minBitrate = min_bitrate;
3261 target_codec.maxBitrate = max_bitrate;
3262
3263 // Set the default number of temporal layers for VP8.
3264 if (webrtc::kVideoCodecVP8 == codec.codecType) {
3265 target_codec.codecSpecific.VP8.numberOfTemporalLayers =
3266 kDefaultNumberOfTemporalLayers;
3267
3268 // Turn off the VP8 error resilience
3269 target_codec.codecSpecific.VP8.resilience = webrtc::kResilienceOff;
3270
3271 bool enable_denoising =
3272 options_.video_noise_reduction.GetWithDefaultIfUnset(false);
3273 target_codec.codecSpecific.VP8.denoisingOn = enable_denoising;
3274 }
3275
3276 // Register external encoder if codec type is supported by encoder factory.
3277 if (engine()->IsExternalEncoderCodecType(codec.codecType) &&
3278 !send_channel->IsEncoderRegistered(target_codec.plType)) {
3279 webrtc::VideoEncoder* encoder =
3280 engine()->CreateExternalEncoder(codec.codecType);
3281 if (encoder) {
3282 if (engine()->vie()->ext_codec()->RegisterExternalSendCodec(
3283 channel_id, target_codec.plType, encoder, false) == 0) {
3284 send_channel->RegisterEncoder(target_codec.plType, encoder);
3285 } else {
3286 LOG_RTCERR2(RegisterExternalSendCodec, channel_id, target_codec.plName);
3287 engine()->DestroyExternalEncoder(encoder);
3288 }
3289 }
3290 }
3291
3292 // Resolution and framerate may vary for different send channels.
3293 const VideoFormat& video_format = send_channel->video_format();
3294 UpdateVideoCodec(video_format, &target_codec);
3295
3296 if (target_codec.width == 0 && target_codec.height == 0) {
3297 const uint32 ssrc = send_channel->stream_params()->first_ssrc();
3298 LOG(LS_INFO) << "0x0 resolution selected. Captured frames will be dropped "
3299 << "for ssrc: " << ssrc << ".";
3300 } else {
3301 MaybeChangeStartBitrate(channel_id, &target_codec);
3302 if (0 != engine()->vie()->codec()->SetSendCodec(channel_id, target_codec)) {
3303 LOG_RTCERR2(SetSendCodec, channel_id, target_codec.plName);
3304 return false;
3305 }
3306
3307 }
3308 send_channel->set_interval(
3309 cricket::VideoFormat::FpsToInterval(target_codec.maxFramerate));
3310 return true;
3311}
3312
3313
3314static std::string ToString(webrtc::VideoCodecComplexity complexity) {
3315 switch (complexity) {
3316 case webrtc::kComplexityNormal:
3317 return "normal";
3318 case webrtc::kComplexityHigh:
3319 return "high";
3320 case webrtc::kComplexityHigher:
3321 return "higher";
3322 case webrtc::kComplexityMax:
3323 return "max";
3324 default:
3325 return "unknown";
3326 }
3327}
3328
3329static std::string ToString(webrtc::VP8ResilienceMode resilience) {
3330 switch (resilience) {
3331 case webrtc::kResilienceOff:
3332 return "off";
3333 case webrtc::kResilientStream:
3334 return "stream";
3335 case webrtc::kResilientFrames:
3336 return "frames";
3337 default:
3338 return "unknown";
3339 }
3340}
3341
3342void WebRtcVideoMediaChannel::LogSendCodecChange(const std::string& reason) {
3343 webrtc::VideoCodec vie_codec;
3344 if (engine()->vie()->codec()->GetSendCodec(vie_channel_, vie_codec) != 0) {
3345 LOG_RTCERR1(GetSendCodec, vie_channel_);
3346 return;
3347 }
3348
3349 LOG(LS_INFO) << reason << " : selected video codec "
3350 << vie_codec.plName << "/"
3351 << vie_codec.width << "x" << vie_codec.height << "x"
3352 << static_cast<int>(vie_codec.maxFramerate) << "fps"
3353 << "@" << vie_codec.maxBitrate << "kbps"
3354 << " (min=" << vie_codec.minBitrate << "kbps,"
3355 << " start=" << vie_codec.startBitrate << "kbps)";
3356 LOG(LS_INFO) << "Video max quantization: " << vie_codec.qpMax;
3357 if (webrtc::kVideoCodecVP8 == vie_codec.codecType) {
3358 LOG(LS_INFO) << "VP8 number of temporal layers: "
3359 << static_cast<int>(
3360 vie_codec.codecSpecific.VP8.numberOfTemporalLayers);
3361 LOG(LS_INFO) << "VP8 options : "
3362 << "picture loss indication = "
3363 << vie_codec.codecSpecific.VP8.pictureLossIndicationOn
3364 << ", feedback mode = "
3365 << vie_codec.codecSpecific.VP8.feedbackModeOn
3366 << ", complexity = "
3367 << ToString(vie_codec.codecSpecific.VP8.complexity)
3368 << ", resilience = "
3369 << ToString(vie_codec.codecSpecific.VP8.resilience)
3370 << ", denoising = "
3371 << vie_codec.codecSpecific.VP8.denoisingOn
3372 << ", error concealment = "
3373 << vie_codec.codecSpecific.VP8.errorConcealmentOn
3374 << ", automatic resize = "
3375 << vie_codec.codecSpecific.VP8.automaticResizeOn
3376 << ", frame dropping = "
3377 << vie_codec.codecSpecific.VP8.frameDroppingOn
3378 << ", key frame interval = "
3379 << vie_codec.codecSpecific.VP8.keyFrameInterval;
3380 }
3381
3382}
3383
3384bool WebRtcVideoMediaChannel::SetReceiveCodecs(
3385 WebRtcVideoChannelRecvInfo* info) {
3386 int red_type = -1;
3387 int fec_type = -1;
3388 int channel_id = info->channel_id();
3389 for (std::vector<webrtc::VideoCodec>::iterator it = receive_codecs_.begin();
3390 it != receive_codecs_.end(); ++it) {
3391 if (it->codecType == webrtc::kVideoCodecRED) {
3392 red_type = it->plType;
3393 } else if (it->codecType == webrtc::kVideoCodecULPFEC) {
3394 fec_type = it->plType;
3395 }
3396 if (engine()->vie()->codec()->SetReceiveCodec(channel_id, *it) != 0) {
3397 LOG_RTCERR2(SetReceiveCodec, channel_id, it->plName);
3398 return false;
3399 }
3400 if (!info->IsDecoderRegistered(it->plType) &&
3401 it->codecType != webrtc::kVideoCodecRED &&
3402 it->codecType != webrtc::kVideoCodecULPFEC) {
3403 webrtc::VideoDecoder* decoder =
3404 engine()->CreateExternalDecoder(it->codecType);
3405 if (decoder) {
3406 if (engine()->vie()->ext_codec()->RegisterExternalReceiveCodec(
3407 channel_id, it->plType, decoder) == 0) {
3408 info->RegisterDecoder(it->plType, decoder);
3409 } else {
3410 LOG_RTCERR2(RegisterExternalReceiveCodec, channel_id, it->plName);
3411 engine()->DestroyExternalDecoder(decoder);
3412 }
3413 }
3414 }
3415 }
3416
3417 // Start receiving packets if at least one receive codec has been set.
3418 if (!receive_codecs_.empty()) {
3419 if (engine()->vie()->base()->StartReceive(channel_id) != 0) {
3420 LOG_RTCERR1(StartReceive, channel_id);
3421 return false;
3422 }
3423 }
3424 return true;
3425}
3426
3427int WebRtcVideoMediaChannel::GetRecvChannelNum(uint32 ssrc) {
3428 if (ssrc == first_receive_ssrc_) {
3429 return vie_channel_;
3430 }
3431 RecvChannelMap::iterator it = recv_channels_.find(ssrc);
3432 return (it != recv_channels_.end()) ? it->second->channel_id() : -1;
3433}
3434
3435// If the new frame size is different from the send codec size we set on vie,
3436// we need to reset the send codec on vie.
3437// The new send codec size should not exceed send_codec_ which is controlled
3438// only by the 'jec' logic.
3439bool WebRtcVideoMediaChannel::MaybeResetVieSendCodec(
3440 WebRtcVideoChannelSendInfo* send_channel,
3441 int new_width,
3442 int new_height,
3443 bool is_screencast,
3444 bool* reset) {
3445 if (reset) {
3446 *reset = false;
3447 }
3448 ASSERT(send_codec_.get() != NULL);
3449
3450 webrtc::VideoCodec target_codec = *send_codec_.get();
3451 const VideoFormat& video_format = send_channel->video_format();
3452 UpdateVideoCodec(video_format, &target_codec);
3453
3454 // Vie send codec size should not exceed target_codec.
3455 int target_width = new_width;
3456 int target_height = new_height;
3457 if (!is_screencast &&
3458 (new_width > target_codec.width || new_height > target_codec.height)) {
3459 target_width = target_codec.width;
3460 target_height = target_codec.height;
3461 }
3462
3463 // Get current vie codec.
3464 webrtc::VideoCodec vie_codec;
3465 const int channel_id = send_channel->channel_id();
3466 if (engine()->vie()->codec()->GetSendCodec(channel_id, vie_codec) != 0) {
3467 LOG_RTCERR1(GetSendCodec, channel_id);
3468 return false;
3469 }
3470 const int cur_width = vie_codec.width;
3471 const int cur_height = vie_codec.height;
3472
3473 // Only reset send codec when there is a size change. Additionally,
3474 // automatic resize needs to be turned off when screencasting and on when
3475 // not screencasting.
3476 // Don't allow automatic resizing for screencasting.
3477 bool automatic_resize = !is_screencast;
3478 // Turn off VP8 frame dropping when screensharing as the current model does
3479 // not work well at low fps.
3480 bool vp8_frame_dropping = !is_screencast;
3481 // Disable denoising for screencasting.
3482 bool enable_denoising =
3483 options_.video_noise_reduction.GetWithDefaultIfUnset(false);
3484 bool denoising = !is_screencast && enable_denoising;
3485 bool reset_send_codec =
3486 target_width != cur_width || target_height != cur_height ||
3487 automatic_resize != vie_codec.codecSpecific.VP8.automaticResizeOn ||
3488 denoising != vie_codec.codecSpecific.VP8.denoisingOn ||
3489 vp8_frame_dropping != vie_codec.codecSpecific.VP8.frameDroppingOn;
3490
3491 if (reset_send_codec) {
3492 // Set the new codec on vie.
3493 vie_codec.width = target_width;
3494 vie_codec.height = target_height;
3495 vie_codec.maxFramerate = target_codec.maxFramerate;
3496 vie_codec.startBitrate = target_codec.startBitrate;
3497 vie_codec.codecSpecific.VP8.automaticResizeOn = automatic_resize;
3498 vie_codec.codecSpecific.VP8.denoisingOn = denoising;
3499 vie_codec.codecSpecific.VP8.frameDroppingOn = vp8_frame_dropping;
3500 // TODO(mflodman): Remove 'is_screencast' check when screen cast settings
3501 // are treated correctly in WebRTC.
3502 if (!is_screencast)
3503 MaybeChangeStartBitrate(channel_id, &vie_codec);
3504
3505 if (engine()->vie()->codec()->SetSendCodec(channel_id, vie_codec) != 0) {
3506 LOG_RTCERR1(SetSendCodec, channel_id);
3507 return false;
3508 }
3509 if (reset) {
3510 *reset = true;
3511 }
3512 LogSendCodecChange("Capture size changed");
3513 }
3514
3515 return true;
3516}
3517
3518void WebRtcVideoMediaChannel::MaybeChangeStartBitrate(
3519 int channel_id, webrtc::VideoCodec* video_codec) {
3520 if (video_codec->startBitrate < video_codec->minBitrate) {
3521 video_codec->startBitrate = video_codec->minBitrate;
3522 } else if (video_codec->startBitrate > video_codec->maxBitrate) {
3523 video_codec->startBitrate = video_codec->maxBitrate;
3524 }
3525
3526 // Use a previous target bitrate, if there is one.
3527 unsigned int current_target_bitrate = 0;
3528 if (engine()->vie()->codec()->GetCodecTargetBitrate(
3529 channel_id, &current_target_bitrate) == 0) {
3530 // Convert to kbps.
3531 current_target_bitrate /= 1000;
3532 if (current_target_bitrate > video_codec->maxBitrate) {
3533 current_target_bitrate = video_codec->maxBitrate;
3534 }
3535 if (current_target_bitrate > video_codec->startBitrate) {
3536 video_codec->startBitrate = current_target_bitrate;
3537 }
3538 }
3539}
3540
3541void WebRtcVideoMediaChannel::OnMessage(talk_base::Message* msg) {
3542 FlushBlackFrameData* black_frame_data =
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00003543 static_cast<FlushBlackFrameData*>(msg->pdata);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003544 FlushBlackFrame(black_frame_data->ssrc, black_frame_data->timestamp);
3545 delete black_frame_data;
3546}
3547
3548int WebRtcVideoMediaChannel::SendPacket(int channel, const void* data,
3549 int len) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003550 talk_base::Buffer packet(data, len, kMaxRtpPacketLen);
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00003551 return MediaChannel::SendPacket(&packet) ? len : -1;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003552}
3553
3554int WebRtcVideoMediaChannel::SendRTCPPacket(int channel,
3555 const void* data,
3556 int len) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003557 talk_base::Buffer packet(data, len, kMaxRtpPacketLen);
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00003558 return MediaChannel::SendRtcp(&packet) ? len : -1;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003559}
3560
3561void WebRtcVideoMediaChannel::QueueBlackFrame(uint32 ssrc, int64 timestamp,
3562 int framerate) {
3563 if (timestamp) {
3564 FlushBlackFrameData* black_frame_data = new FlushBlackFrameData(
3565 ssrc,
3566 timestamp);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00003567 const int delay_ms = static_cast<int>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003568 2 * cricket::VideoFormat::FpsToInterval(framerate) *
3569 talk_base::kNumMillisecsPerSec / talk_base::kNumNanosecsPerSec);
3570 worker_thread()->PostDelayed(delay_ms, this, 0, black_frame_data);
3571 }
3572}
3573
3574void WebRtcVideoMediaChannel::FlushBlackFrame(uint32 ssrc, int64 timestamp) {
3575 WebRtcVideoChannelSendInfo* send_channel = GetSendChannel(ssrc);
3576 if (!send_channel) {
3577 return;
3578 }
3579 talk_base::scoped_ptr<const VideoFrame> black_frame_ptr;
3580
3581 const WebRtcLocalStreamInfo* channel_stream_info =
3582 send_channel->local_stream_info();
3583 int64 last_frame_time_stamp = channel_stream_info->time_stamp();
3584 if (last_frame_time_stamp == timestamp) {
3585 size_t last_frame_width = 0;
3586 size_t last_frame_height = 0;
3587 int64 last_frame_elapsed_time = 0;
3588 channel_stream_info->GetLastFrameInfo(&last_frame_width, &last_frame_height,
3589 &last_frame_elapsed_time);
3590 if (!last_frame_width || !last_frame_height) {
3591 return;
3592 }
3593 WebRtcVideoFrame black_frame;
3594 // Black frame is not screencast.
3595 const bool screencasting = false;
3596 const int64 timestamp_delta = send_channel->interval();
3597 if (!black_frame.InitToBlack(send_codec_->width, send_codec_->height, 1, 1,
3598 last_frame_elapsed_time + timestamp_delta,
3599 last_frame_time_stamp + timestamp_delta) ||
3600 !SendFrame(send_channel, &black_frame, screencasting)) {
3601 LOG(LS_ERROR) << "Failed to send black frame.";
3602 }
3603 }
3604}
3605
wu@webrtc.orgd64719d2013-08-01 00:00:07 +00003606void WebRtcVideoMediaChannel::OnCpuAdaptationUnable() {
3607 // ssrc is hardcoded to 0. This message is based on a system wide issue,
3608 // so finding which ssrc caused it doesn't matter.
3609 SignalMediaError(0, VideoMediaChannel::ERROR_REC_CPU_MAX_CANT_DOWNGRADE);
3610}
3611
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003612void WebRtcVideoMediaChannel::SetNetworkTransmissionState(
3613 bool is_transmitting) {
3614 LOG(LS_INFO) << "SetNetworkTransmissionState: " << is_transmitting;
3615 for (SendChannelMap::iterator iter = send_channels_.begin();
3616 iter != send_channels_.end(); ++iter) {
3617 WebRtcVideoChannelSendInfo* send_channel = iter->second;
3618 int channel_id = send_channel->channel_id();
3619 engine_->vie()->network()->SetNetworkTransmissionState(channel_id,
3620 is_transmitting);
3621 }
3622}
3623
3624bool WebRtcVideoMediaChannel::SetHeaderExtension(ExtensionSetterFunction setter,
3625 int channel_id, const RtpHeaderExtension* extension) {
3626 bool enable = false;
3627 int id = 0;
3628 if (extension) {
3629 enable = true;
3630 id = extension->id;
3631 }
3632 if ((engine_->vie()->rtp()->*setter)(channel_id, enable, id) != 0) {
3633 LOG_RTCERR4(*setter, extension->uri, channel_id, enable, id);
3634 return false;
3635 }
3636 return true;
3637}
3638
3639bool WebRtcVideoMediaChannel::SetHeaderExtension(ExtensionSetterFunction setter,
3640 int channel_id, const std::vector<RtpHeaderExtension>& extensions,
3641 const char header_extension_uri[]) {
3642 const RtpHeaderExtension* extension = FindHeaderExtension(extensions,
3643 header_extension_uri);
3644 return SetHeaderExtension(setter, channel_id, extension);
3645}
3646} // namespace cricket
3647
3648#endif // HAVE_WEBRTC_VIDEO