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