OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/renderer/extensions/cast_streaming_native_handler.h" | 5 #include "chrome/renderer/extensions/cast_streaming_native_handler.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <algorithm> | 10 #include <algorithm> |
11 #include <functional> | 11 #include <functional> |
12 #include <iterator> | 12 #include <iterator> |
13 #include <memory> | 13 #include <memory> |
14 #include <string> | 14 #include <string> |
15 #include <utility> | 15 #include <utility> |
16 #include <vector> | 16 #include <vector> |
17 | 17 |
18 #include "base/location.h" | 18 #include "base/location.h" |
19 #include "base/logging.h" | 19 #include "base/logging.h" |
20 #include "base/macros.h" | 20 #include "base/macros.h" |
21 #include "base/memory/ptr_util.h" | 21 #include "base/memory/ptr_util.h" |
22 #include "base/single_thread_task_runner.h" | 22 #include "base/single_thread_task_runner.h" |
23 #include "base/strings/string_number_conversions.h" | 23 #include "base/strings/string_number_conversions.h" |
| 24 #include "base/sys_info.h" |
24 #include "base/threading/thread_task_runner_handle.h" | 25 #include "base/threading/thread_task_runner_handle.h" |
25 #include "chrome/common/extensions/api/cast_streaming_receiver_session.h" | 26 #include "chrome/common/extensions/api/cast_streaming_receiver_session.h" |
26 #include "chrome/common/extensions/api/cast_streaming_rtp_stream.h" | 27 #include "chrome/common/extensions/api/cast_streaming_rtp_stream.h" |
27 #include "chrome/common/extensions/api/cast_streaming_udp_transport.h" | 28 #include "chrome/common/extensions/api/cast_streaming_udp_transport.h" |
28 #include "chrome/renderer/media/cast_receiver_session.h" | 29 #include "chrome/renderer/media/cast_receiver_session.h" |
29 #include "chrome/renderer/media/cast_rtp_stream.h" | 30 #include "chrome/renderer/media/cast_rtp_stream.h" |
30 #include "chrome/renderer/media/cast_session.h" | 31 #include "chrome/renderer/media/cast_session.h" |
31 #include "chrome/renderer/media/cast_udp_transport.h" | 32 #include "chrome/renderer/media/cast_udp_transport.h" |
32 #include "content/public/child/v8_value_converter.h" | 33 #include "content/public/child/v8_value_converter.h" |
33 #include "content/public/renderer/media_stream_utils.h" | 34 #include "content/public/renderer/media_stream_utils.h" |
34 #include "extensions/renderer/script_context.h" | 35 #include "extensions/renderer/script_context.h" |
35 #include "media/base/audio_parameters.h" | 36 #include "media/base/audio_parameters.h" |
| 37 #include "media/base/limits.h" |
36 #include "net/base/host_port_pair.h" | 38 #include "net/base/host_port_pair.h" |
37 #include "net/base/ip_address.h" | 39 #include "net/base/ip_address.h" |
38 #include "third_party/WebKit/public/platform/WebMediaStream.h" | 40 #include "third_party/WebKit/public/platform/WebMediaStream.h" |
39 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" | 41 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" |
40 #include "third_party/WebKit/public/platform/WebURL.h" | 42 #include "third_party/WebKit/public/platform/WebURL.h" |
41 #include "third_party/WebKit/public/web/WebDOMMediaStreamTrack.h" | 43 #include "third_party/WebKit/public/web/WebDOMMediaStreamTrack.h" |
42 #include "third_party/WebKit/public/web/WebMediaStreamRegistry.h" | 44 #include "third_party/WebKit/public/web/WebMediaStreamRegistry.h" |
43 #include "url/gurl.h" | 45 #include "url/gurl.h" |
44 | 46 |
45 using content::V8ValueConverter; | 47 using content::V8ValueConverter; |
| 48 using media::cast::FrameSenderConfig; |
46 | 49 |
47 // Extension types. | 50 // Extension types. |
48 using extensions::api::cast_streaming_receiver_session::RtpReceiverParams; | 51 using extensions::api::cast_streaming_receiver_session::RtpReceiverParams; |
49 using extensions::api::cast_streaming_rtp_stream::CodecSpecificParams; | |
50 using extensions::api::cast_streaming_rtp_stream::RtpParams; | 52 using extensions::api::cast_streaming_rtp_stream::RtpParams; |
51 using extensions::api::cast_streaming_rtp_stream::RtpPayloadParams; | 53 using extensions::api::cast_streaming_rtp_stream::RtpPayloadParams; |
52 using extensions::api::cast_streaming_udp_transport::IPEndPoint; | 54 using extensions::api::cast_streaming_udp_transport::IPEndPoint; |
53 | 55 |
54 namespace extensions { | 56 namespace extensions { |
55 | 57 |
56 namespace { | 58 namespace { |
57 const char kInvalidAesIvMask[] = "Invalid value for AES IV mask"; | |
58 const char kInvalidAesKey[] = "Invalid value for AES key"; | |
59 const char kInvalidAudioParams[] = "Invalid audio params"; | |
60 const char kInvalidDestination[] = "Invalid destination"; | |
61 const char kInvalidFPS[] = "Invalid FPS"; | |
62 const char kInvalidMediaStreamURL[] = "Invalid MediaStream URL"; | |
63 const char kInvalidRtpParams[] = "Invalid value for RTP params"; | |
64 const char kInvalidLatency[] = "Invalid value for max_latency. (0-1000)"; | |
65 const char kInvalidRtpTimebase[] = "Invalid rtp_timebase. (1000-1000000)"; | |
66 const char kInvalidStreamArgs[] = "Invalid stream arguments"; | |
67 const char kRtpStreamNotFound[] = "The RTP stream cannot be found"; | |
68 const char kUdpTransportNotFound[] = "The UDP transport cannot be found"; | |
69 const char kUnableToConvertArgs[] = "Unable to convert arguments"; | |
70 const char kUnableToConvertParams[] = "Unable to convert params"; | |
71 | 59 |
72 // These helper methods are used to convert between Extension API | 60 constexpr char kInvalidAesIvMask[] = "Invalid value for AES IV mask"; |
73 // types and Cast types. | 61 constexpr char kInvalidAesKey[] = "Invalid value for AES key"; |
74 void ToCastCodecSpecificParams(const CodecSpecificParams& ext_params, | 62 constexpr char kInvalidAudioParams[] = "Invalid audio params"; |
75 CastCodecSpecificParams* cast_params) { | 63 constexpr char kInvalidDestination[] = "Invalid destination"; |
76 cast_params->key = ext_params.key; | 64 constexpr char kInvalidFPS[] = "Invalid FPS"; |
77 cast_params->value = ext_params.value; | 65 constexpr char kInvalidMediaStreamURL[] = "Invalid MediaStream URL"; |
78 } | 66 constexpr char kInvalidRtpParams[] = "Invalid value for RTP params"; |
| 67 constexpr char kInvalidLatency[] = "Invalid value for max_latency. (0-1000)"; |
| 68 constexpr char kInvalidRtpTimebase[] = "Invalid rtp_timebase. (1000-1000000)"; |
| 69 constexpr char kInvalidStreamArgs[] = "Invalid stream arguments"; |
| 70 constexpr char kRtpStreamNotFound[] = "The RTP stream cannot be found"; |
| 71 constexpr char kUdpTransportNotFound[] = "The UDP transport cannot be found"; |
| 72 constexpr char kUnableToConvertArgs[] = "Unable to convert arguments"; |
| 73 constexpr char kUnableToConvertParams[] = "Unable to convert params"; |
| 74 constexpr char kCodecNameOpus[] = "OPUS"; |
| 75 constexpr char kCodecNameVp8[] = "VP8"; |
| 76 constexpr char kCodecNameH264[] = "H264"; |
79 | 77 |
80 void FromCastCodecSpecificParams(const CastCodecSpecificParams& cast_params, | 78 // To convert from kilobits per second to bits per second. |
81 CodecSpecificParams* ext_params) { | 79 constexpr int kBitsPerKilobit = 1000; |
82 ext_params->key = cast_params.key; | |
83 ext_params->value = cast_params.value; | |
84 } | |
85 | 80 |
86 namespace { | |
87 bool HexDecode(const std::string& input, std::string* output) { | 81 bool HexDecode(const std::string& input, std::string* output) { |
88 std::vector<uint8_t> bytes; | 82 std::vector<uint8_t> bytes; |
89 if (!base::HexStringToBytes(input, &bytes)) | 83 if (!base::HexStringToBytes(input, &bytes)) |
90 return false; | 84 return false; |
91 output->assign(reinterpret_cast<const char*>(&bytes[0]), bytes.size()); | 85 output->assign(reinterpret_cast<const char*>(&bytes[0]), bytes.size()); |
92 return true; | 86 return true; |
93 } | 87 } |
94 } // namespace | |
95 | 88 |
96 bool ToCastRtpPayloadParamsOrThrow(v8::Isolate* isolate, | 89 int NumberOfEncodeThreads() { |
97 const RtpPayloadParams& ext_params, | 90 // Do not saturate CPU utilization just for encoding. On a lower-end system |
98 CastRtpPayloadParams* cast_params) { | 91 // with only 1 or 2 cores, use only one thread for encoding. On systems with |
99 cast_params->max_latency_ms = ext_params.max_latency; | 92 // more cores, allow half of the cores to be used for encoding. |
100 cast_params->min_latency_ms = | 93 return std::min(8, (base::SysInfo::NumberOfProcessors() + 1) / 2); |
101 ext_params.min_latency ? *ext_params.min_latency : ext_params.max_latency; | 94 } |
102 cast_params->animated_latency_ms = ext_params.animated_latency | 95 |
103 ? *ext_params.animated_latency | 96 bool ToFrameSenderConfigOrThrow(v8::Isolate* isolate, |
104 : ext_params.max_latency; | 97 const RtpPayloadParams& ext_params, |
105 cast_params->codec_name = ext_params.codec_name; | 98 FrameSenderConfig* config) { |
106 if (cast_params->codec_name == "OPUS") { | 99 config->sender_ssrc = ext_params.ssrc; |
107 cast_params->payload_type = media::cast::RtpPayloadType::AUDIO_OPUS; | 100 config->receiver_ssrc = ext_params.feedback_ssrc; |
108 } else if (cast_params->codec_name == "PCM16") { | 101 if (config->sender_ssrc == config->receiver_ssrc) { |
109 cast_params->payload_type = media::cast::RtpPayloadType::AUDIO_PCM16; | 102 DVLOG(1) << "sender_ssrc " << config->sender_ssrc |
110 } else if (cast_params->codec_name == "AAC") { | 103 << " cannot be equal to receiver_ssrc"; |
111 cast_params->payload_type = media::cast::RtpPayloadType::AUDIO_AAC; | 104 isolate->ThrowException(v8::Exception::Error( |
112 } else if (cast_params->codec_name == "VP8") { | 105 v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); |
113 cast_params->payload_type = media::cast::RtpPayloadType::VIDEO_VP8; | 106 return false; |
114 } else if (cast_params->codec_name == "H264") { | |
115 cast_params->payload_type = media::cast::RtpPayloadType::VIDEO_H264; | |
116 } | 107 } |
117 cast_params->ssrc = ext_params.ssrc; | 108 config->min_playout_delay = base::TimeDelta::FromMilliseconds( |
118 cast_params->feedback_ssrc = ext_params.feedback_ssrc; | 109 ext_params.min_latency ? *ext_params.min_latency |
119 cast_params->clock_rate = ext_params.clock_rate ? *ext_params.clock_rate : 0; | 110 : ext_params.max_latency); |
120 cast_params->min_bitrate = | 111 config->max_playout_delay = |
121 ext_params.min_bitrate ? *ext_params.min_bitrate : 0; | 112 base::TimeDelta::FromMilliseconds(ext_params.max_latency); |
122 cast_params->max_bitrate = | 113 config->animated_playout_delay = base::TimeDelta::FromMilliseconds( |
123 ext_params.max_bitrate ? *ext_params.max_bitrate : 0; | 114 ext_params.animated_latency ? *ext_params.animated_latency |
124 cast_params->channels = ext_params.channels ? *ext_params.channels : 0; | 115 : ext_params.max_latency); |
125 cast_params->max_frame_rate = | 116 if (config->min_playout_delay <= base::TimeDelta()) { |
126 ext_params.max_frame_rate ? *ext_params.max_frame_rate : 0.0; | 117 DVLOG(1) << "min_playout_delay " << config->min_playout_delay |
127 if (ext_params.aes_key && | 118 << " must be greater than zero"; |
128 !HexDecode(*ext_params.aes_key, &cast_params->aes_key)) { | 119 isolate->ThrowException(v8::Exception::Error( |
| 120 v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); |
| 121 return false; |
| 122 } |
| 123 if (config->min_playout_delay > config->max_playout_delay) { |
| 124 DVLOG(1) << "min_playout_delay " << config->min_playout_delay |
| 125 << " must be less than or equal to max_palyout_delay"; |
| 126 isolate->ThrowException(v8::Exception::Error( |
| 127 v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); |
| 128 return false; |
| 129 } |
| 130 if (config->animated_playout_delay < config->min_playout_delay || |
| 131 config->animated_playout_delay > config->max_playout_delay) { |
| 132 DVLOG(1) << "animated_playout_delay " << config->animated_playout_delay |
| 133 << " must be between (inclusive) the min and max playout delay"; |
| 134 isolate->ThrowException(v8::Exception::Error( |
| 135 v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); |
| 136 return false; |
| 137 } |
| 138 if (ext_params.codec_name == kCodecNameOpus) { |
| 139 config->rtp_payload_type = media::cast::RtpPayloadType::AUDIO_OPUS; |
| 140 config->use_external_encoder = false; |
| 141 config->rtp_timebase = ext_params.clock_rate |
| 142 ? *ext_params.clock_rate |
| 143 : media::cast::kDefaultAudioSamplingRate; |
| 144 // Sampling rate must be one of the Opus-supported values. |
| 145 switch (config->rtp_timebase) { |
| 146 case 48000: |
| 147 case 24000: |
| 148 case 16000: |
| 149 case 12000: |
| 150 case 8000: |
| 151 break; |
| 152 default: |
| 153 DVLOG(1) << "rtp_timebase " << config->rtp_timebase << " is invalid"; |
| 154 isolate->ThrowException(v8::Exception::Error( |
| 155 v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); |
| 156 return false; |
| 157 } |
| 158 config->channels = ext_params.channels ? *ext_params.channels : 2; |
| 159 if (config->channels != 1 && config->channels != 2) { |
| 160 isolate->ThrowException(v8::Exception::Error( |
| 161 v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); |
| 162 DVLOG(1) << "channels " << config->channels << " is invalid"; |
| 163 return false; |
| 164 } |
| 165 config->min_bitrate = config->start_bitrate = config->max_bitrate = |
| 166 ext_params.max_bitrate ? (*ext_params.max_bitrate) * kBitsPerKilobit |
| 167 : media::cast::kDefaultAudioEncoderBitrate; |
| 168 config->max_frame_rate = 100; // 10ms audio frames. |
| 169 config->codec = media::cast::CODEC_AUDIO_OPUS; |
| 170 } else if (ext_params.codec_name == kCodecNameVp8 || |
| 171 ext_params.codec_name == kCodecNameH264) { |
| 172 config->rtp_timebase = media::cast::kVideoFrequency; |
| 173 config->channels = ext_params.channels ? *ext_params.channels : 1; |
| 174 if (config->channels != 1) { |
| 175 isolate->ThrowException(v8::Exception::Error( |
| 176 v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); |
| 177 DVLOG(1) << "channels " << config->channels << " is invalid"; |
| 178 return false; |
| 179 } |
| 180 config->min_bitrate = ext_params.min_bitrate |
| 181 ? (*ext_params.min_bitrate) * kBitsPerKilobit |
| 182 : media::cast::kDefaultMinVideoBitrate; |
| 183 config->max_bitrate = ext_params.max_bitrate |
| 184 ? (*ext_params.max_bitrate) * kBitsPerKilobit |
| 185 : media::cast::kDefaultMaxVideoBitrate; |
| 186 if (config->min_bitrate > config->max_bitrate) { |
| 187 DVLOG(1) << "min_bitrate " << config->min_bitrate << " is larger than " |
| 188 << "max_bitrate " << config->max_bitrate; |
| 189 isolate->ThrowException(v8::Exception::Error( |
| 190 v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); |
| 191 return false; |
| 192 } |
| 193 config->start_bitrate = config->min_bitrate; |
| 194 config->max_frame_rate = std::max( |
| 195 1.0, ext_params.max_frame_rate ? *ext_params.max_frame_rate : 0.0); |
| 196 if (config->max_frame_rate > media::limits::kMaxFramesPerSecond) { |
| 197 DVLOG(1) << "max_frame_rate " << config->max_frame_rate << " is invalid"; |
| 198 isolate->ThrowException(v8::Exception::Error( |
| 199 v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); |
| 200 return false; |
| 201 } |
| 202 if (ext_params.codec_name == kCodecNameVp8) { |
| 203 config->rtp_payload_type = media::cast::RtpPayloadType::VIDEO_VP8; |
| 204 config->codec = media::cast::CODEC_VIDEO_VP8; |
| 205 config->use_external_encoder = |
| 206 CastRtpStream::IsHardwareVP8EncodingSupported(); |
| 207 } else { |
| 208 config->rtp_payload_type = media::cast::RtpPayloadType::VIDEO_H264; |
| 209 config->codec = media::cast::CODEC_VIDEO_H264; |
| 210 config->use_external_encoder = |
| 211 CastRtpStream::IsHardwareH264EncodingSupported(); |
| 212 } |
| 213 if (!config->use_external_encoder) |
| 214 config->video_codec_params.number_of_encode_threads = |
| 215 NumberOfEncodeThreads(); |
| 216 } else { |
| 217 DVLOG(1) << "codec_name " << ext_params.codec_name << " is invalid"; |
| 218 isolate->ThrowException(v8::Exception::Error( |
| 219 v8::String::NewFromUtf8(isolate, kInvalidRtpParams))); |
| 220 return false; |
| 221 } |
| 222 if (ext_params.aes_key && !HexDecode(*ext_params.aes_key, &config->aes_key)) { |
129 isolate->ThrowException(v8::Exception::Error( | 223 isolate->ThrowException(v8::Exception::Error( |
130 v8::String::NewFromUtf8(isolate, kInvalidAesKey))); | 224 v8::String::NewFromUtf8(isolate, kInvalidAesKey))); |
131 return false; | 225 return false; |
132 } | 226 } |
133 if (ext_params.aes_iv_mask && | 227 if (ext_params.aes_iv_mask && |
134 !HexDecode(*ext_params.aes_iv_mask, &cast_params->aes_iv_mask)) { | 228 !HexDecode(*ext_params.aes_iv_mask, &config->aes_iv_mask)) { |
135 isolate->ThrowException(v8::Exception::Error( | 229 isolate->ThrowException(v8::Exception::Error( |
136 v8::String::NewFromUtf8(isolate, kInvalidAesIvMask))); | 230 v8::String::NewFromUtf8(isolate, kInvalidAesIvMask))); |
137 return false; | 231 return false; |
138 } | 232 } |
139 for (size_t i = 0; i < ext_params.codec_specific_params.size(); ++i) { | |
140 CastCodecSpecificParams cast_codec_params; | |
141 ToCastCodecSpecificParams(ext_params.codec_specific_params[i], | |
142 &cast_codec_params); | |
143 cast_params->codec_specific_params.push_back(cast_codec_params); | |
144 } | |
145 return true; | |
146 } | |
147 | |
148 void FromCastRtpPayloadParams(const CastRtpPayloadParams& cast_params, | |
149 RtpPayloadParams* ext_params) { | |
150 ext_params->payload_type = static_cast<int>(cast_params.payload_type); | |
151 ext_params->max_latency = cast_params.max_latency_ms; | |
152 ext_params->min_latency.reset(new int(cast_params.min_latency_ms)); | |
153 ext_params->animated_latency.reset(new int(cast_params.animated_latency_ms)); | |
154 ext_params->codec_name = cast_params.codec_name; | |
155 ext_params->ssrc = cast_params.ssrc; | |
156 ext_params->feedback_ssrc = cast_params.feedback_ssrc; | |
157 if (cast_params.clock_rate) | |
158 ext_params->clock_rate.reset(new int(cast_params.clock_rate)); | |
159 if (cast_params.min_bitrate) | |
160 ext_params->min_bitrate.reset(new int(cast_params.min_bitrate)); | |
161 if (cast_params.max_bitrate) | |
162 ext_params->max_bitrate.reset(new int(cast_params.max_bitrate)); | |
163 if (cast_params.channels) | |
164 ext_params->channels.reset(new int(cast_params.channels)); | |
165 if (cast_params.max_frame_rate > 0.0) | |
166 ext_params->max_frame_rate.reset(new double(cast_params.max_frame_rate)); | |
167 for (size_t i = 0; i < cast_params.codec_specific_params.size(); ++i) { | |
168 CodecSpecificParams ext_codec_params; | |
169 FromCastCodecSpecificParams(cast_params.codec_specific_params[i], | |
170 &ext_codec_params); | |
171 ext_params->codec_specific_params.push_back(std::move(ext_codec_params)); | |
172 } | |
173 } | |
174 | |
175 void FromCastRtpParams(const CastRtpParams& cast_params, | |
176 RtpParams* ext_params) { | |
177 std::copy(cast_params.rtcp_features.begin(), | |
178 cast_params.rtcp_features.end(), | |
179 std::back_inserter(ext_params->rtcp_features)); | |
180 FromCastRtpPayloadParams(cast_params.payload, &ext_params->payload); | |
181 } | |
182 | |
183 bool ToCastRtpParamsOrThrow(v8::Isolate* isolate, | |
184 const RtpParams& ext_params, | |
185 CastRtpParams* cast_params) { | |
186 std::copy(ext_params.rtcp_features.begin(), | |
187 ext_params.rtcp_features.end(), | |
188 std::back_inserter(cast_params->rtcp_features)); | |
189 if (!ToCastRtpPayloadParamsOrThrow(isolate, | |
190 ext_params.payload, | |
191 &cast_params->payload)) { | |
192 return false; | |
193 } | |
194 return true; | 233 return true; |
195 } | 234 } |
196 | 235 |
| 236 void FromFrameSenderConfig(const FrameSenderConfig& config, |
| 237 RtpPayloadParams* ext_params) { |
| 238 ext_params->payload_type = static_cast<int>(config.rtp_payload_type); |
| 239 ext_params->max_latency = config.max_playout_delay.InMilliseconds(); |
| 240 ext_params->min_latency.reset( |
| 241 new int(config.min_playout_delay.InMilliseconds())); |
| 242 ext_params->animated_latency.reset( |
| 243 new int(config.animated_playout_delay.InMilliseconds())); |
| 244 switch (config.codec) { |
| 245 case media::cast::CODEC_AUDIO_OPUS: |
| 246 ext_params->codec_name = kCodecNameOpus; |
| 247 break; |
| 248 case media::cast::CODEC_VIDEO_VP8: |
| 249 ext_params->codec_name = kCodecNameVp8; |
| 250 break; |
| 251 case media::cast::CODEC_VIDEO_H264: |
| 252 ext_params->codec_name = kCodecNameH264; |
| 253 break; |
| 254 default: |
| 255 NOTREACHED(); |
| 256 } |
| 257 ext_params->ssrc = config.sender_ssrc; |
| 258 ext_params->feedback_ssrc = config.receiver_ssrc; |
| 259 if (config.rtp_timebase) |
| 260 ext_params->clock_rate.reset(new int(config.rtp_timebase)); |
| 261 if (config.min_bitrate) |
| 262 ext_params->min_bitrate.reset( |
| 263 new int(config.min_bitrate / kBitsPerKilobit)); |
| 264 if (config.max_bitrate) |
| 265 ext_params->max_bitrate.reset( |
| 266 new int(config.max_bitrate / kBitsPerKilobit)); |
| 267 if (config.channels) |
| 268 ext_params->channels.reset(new int(config.channels)); |
| 269 if (config.max_frame_rate > 0.0) |
| 270 ext_params->max_frame_rate.reset(new double(config.max_frame_rate)); |
| 271 } |
| 272 |
197 } // namespace | 273 } // namespace |
198 | 274 |
199 CastStreamingNativeHandler::CastStreamingNativeHandler(ScriptContext* context) | 275 CastStreamingNativeHandler::CastStreamingNativeHandler(ScriptContext* context) |
200 : ObjectBackedNativeHandler(context), | 276 : ObjectBackedNativeHandler(context), |
201 last_transport_id_(1), | 277 last_transport_id_(1), |
202 weak_factory_(this) { | 278 weak_factory_(this) { |
203 RouteFunction("CreateSession", "cast.streaming.session", | 279 RouteFunction("CreateSession", "cast.streaming.session", |
204 base::Bind(&CastStreamingNativeHandler::CreateCastSession, | 280 base::Bind(&CastStreamingNativeHandler::CreateCastSession, |
205 weak_factory_.GetWeakPtr())); | 281 weak_factory_.GetWeakPtr())); |
206 RouteFunction("DestroyCastRtpStream", "cast.streaming.rtpStream", | 282 RouteFunction("DestroyCastRtpStream", "cast.streaming.rtpStream", |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
392 const v8::FunctionCallbackInfo<v8::Value>& args) const { | 468 const v8::FunctionCallbackInfo<v8::Value>& args) const { |
393 CHECK_EQ(1, args.Length()); | 469 CHECK_EQ(1, args.Length()); |
394 CHECK(args[0]->IsInt32()); | 470 CHECK(args[0]->IsInt32()); |
395 | 471 |
396 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value(); | 472 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value(); |
397 CastRtpStream* transport = GetRtpStreamOrThrow(transport_id); | 473 CastRtpStream* transport = GetRtpStreamOrThrow(transport_id); |
398 if (!transport) | 474 if (!transport) |
399 return; | 475 return; |
400 | 476 |
401 std::unique_ptr<V8ValueConverter> converter(V8ValueConverter::create()); | 477 std::unique_ptr<V8ValueConverter> converter(V8ValueConverter::create()); |
402 std::vector<CastRtpParams> cast_params = transport->GetSupportedParams(); | 478 std::vector<FrameSenderConfig> configs = transport->GetSupportedConfigs(); |
403 v8::Local<v8::Array> result = | 479 v8::Local<v8::Array> result = |
404 v8::Array::New(args.GetIsolate(), | 480 v8::Array::New(args.GetIsolate(), static_cast<int>(configs.size())); |
405 static_cast<int>(cast_params.size())); | 481 for (size_t i = 0; i < configs.size(); ++i) { |
406 for (size_t i = 0; i < cast_params.size(); ++i) { | |
407 RtpParams params; | 482 RtpParams params; |
408 FromCastRtpParams(cast_params[i], ¶ms); | 483 FromFrameSenderConfig(configs[i], ¶ms.payload); |
409 std::unique_ptr<base::DictionaryValue> params_value = params.ToValue(); | 484 std::unique_ptr<base::DictionaryValue> params_value = params.ToValue(); |
410 result->Set( | 485 result->Set( |
411 static_cast<int>(i), | 486 static_cast<int>(i), |
412 converter->ToV8Value(params_value.get(), context()->v8_context())); | 487 converter->ToV8Value(params_value.get(), context()->v8_context())); |
413 } | 488 } |
414 args.GetReturnValue().Set(result); | 489 args.GetReturnValue().Set(result); |
415 } | 490 } |
416 | 491 |
417 void CastStreamingNativeHandler::StartCastRtpStream( | 492 void CastStreamingNativeHandler::StartCastRtpStream( |
418 const v8::FunctionCallbackInfo<v8::Value>& args) { | 493 const v8::FunctionCallbackInfo<v8::Value>& args) { |
(...skipping 14 matching lines...) Expand all Loading... |
433 v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertParams))); | 508 v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertParams))); |
434 return; | 509 return; |
435 } | 510 } |
436 std::unique_ptr<RtpParams> params = RtpParams::FromValue(*params_value); | 511 std::unique_ptr<RtpParams> params = RtpParams::FromValue(*params_value); |
437 if (!params) { | 512 if (!params) { |
438 args.GetIsolate()->ThrowException(v8::Exception::TypeError( | 513 args.GetIsolate()->ThrowException(v8::Exception::TypeError( |
439 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidRtpParams))); | 514 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidRtpParams))); |
440 return; | 515 return; |
441 } | 516 } |
442 | 517 |
443 CastRtpParams cast_params; | 518 FrameSenderConfig config; |
444 v8::Isolate* isolate = context()->v8_context()->GetIsolate(); | 519 v8::Isolate* isolate = context()->v8_context()->GetIsolate(); |
445 if (!ToCastRtpParamsOrThrow(isolate, *params, &cast_params)) | 520 if (!ToFrameSenderConfigOrThrow(isolate, params->payload, &config)) |
446 return; | 521 return; |
447 | 522 |
448 base::Closure start_callback = | 523 base::Closure start_callback = |
449 base::Bind(&CastStreamingNativeHandler::CallStartCallback, | 524 base::Bind(&CastStreamingNativeHandler::CallStartCallback, |
450 weak_factory_.GetWeakPtr(), | 525 weak_factory_.GetWeakPtr(), |
451 transport_id); | 526 transport_id); |
452 base::Closure stop_callback = | 527 base::Closure stop_callback = |
453 base::Bind(&CastStreamingNativeHandler::CallStopCallback, | 528 base::Bind(&CastStreamingNativeHandler::CallStopCallback, |
454 weak_factory_.GetWeakPtr(), | 529 weak_factory_.GetWeakPtr(), |
455 transport_id); | 530 transport_id); |
456 CastRtpStream::ErrorCallback error_callback = | 531 CastRtpStream::ErrorCallback error_callback = |
457 base::Bind(&CastStreamingNativeHandler::CallErrorCallback, | 532 base::Bind(&CastStreamingNativeHandler::CallErrorCallback, |
458 weak_factory_.GetWeakPtr(), | 533 weak_factory_.GetWeakPtr(), |
459 transport_id); | 534 transport_id); |
460 transport->Start(cast_params, start_callback, stop_callback, error_callback); | 535 transport->Start(config, start_callback, stop_callback, error_callback); |
461 } | 536 } |
462 | 537 |
463 void CastStreamingNativeHandler::StopCastRtpStream( | 538 void CastStreamingNativeHandler::StopCastRtpStream( |
464 const v8::FunctionCallbackInfo<v8::Value>& args) { | 539 const v8::FunctionCallbackInfo<v8::Value>& args) { |
465 CHECK_EQ(1, args.Length()); | 540 CHECK_EQ(1, args.Length()); |
466 CHECK(args[0]->IsInt32()); | 541 CHECK(args[0]->IsInt32()); |
467 | 542 |
468 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value(); | 543 const int transport_id = args[0]->ToInt32(args.GetIsolate())->Value(); |
469 CastRtpStream* transport = GetRtpStreamOrThrow(transport_id); | 544 CastRtpStream* transport = GetRtpStreamOrThrow(transport_id); |
470 if (!transport) | 545 if (!transport) |
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
809 media::VideoCaptureFormat capture_format(gfx::Size(max_width, max_height), | 884 media::VideoCaptureFormat capture_format(gfx::Size(max_width, max_height), |
810 fps, media::PIXEL_FORMAT_I420); | 885 fps, media::PIXEL_FORMAT_I420); |
811 | 886 |
812 video_config.target_frame_rate = fps; | 887 video_config.target_frame_rate = fps; |
813 audio_config.target_frame_rate = 100; | 888 audio_config.target_frame_rate = 100; |
814 | 889 |
815 media::AudioParameters params( | 890 media::AudioParameters params( |
816 media::AudioParameters::AUDIO_PCM_LINEAR, | 891 media::AudioParameters::AUDIO_PCM_LINEAR, |
817 media::GuessChannelLayout(audio_config.channels), | 892 media::GuessChannelLayout(audio_config.channels), |
818 audio_config.rtp_timebase, // sampling rate | 893 audio_config.rtp_timebase, // sampling rate |
819 16, audio_config.rtp_timebase / audio_config.target_frame_rate); | 894 16, static_cast<int>(audio_config.rtp_timebase / |
| 895 audio_config.target_frame_rate)); |
820 | 896 |
821 if (!params.IsValid()) { | 897 if (!params.IsValid()) { |
822 args.GetIsolate()->ThrowException(v8::Exception::TypeError( | 898 args.GetIsolate()->ThrowException(v8::Exception::TypeError( |
823 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidAudioParams))); | 899 v8::String::NewFromUtf8(args.GetIsolate(), kInvalidAudioParams))); |
824 return; | 900 return; |
825 } | 901 } |
826 | 902 |
827 std::unique_ptr<base::DictionaryValue> options; | 903 std::unique_ptr<base::DictionaryValue> options; |
828 if (args.Length() >= 9) { | 904 if (args.Length() >= 9) { |
829 std::unique_ptr<V8ValueConverter> converter(V8ValueConverter::create()); | 905 std::unique_ptr<V8ValueConverter> converter(V8ValueConverter::create()); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
887 LOG(ERROR) << "Failed to add Cast audio track to media stream."; | 963 LOG(ERROR) << "Failed to add Cast audio track to media stream."; |
888 } | 964 } |
889 if (!content::AddVideoTrackToMediaStream(std::move(video), true, // is_remote | 965 if (!content::AddVideoTrackToMediaStream(std::move(video), true, // is_remote |
890 true, // is_readonly | 966 true, // is_readonly |
891 &web_stream)) { | 967 &web_stream)) { |
892 LOG(ERROR) << "Failed to add Cast video track to media stream."; | 968 LOG(ERROR) << "Failed to add Cast video track to media stream."; |
893 } | 969 } |
894 } | 970 } |
895 | 971 |
896 } // namespace extensions | 972 } // namespace extensions |
OLD | NEW |