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