18bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
28bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
38bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// found in the LICENSE file.
48bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/renderer/media/cast_rtp_stream.h"
68bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/bind.h"
823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "base/debug/trace_event.h"
98bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/logging.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/memory/weak_ptr.h"
115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/strings/stringprintf.h"
12c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/sys_info.h"
131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/renderer/media/cast_session.h"
141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/renderer/media/cast_udp_transport.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/renderer/media_stream_audio_sink.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/renderer/media_stream_video_sink.h"
1723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "content/public/renderer/render_thread.h"
18e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "content/public/renderer/video_encode_accelerator.h"
19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "media/audio/audio_parameters.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "media/base/audio_bus.h"
21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "media/base/audio_fifo.h"
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "media/base/bind_to_current_loop.h"
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "media/base/multi_channel_resampler.h"
24effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "media/base/video_frame.h"
25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "media/cast/cast_config.h"
26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "media/cast/cast_defines.h"
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "media/cast/cast_sender.h"
28116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/cast/net/cast_transport_config.h"
29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
30effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "ui/gfx/geometry/size.h"
318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using media::cast::AudioSenderConfig;
33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using media::cast::VideoSenderConfig;
34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace {
36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const char kCodecNameOpus[] = "OPUS";
38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const char kCodecNameVp8[] = "VP8";
39e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochconst char kCodecNameH264[] = "H264";
40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
41effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// To convert from kilobits per second to bits to per second.
42effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochconst int kBitrateMultiplier = 1000;
43effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// This constant defines the number of sets of audio data to buffer
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// in the FIFO. If input audio and output data have different resampling
46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// rates then buffer is necessary to avoid audio glitches.
47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// See CastAudioSink::ResampleData() and CastAudioSink::OnSetFormat()
48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// for more defaults.
49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kBufferAudioData = 2;
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)CastRtpPayloadParams DefaultOpusPayload() {
52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  CastRtpPayloadParams payload;
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  payload.payload_type = 127;
54c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  payload.max_latency_ms = media::cast::kDefaultRtpMaxDelayMs;
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  payload.ssrc = 1;
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  payload.feedback_ssrc = 2;
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  payload.clock_rate = media::cast::kDefaultAudioSamplingRate;
58effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // The value is 0 which means VBR.
59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  payload.min_bitrate = payload.max_bitrate =
60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      media::cast::kDefaultAudioEncoderBitrate;
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  payload.channels = 2;
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  payload.max_frame_rate = 100;  // 10 ms audio frames
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  payload.codec_name = kCodecNameOpus;
64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return payload;
65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)CastRtpPayloadParams DefaultVp8Payload() {
68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  CastRtpPayloadParams payload;
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  payload.payload_type = 96;
70c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  payload.max_latency_ms = media::cast::kDefaultRtpMaxDelayMs;
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  payload.ssrc = 11;
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  payload.feedback_ssrc = 12;
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  payload.clock_rate = media::cast::kVideoFrequency;
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  payload.max_bitrate = 2000;
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  payload.min_bitrate = 50;
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  payload.channels = 1;
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  payload.max_frame_rate = media::cast::kDefaultMaxFrameRate;
78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  payload.width = 1280;
79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  payload.height = 720;
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  payload.codec_name = kCodecNameVp8;
81f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return payload;
82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
84e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochCastRtpPayloadParams DefaultH264Payload() {
85e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  CastRtpPayloadParams payload;
86e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // TODO(hshi): set different ssrc/rtpPayloadType values for H264 and VP8
87e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // once b/13696137 is fixed.
88e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  payload.payload_type = 96;
89c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  payload.max_latency_ms = media::cast::kDefaultRtpMaxDelayMs;
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  payload.ssrc = 11;
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  payload.feedback_ssrc = 12;
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  payload.clock_rate = media::cast::kVideoFrequency;
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  payload.max_bitrate = 2000;
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  payload.min_bitrate = 50;
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  payload.channels = 1;
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  payload.max_frame_rate = media::cast::kDefaultMaxFrameRate;
97e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  payload.width = 1280;
98e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  payload.height = 720;
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  payload.codec_name = kCodecNameH264;
100e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  return payload;
101e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
102e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
103e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochbool IsHardwareVP8EncodingSupported() {
104e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // Query for hardware VP8 encoder support.
105e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  std::vector<media::VideoEncodeAccelerator::SupportedProfile> vea_profiles =
106e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      content::GetSupportedVideoEncodeAcceleratorProfiles();
107e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  for (size_t i = 0; i < vea_profiles.size(); ++i) {
108e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    if (vea_profiles[i].profile >= media::VP8PROFILE_MIN &&
109e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        vea_profiles[i].profile <= media::VP8PROFILE_MAX) {
110e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      return true;
111e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    }
112e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
113e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  return false;
114e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
115e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
116e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochbool IsHardwareH264EncodingSupported() {
117e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // Query for hardware H.264 encoder support.
118e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  std::vector<media::VideoEncodeAccelerator::SupportedProfile> vea_profiles =
119e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      content::GetSupportedVideoEncodeAcceleratorProfiles();
120e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  for (size_t i = 0; i < vea_profiles.size(); ++i) {
121e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    if (vea_profiles[i].profile >= media::H264PROFILE_MIN &&
122e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        vea_profiles[i].profile <= media::H264PROFILE_MAX) {
123e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      return true;
124e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    }
125e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
126e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  return false;
127e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
128e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
129c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochint NumberOfEncodeThreads() {
130c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // We want to give CPU cycles for capturing and not to saturate the system
131c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // just for encoding. So on a lower end system with only 1 or 2 cores we
132c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // use only one thread for encoding.
133c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (base::SysInfo::NumberOfProcessors() <= 2)
134c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return 1;
135c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
136c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // On higher end we want to use 2 threads for encoding to reduce latency.
137c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // In theory a physical CPU core has maximum 2 hyperthreads. Having 3 or
138c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // more logical processors means the system has at least 2 physical cores.
139c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return 2;
140c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
141c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::vector<CastRtpParams> SupportedAudioParams() {
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(hclam): Fill in more codecs here.
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<CastRtpParams> supported_params;
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  supported_params.push_back(CastRtpParams(DefaultOpusPayload()));
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return supported_params;
147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::vector<CastRtpParams> SupportedVideoParams() {
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<CastRtpParams> supported_params;
151e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (IsHardwareH264EncodingSupported())
152e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    supported_params.push_back(CastRtpParams(DefaultH264Payload()));
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  supported_params.push_back(CastRtpParams(DefaultVp8Payload()));
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return supported_params;
155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool ToAudioSenderConfig(const CastRtpParams& params,
158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         AudioSenderConfig* config) {
159116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  config->ssrc = params.payload.ssrc;
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  config->incoming_feedback_ssrc = params.payload.feedback_ssrc;
161116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (config->ssrc == config->incoming_feedback_ssrc)
162116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  config->min_playout_delay =
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::TimeDelta::FromMilliseconds(
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          params.payload.min_latency_ms ?
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          params.payload.min_latency_ms :
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          params.payload.max_latency_ms);
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  config->max_playout_delay =
169116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::TimeDelta::FromMilliseconds(params.payload.max_latency_ms);
1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (config->min_playout_delay <= base::TimeDelta())
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return false;
1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (config->min_playout_delay > config->max_playout_delay)
173116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
174116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  config->rtp_payload_type = params.payload.payload_type;
175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  config->use_external_encoder = false;
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  config->frequency = params.payload.clock_rate;
177116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (config->frequency < 8000)
178116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  config->channels = params.payload.channels;
180116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (config->channels < 1)
181116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
182effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  config->bitrate = params.payload.max_bitrate * kBitrateMultiplier;
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (params.payload.codec_name == kCodecNameOpus)
184116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    config->codec = media::cast::CODEC_AUDIO_OPUS;
185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  else
186f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
187116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  config->aes_key = params.payload.aes_key;
188116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  config->aes_iv_mask = params.payload.aes_iv_mask;
189f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return true;
1908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
1918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
192f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool ToVideoSenderConfig(const CastRtpParams& params,
193f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         VideoSenderConfig* config) {
194116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  config->ssrc = params.payload.ssrc;
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  config->incoming_feedback_ssrc = params.payload.feedback_ssrc;
196116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (config->ssrc == config->incoming_feedback_ssrc)
197116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
1981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  config->min_playout_delay =
1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::TimeDelta::FromMilliseconds(
2001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          params.payload.min_latency_ms ?
2011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          params.payload.min_latency_ms :
2021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          params.payload.max_latency_ms);
2031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  config->max_playout_delay =
204116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::TimeDelta::FromMilliseconds(params.payload.max_latency_ms);
2051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (config->min_playout_delay <= base::TimeDelta())
2061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return false;
2071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (config->min_playout_delay > config->max_playout_delay)
208116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
209116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  config->rtp_payload_type = params.payload.payload_type;
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  config->width = params.payload.width;
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  config->height = params.payload.height;
212116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (config->width < 2 || config->height < 2)
213116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
214effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  config->min_bitrate = config->start_bitrate =
215effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      params.payload.min_bitrate * kBitrateMultiplier;
216effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  config->max_bitrate = params.payload.max_bitrate * kBitrateMultiplier;
217116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (config->min_bitrate > config->max_bitrate)
218116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
219116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  config->start_bitrate = config->min_bitrate;
2205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  config->max_frame_rate = static_cast<int>(
2215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      std::max(1.0, params.payload.max_frame_rate) + 0.5);
2225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (config->max_frame_rate > 120)
2235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
224e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (params.payload.codec_name == kCodecNameVp8) {
225e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    config->use_external_encoder = IsHardwareVP8EncodingSupported();
226116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    config->codec = media::cast::CODEC_VIDEO_VP8;
227e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  } else if (params.payload.codec_name == kCodecNameH264) {
228e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    config->use_external_encoder = IsHardwareH264EncodingSupported();
229116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    config->codec = media::cast::CODEC_VIDEO_H264;
230e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  } else {
231f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
232e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
233c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!config->use_external_encoder) {
234c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    config->number_of_encode_threads = NumberOfEncodeThreads();
235c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
236116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  config->aes_key = params.payload.aes_key;
237116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  config->aes_iv_mask = params.payload.aes_iv_mask;
238f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return true;
2398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
2408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// This class receives MediaStreamTrack events and video frames from a
244cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// MediaStreamTrack.
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)//
246cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Threading: Video frames are received on the IO thread and then
247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// forwarded to media::cast::VideoFrameInput through a static method.
248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Member variables of this class are only accessed on the render thread.
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class CastVideoSink : public base::SupportsWeakPtr<CastVideoSink>,
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      public content::MediaStreamVideoSink {
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // |track| provides data for this sink.
2536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // |expected_natural_size| is the expected dimension of the video frame.
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // |error_callback| is called if video formats don't match.
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CastVideoSink(const blink::WebMediaStreamTrack& track,
2566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                const gfx::Size& expected_natural_size,
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                const CastRtpStream::ErrorCallback& error_callback)
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      : track_(track),
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        sink_added_(false),
2606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        expected_natural_size_(expected_natural_size),
261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        error_callback_(error_callback) {}
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ~CastVideoSink() {
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (sink_added_)
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      RemoveFromVideoTrack(this, track_);
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
268cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // This static method is used to forward video frames to |frame_input|.
269cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  static void OnVideoFrame(
270cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // These parameters are already bound when callback is created.
2716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      const gfx::Size& expected_natural_size,
272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const CastRtpStream::ErrorCallback& error_callback,
273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const scoped_refptr<media::cast::VideoFrameInput> frame_input,
274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // These parameters are passed for each frame.
275cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const scoped_refptr<media::VideoFrame>& frame,
27646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      const media::VideoCaptureFormat& format,
27746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      const base::TimeTicks& estimated_capture_time) {
2786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (frame->natural_size() != expected_natural_size) {
2795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      error_callback.Run(
2805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          base::StringPrintf("Video frame resolution does not match config."
2815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                             " Expected %dx%d. Got %dx%d.",
2826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                             expected_natural_size.width(),
2836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                             expected_natural_size.height(),
2846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                             frame->natural_size().width(),
2856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                             frame->natural_size().height()));
28623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      return;
28723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
28946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    base::TimeTicks timestamp;
29046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (estimated_capture_time.is_null())
29146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      timestamp = base::TimeTicks::Now();
29246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    else
29346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      timestamp = estimated_capture_time;
29423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
29523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc
29623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    TRACE_EVENT_INSTANT2(
297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        "cast_perf_test", "MediaStreamVideoSink::OnVideoFrame",
29823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        TRACE_EVENT_SCOPE_THREAD,
29946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        "timestamp",  timestamp.ToInternalValue(),
300c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "time_delta", frame->timestamp().ToInternalValue());
30146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    frame_input->InsertRawVideoFrame(frame, timestamp);
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
304a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Attach this sink to a video track represented by |track_|.
305a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Data received from the track will be submitted to |frame_input|.
306a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void AddToTrack(
307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const scoped_refptr<media::cast::VideoFrameInput>& frame_input) {
308a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK(!sink_added_);
309a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    sink_added_ = true;
310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    AddToVideoTrack(
311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        this,
312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        base::Bind(
313cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            &CastVideoSink::OnVideoFrame,
3146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)            expected_natural_size_,
315cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            error_callback_,
316cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            frame_input),
317cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        track_);
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blink::WebMediaStreamTrack track_;
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool sink_added_;
3236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  gfx::Size expected_natural_size_;
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CastRtpStream::ErrorCallback error_callback_;
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(CastVideoSink);
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Receives audio data from a MediaStreamTrack. Data is submitted to
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// media::cast::FrameInput.
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)//
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Threading: Audio frames are received on the real-time audio thread.
333cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Note that RemoveFromAudioTrack() is synchronous and we have
334cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// gurantee that there will be no more audio data after calling it.
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class CastAudioSink : public base::SupportsWeakPtr<CastAudioSink>,
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      public content::MediaStreamAudioSink {
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // |track| provides data for this sink.
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // |error_callback| is called if audio formats don't match.
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CastAudioSink(const blink::WebMediaStreamTrack& track,
341a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                const CastRtpStream::ErrorCallback& error_callback,
342a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                int output_channels,
343a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                int output_sample_rate)
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      : track_(track),
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        sink_added_(false),
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        error_callback_(error_callback),
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        weak_factory_(this),
348a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        output_channels_(output_channels),
349cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        output_sample_rate_(output_sample_rate),
350cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        input_preroll_(0) {}
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ~CastAudioSink() {
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (sink_added_)
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      RemoveFromAudioTrack(this, track_);
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Called on real-time audio thread.
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // content::MediaStreamAudioSink implementation.
3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void OnData(const int16* audio_data,
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      int sample_rate,
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      int number_of_channels,
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      int number_of_frames) OVERRIDE {
363a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<media::AudioBus> input_bus;
364a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (resampler_) {
365a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      input_bus = ResampleData(
366a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          audio_data, sample_rate, number_of_channels, number_of_frames);
367a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (!input_bus)
368a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        return;
369a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    } else {
370a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      input_bus = media::AudioBus::Create(
371a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          number_of_channels, number_of_frames);
372a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      input_bus->FromInterleaved(
373a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          audio_data, number_of_frames, number_of_channels);
374a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // TODO(hclam): Pass in the accurate capture time to have good
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // audio / video sync.
378a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    frame_input_->InsertAudio(input_bus.Pass(), base::TimeTicks::Now());
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
381a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Return a resampled audio data from input. This is called when the
382a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // input sample rate doesn't match the output.
383a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // The flow of data is as follows:
384a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // |audio_data| ->
385a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  //     AudioFifo |fifo_| ->
386a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  //         MultiChannelResampler |resampler|.
387a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  //
388a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // The resampler pulls data out of the FIFO and resample the data in
389a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // frequency domain. It might call |fifo_| for more than once. But no more
390a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // than |kBufferAudioData| times. We preroll audio data into the FIFO to
391a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // make sure there's enough data for resampling.
392a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<media::AudioBus> ResampleData(
393a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const int16* audio_data,
394a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      int sample_rate,
395a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      int number_of_channels,
396a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      int number_of_frames) {
397a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK_EQ(number_of_channels, output_channels_);
398a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    fifo_input_bus_->FromInterleaved(
399a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        audio_data, number_of_frames, number_of_channels);
400a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    fifo_->Push(fifo_input_bus_.get());
401a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
402a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (input_preroll_ < kBufferAudioData - 1) {
403a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ++input_preroll_;
404a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return scoped_ptr<media::AudioBus>();
405a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
406a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
407a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<media::AudioBus> output_bus(
408a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        media::AudioBus::Create(
409a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            output_channels_,
410a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            output_sample_rate_ * fifo_input_bus_->frames() / sample_rate));
411a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
412a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Resampler will then call ProvideData() below to fetch data from
413a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // |input_data_|.
414a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    resampler_->Resample(output_bus->frames(), output_bus.get());
415a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return output_bus.Pass();
4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Called on real-time audio thread.
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void OnSetFormat(const media::AudioParameters& params) OVERRIDE {
420a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (params.sample_rate() == output_sample_rate_)
421a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return;
422a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    fifo_.reset(new media::AudioFifo(
423a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        output_channels_,
424a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        kBufferAudioData * params.frames_per_buffer()));
425a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    fifo_input_bus_ = media::AudioBus::Create(
426a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        params.channels(), params.frames_per_buffer());
427a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    resampler_.reset(new media::MultiChannelResampler(
428a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        output_channels_,
429a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        static_cast<double>(params.sample_rate()) / output_sample_rate_,
430a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        params.frames_per_buffer(),
431a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::Bind(&CastAudioSink::ProvideData, base::Unretained(this))));
4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
434a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Add this sink to the track. Data received from the track will be
435a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // submitted to |frame_input|.
436a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void AddToTrack(
437a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const scoped_refptr<media::cast::AudioFrameInput>& frame_input) {
438a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK(!sink_added_);
439a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    sink_added_ = true;
440a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
441a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // This member is written here and then accessed on the IO thread
442a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // We will not get data until AddToAudioTrack is called so it is
443a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // safe to access this member now.
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    frame_input_ = frame_input;
445a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    AddToAudioTrack(this, track_);
446a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
447a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
448a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void ProvideData(int frame_delay, media::AudioBus* output_bus) {
449a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    fifo_->Consume(output_bus, 0, output_bus->frames());
4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
4535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  blink::WebMediaStreamTrack track_;
4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool sink_added_;
4555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CastRtpStream::ErrorCallback error_callback_;
4565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::WeakPtrFactory<CastAudioSink> weak_factory_;
457a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
458a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const int output_channels_;
459a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const int output_sample_rate_;
460a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
461cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // These member are accessed on the real-time audio time only.
462a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_refptr<media::cast::AudioFrameInput> frame_input_;
463cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<media::MultiChannelResampler> resampler_;
464cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<media::AudioFifo> fifo_;
465cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<media::AudioBus> fifo_input_bus_;
466cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int input_preroll_;
4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(CastAudioSink);
4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
4705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)CastRtpParams::CastRtpParams(const CastRtpPayloadParams& payload_params)
4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : payload(payload_params) {}
4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)CastCodecSpecificParams::CastCodecSpecificParams() {}
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)CastCodecSpecificParams::~CastCodecSpecificParams() {}
477f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
478f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)CastRtpPayloadParams::CastRtpPayloadParams()
4798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    : payload_type(0),
480c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      max_latency_ms(0),
4811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      min_latency_ms(0),
4828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      ssrc(0),
4835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      feedback_ssrc(0),
4848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      clock_rate(0),
485f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      max_bitrate(0),
486f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      min_bitrate(0),
4878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      channels(0),
4885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      max_frame_rate(0.0),
4898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      width(0),
490a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      height(0) {}
4918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
492a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)CastRtpPayloadParams::~CastRtpPayloadParams() {}
4938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
494a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)CastRtpParams::CastRtpParams() {}
4958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
496a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)CastRtpParams::~CastRtpParams() {}
4978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
4985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)CastRtpStream::CastRtpStream(const blink::WebMediaStreamTrack& track,
4995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             const scoped_refptr<CastSession>& session)
5005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : track_(track), cast_session_(session), weak_factory_(this) {}
5018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
502a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)CastRtpStream::~CastRtpStream() {}
5038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
5045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::vector<CastRtpParams> CastRtpStream::GetSupportedParams() {
505f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (IsAudio())
5065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return SupportedAudioParams();
507f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  else
5085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return SupportedVideoParams();
5098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
5108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
511a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)CastRtpParams CastRtpStream::GetParams() { return params_; }
5128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
5135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void CastRtpStream::Start(const CastRtpParams& params,
5145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const base::Closure& start_callback,
5155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const base::Closure& stop_callback,
5165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const ErrorCallback& error_callback) {
5175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VLOG(1) << "CastRtpStream::Start = " << (IsAudio() ? "audio" : "video");
5185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  stop_callback_ = stop_callback;
5195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  error_callback_ = error_callback;
5205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
521f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (IsAudio()) {
522f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    AudioSenderConfig config;
523f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!ToAudioSenderConfig(params, &config)) {
5245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DidEncounterError("Invalid parameters for audio.");
5255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return;
526f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
527a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
5285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // In case of error we have to go through DidEncounterError() to stop
5295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // the streaming after reporting the error.
5305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    audio_sink_.reset(new CastAudioSink(
5315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        track_,
5325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        media::BindToCurrentLoop(base::Bind(&CastRtpStream::DidEncounterError,
533a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                            weak_factory_.GetWeakPtr())),
534a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        params.payload.channels,
535a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        params.payload.clock_rate));
5365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    cast_session_->StartAudio(
5375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        config,
53823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        base::Bind(&CastAudioSink::AddToTrack, audio_sink_->AsWeakPtr()),
53923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        base::Bind(&CastRtpStream::DidEncounterError,
54023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                   weak_factory_.GetWeakPtr()));
5415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    start_callback.Run();
542f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
543f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    VideoSenderConfig config;
544f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!ToVideoSenderConfig(params, &config)) {
5455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DidEncounterError("Invalid parameters for video.");
5465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return;
547f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
5485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // See the code for audio above for explanation of callbacks.
5495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    video_sink_.reset(new CastVideoSink(
5505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        track_,
55123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        gfx::Size(config.width, config.height),
5525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        media::BindToCurrentLoop(base::Bind(&CastRtpStream::DidEncounterError,
5535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            weak_factory_.GetWeakPtr()))));
5545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    cast_session_->StartVideo(
5555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        config,
55623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        base::Bind(&CastVideoSink::AddToTrack, video_sink_->AsWeakPtr()),
55723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        base::Bind(&CastRtpStream::DidEncounterError,
55823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                   weak_factory_.GetWeakPtr()));
5595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    start_callback.Run();
560f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
5618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
5628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
563a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void CastRtpStream::Stop() {
5645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VLOG(1) << "CastRtpStream::Stop = " << (IsAudio() ? "audio" : "video");
5655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  audio_sink_.reset();
5665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  video_sink_.reset();
567cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!stop_callback_.is_null())
568cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    stop_callback_.Run();
5698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
5708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
571a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void CastRtpStream::ToggleLogging(bool enable) {
5725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VLOG(1) << "CastRtpStream::ToggleLogging(" << enable << ") = "
5735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          << (IsAudio() ? "audio" : "video");
574a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  cast_session_->ToggleLogging(IsAudio(), enable);
575a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
576a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
577a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void CastRtpStream::GetRawEvents(
578cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::Callback<void(scoped_ptr<base::BinaryValue>)>& callback,
579cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& extra_data) {
5805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VLOG(1) << "CastRtpStream::GetRawEvents = "
5815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          << (IsAudio() ? "audio" : "video");
582cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  cast_session_->GetEventLogsAndReset(IsAudio(), extra_data, callback);
583a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
584a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
585a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void CastRtpStream::GetStats(
586a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const base::Callback<void(scoped_ptr<base::DictionaryValue>)>& callback) {
5875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VLOG(1) << "CastRtpStream::GetStats = "
5885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          << (IsAudio() ? "audio" : "video");
589a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  cast_session_->GetStatsAndReset(IsAudio(), callback);
590a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
591a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
592a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool CastRtpStream::IsAudio() const {
593f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return track_.source().type() == blink::WebMediaStreamSource::TypeAudio;
5948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
5955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void CastRtpStream::DidEncounterError(const std::string& message) {
5975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VLOG(1) << "CastRtpStream::DidEncounterError(" << message << ") = "
5985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          << (IsAudio() ? "audio" : "video");
59923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Save the WeakPtr first because the error callback might delete this object.
60023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  base::WeakPtr<CastRtpStream> ptr = weak_factory_.GetWeakPtr();
6015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  error_callback_.Run(message);
60223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  content::RenderThread::Get()->GetMessageLoop()->PostTask(
60323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      FROM_HERE,
60423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      base::Bind(&CastRtpStream::Stop, ptr));
6055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
606