blob: ed6e7f15bf17cdfd68a9a170609502810fd00c7a [file] [log] [blame]
erickung1fc58a42016-09-24 03:00:071// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
miu9f7788e2017-01-25 00:46:095#include "media/remoting/proto_utils.h"
erickung1fc58a42016-09-24 03:00:076
7#include <algorithm>
8
9#include "base/big_endian.h"
10#include "base/logging.h"
11#include "base/time/time.h"
12#include "base/values.h"
13#include "media/base/encryption_scheme.h"
Chris Cunninghamfe34199b2017-07-07 20:06:4514#include "media/base/timestamp_constants.h"
miu9f7788e2017-01-25 00:46:0915#include "media/remoting/proto_enum_utils.h"
erickung1fc58a42016-09-24 03:00:0716
17namespace media {
18namespace remoting {
19
20namespace {
21
22constexpr size_t kPayloadVersionFieldSize = sizeof(uint8_t);
23constexpr size_t kProtoBufferHeaderSize = sizeof(uint16_t);
24constexpr size_t kDataBufferHeaderSize = sizeof(uint32_t);
25
miu9f7788e2017-01-25 00:46:0926std::unique_ptr<DecryptConfig> ConvertProtoToDecryptConfig(
erickung1fc58a42016-09-24 03:00:0727 const pb::DecryptConfig& config_message) {
28 if (!config_message.has_key_id())
29 return nullptr;
30 if (!config_message.has_iv())
31 return nullptr;
32
miu9f7788e2017-01-25 00:46:0933 std::vector<SubsampleEntry> entries(config_message.sub_samples_size());
erickung1fc58a42016-09-24 03:00:0734 for (int i = 0; i < config_message.sub_samples_size(); ++i) {
35 entries.push_back(
miu9f7788e2017-01-25 00:46:0936 SubsampleEntry(config_message.sub_samples(i).clear_bytes(),
37 config_message.sub_samples(i).cypher_bytes()));
erickung1fc58a42016-09-24 03:00:0738 }
39
miu9f7788e2017-01-25 00:46:0940 std::unique_ptr<DecryptConfig> decrypt_config(
41 new DecryptConfig(config_message.key_id(), config_message.iv(), entries));
erickung1fc58a42016-09-24 03:00:0742 return decrypt_config;
43}
44
miu9f7788e2017-01-25 00:46:0945scoped_refptr<DecoderBuffer> ConvertProtoToDecoderBuffer(
erickung1fc58a42016-09-24 03:00:0746 const pb::DecoderBuffer& buffer_message,
miu9f7788e2017-01-25 00:46:0947 scoped_refptr<DecoderBuffer> buffer) {
erickung1fc58a42016-09-24 03:00:0748 if (buffer_message.is_eos()) {
49 VLOG(1) << "EOS data";
miu9f7788e2017-01-25 00:46:0950 return DecoderBuffer::CreateEOSBuffer();
erickung1fc58a42016-09-24 03:00:0751 }
52
53 if (buffer_message.has_timestamp_usec()) {
54 buffer->set_timestamp(
55 base::TimeDelta::FromMicroseconds(buffer_message.timestamp_usec()));
56 }
57
58 if (buffer_message.has_duration_usec()) {
59 buffer->set_duration(
60 base::TimeDelta::FromMicroseconds(buffer_message.duration_usec()));
61 }
62 VLOG(3) << "timestamp:" << buffer_message.timestamp_usec()
63 << " duration:" << buffer_message.duration_usec();
64
65 if (buffer_message.has_is_key_frame())
66 buffer->set_is_key_frame(buffer_message.is_key_frame());
67
68 if (buffer_message.has_decrypt_config()) {
69 buffer->set_decrypt_config(
70 ConvertProtoToDecryptConfig(buffer_message.decrypt_config()));
71 }
72
73 bool has_discard = false;
74 base::TimeDelta front_discard;
75 if (buffer_message.has_front_discard_usec()) {
76 has_discard = true;
77 front_discard =
78 base::TimeDelta::FromMicroseconds(buffer_message.front_discard_usec());
79 }
80 base::TimeDelta back_discard;
81 if (buffer_message.has_back_discard_usec()) {
82 has_discard = true;
83 back_discard =
84 base::TimeDelta::FromMicroseconds(buffer_message.back_discard_usec());
85 }
86
87 if (has_discard) {
88 buffer->set_discard_padding(
miu9f7788e2017-01-25 00:46:0989 DecoderBuffer::DiscardPadding(front_discard, back_discard));
erickung1fc58a42016-09-24 03:00:0790 }
91
erickung1fc58a42016-09-24 03:00:0792 if (buffer_message.has_side_data()) {
93 buffer->CopySideDataFrom(
94 reinterpret_cast<const uint8_t*>(buffer_message.side_data().data()),
95 buffer_message.side_data().size());
96 }
97
98 return buffer;
99}
100
miu9f7788e2017-01-25 00:46:09101void ConvertDecryptConfigToProto(const DecryptConfig& decrypt_config,
erickung1fc58a42016-09-24 03:00:07102 pb::DecryptConfig* config_message) {
103 DCHECK(config_message);
104
105 config_message->set_key_id(decrypt_config.key_id());
106 config_message->set_iv(decrypt_config.iv());
107
108 for (const auto& entry : decrypt_config.subsamples()) {
109 pb::DecryptConfig::SubSample* sub_sample =
110 config_message->add_sub_samples();
111 sub_sample->set_clear_bytes(entry.clear_bytes);
112 sub_sample->set_cypher_bytes(entry.cypher_bytes);
113 }
114}
115
miu9f7788e2017-01-25 00:46:09116void ConvertDecoderBufferToProto(const DecoderBuffer& decoder_buffer,
117 pb::DecoderBuffer* buffer_message) {
118 if (decoder_buffer.end_of_stream()) {
erickung1fc58a42016-09-24 03:00:07119 buffer_message->set_is_eos(true);
120 return;
121 }
122
miu9f7788e2017-01-25 00:46:09123 VLOG(3) << "timestamp:" << decoder_buffer.timestamp().InMicroseconds()
124 << " duration:" << decoder_buffer.duration().InMicroseconds();
erickung1fc58a42016-09-24 03:00:07125 buffer_message->set_timestamp_usec(
miu9f7788e2017-01-25 00:46:09126 decoder_buffer.timestamp().InMicroseconds());
127 buffer_message->set_duration_usec(decoder_buffer.duration().InMicroseconds());
128 buffer_message->set_is_key_frame(decoder_buffer.is_key_frame());
erickung1fc58a42016-09-24 03:00:07129
miu9f7788e2017-01-25 00:46:09130 if (decoder_buffer.decrypt_config()) {
131 ConvertDecryptConfigToProto(*decoder_buffer.decrypt_config(),
erickung1fc58a42016-09-24 03:00:07132 buffer_message->mutable_decrypt_config());
133 }
134
135 buffer_message->set_front_discard_usec(
miu9f7788e2017-01-25 00:46:09136 decoder_buffer.discard_padding().first.InMicroseconds());
erickung1fc58a42016-09-24 03:00:07137 buffer_message->set_back_discard_usec(
miu9f7788e2017-01-25 00:46:09138 decoder_buffer.discard_padding().second.InMicroseconds());
erickung1fc58a42016-09-24 03:00:07139
miu9f7788e2017-01-25 00:46:09140 if (decoder_buffer.side_data_size()) {
141 buffer_message->set_side_data(decoder_buffer.side_data(),
142 decoder_buffer.side_data_size());
erickung1fc58a42016-09-24 03:00:07143 }
144}
145
146} // namespace
147
miu9f7788e2017-01-25 00:46:09148scoped_refptr<DecoderBuffer> ByteArrayToDecoderBuffer(const uint8_t* data,
149 uint32_t size) {
erickung1fc58a42016-09-24 03:00:07150 base::BigEndianReader reader(reinterpret_cast<const char*>(data), size);
151 uint8_t payload_version = 0;
152 uint16_t proto_size = 0;
153 pb::DecoderBuffer segment;
154 uint32_t buffer_size = 0;
155 if (reader.ReadU8(&payload_version) && payload_version == 0 &&
156 reader.ReadU16(&proto_size) &&
157 static_cast<int>(proto_size) < reader.remaining() &&
158 segment.ParseFromArray(reader.ptr(), proto_size) &&
159 reader.Skip(proto_size) && reader.ReadU32(&buffer_size) &&
160 static_cast<int64_t>(buffer_size) <= reader.remaining()) {
161 // Deserialize proto buffer. It passes the pre allocated DecoderBuffer into
162 // the function because the proto buffer may overwrite DecoderBuffer since
163 // it may be EOS buffer.
miu9f7788e2017-01-25 00:46:09164 scoped_refptr<DecoderBuffer> decoder_buffer = ConvertProtoToDecoderBuffer(
165 segment,
166 DecoderBuffer::CopyFrom(reinterpret_cast<const uint8_t*>(reader.ptr()),
167 buffer_size));
erickung1fc58a42016-09-24 03:00:07168 return decoder_buffer;
169 }
170
erickung1fc58a42016-09-24 03:00:07171 return nullptr;
172}
173
174std::vector<uint8_t> DecoderBufferToByteArray(
miu9f7788e2017-01-25 00:46:09175 const DecoderBuffer& decoder_buffer) {
erickung1fc58a42016-09-24 03:00:07176 pb::DecoderBuffer decoder_buffer_message;
177 ConvertDecoderBufferToProto(decoder_buffer, &decoder_buffer_message);
178
179 size_t decoder_buffer_size =
miu9f7788e2017-01-25 00:46:09180 decoder_buffer.end_of_stream() ? 0 : decoder_buffer.data_size();
erickung1fc58a42016-09-24 03:00:07181 size_t size = kPayloadVersionFieldSize + kProtoBufferHeaderSize +
182 decoder_buffer_message.ByteSize() + kDataBufferHeaderSize +
183 decoder_buffer_size;
184 std::vector<uint8_t> buffer(size);
185 base::BigEndianWriter writer(reinterpret_cast<char*>(buffer.data()),
186 buffer.size());
187 if (writer.WriteU8(0) &&
188 writer.WriteU16(
189 static_cast<uint16_t>(decoder_buffer_message.GetCachedSize())) &&
190 decoder_buffer_message.SerializeToArray(
191 writer.ptr(), decoder_buffer_message.GetCachedSize()) &&
192 writer.Skip(decoder_buffer_message.GetCachedSize()) &&
193 writer.WriteU32(decoder_buffer_size)) {
194 if (decoder_buffer_size) {
195 // DecoderBuffer frame data.
miu9f7788e2017-01-25 00:46:09196 writer.WriteBytes(reinterpret_cast<const void*>(decoder_buffer.data()),
197 decoder_buffer.data_size());
erickung1fc58a42016-09-24 03:00:07198 }
199 return buffer;
200 }
201
miu9f7788e2017-01-25 00:46:09202 NOTREACHED();
erickung1fc58a42016-09-24 03:00:07203 // Reset buffer since serialization of the data failed.
erickung1fc58a42016-09-24 03:00:07204 buffer.clear();
205 return buffer;
206}
207
miu9f7788e2017-01-25 00:46:09208void ConvertEncryptionSchemeToProto(const EncryptionScheme& encryption_scheme,
209 pb::EncryptionScheme* message) {
erickung1fc58a42016-09-24 03:00:07210 DCHECK(message);
211 message->set_mode(
212 ToProtoEncryptionSchemeCipherMode(encryption_scheme.mode()).value());
213 message->set_encrypt_blocks(encryption_scheme.pattern().encrypt_blocks());
214 message->set_skip_blocks(encryption_scheme.pattern().skip_blocks());
215}
216
miu9f7788e2017-01-25 00:46:09217EncryptionScheme ConvertProtoToEncryptionScheme(
erickung1fc58a42016-09-24 03:00:07218 const pb::EncryptionScheme& message) {
miu9f7788e2017-01-25 00:46:09219 return EncryptionScheme(
erickung1fc58a42016-09-24 03:00:07220 ToMediaEncryptionSchemeCipherMode(message.mode()).value(),
miu9f7788e2017-01-25 00:46:09221 EncryptionScheme::Pattern(message.encrypt_blocks(),
222 message.skip_blocks()));
erickung1fc58a42016-09-24 03:00:07223}
224
miu9f7788e2017-01-25 00:46:09225void ConvertAudioDecoderConfigToProto(const AudioDecoderConfig& audio_config,
226 pb::AudioDecoderConfig* audio_message) {
erickung1fc58a42016-09-24 03:00:07227 DCHECK(audio_config.IsValidConfig());
228 DCHECK(audio_message);
229
230 audio_message->set_codec(
231 ToProtoAudioDecoderConfigCodec(audio_config.codec()).value());
232 audio_message->set_sample_format(
233 ToProtoAudioDecoderConfigSampleFormat(audio_config.sample_format())
234 .value());
235 audio_message->set_channel_layout(
236 ToProtoAudioDecoderConfigChannelLayout(audio_config.channel_layout())
237 .value());
238 audio_message->set_samples_per_second(audio_config.samples_per_second());
239 audio_message->set_seek_preroll_usec(
240 audio_config.seek_preroll().InMicroseconds());
241 audio_message->set_codec_delay(audio_config.codec_delay());
242
243 if (!audio_config.extra_data().empty()) {
244 audio_message->set_extra_data(audio_config.extra_data().data(),
245 audio_config.extra_data().size());
246 }
247
248 if (audio_config.is_encrypted()) {
249 pb::EncryptionScheme* encryption_scheme_message =
250 audio_message->mutable_encryption_scheme();
251 ConvertEncryptionSchemeToProto(audio_config.encryption_scheme(),
252 encryption_scheme_message);
253 }
254}
255
256bool ConvertProtoToAudioDecoderConfig(
257 const pb::AudioDecoderConfig& audio_message,
miu9f7788e2017-01-25 00:46:09258 AudioDecoderConfig* audio_config) {
erickung1fc58a42016-09-24 03:00:07259 DCHECK(audio_config);
260 audio_config->Initialize(
261 ToMediaAudioCodec(audio_message.codec()).value(),
262 ToMediaSampleFormat(audio_message.sample_format()).value(),
263 ToMediaChannelLayout(audio_message.channel_layout()).value(),
264 audio_message.samples_per_second(),
265 std::vector<uint8_t>(audio_message.extra_data().begin(),
266 audio_message.extra_data().end()),
267 ConvertProtoToEncryptionScheme(audio_message.encryption_scheme()),
268 base::TimeDelta::FromMicroseconds(audio_message.seek_preroll_usec()),
269 audio_message.codec_delay());
270 return audio_config->IsValidConfig();
271}
272
miu9f7788e2017-01-25 00:46:09273void ConvertVideoDecoderConfigToProto(const VideoDecoderConfig& video_config,
274 pb::VideoDecoderConfig* video_message) {
erickung1fc58a42016-09-24 03:00:07275 DCHECK(video_config.IsValidConfig());
276 DCHECK(video_message);
277
278 video_message->set_codec(
279 ToProtoVideoDecoderConfigCodec(video_config.codec()).value());
280 video_message->set_profile(
281 ToProtoVideoDecoderConfigProfile(video_config.profile()).value());
282 video_message->set_format(
283 ToProtoVideoDecoderConfigFormat(video_config.format()).value());
284 video_message->set_color_space(
285 ToProtoVideoDecoderConfigColorSpace(video_config.color_space()).value());
286
287 pb::Size* coded_size_message = video_message->mutable_coded_size();
288 coded_size_message->set_width(video_config.coded_size().width());
289 coded_size_message->set_height(video_config.coded_size().height());
290
291 pb::Rect* visible_rect_message = video_message->mutable_visible_rect();
292 visible_rect_message->set_x(video_config.visible_rect().x());
293 visible_rect_message->set_y(video_config.visible_rect().y());
294 visible_rect_message->set_width(video_config.visible_rect().width());
295 visible_rect_message->set_height(video_config.visible_rect().height());
296
297 pb::Size* natural_size_message = video_message->mutable_natural_size();
298 natural_size_message->set_width(video_config.natural_size().width());
299 natural_size_message->set_height(video_config.natural_size().height());
300
301 if (!video_config.extra_data().empty()) {
302 video_message->set_extra_data(video_config.extra_data().data(),
303 video_config.extra_data().size());
304 }
305
306 if (video_config.is_encrypted()) {
307 pb::EncryptionScheme* encryption_scheme_message =
308 video_message->mutable_encryption_scheme();
309 ConvertEncryptionSchemeToProto(video_config.encryption_scheme(),
310 encryption_scheme_message);
311 }
312}
313
314bool ConvertProtoToVideoDecoderConfig(
315 const pb::VideoDecoderConfig& video_message,
miu9f7788e2017-01-25 00:46:09316 VideoDecoderConfig* video_config) {
erickung1fc58a42016-09-24 03:00:07317 DCHECK(video_config);
miu9f7788e2017-01-25 00:46:09318 EncryptionScheme encryption_scheme;
erickung1fc58a42016-09-24 03:00:07319 video_config->Initialize(
320 ToMediaVideoCodec(video_message.codec()).value(),
321 ToMediaVideoCodecProfile(video_message.profile()).value(),
322 ToMediaVideoPixelFormat(video_message.format()).value(),
Julien Isorce6c83d8de2017-10-12 13:11:29323 ToMediaColorSpace(video_message.color_space()).value(), VIDEO_ROTATION_0,
erickung1fc58a42016-09-24 03:00:07324 gfx::Size(video_message.coded_size().width(),
325 video_message.coded_size().height()),
326 gfx::Rect(video_message.visible_rect().x(),
327 video_message.visible_rect().y(),
328 video_message.visible_rect().width(),
329 video_message.visible_rect().height()),
330 gfx::Size(video_message.natural_size().width(),
331 video_message.natural_size().height()),
332 std::vector<uint8_t>(video_message.extra_data().begin(),
333 video_message.extra_data().end()),
334 ConvertProtoToEncryptionScheme(video_message.encryption_scheme()));
335 return video_config->IsValidConfig();
336}
337
miu9f7788e2017-01-25 00:46:09338void ConvertProtoToPipelineStatistics(
339 const pb::PipelineStatistics& stats_message,
340 PipelineStatistics* stats) {
341 stats->audio_bytes_decoded = stats_message.audio_bytes_decoded();
342 stats->video_bytes_decoded = stats_message.video_bytes_decoded();
343 stats->video_frames_decoded = stats_message.video_frames_decoded();
344 stats->video_frames_dropped = stats_message.video_frames_dropped();
345 stats->audio_memory_usage = stats_message.audio_memory_usage();
346 stats->video_memory_usage = stats_message.video_memory_usage();
347 // HACK: Set the following to prevent "disable video when hidden" logic in
348 // media::blink::WebMediaPlayerImpl.
349 stats->video_keyframe_distance_average = base::TimeDelta::Max();
Chris Cunninghamfe34199b2017-07-07 20:06:45350
Mounir Lamouria8d3ca062017-11-06 16:11:19351 // This field is not used by the rpc field.
352 stats->video_frames_decoded_power_efficient = 0;
353
Dale Curtisc7d2a7d22018-01-11 20:01:05354 // The following fields were added after the initial message definition. Check
355 // that sender provided the values.
356 if (stats_message.has_audio_decoder_name())
357 stats->audio_decoder_name = stats_message.audio_decoder_name();
358 if (stats_message.has_video_decoder_name())
359 stats->video_decoder_name = stats_message.video_decoder_name();
Chris Cunninghamfe34199b2017-07-07 20:06:45360 if (stats_message.has_video_frame_duration_average_usec()) {
361 stats->video_frame_duration_average = base::TimeDelta::FromMicroseconds(
362 stats_message.video_frame_duration_average_usec());
363 }
miu9f7788e2017-01-25 00:46:09364}
365
erickung1fc58a42016-09-24 03:00:07366void ConvertCdmKeyInfoToProto(
miu9f7788e2017-01-25 00:46:09367 const CdmKeysInfo& keys_information,
erickung1fc58a42016-09-24 03:00:07368 pb::CdmClientOnSessionKeysChange* key_change_message) {
xiaofeng.zhang8235be22017-05-21 11:39:34369 for (auto& info : keys_information) {
erickung1fc58a42016-09-24 03:00:07370 pb::CdmKeyInformation* key = key_change_message->add_key_information();
371 key->set_key_id(info->key_id.data(), info->key_id.size());
372 key->set_status(ToProtoCdmKeyInformation(info->status).value());
373 key->set_system_code(info->system_code);
374 }
375}
376
377void ConvertProtoToCdmKeyInfo(
378 const pb::CdmClientOnSessionKeysChange keychange_message,
379 CdmKeysInfo* key_information) {
380 DCHECK(key_information);
381 key_information->reserve(keychange_message.key_information_size());
382 for (int i = 0; i < keychange_message.key_information_size(); ++i) {
383 const pb::CdmKeyInformation key_info_msg =
384 keychange_message.key_information(i);
385
miu9f7788e2017-01-25 00:46:09386 std::unique_ptr<CdmKeyInformation> key(new CdmKeyInformation(
387 key_info_msg.key_id(),
388 ToMediaCdmKeyInformationKeyStatus(key_info_msg.status()).value(),
389 key_info_msg.system_code()));
erickung1fc58a42016-09-24 03:00:07390 key_information->push_back(std::move(key));
391 }
392}
393
394void ConvertCdmPromiseToProto(const CdmPromiseResult& result,
395 pb::CdmPromise* promise_message) {
396 promise_message->set_success(result.success());
397 if (!result.success()) {
398 promise_message->set_exception(
xhwang79b193042016-12-13 18:52:43399 ToProtoCdmException(result.exception()).value());
erickung1fc58a42016-09-24 03:00:07400 promise_message->set_system_code(result.system_code());
401 promise_message->set_error_message(result.error_message());
402 }
403}
404
405void ConvertCdmPromiseWithSessionIdToProto(const CdmPromiseResult& result,
406 const std::string& session_id,
407 pb::CdmPromise* promise_message) {
408 ConvertCdmPromiseToProto(result, promise_message);
409 promise_message->set_session_id(session_id);
410}
411
412void ConvertCdmPromiseWithCdmIdToProto(const CdmPromiseResult& result,
413 int cdm_id,
414 pb::CdmPromise* promise_message) {
415 ConvertCdmPromiseToProto(result, promise_message);
416 promise_message->set_cdm_id(cdm_id);
417}
418
419bool ConvertProtoToCdmPromise(const pb::CdmPromise& promise_message,
420 CdmPromiseResult* result) {
421 if (!promise_message.has_success())
422 return false;
423
424 bool success = promise_message.success();
425 if (success) {
426 *result = CdmPromiseResult::SuccessResult();
427 return true;
428 }
429
John Rummell4ec584b912017-08-15 22:54:25430 CdmPromise::Exception exception = CdmPromise::Exception::NOT_SUPPORTED_ERROR;
erickung1fc58a42016-09-24 03:00:07431 uint32_t system_code = 0;
432 std::string error_message;
433
corona101f1c7d32016-10-27 17:08:10434 exception = ToCdmPromiseException(promise_message.exception()).value();
erickung1fc58a42016-09-24 03:00:07435 system_code = promise_message.system_code();
436 error_message = promise_message.error_message();
437 *result = CdmPromiseResult(exception, system_code, error_message);
438 return true;
439}
440
441bool ConvertProtoToCdmPromiseWithCdmIdSessionId(const pb::RpcMessage& message,
442 CdmPromiseResult* result,
443 int* cdm_id,
444 std::string* session_id) {
445 if (!message.has_cdm_promise_rpc())
446 return false;
447
448 const auto& promise_message = message.cdm_promise_rpc();
449 if (!ConvertProtoToCdmPromise(promise_message, result))
450 return false;
451
452 if (cdm_id)
453 *cdm_id = promise_message.cdm_id();
454 if (session_id)
455 *session_id = promise_message.session_id();
456
457 return true;
458}
459
460//==============================================================================
461CdmPromiseResult::CdmPromiseResult()
John Rummell4ec584b912017-08-15 22:54:25462 : CdmPromiseResult(CdmPromise::Exception::NOT_SUPPORTED_ERROR, 0, "") {}
erickung1fc58a42016-09-24 03:00:07463
miu9f7788e2017-01-25 00:46:09464CdmPromiseResult::CdmPromiseResult(CdmPromise::Exception exception,
erickung1fc58a42016-09-24 03:00:07465 uint32_t system_code,
466 std::string error_message)
467 : success_(false),
468 exception_(exception),
469 system_code_(system_code),
470 error_message_(error_message) {}
471
472CdmPromiseResult::CdmPromiseResult(const CdmPromiseResult& other) = default;
473
474CdmPromiseResult::~CdmPromiseResult() = default;
475
476CdmPromiseResult CdmPromiseResult::SuccessResult() {
miu9f7788e2017-01-25 00:46:09477 CdmPromiseResult result(static_cast<CdmPromise::Exception>(0), 0, "");
erickung1fc58a42016-09-24 03:00:07478 result.success_ = true;
479 return result;
480}
481
482} // namespace remoting
483} // namespace media