Define remote playback proto buffer
This allows us to send RPC message to remote device for content playback.
Review-Url: https://codereview.chromium.org/2261503002
Cr-Commit-Position: refs/heads/master@{#420821}
diff --git a/media/remoting/BUILD.gn b/media/remoting/BUILD.gn
new file mode 100644
index 0000000..90aeeada
--- /dev/null
+++ b/media/remoting/BUILD.gn
@@ -0,0 +1,48 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/protobuf/proto_library.gni")
+import("//testing/test.gni")
+
+proto_library("media_remoting_proto") {
+ proto_out_dir = "media/remoting"
+ sources = [
+ "proto/remoting_rpc_message.proto",
+ ]
+}
+
+source_set("rpc") {
+ sources = [
+ "rpc/proto_enum_utils.cc",
+ "rpc/proto_enum_utils.h",
+ "rpc/proto_utils.cc",
+ "rpc/proto_utils.h",
+ ]
+
+ deps = [
+ "//base",
+ ]
+
+ public_deps = [
+ ":media_remoting_proto",
+ ]
+}
+
+test("media_remoting_unittests") {
+ sources = [
+ "rpc/proto_utils_unittest.cc",
+ ]
+
+ deps = [
+ ":rpc",
+ "//base",
+ "//base/test:run_all_unittests",
+ "//base/test:test_support",
+ "//media",
+ "//testing/gmock",
+ "//testing/gtest",
+ "//ui/gfx:test_support",
+ "//ui/gfx/geometry",
+ ]
+}
diff --git a/media/remoting/OWNERS b/media/remoting/OWNERS
new file mode 100644
index 0000000..98698443
--- /dev/null
+++ b/media/remoting/OWNERS
@@ -0,0 +1,2 @@
+erickung@chromium.org
+miu@chromium.org
diff --git a/media/remoting/README b/media/remoting/README
new file mode 100644
index 0000000..6ef5278
--- /dev/null
+++ b/media/remoting/README
@@ -0,0 +1,3 @@
+This folder provides an interface to play local content to the remote device.
+All the command and control messages will be converted into proto buffer as
+RPC message to the end point.
\ No newline at end of file
diff --git a/media/remoting/proto/remoting_rpc_message.proto b/media/remoting/proto/remoting_rpc_message.proto
new file mode 100644
index 0000000..e9b9e7e
--- /dev/null
+++ b/media/remoting/proto/remoting_rpc_message.proto
@@ -0,0 +1,563 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Protocol buffer for Media Remoting.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package media.remoting.pb;
+
+// DecoderBuffer information which will be sent using RTP packets. The actual
+// decoder buffer is not included in this proto data structure.
+message DecoderBuffer {
+ optional int64 timestamp_usec = 1;
+ optional int64 duration_usec = 2;
+ optional bool is_key_frame = 3;
+ optional DecryptConfig decrypt_config = 4;
+ optional int64 front_discard_usec = 5;
+ optional int64 back_discard_usec = 6;
+ optional int64 splice_timestamp_usec = 7;
+ optional bytes side_data = 8;
+ // To distinguish from valid 0-length buffers
+ optional bool is_eos = 9;
+}
+
+// Utility proto data structure
+message Size {
+ optional int32 width = 1;
+ optional int32 height = 2;
+}
+
+message EncryptionScheme {
+ // Align with EncryptionScheme::CipherMode
+ enum CipherMode {
+ CIPHER_MODE_UNENCRYPTED = 0;
+ CIPHER_MODE_AES_CTR = 1;
+ CIPHER_MODE_AES_CBC = 2;
+ }
+
+ optional CipherMode mode = 1;
+ optional uint32 encrypt_blocks = 2;
+ optional uint32 skip_blocks = 3;
+}
+
+message AudioDecoderConfig {
+ // Should align with ::media::Codec
+ enum Codec {
+ kUnknownAudioCodec = 0;
+ kCodecAAC = 1;
+ kCodecMP3 = 2;
+ kCodecPCM = 3;
+ kCodecVorbis = 4;
+ kCodecFLAC = 5;
+ kCodecAMR_NB = 6;
+ kCodecAMR_WB = 7;
+ kCodecPCM_MULAW = 8;
+ kCodecGSM_MS = 9;
+ kCodecPCM_S16BE = 10;
+ kCodecPCM_S24BE = 11;
+ kCodecOpus = 12;
+ kCodecEAC3 = 13;
+ kCodecPCM_ALAW = 14;
+ kCodecALAC = 15;
+ kCodecAC3 = 16;
+ }
+
+ // Should align with ::media::SampleFormat
+ enum SampleFormat {
+ kUnknownSampleFormat = 0;
+ kSampleFormatU8 = 1;
+ kSampleFormatS16 = 2;
+ kSampleFormatS32 = 3;
+ kSampleFormatF32 = 4;
+ kSampleFormatPlanarS16 = 5;
+ kSampleFormatPlanarF32 = 6;
+ kSampleFormatPlanarS32 = 7;
+ kSampleFormatS24 = 8;
+ };
+
+ // Should align with ::media::ChannelLayout
+ enum ChannelLayout {
+ CHANNEL_LAYOUT_NONE = 0;
+ CHANNEL_LAYOUT_UNSUPPORTED = 1;
+ CHANNEL_LAYOUT_MONO = 2;
+ CHANNEL_LAYOUT_STEREO = 3;
+ CHANNEL_LAYOUT_2_1 = 4;
+ CHANNEL_LAYOUT_SURROUND = 5;
+ CHANNEL_LAYOUT_4_0 = 6;
+ CHANNEL_LAYOUT_2_2 = 7;
+ CHANNEL_LAYOUT_QUAD = 8;
+ CHANNEL_LAYOUT_5_0 = 9;
+ CHANNEL_LAYOUT_5_1 = 10;
+ CHANNEL_LAYOUT_5_0_BACK = 11;
+ CHANNEL_LAYOUT_5_1_BACK = 12;
+ CHANNEL_LAYOUT_7_0 = 13;
+ CHANNEL_LAYOUT_7_1 = 14;
+ CHANNEL_LAYOUT_7_1_WIDE = 15;
+ CHANNEL_LAYOUT_STEREO_DOWNMIX = 16;
+ CHANNEL_LAYOUT_2POINT1 = 17;
+ CHANNEL_LAYOUT_3_1 = 18;
+ CHANNEL_LAYOUT_4_1 = 19;
+ CHANNEL_LAYOUT_6_0 = 20;
+ CHANNEL_LAYOUT_6_0_FRONT = 21;
+ CHANNEL_LAYOUT_HEXAGONAL = 22;
+ CHANNEL_LAYOUT_6_1 = 23;
+ CHANNEL_LAYOUT_6_1_BACK = 24;
+ CHANNEL_LAYOUT_6_1_FRONT = 25;
+ CHANNEL_LAYOUT_7_0_FRONT = 26;
+ CHANNEL_LAYOUT_7_1_WIDE_BACK = 27;
+ CHANNEL_LAYOUT_OCTAGONAL = 28;
+ CHANNEL_LAYOUT_DISCRETE = 29;
+ CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC = 30;
+ CHANNEL_LAYOUT_4_1_QUAD_SIDE = 31;
+ };
+
+ optional Codec codec = 1;
+ optional EncryptionScheme encryption_scheme = 2;
+ optional SampleFormat sample_format = 3;
+ optional ChannelLayout channel_layout = 4;
+ optional int32 samples_per_second = 5;
+ optional int64 seek_preroll_usec = 6;
+ optional int32 codec_delay = 7;
+ optional bytes extra_data = 8;
+}
+
+message Rect {
+ optional int32 x = 1;
+ optional int32 y = 2;
+ optional int32 width = 3;
+ optional int32 height = 4;
+}
+
+message VideoDecoderConfig {
+ // Should align with ::media::VideoCodec
+ enum Codec {
+ kUnknownVideoCodec = 0;
+ kCodecH264 = 1;
+ kCodecVC1 = 2;
+ kCodecMPEG2 = 3;
+ kCodecMPEG4 = 4;
+ kCodecTheora = 5;
+ kCodecVP8 = 6;
+ kCodecVP9 = 7;
+ kCodecHEVC = 8;
+ }
+
+ // Should align with ::media::VideoCodecProfile
+ enum Profile {
+ VIDEO_CODEC_PROFILE_UNKNOWN = -1;
+ H264PROFILE_BASELINE = 0;
+ H264PROFILE_MAIN = 1;
+ H264PROFILE_EXTENDED = 2;
+ H264PROFILE_HIGH = 3;
+ H264PROFILE_HIGH10PROFILE = 4;
+ H264PROFILE_HIGH422PROFILE = 5;
+ H264PROFILE_HIGH444PREDICTIVEPROFILE = 6;
+ H264PROFILE_SCALABLEBASELINE = 7;
+ H264PROFILE_SCALABLEHIGH = 8;
+ H264PROFILE_STEREOHIGH = 9;
+ H264PROFILE_MULTIVIEWHIGH = 10;
+ VP8PROFILE_ANY = 11;
+ VP9PROFILE_PROFILE0 = 12;
+ VP9PROFILE_PROFILE1 = 13;
+ VP9PROFILE_PROFILE2 = 14;
+ VP9PROFILE_PROFILE3 = 15;
+ HEVCPROFILE_MAIN = 16;
+ HEVCPROFILE_MAIN10 = 17;
+ HEVCPROFILE_MAIN_STILL_PICTURE = 18;
+ };
+
+ // Should align with ::media::VideoPixelFormat
+ enum Format {
+ PIXEL_FORMAT_UNKNOWN = 0;
+ PIXEL_FORMAT_I420 = 1;
+ PIXEL_FORMAT_YV12 = 2;
+ PIXEL_FORMAT_YV16 = 3;
+ PIXEL_FORMAT_YV12A = 4;
+ PIXEL_FORMAT_YV24 = 5;
+ PIXEL_FORMAT_NV12 = 6;
+ PIXEL_FORMAT_NV21 = 7;
+ PIXEL_FORMAT_UYVY = 8;
+ PIXEL_FORMAT_YUY2 = 9;
+ PIXEL_FORMAT_ARGB = 10;
+ PIXEL_FORMAT_XRGB = 11;
+ PIXEL_FORMAT_RGB24 = 12;
+ PIXEL_FORMAT_RGB32 = 13;
+ PIXEL_FORMAT_MJPEG = 14;
+ PIXEL_FORMAT_MT21 = 15;
+ PIXEL_FORMAT_YUV420P9 = 16;
+ PIXEL_FORMAT_YUV420P10 = 17;
+ PIXEL_FORMAT_YUV422P9 = 18;
+ PIXEL_FORMAT_YUV422P10 = 19;
+ PIXEL_FORMAT_YUV444P9 = 20;
+ PIXEL_FORMAT_YUV444P10 = 21;
+ };
+
+ // Should align with ::media::ColorSpace
+ enum ColorSpace {
+ COLOR_SPACE_UNSPECIFIED = 0;
+ COLOR_SPACE_JPEG = 1;
+ COLOR_SPACE_HD_REC709 = 2;
+ COLOR_SPACE_SD_REC601 = 3;
+ };
+
+ optional Codec codec = 1;
+ optional EncryptionScheme encryption_scheme = 2;
+ optional Profile profile = 3;
+ optional Format format = 4;
+ optional ColorSpace color_space = 5;
+ optional Size coded_size = 6;
+ optional Rect visible_rect = 7;
+ optional Size natural_size = 8;
+ optional bytes extra_data = 9;
+}
+
+message DecryptConfig {
+ message SubSample {
+ optional uint32 clear_bytes = 1;
+ optional uint32 cypher_bytes = 2;
+ }
+
+ optional bytes key_id = 1;
+ optional bytes iv = 2;
+ repeated SubSample sub_samples = 3;
+}
+
+message PipelineStatistics {
+ optional uint64 audio_bytes_decoded = 1;
+ optional uint64 video_bytes_decoded = 2;
+ optional uint32 video_frames_decoded = 3;
+ optional uint32 video_frames_dropped = 4;
+ optional int64 audio_memory_usage = 5;
+ optional int64 video_memory_usage = 6;
+};
+
+message CdmKeyInformation {
+ // Align with ::media::CdmKeyInformation::KeyStatus
+ enum KeyStatus {
+ USABLE = 0;
+ INTERNAL_ERROR = 1;
+ EXPIRED = 2;
+ OUTPUT_RESTRICTED = 3;
+ OUTPUT_DOWNSCALED = 4;
+ KEY_STATUS_PENDING = 5;
+ RELEASED = 6;
+ }
+
+ optional bytes key_id = 1;
+ optional KeyStatus status = 2;
+ optional uint32 system_code = 3;
+}
+
+// Should align with ::media::MediaKeys::Exception
+enum MediaKeysException {
+ NOT_SUPPORTED_ERROR = 0;
+ INVALID_STATE_ERROR = 1;
+ INVALID_ACCESS_ERROR = 2;
+ QUOTA_EXCEEDED_ERROR = 3;
+ UNKNOWN_ERROR = 4;
+ CLIENT_ERROR = 5;
+ OUTPUT_ERROR = 6;
+}
+
+// Should align with ::media::MediaKeys::MessageType
+enum MediaKeysMessageType {
+ LICENSE_REQUEST = 0;
+ LICENSE_RENEWAL = 1;
+ LICENSE_RELEASE = 2;
+}
+
+// Should align with ::media::MediaKeys::SessionType
+enum MediaKeysSessionType {
+ TEMPORARY_SESSION = 0;
+ PERSISTENT_LICENSE_SESSION = 1;
+ PERSISTENT_RELEASE_MESSAGE_SESSION = 2;
+};
+
+// Custom proto data structure
+message RendererInitialize {
+ optional int32 client_handle = 1;
+ optional int32 audio_demuxer_handle = 2;
+ optional int32 video_demuxer_handle = 3;
+ optional int32 callback_handle = 4;
+}
+
+message RendererFlushUntil {
+ optional uint32 audio_count = 1;
+ optional uint32 video_count = 2;
+ optional int32 callback_handle = 3;
+}
+
+message RendererSetCdm {
+ optional int32 cdm_id = 1;
+ optional int32 callback_handle = 2;
+}
+
+message RendererClientOnTimeUpdate {
+ optional int64 time_usec = 1;
+ optional int64 max_time_usec = 2;
+}
+
+message DemuxerStreamReadUntil {
+ optional int32 callback_handle = 1;
+ optional uint32 count = 2;
+}
+
+message DemuxerStreamInitializeCallback {
+ optional int32 type = 1;
+ optional AudioDecoderConfig audio_decoder_config = 2;
+ optional VideoDecoderConfig video_decoder_config = 3;
+}
+
+message DemuxerStreamReadUntilCallback {
+ // Should align with ::media::DemuxerStream::Status
+ enum Status {
+ kOk = 0;
+ kAborted = 1;
+ kConfigChanged = 2;
+ };
+
+ optional Status status = 1;
+ optional uint32 count = 2;
+ optional AudioDecoderConfig audio_decoder_config = 3;
+ optional VideoDecoderConfig video_decoder_config = 4;
+}
+
+message CdmInitialize {
+ optional string key_system = 1;
+ optional string security_origin = 2;
+ optional bool allow_distinctive_identifier = 3;
+ optional bool allow_persistent_state = 4;
+ optional bool use_hw_secure_codecs = 5;
+ optional int32 callback_handle = 6;
+}
+
+message CdmSetServerCertificate {
+ optional int32 callback_handle = 1;
+ optional bytes certificate_data = 2;
+}
+
+message CdmCreateSessionAndGenerateRequest {
+ enum EmeInitDataType {
+ UNKNOWN = 0;
+ WEBM = 1;
+ CENC = 2;
+ KEYIDS = 3;
+ };
+
+ optional MediaKeysSessionType session_type = 1;
+ optional EmeInitDataType init_data_type = 2;
+ optional int32 callback_handle = 3;
+ optional bytes init_data = 4;
+}
+
+message CdmLoadSession {
+ optional MediaKeysSessionType session_type = 1;
+ optional string session_id = 2;
+ optional int32 callback_handle = 3;
+}
+
+message CdmUpdateSession {
+ optional string session_id = 1;
+ optional int32 callback_handle = 2;
+ optional bytes response = 3;
+}
+
+message CdmCloseSession {
+ optional string session_id = 1;
+ optional int32 callback_handle = 2;
+}
+
+message CdmRemoveSession {
+ optional string session_id = 1;
+ optional int32 callback_handle = 2;
+}
+
+message CdmPromise {
+ // These two fields are used only for RPC_CDM_INITIALIZE_CALLBACK
+ optional int32 cdm_id = 1;
+ optional int32 decryptor_handle = 2;
+
+ optional string session_id = 3;
+ optional bool success = 4;
+ optional MediaKeysException exception = 5;
+ optional uint32 system_code = 6;
+ optional string error_message = 7;
+}
+
+message CdmClientOnSessionMessage {
+ optional string session_id = 1;
+ optional MediaKeysMessageType message_type = 2;
+ optional bytes message = 3;
+}
+
+message CdmClientOnSessionKeysChange {
+ optional string session_id = 1;
+ optional bool has_additional_usable_key = 2;
+ repeated CdmKeyInformation key_information = 3;
+}
+
+message CdmClientOnSessionExpirationUpdate {
+ optional string session_id = 1;
+ optional double new_expiry_time_sec = 2;
+}
+
+message RpcMessage {
+ enum RpcProc {
+ // Remoting setup
+ RPC_INTERNAL = 0;
+ RPC_ACQUIRE_RENDERER = 1;
+ RPC_ACQUIRE_RENDERER_DONE = 2;
+ RPC_ACQUIRE_CDM = 3;
+ RPC_ACQUIRE_CDM_DONE = 4;
+ // Renderer message
+ RPC_R_INITIALIZE = 1000;
+ RPC_R_FLUSHUNTIL = 1001;
+ RPC_R_STARTPLAYINGFROM = 1002;
+ RPC_R_SETPLAYBACKRATE = 1003;
+ RPC_R_SETVOLUME = 1004;
+ RPC_R_SETCDM = 1005;
+ // Renderer callbacks
+ RPC_R_INITIALIZE_CALLBACK = 1100;
+ RPC_R_FLUSHUNTIL_CALLBACK = 1101;
+ RPC_R_SETCDM_CALLBACK = 1102;
+ // Renderer client message
+ RPC_RC_ONTIMEUPDATE = 2000;
+ RPC_RC_ONBUFFERINGSTATECHANGE = 2001;
+ RPC_RC_ONENDED = 2002;
+ RPC_RC_ONERROR = 2003;
+ RPC_RC_ONVIDEONATURALSIZECHANGE = 2004;
+ RPC_RC_ONVIDEOOPACITYCHANGE = 2005;
+ RPC_RC_ONSTATISTICSUPDATE = 2006;
+ RPC_RC_ONWAITINGFORDECRYPTIONKEY = 2007;
+ RPC_RC_ONDURATIONCHANGE = 2008;
+ // DemuxerStream message
+ RPC_DS_INITIALIZE = 3000;
+ RPC_DS_READUNTIL = 3001;
+ RPC_DS_ENABLEBITSTREAMCONVERTER = 3002;
+ // DemuxerStream callbacks
+ RPC_DS_INITIALIZE_CALLBACK = 3100;
+ RPC_DS_READUNTIL_CALLBACK = 3101;
+ // ContentDecryptionModule
+ RPC_CDM_SETCLIENT = 4000;
+ RPC_CDM_INITIALIZE = 4001;
+ RPC_CDM_SETSERVERCERTIFICATE = 4002;
+ RPC_CDM_CREATESESSIONANDGENERATEREQUEST = 4003;
+ RPC_CDM_LOADSESSION = 4004;
+ RPC_CDM_UPDATESESSION = 4005;
+ RPC_CDM_CLOSESESSION = 4006;
+ RPC_CDM_REMOVESESSION = 4007;
+ // ContentDecryptionModule callbacks
+ RPC_CDM_INITIALIZE_CALLBACK = 4100;
+ RPC_CDM_SETSERVERCERTIFICATE_CALLBACK = 4101;
+ RPC_CDM_CREATESESSIONANDGENERATEREQUEST_CALLBACK = 4102;
+ RPC_CDM_LOADSESSION_CALLBACK = 4103;
+ RPC_CDM_UPDATESESSION_CALLBACK = 4104;
+ RPC_CDM_CLOSESESSION_CALLBACK = 4105;
+ RPC_CDM_REMOVESESSION_CALLBACK = 4106;
+ // ContentDecryptionModule client
+ RPC_CDMC_ONSESSIONMESSAGE = 5000;
+ RPC_CDMC_ONSESSIONCLOSED = 5001;
+ RPC_CDMC_ONSESSIONKEYSCHANGE = 5002;
+ RPC_CDMC_ONSESSIONEXPIRATIONUPDATE = 5003;
+ };
+
+ // Component base of RPC message handle. This allows both sender and receiver
+ // to send or handle message in desired individual components.
+ optional int32 handle = 1;
+
+ // RpcProc of this RPC message
+ optional RpcProc proc = 2;
+
+ oneof rpc_oneof {
+ // For simple RPC which only passes one parameters can use the following
+ // various data type variables without using specific proto data structure.
+ // RPC_ACQUIRE_RENDERER
+ // RPC_ACQUIRE_RENDERER_DONE
+ // RPC_ACQUIRE_CDM
+ // RPC_ACQUIRE_CDM_DONE
+ // RPC_RC_ONBUFFERINGSTATECHANGE
+ // RPC_DS_INITIALIZE_CALLBACK
+ // RPC_DS_READ
+ // RPC_CDM_SETCLIENT
+ int32 integer_value = 3;
+
+ // RPC_R_STARTPLAYINGFROM
+ // RPC_RC_ONDURATIONCHANGE
+ int64 integer64_value = 4;
+
+ // RPC_R_SETPLAYBACKRATE
+ // RPC_R_SETVOLUME
+ double double_value = 5;
+
+ // RPC_R_INITIALIZE_CALLBACK
+ // RPC_R_SETCDM_CALLBACK
+ // RPC_RC_ONVIDEOOPACITYCHANGE
+ bool boolean_value = 6;
+
+ // string only:
+ // RPC_CDMC_ONSESSIONCLOSED
+ string string_value = 7;
+
+ // RPC_R_INITIALIZE
+ RendererInitialize renderer_initialize_rpc = 100;
+
+ // RPC_R_FLUSHUNTIL
+ RendererFlushUntil renderer_flushuntil_rpc = 101;
+
+ // RPC_R_SETCDM
+ RendererSetCdm renderer_set_cdm_rpc = 102;
+
+ // RPC_RC_ONTIMEUPDATE
+ RendererClientOnTimeUpdate rendererclient_ontimeupdate_rpc = 200;
+ // RPC_RC_ONVIDEONATURALSIZECHANGE
+ Size rendererclient_onvideonatualsizechange_rpc = 201;
+ // RPC_RC_ONSTATISTICSUPDATE
+ PipelineStatistics rendererclient_onstatisticsupdate_rpc = 202;
+
+ // RPC_DS_READUNTIL
+ DemuxerStreamReadUntil demuxerstream_readuntil_rpc = 300;
+
+ // RPC_DS_INITIALIZE_CALLBACK
+ DemuxerStreamInitializeCallback demuxerstream_initializecb_rpc = 400;
+ // RPC_DS_READUNTIL_CALLBACK
+ DemuxerStreamReadUntilCallback demuxerstream_readuntilcb_rpc = 401;
+
+ // RPC_CDM_INITIALIZE
+ CdmInitialize cdm_initialize_rpc = 500;
+ // RPC_CDM_SETSERVERCERTIFICATE
+ CdmSetServerCertificate cdm_setservercertificate_rpc = 501;
+ // RPC_CDM_CREATESESSIONANDGENERATEREQUEST
+ CdmCreateSessionAndGenerateRequest cdm_createsessionandgeneraterequest_rpc =
+ 502;
+ // RPC_CDM_LOADSESSION
+ CdmLoadSession cdm_loadsession_rpc = 503;
+ // RPC_CDM_UPDATESESSION
+ CdmUpdateSession cdm_updatesession_rpc = 504;
+ // RPC_CDM_CLOSESESSION
+ CdmCloseSession cdm_closesession_rpc = 505;
+ // RPC_CDM_REMOVESESSION
+ CdmRemoveSession cdm_removesession_rpc = 506;
+
+ // CdmPromise message type used for the following procedure
+ // RPC_CDM_INITIALIZE_CALLBACK
+ // RPC_CDM_SETSERVERCERTIFICATE_CALLBACK
+ // RPC_CDM_CREATESESSIONANDGENERATEREQUEST_CALLBACK
+ // RPC_CDM_LOADSESSION_CALLBACK
+ // RPC_CDM_UPDATESESSION_CALLBACK
+ // RPC_CDM_CLOSESESSION_CALLBACK
+ // RPC_CDM_REMOVESESSION_CALLBACK
+ CdmPromise cdm_promise_rpc = 600;
+
+ // RPC_CDMC_ONSESSIONMESSAGE
+ CdmClientOnSessionMessage cdmclient_onsessionmessage_rpc = 601;
+ // RPC_CDMC_ONSESSIONKEYSCHANGE
+ CdmClientOnSessionKeysChange cdmclient_onsessionkeychange_rpc = 602;
+ // RPC_CDMC_ONSESSIONEXPIRATIONUPDATE
+ CdmClientOnSessionExpirationUpdate cdmclient_onsessionexpirationupdate_rpc =
+ 603;
+ };
+}
\ No newline at end of file
diff --git a/media/remoting/rpc/proto_enum_utils.cc b/media/remoting/rpc/proto_enum_utils.cc
new file mode 100644
index 0000000..5fd0ac7
--- /dev/null
+++ b/media/remoting/rpc/proto_enum_utils.cc
@@ -0,0 +1,553 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/remoting/rpc/proto_enum_utils.h"
+
+namespace media {
+namespace remoting {
+
+#define CASE_RETURN_OTHER(x) \
+ case OriginType::x: \
+ return OtherType::x
+
+base::Optional<::media::EncryptionScheme::CipherMode>
+ToMediaEncryptionSchemeCipherMode(pb::EncryptionScheme::CipherMode value) {
+ using OriginType = pb::EncryptionScheme;
+ using OtherType = ::media::EncryptionScheme;
+ switch (value) {
+ CASE_RETURN_OTHER(CIPHER_MODE_UNENCRYPTED);
+ CASE_RETURN_OTHER(CIPHER_MODE_AES_CTR);
+ CASE_RETURN_OTHER(CIPHER_MODE_AES_CBC);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<pb::EncryptionScheme::CipherMode>
+ToProtoEncryptionSchemeCipherMode(::media::EncryptionScheme::CipherMode value) {
+ using OriginType = ::media::EncryptionScheme;
+ using OtherType = pb::EncryptionScheme;
+ switch (value) {
+ CASE_RETURN_OTHER(CIPHER_MODE_UNENCRYPTED);
+ CASE_RETURN_OTHER(CIPHER_MODE_AES_CTR);
+ CASE_RETURN_OTHER(CIPHER_MODE_AES_CBC);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<::media::AudioCodec> ToMediaAudioCodec(
+ pb::AudioDecoderConfig::Codec value) {
+ using OriginType = pb::AudioDecoderConfig;
+ using OtherType = ::media::AudioCodec;
+ switch (value) {
+ CASE_RETURN_OTHER(kUnknownAudioCodec);
+ CASE_RETURN_OTHER(kCodecAAC);
+ CASE_RETURN_OTHER(kCodecMP3);
+ CASE_RETURN_OTHER(kCodecPCM);
+ CASE_RETURN_OTHER(kCodecVorbis);
+ CASE_RETURN_OTHER(kCodecFLAC);
+ CASE_RETURN_OTHER(kCodecAMR_NB);
+ CASE_RETURN_OTHER(kCodecAMR_WB);
+ CASE_RETURN_OTHER(kCodecPCM_MULAW);
+ CASE_RETURN_OTHER(kCodecGSM_MS);
+ CASE_RETURN_OTHER(kCodecPCM_S16BE);
+ CASE_RETURN_OTHER(kCodecPCM_S24BE);
+ CASE_RETURN_OTHER(kCodecOpus);
+ CASE_RETURN_OTHER(kCodecEAC3);
+ CASE_RETURN_OTHER(kCodecPCM_ALAW);
+ CASE_RETURN_OTHER(kCodecALAC);
+ CASE_RETURN_OTHER(kCodecAC3);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<pb::AudioDecoderConfig::Codec> ToProtoAudioDecoderConfigCodec(
+ ::media::AudioCodec value) {
+ using OriginType = ::media::AudioCodec;
+ using OtherType = pb::AudioDecoderConfig;
+ switch (value) {
+ CASE_RETURN_OTHER(kUnknownAudioCodec);
+ CASE_RETURN_OTHER(kCodecAAC);
+ CASE_RETURN_OTHER(kCodecMP3);
+ CASE_RETURN_OTHER(kCodecPCM);
+ CASE_RETURN_OTHER(kCodecVorbis);
+ CASE_RETURN_OTHER(kCodecFLAC);
+ CASE_RETURN_OTHER(kCodecAMR_NB);
+ CASE_RETURN_OTHER(kCodecAMR_WB);
+ CASE_RETURN_OTHER(kCodecPCM_MULAW);
+ CASE_RETURN_OTHER(kCodecGSM_MS);
+ CASE_RETURN_OTHER(kCodecPCM_S16BE);
+ CASE_RETURN_OTHER(kCodecPCM_S24BE);
+ CASE_RETURN_OTHER(kCodecOpus);
+ CASE_RETURN_OTHER(kCodecEAC3);
+ CASE_RETURN_OTHER(kCodecPCM_ALAW);
+ CASE_RETURN_OTHER(kCodecALAC);
+ CASE_RETURN_OTHER(kCodecAC3);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<::media::SampleFormat> ToMediaSampleFormat(
+ pb::AudioDecoderConfig::SampleFormat value) {
+ using OriginType = pb::AudioDecoderConfig;
+ using OtherType = ::media::SampleFormat;
+ switch (value) {
+ CASE_RETURN_OTHER(kUnknownSampleFormat);
+ CASE_RETURN_OTHER(kSampleFormatU8);
+ CASE_RETURN_OTHER(kSampleFormatS16);
+ CASE_RETURN_OTHER(kSampleFormatS32);
+ CASE_RETURN_OTHER(kSampleFormatF32);
+ CASE_RETURN_OTHER(kSampleFormatPlanarS16);
+ CASE_RETURN_OTHER(kSampleFormatPlanarF32);
+ CASE_RETURN_OTHER(kSampleFormatPlanarS32);
+ CASE_RETURN_OTHER(kSampleFormatS24);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<pb::AudioDecoderConfig::SampleFormat>
+ToProtoAudioDecoderConfigSampleFormat(::media::SampleFormat value) {
+ using OriginType = ::media::SampleFormat;
+ using OtherType = pb::AudioDecoderConfig;
+ switch (value) {
+ CASE_RETURN_OTHER(kUnknownSampleFormat);
+ CASE_RETURN_OTHER(kSampleFormatU8);
+ CASE_RETURN_OTHER(kSampleFormatS16);
+ CASE_RETURN_OTHER(kSampleFormatS32);
+ CASE_RETURN_OTHER(kSampleFormatF32);
+ CASE_RETURN_OTHER(kSampleFormatPlanarS16);
+ CASE_RETURN_OTHER(kSampleFormatPlanarF32);
+ CASE_RETURN_OTHER(kSampleFormatPlanarS32);
+ CASE_RETURN_OTHER(kSampleFormatS24);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<::media::ChannelLayout> ToMediaChannelLayout(
+ pb::AudioDecoderConfig::ChannelLayout value) {
+ using OriginType = pb::AudioDecoderConfig;
+ using OtherType = ::media::ChannelLayout;
+ switch (value) {
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_NONE);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_UNSUPPORTED);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_MONO);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_STEREO);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_2_1);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_SURROUND);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_4_0);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_2_2);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_QUAD);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_5_0);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_5_1);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_5_0_BACK);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_5_1_BACK);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_7_0);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_7_1);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_7_1_WIDE);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_STEREO_DOWNMIX);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_2POINT1);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_3_1);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_4_1);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_6_0);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_6_0_FRONT);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_HEXAGONAL);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_6_1);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_6_1_BACK);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_6_1_FRONT);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_7_0_FRONT);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_7_1_WIDE_BACK);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_OCTAGONAL);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_DISCRETE);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_4_1_QUAD_SIDE);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<pb::AudioDecoderConfig::ChannelLayout>
+ToProtoAudioDecoderConfigChannelLayout(::media::ChannelLayout value) {
+ using OriginType = ::media::ChannelLayout;
+ using OtherType = pb::AudioDecoderConfig;
+ switch (value) {
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_NONE);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_UNSUPPORTED);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_MONO);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_STEREO);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_2_1);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_SURROUND);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_4_0);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_2_2);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_QUAD);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_5_0);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_5_1);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_5_0_BACK);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_5_1_BACK);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_7_0);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_7_1);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_7_1_WIDE);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_STEREO_DOWNMIX);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_2POINT1);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_3_1);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_4_1);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_6_0);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_6_0_FRONT);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_HEXAGONAL);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_6_1);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_6_1_BACK);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_6_1_FRONT);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_7_0_FRONT);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_7_1_WIDE_BACK);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_OCTAGONAL);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_DISCRETE);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC);
+ CASE_RETURN_OTHER(CHANNEL_LAYOUT_4_1_QUAD_SIDE);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<::media::VideoCodec> ToMediaVideoCodec(
+ pb::VideoDecoderConfig::Codec value) {
+ using OriginType = pb::VideoDecoderConfig;
+ using OtherType = ::media::VideoCodec;
+ switch (value) {
+ CASE_RETURN_OTHER(kUnknownVideoCodec);
+ CASE_RETURN_OTHER(kCodecH264);
+ CASE_RETURN_OTHER(kCodecVC1);
+ CASE_RETURN_OTHER(kCodecMPEG2);
+ CASE_RETURN_OTHER(kCodecMPEG4);
+ CASE_RETURN_OTHER(kCodecTheora);
+ CASE_RETURN_OTHER(kCodecVP8);
+ CASE_RETURN_OTHER(kCodecVP9);
+ CASE_RETURN_OTHER(kCodecHEVC);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<pb::VideoDecoderConfig::Codec> ToProtoVideoDecoderConfigCodec(
+ ::media::VideoCodec value) {
+ using OriginType = ::media::VideoCodec;
+ using OtherType = pb::VideoDecoderConfig;
+ switch (value) {
+ CASE_RETURN_OTHER(kUnknownVideoCodec);
+ CASE_RETURN_OTHER(kCodecH264);
+ CASE_RETURN_OTHER(kCodecVC1);
+ CASE_RETURN_OTHER(kCodecMPEG2);
+ CASE_RETURN_OTHER(kCodecMPEG4);
+ CASE_RETURN_OTHER(kCodecTheora);
+ CASE_RETURN_OTHER(kCodecVP8);
+ CASE_RETURN_OTHER(kCodecVP9);
+ CASE_RETURN_OTHER(kCodecHEVC);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<::media::VideoCodecProfile> ToMediaVideoCodecProfile(
+ pb::VideoDecoderConfig::Profile value) {
+ using OriginType = pb::VideoDecoderConfig;
+ using OtherType = ::media::VideoCodecProfile;
+ switch (value) {
+ CASE_RETURN_OTHER(VIDEO_CODEC_PROFILE_UNKNOWN);
+ CASE_RETURN_OTHER(H264PROFILE_BASELINE);
+ CASE_RETURN_OTHER(H264PROFILE_MAIN);
+ CASE_RETURN_OTHER(H264PROFILE_EXTENDED);
+ CASE_RETURN_OTHER(H264PROFILE_HIGH);
+ CASE_RETURN_OTHER(H264PROFILE_HIGH10PROFILE);
+ CASE_RETURN_OTHER(H264PROFILE_HIGH422PROFILE);
+ CASE_RETURN_OTHER(H264PROFILE_HIGH444PREDICTIVEPROFILE);
+ CASE_RETURN_OTHER(H264PROFILE_SCALABLEBASELINE);
+ CASE_RETURN_OTHER(H264PROFILE_SCALABLEHIGH);
+ CASE_RETURN_OTHER(H264PROFILE_STEREOHIGH);
+ CASE_RETURN_OTHER(H264PROFILE_MULTIVIEWHIGH);
+ CASE_RETURN_OTHER(VP8PROFILE_ANY);
+ CASE_RETURN_OTHER(VP9PROFILE_PROFILE0);
+ CASE_RETURN_OTHER(VP9PROFILE_PROFILE1);
+ CASE_RETURN_OTHER(VP9PROFILE_PROFILE2);
+ CASE_RETURN_OTHER(VP9PROFILE_PROFILE3);
+ CASE_RETURN_OTHER(HEVCPROFILE_MAIN);
+ CASE_RETURN_OTHER(HEVCPROFILE_MAIN10);
+ CASE_RETURN_OTHER(HEVCPROFILE_MAIN_STILL_PICTURE);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<pb::VideoDecoderConfig::Profile>
+ToProtoVideoDecoderConfigProfile(::media::VideoCodecProfile value) {
+ using OriginType = ::media::VideoCodecProfile;
+ using OtherType = pb::VideoDecoderConfig;
+ switch (value) {
+ CASE_RETURN_OTHER(VIDEO_CODEC_PROFILE_UNKNOWN);
+ CASE_RETURN_OTHER(H264PROFILE_BASELINE);
+ CASE_RETURN_OTHER(H264PROFILE_MAIN);
+ CASE_RETURN_OTHER(H264PROFILE_EXTENDED);
+ CASE_RETURN_OTHER(H264PROFILE_HIGH);
+ CASE_RETURN_OTHER(H264PROFILE_HIGH10PROFILE);
+ CASE_RETURN_OTHER(H264PROFILE_HIGH422PROFILE);
+ CASE_RETURN_OTHER(H264PROFILE_HIGH444PREDICTIVEPROFILE);
+ CASE_RETURN_OTHER(H264PROFILE_SCALABLEBASELINE);
+ CASE_RETURN_OTHER(H264PROFILE_SCALABLEHIGH);
+ CASE_RETURN_OTHER(H264PROFILE_STEREOHIGH);
+ CASE_RETURN_OTHER(H264PROFILE_MULTIVIEWHIGH);
+ CASE_RETURN_OTHER(VP8PROFILE_ANY);
+ CASE_RETURN_OTHER(VP9PROFILE_PROFILE0);
+ CASE_RETURN_OTHER(VP9PROFILE_PROFILE1);
+ CASE_RETURN_OTHER(VP9PROFILE_PROFILE2);
+ CASE_RETURN_OTHER(VP9PROFILE_PROFILE3);
+ CASE_RETURN_OTHER(HEVCPROFILE_MAIN);
+ CASE_RETURN_OTHER(HEVCPROFILE_MAIN10);
+ CASE_RETURN_OTHER(HEVCPROFILE_MAIN_STILL_PICTURE);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<::media::VideoPixelFormat> ToMediaVideoPixelFormat(
+ pb::VideoDecoderConfig::Format value) {
+ using OriginType = pb::VideoDecoderConfig;
+ using OtherType = ::media::VideoPixelFormat;
+ switch (value) {
+ CASE_RETURN_OTHER(PIXEL_FORMAT_UNKNOWN);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_I420);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_YV12);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_YV16);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_YV12A);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_YV24);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_NV12);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_NV21);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_UYVY);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_YUY2);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_ARGB);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_XRGB);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_RGB24);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_RGB32);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_MJPEG);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_MT21);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_YUV420P9);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_YUV420P10);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_YUV422P9);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_YUV422P10);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_YUV444P9);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_YUV444P10);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<pb::VideoDecoderConfig::Format> ToProtoVideoDecoderConfigFormat(
+ ::media::VideoPixelFormat value) {
+ using OriginType = ::media::VideoPixelFormat;
+ using OtherType = pb::VideoDecoderConfig;
+ switch (value) {
+ CASE_RETURN_OTHER(PIXEL_FORMAT_UNKNOWN);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_I420);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_YV12);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_YV16);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_YV12A);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_YV24);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_NV12);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_NV21);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_UYVY);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_YUY2);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_ARGB);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_XRGB);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_RGB24);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_RGB32);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_MJPEG);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_MT21);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_YUV420P9);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_YUV420P10);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_YUV422P9);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_YUV422P10);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_YUV444P9);
+ CASE_RETURN_OTHER(PIXEL_FORMAT_YUV444P10);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<::media::ColorSpace> ToMediaColorSpace(
+ pb::VideoDecoderConfig::ColorSpace value) {
+ using OriginType = pb::VideoDecoderConfig;
+ using OtherType = ::media::ColorSpace;
+ switch (value) {
+ CASE_RETURN_OTHER(COLOR_SPACE_UNSPECIFIED);
+ CASE_RETURN_OTHER(COLOR_SPACE_JPEG);
+ CASE_RETURN_OTHER(COLOR_SPACE_HD_REC709);
+ CASE_RETURN_OTHER(COLOR_SPACE_SD_REC601);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<pb::VideoDecoderConfig::ColorSpace>
+ToProtoVideoDecoderConfigColorSpace(::media::ColorSpace value) {
+ using OriginType = ::media::ColorSpace;
+ using OtherType = pb::VideoDecoderConfig;
+ switch (value) {
+ CASE_RETURN_OTHER(COLOR_SPACE_UNSPECIFIED);
+ CASE_RETURN_OTHER(COLOR_SPACE_JPEG);
+ CASE_RETURN_OTHER(COLOR_SPACE_HD_REC709);
+ CASE_RETURN_OTHER(COLOR_SPACE_SD_REC601);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<::media::CdmKeyInformation::KeyStatus>
+ToMediaCdmKeyInformationKeyStatus(pb::CdmKeyInformation::KeyStatus value) {
+ using OriginType = pb::CdmKeyInformation;
+ using OtherType = ::media::CdmKeyInformation;
+ switch (value) {
+ CASE_RETURN_OTHER(USABLE);
+ CASE_RETURN_OTHER(INTERNAL_ERROR);
+ CASE_RETURN_OTHER(EXPIRED);
+ CASE_RETURN_OTHER(OUTPUT_RESTRICTED);
+ CASE_RETURN_OTHER(OUTPUT_DOWNSCALED);
+ CASE_RETURN_OTHER(KEY_STATUS_PENDING);
+ CASE_RETURN_OTHER(RELEASED);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<pb::CdmKeyInformation::KeyStatus> ToProtoCdmKeyInformation(
+ ::media::CdmKeyInformation::KeyStatus value) {
+ using OriginType = ::media::CdmKeyInformation;
+ using OtherType = pb::CdmKeyInformation;
+ switch (value) {
+ CASE_RETURN_OTHER(USABLE);
+ CASE_RETURN_OTHER(INTERNAL_ERROR);
+ CASE_RETURN_OTHER(EXPIRED);
+ CASE_RETURN_OTHER(OUTPUT_RESTRICTED);
+ CASE_RETURN_OTHER(OUTPUT_DOWNSCALED);
+ CASE_RETURN_OTHER(KEY_STATUS_PENDING);
+ CASE_RETURN_OTHER(RELEASED);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<::media::MediaKeys::Exception> ToMediaMediaKeysException(
+ pb::MediaKeysException value) {
+ using OriginType = pb::MediaKeysException;
+ using OtherType = ::media::MediaKeys;
+ switch (value) {
+ CASE_RETURN_OTHER(NOT_SUPPORTED_ERROR);
+ CASE_RETURN_OTHER(INVALID_STATE_ERROR);
+ CASE_RETURN_OTHER(INVALID_ACCESS_ERROR);
+ CASE_RETURN_OTHER(QUOTA_EXCEEDED_ERROR);
+ CASE_RETURN_OTHER(UNKNOWN_ERROR);
+ CASE_RETURN_OTHER(CLIENT_ERROR);
+ CASE_RETURN_OTHER(OUTPUT_ERROR);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<pb::MediaKeysException> ToProtoMediaKeysException(
+ ::media::MediaKeys::Exception value) {
+ using OriginType = ::media::MediaKeys;
+ using OtherType = pb::MediaKeysException;
+ switch (value) {
+ CASE_RETURN_OTHER(NOT_SUPPORTED_ERROR);
+ CASE_RETURN_OTHER(INVALID_STATE_ERROR);
+ CASE_RETURN_OTHER(INVALID_ACCESS_ERROR);
+ CASE_RETURN_OTHER(QUOTA_EXCEEDED_ERROR);
+ CASE_RETURN_OTHER(UNKNOWN_ERROR);
+ CASE_RETURN_OTHER(CLIENT_ERROR);
+ CASE_RETURN_OTHER(OUTPUT_ERROR);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<::media::MediaKeys::MessageType> ToMediaMediaKeysMessageType(
+ pb::MediaKeysMessageType value) {
+ using OriginType = pb::MediaKeysMessageType;
+ using OtherType = ::media::MediaKeys;
+ switch (value) {
+ CASE_RETURN_OTHER(LICENSE_REQUEST);
+ CASE_RETURN_OTHER(LICENSE_RENEWAL);
+ CASE_RETURN_OTHER(LICENSE_RELEASE);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<pb::MediaKeysMessageType> ToProtoMediaKeysMessageType(
+ ::media::MediaKeys::MessageType value) {
+ using OriginType = ::media::MediaKeys;
+ using OtherType = pb::MediaKeysMessageType;
+ switch (value) {
+ CASE_RETURN_OTHER(LICENSE_REQUEST);
+ CASE_RETURN_OTHER(LICENSE_RENEWAL);
+ CASE_RETURN_OTHER(LICENSE_RELEASE);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<::media::MediaKeys::SessionType> ToMediaKeysSessionType(
+ pb::MediaKeysSessionType value) {
+ using OriginType = pb::MediaKeysSessionType;
+ using OtherType = ::media::MediaKeys;
+ switch (value) {
+ CASE_RETURN_OTHER(TEMPORARY_SESSION);
+ CASE_RETURN_OTHER(PERSISTENT_LICENSE_SESSION);
+ CASE_RETURN_OTHER(PERSISTENT_RELEASE_MESSAGE_SESSION);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<pb::MediaKeysSessionType> ToProtoMediaKeysSessionType(
+ ::media::MediaKeys::SessionType value) {
+ using OriginType = ::media::MediaKeys;
+ using OtherType = pb::MediaKeysSessionType;
+ switch (value) {
+ CASE_RETURN_OTHER(TEMPORARY_SESSION);
+ CASE_RETURN_OTHER(PERSISTENT_LICENSE_SESSION);
+ CASE_RETURN_OTHER(PERSISTENT_RELEASE_MESSAGE_SESSION);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<::media::EmeInitDataType> ToMediaEmeInitDataType(
+ pb::CdmCreateSessionAndGenerateRequest::EmeInitDataType value) {
+ using OriginType = pb::CdmCreateSessionAndGenerateRequest;
+ using OtherType = ::media::EmeInitDataType;
+ switch (value) {
+ CASE_RETURN_OTHER(UNKNOWN);
+ CASE_RETURN_OTHER(WEBM);
+ CASE_RETURN_OTHER(CENC);
+ CASE_RETURN_OTHER(KEYIDS);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<pb::CdmCreateSessionAndGenerateRequest::EmeInitDataType>
+ToProtoMediaEmeInitDataType(::media::EmeInitDataType value) {
+ using OriginType = ::media::EmeInitDataType;
+ using OtherType = pb::CdmCreateSessionAndGenerateRequest;
+ switch (value) {
+ CASE_RETURN_OTHER(UNKNOWN);
+ CASE_RETURN_OTHER(WEBM);
+ CASE_RETURN_OTHER(CENC);
+ CASE_RETURN_OTHER(KEYIDS);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<::media::DemuxerStream::Status> ToDemuxerStreamStatus(
+ pb::DemuxerStreamReadUntilCallback::Status value) {
+ using OriginType = pb::DemuxerStreamReadUntilCallback;
+ using OtherType = ::media::DemuxerStream;
+ switch (value) {
+ CASE_RETURN_OTHER(kOk);
+ CASE_RETURN_OTHER(kAborted);
+ CASE_RETURN_OTHER(kConfigChanged);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+base::Optional<pb::DemuxerStreamReadUntilCallback::Status>
+ToProtoToDemuxerStreamStatus(::media::DemuxerStream::Status value) {
+ using OriginType = ::media::DemuxerStream;
+ using OtherType = pb::DemuxerStreamReadUntilCallback;
+ switch (value) {
+ CASE_RETURN_OTHER(kOk);
+ CASE_RETURN_OTHER(kAborted);
+ CASE_RETURN_OTHER(kConfigChanged);
+ }
+ return base::nullopt; // Not a 'default' to ensure compile-time checks.
+}
+
+} // namespace remoting
+} // namespace media
diff --git a/media/remoting/rpc/proto_enum_utils.h b/media/remoting/rpc/proto_enum_utils.h
new file mode 100644
index 0000000..62af79b
--- /dev/null
+++ b/media/remoting/rpc/proto_enum_utils.h
@@ -0,0 +1,105 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_REMOTING_RPC_PROTO_ENUM_UTILS_H_
+#define MEDIA_REMOTING_RPC_PROTO_ENUM_UTILS_H_
+
+#include "base/optional.h"
+#include "media/base/audio_codecs.h"
+#include "media/base/cdm_key_information.h"
+#include "media/base/channel_layout.h"
+#include "media/base/demuxer_stream.h"
+#include "media/base/encryption_scheme.h"
+#include "media/base/media_keys.h"
+#include "media/base/sample_format.h"
+#include "media/base/video_codecs.h"
+#include "media/base/video_types.h"
+#include "media/remoting/remoting_rpc_message.pb.h"
+
+namespace media {
+namespace remoting {
+
+// The following functions map between the enum values in media/base modules and
+// the equivalents in the media/remoting protobuf classes. The purpose of these
+// converters is to decouple the media/base modules from the media/remoting
+// modules while maintaining compile-time checks to ensure that there are always
+// valid, backwards-compatible mappings between the two.
+//
+// Each returns a base::Optional value. If it is not set, that indicates the
+// conversion failed.
+
+base::Optional<::media::EncryptionScheme::CipherMode>
+ToMediaEncryptionSchemeCipherMode(pb::EncryptionScheme::CipherMode value);
+base::Optional<pb::EncryptionScheme::CipherMode>
+ToProtoEncryptionSchemeCipherMode(::media::EncryptionScheme::CipherMode value);
+
+base::Optional<::media::AudioCodec> ToMediaAudioCodec(
+ pb::AudioDecoderConfig::Codec value);
+base::Optional<pb::AudioDecoderConfig::Codec> ToProtoAudioDecoderConfigCodec(
+ ::media::AudioCodec value);
+
+base::Optional<::media::SampleFormat> ToMediaSampleFormat(
+ pb::AudioDecoderConfig::SampleFormat value);
+base::Optional<pb::AudioDecoderConfig::SampleFormat>
+ToProtoAudioDecoderConfigSampleFormat(::media::SampleFormat value);
+
+base::Optional<::media::ChannelLayout> ToMediaChannelLayout(
+ pb::AudioDecoderConfig::ChannelLayout value);
+base::Optional<pb::AudioDecoderConfig::ChannelLayout>
+ToProtoAudioDecoderConfigChannelLayout(::media::ChannelLayout value);
+
+base::Optional<::media::VideoCodec> ToMediaVideoCodec(
+ pb::VideoDecoderConfig::Codec value);
+base::Optional<pb::VideoDecoderConfig::Codec> ToProtoVideoDecoderConfigCodec(
+ ::media::VideoCodec value);
+
+base::Optional<::media::VideoCodecProfile> ToMediaVideoCodecProfile(
+ pb::VideoDecoderConfig::Profile value);
+base::Optional<pb::VideoDecoderConfig::Profile>
+ToProtoVideoDecoderConfigProfile(::media::VideoCodecProfile value);
+
+base::Optional<::media::VideoPixelFormat> ToMediaVideoPixelFormat(
+ pb::VideoDecoderConfig::Format value);
+base::Optional<pb::VideoDecoderConfig::Format> ToProtoVideoDecoderConfigFormat(
+ ::media::VideoPixelFormat value);
+
+base::Optional<::media::ColorSpace> ToMediaColorSpace(
+ pb::VideoDecoderConfig::ColorSpace value);
+base::Optional<pb::VideoDecoderConfig::ColorSpace>
+ToProtoVideoDecoderConfigColorSpace(::media::ColorSpace value);
+
+base::Optional<::media::CdmKeyInformation::KeyStatus>
+ToMediaCdmKeyInformationKeyStatus(pb::CdmKeyInformation::KeyStatus value);
+base::Optional<pb::CdmKeyInformation::KeyStatus> ToProtoCdmKeyInformation(
+ ::media::CdmKeyInformation::KeyStatus value);
+
+base::Optional<::media::MediaKeys::Exception> ToMediaMediaKeysException(
+ pb::MediaKeysException value);
+base::Optional<pb::MediaKeysException> ToProtoMediaKeysException(
+ ::media::MediaKeys::Exception value);
+
+base::Optional<::media::MediaKeys::MessageType> ToMediaMediaKeysMessageType(
+ pb::MediaKeysMessageType value);
+base::Optional<pb::MediaKeysMessageType> ToProtoMediaKeysMessageType(
+ ::media::MediaKeys::MessageType value);
+
+base::Optional<::media::MediaKeys::SessionType> ToMediaKeysSessionType(
+ pb::MediaKeysSessionType value);
+base::Optional<pb::MediaKeysSessionType> ToProtoMediaKeysSessionType(
+ ::media::MediaKeys::SessionType value);
+
+base::Optional<::media::EmeInitDataType> ToMediaEmeInitDataType(
+ pb::CdmCreateSessionAndGenerateRequest::EmeInitDataType value);
+base::Optional<pb::CdmCreateSessionAndGenerateRequest::EmeInitDataType>
+ToProtoMediaEmeInitDataType(::media::EmeInitDataType value);
+
+base::Optional<::media::DemuxerStream::Status> ToDemuxerStreamStatus(
+ pb::DemuxerStreamReadUntilCallback::Status value);
+base::Optional<pb::DemuxerStreamReadUntilCallback::Status>
+ToProtoToDemuxerStreamStatus(::media::DemuxerStream::Status value);
+
+} // namespace remoting
+} // namespace media
+
+#endif // MEDIA_REMOTING_RPC_PROTO_ENUM_UTILS_H_
diff --git a/media/remoting/rpc/proto_utils.cc b/media/remoting/rpc/proto_utils.cc
new file mode 100644
index 0000000..d8fbd06
--- /dev/null
+++ b/media/remoting/rpc/proto_utils.cc
@@ -0,0 +1,472 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/remoting/rpc/proto_utils.h"
+
+#include <algorithm>
+
+#include "base/big_endian.h"
+#include "base/logging.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "media/base/encryption_scheme.h"
+#include "media/remoting/rpc/proto_enum_utils.h"
+
+namespace media {
+namespace remoting {
+
+namespace {
+
+constexpr size_t kPayloadVersionFieldSize = sizeof(uint8_t);
+constexpr size_t kProtoBufferHeaderSize = sizeof(uint16_t);
+constexpr size_t kDataBufferHeaderSize = sizeof(uint32_t);
+
+std::unique_ptr<::media::DecryptConfig> ConvertProtoToDecryptConfig(
+ const pb::DecryptConfig& config_message) {
+ if (!config_message.has_key_id())
+ return nullptr;
+ if (!config_message.has_iv())
+ return nullptr;
+
+ std::vector<::media::SubsampleEntry> entries(
+ config_message.sub_samples_size());
+ for (int i = 0; i < config_message.sub_samples_size(); ++i) {
+ entries.push_back(
+ ::media::SubsampleEntry(config_message.sub_samples(i).clear_bytes(),
+ config_message.sub_samples(i).cypher_bytes()));
+ }
+
+ std::unique_ptr<::media::DecryptConfig> decrypt_config(
+ new ::media::DecryptConfig(config_message.key_id(), config_message.iv(),
+ entries));
+ return decrypt_config;
+}
+
+scoped_refptr<::media::DecoderBuffer> ConvertProtoToDecoderBuffer(
+ const pb::DecoderBuffer& buffer_message,
+ scoped_refptr<::media::DecoderBuffer> buffer) {
+ if (buffer_message.is_eos()) {
+ VLOG(1) << "EOS data";
+ return ::media::DecoderBuffer::CreateEOSBuffer();
+ }
+
+ if (buffer_message.has_timestamp_usec()) {
+ buffer->set_timestamp(
+ base::TimeDelta::FromMicroseconds(buffer_message.timestamp_usec()));
+ }
+
+ if (buffer_message.has_duration_usec()) {
+ buffer->set_duration(
+ base::TimeDelta::FromMicroseconds(buffer_message.duration_usec()));
+ }
+ VLOG(3) << "timestamp:" << buffer_message.timestamp_usec()
+ << " duration:" << buffer_message.duration_usec();
+
+ if (buffer_message.has_is_key_frame())
+ buffer->set_is_key_frame(buffer_message.is_key_frame());
+
+ if (buffer_message.has_decrypt_config()) {
+ buffer->set_decrypt_config(
+ ConvertProtoToDecryptConfig(buffer_message.decrypt_config()));
+ }
+
+ bool has_discard = false;
+ base::TimeDelta front_discard;
+ if (buffer_message.has_front_discard_usec()) {
+ has_discard = true;
+ front_discard =
+ base::TimeDelta::FromMicroseconds(buffer_message.front_discard_usec());
+ }
+ base::TimeDelta back_discard;
+ if (buffer_message.has_back_discard_usec()) {
+ has_discard = true;
+ back_discard =
+ base::TimeDelta::FromMicroseconds(buffer_message.back_discard_usec());
+ }
+
+ if (has_discard) {
+ buffer->set_discard_padding(
+ ::media::DecoderBuffer::DiscardPadding(front_discard, back_discard));
+ }
+
+ if (buffer_message.has_splice_timestamp_usec()) {
+ buffer->set_splice_timestamp(base::TimeDelta::FromMicroseconds(
+ buffer_message.splice_timestamp_usec()));
+ }
+
+ if (buffer_message.has_side_data()) {
+ buffer->CopySideDataFrom(
+ reinterpret_cast<const uint8_t*>(buffer_message.side_data().data()),
+ buffer_message.side_data().size());
+ }
+
+ return buffer;
+}
+
+void ConvertDecryptConfigToProto(const ::media::DecryptConfig& decrypt_config,
+ pb::DecryptConfig* config_message) {
+ DCHECK(config_message);
+
+ config_message->set_key_id(decrypt_config.key_id());
+ config_message->set_iv(decrypt_config.iv());
+
+ for (const auto& entry : decrypt_config.subsamples()) {
+ pb::DecryptConfig::SubSample* sub_sample =
+ config_message->add_sub_samples();
+ sub_sample->set_clear_bytes(entry.clear_bytes);
+ sub_sample->set_cypher_bytes(entry.cypher_bytes);
+ }
+}
+
+void ConvertDecoderBufferToProto(
+ const scoped_refptr<::media::DecoderBuffer>& decoder_buffer,
+ pb::DecoderBuffer* buffer_message) {
+ if (decoder_buffer->end_of_stream()) {
+ buffer_message->set_is_eos(true);
+ return;
+ }
+
+ VLOG(3) << "timestamp:" << decoder_buffer->timestamp().InMicroseconds()
+ << " duration:" << decoder_buffer->duration().InMicroseconds();
+ buffer_message->set_timestamp_usec(
+ decoder_buffer->timestamp().InMicroseconds());
+ buffer_message->set_duration_usec(
+ decoder_buffer->duration().InMicroseconds());
+ buffer_message->set_is_key_frame(decoder_buffer->is_key_frame());
+
+ if (decoder_buffer->decrypt_config()) {
+ ConvertDecryptConfigToProto(*decoder_buffer->decrypt_config(),
+ buffer_message->mutable_decrypt_config());
+ }
+
+ buffer_message->set_front_discard_usec(
+ decoder_buffer->discard_padding().first.InMicroseconds());
+ buffer_message->set_back_discard_usec(
+ decoder_buffer->discard_padding().second.InMicroseconds());
+ buffer_message->set_splice_timestamp_usec(
+ decoder_buffer->splice_timestamp().InMicroseconds());
+
+ if (decoder_buffer->side_data_size()) {
+ buffer_message->set_side_data(decoder_buffer->side_data(),
+ decoder_buffer->side_data_size());
+ }
+}
+
+} // namespace
+
+scoped_refptr<::media::DecoderBuffer> ByteArrayToDecoderBuffer(
+ const uint8_t* data,
+ uint32_t size) {
+ base::BigEndianReader reader(reinterpret_cast<const char*>(data), size);
+ uint8_t payload_version = 0;
+ uint16_t proto_size = 0;
+ pb::DecoderBuffer segment;
+ uint32_t buffer_size = 0;
+ if (reader.ReadU8(&payload_version) && payload_version == 0 &&
+ reader.ReadU16(&proto_size) &&
+ static_cast<int>(proto_size) < reader.remaining() &&
+ segment.ParseFromArray(reader.ptr(), proto_size) &&
+ reader.Skip(proto_size) && reader.ReadU32(&buffer_size) &&
+ static_cast<int64_t>(buffer_size) <= reader.remaining()) {
+ // Deserialize proto buffer. It passes the pre allocated DecoderBuffer into
+ // the function because the proto buffer may overwrite DecoderBuffer since
+ // it may be EOS buffer.
+ scoped_refptr<media::DecoderBuffer> decoder_buffer =
+ ConvertProtoToDecoderBuffer(
+ segment,
+ DecoderBuffer::CopyFrom(
+ reinterpret_cast<const uint8_t*>(reader.ptr()), buffer_size));
+ return decoder_buffer;
+ }
+
+ LOG(ERROR) << "Not able to convert byte array to ::media::DecoderBuffer";
+ return nullptr;
+}
+
+std::vector<uint8_t> DecoderBufferToByteArray(
+ const scoped_refptr<::media::DecoderBuffer>& decoder_buffer) {
+ pb::DecoderBuffer decoder_buffer_message;
+ ConvertDecoderBufferToProto(decoder_buffer, &decoder_buffer_message);
+
+ size_t decoder_buffer_size =
+ decoder_buffer->end_of_stream() ? 0 : decoder_buffer->data_size();
+ size_t size = kPayloadVersionFieldSize + kProtoBufferHeaderSize +
+ decoder_buffer_message.ByteSize() + kDataBufferHeaderSize +
+ decoder_buffer_size;
+ std::vector<uint8_t> buffer(size);
+ base::BigEndianWriter writer(reinterpret_cast<char*>(buffer.data()),
+ buffer.size());
+ if (writer.WriteU8(0) &&
+ writer.WriteU16(
+ static_cast<uint16_t>(decoder_buffer_message.GetCachedSize())) &&
+ decoder_buffer_message.SerializeToArray(
+ writer.ptr(), decoder_buffer_message.GetCachedSize()) &&
+ writer.Skip(decoder_buffer_message.GetCachedSize()) &&
+ writer.WriteU32(decoder_buffer_size)) {
+ if (decoder_buffer_size) {
+ // DecoderBuffer frame data.
+ writer.WriteBytes(reinterpret_cast<const void*>(decoder_buffer->data()),
+ decoder_buffer->data_size());
+ }
+ return buffer;
+ }
+
+ // Reset buffer since serialization of the data failed.
+ LOG(ERROR) << "Not able to convert ::media::DecoderBuffer to byte array";
+ buffer.clear();
+ return buffer;
+}
+
+void ConvertEncryptionSchemeToProto(
+ const ::media::EncryptionScheme& encryption_scheme,
+ pb::EncryptionScheme* message) {
+ DCHECK(message);
+ message->set_mode(
+ ToProtoEncryptionSchemeCipherMode(encryption_scheme.mode()).value());
+ message->set_encrypt_blocks(encryption_scheme.pattern().encrypt_blocks());
+ message->set_skip_blocks(encryption_scheme.pattern().skip_blocks());
+}
+
+::media::EncryptionScheme ConvertProtoToEncryptionScheme(
+ const pb::EncryptionScheme& message) {
+ return ::media::EncryptionScheme(
+ ToMediaEncryptionSchemeCipherMode(message.mode()).value(),
+ ::media::EncryptionScheme::Pattern(message.encrypt_blocks(),
+ message.skip_blocks()));
+}
+
+void ConvertAudioDecoderConfigToProto(
+ const ::media::AudioDecoderConfig& audio_config,
+ pb::AudioDecoderConfig* audio_message) {
+ DCHECK(audio_config.IsValidConfig());
+ DCHECK(audio_message);
+
+ audio_message->set_codec(
+ ToProtoAudioDecoderConfigCodec(audio_config.codec()).value());
+ audio_message->set_sample_format(
+ ToProtoAudioDecoderConfigSampleFormat(audio_config.sample_format())
+ .value());
+ audio_message->set_channel_layout(
+ ToProtoAudioDecoderConfigChannelLayout(audio_config.channel_layout())
+ .value());
+ audio_message->set_samples_per_second(audio_config.samples_per_second());
+ audio_message->set_seek_preroll_usec(
+ audio_config.seek_preroll().InMicroseconds());
+ audio_message->set_codec_delay(audio_config.codec_delay());
+
+ if (!audio_config.extra_data().empty()) {
+ audio_message->set_extra_data(audio_config.extra_data().data(),
+ audio_config.extra_data().size());
+ }
+
+ if (audio_config.is_encrypted()) {
+ pb::EncryptionScheme* encryption_scheme_message =
+ audio_message->mutable_encryption_scheme();
+ ConvertEncryptionSchemeToProto(audio_config.encryption_scheme(),
+ encryption_scheme_message);
+ }
+}
+
+bool ConvertProtoToAudioDecoderConfig(
+ const pb::AudioDecoderConfig& audio_message,
+ ::media::AudioDecoderConfig* audio_config) {
+ DCHECK(audio_config);
+ audio_config->Initialize(
+ ToMediaAudioCodec(audio_message.codec()).value(),
+ ToMediaSampleFormat(audio_message.sample_format()).value(),
+ ToMediaChannelLayout(audio_message.channel_layout()).value(),
+ audio_message.samples_per_second(),
+ std::vector<uint8_t>(audio_message.extra_data().begin(),
+ audio_message.extra_data().end()),
+ ConvertProtoToEncryptionScheme(audio_message.encryption_scheme()),
+ base::TimeDelta::FromMicroseconds(audio_message.seek_preroll_usec()),
+ audio_message.codec_delay());
+ return audio_config->IsValidConfig();
+}
+
+void ConvertVideoDecoderConfigToProto(
+ const ::media::VideoDecoderConfig& video_config,
+ pb::VideoDecoderConfig* video_message) {
+ DCHECK(video_config.IsValidConfig());
+ DCHECK(video_message);
+
+ video_message->set_codec(
+ ToProtoVideoDecoderConfigCodec(video_config.codec()).value());
+ video_message->set_profile(
+ ToProtoVideoDecoderConfigProfile(video_config.profile()).value());
+ video_message->set_format(
+ ToProtoVideoDecoderConfigFormat(video_config.format()).value());
+ video_message->set_color_space(
+ ToProtoVideoDecoderConfigColorSpace(video_config.color_space()).value());
+
+ pb::Size* coded_size_message = video_message->mutable_coded_size();
+ coded_size_message->set_width(video_config.coded_size().width());
+ coded_size_message->set_height(video_config.coded_size().height());
+
+ pb::Rect* visible_rect_message = video_message->mutable_visible_rect();
+ visible_rect_message->set_x(video_config.visible_rect().x());
+ visible_rect_message->set_y(video_config.visible_rect().y());
+ visible_rect_message->set_width(video_config.visible_rect().width());
+ visible_rect_message->set_height(video_config.visible_rect().height());
+
+ pb::Size* natural_size_message = video_message->mutable_natural_size();
+ natural_size_message->set_width(video_config.natural_size().width());
+ natural_size_message->set_height(video_config.natural_size().height());
+
+ if (!video_config.extra_data().empty()) {
+ video_message->set_extra_data(video_config.extra_data().data(),
+ video_config.extra_data().size());
+ }
+
+ if (video_config.is_encrypted()) {
+ pb::EncryptionScheme* encryption_scheme_message =
+ video_message->mutable_encryption_scheme();
+ ConvertEncryptionSchemeToProto(video_config.encryption_scheme(),
+ encryption_scheme_message);
+ }
+}
+
+bool ConvertProtoToVideoDecoderConfig(
+ const pb::VideoDecoderConfig& video_message,
+ ::media::VideoDecoderConfig* video_config) {
+ DCHECK(video_config);
+ ::media::EncryptionScheme encryption_scheme;
+ video_config->Initialize(
+ ToMediaVideoCodec(video_message.codec()).value(),
+ ToMediaVideoCodecProfile(video_message.profile()).value(),
+ ToMediaVideoPixelFormat(video_message.format()).value(),
+ ToMediaColorSpace(video_message.color_space()).value(),
+ gfx::Size(video_message.coded_size().width(),
+ video_message.coded_size().height()),
+ gfx::Rect(video_message.visible_rect().x(),
+ video_message.visible_rect().y(),
+ video_message.visible_rect().width(),
+ video_message.visible_rect().height()),
+ gfx::Size(video_message.natural_size().width(),
+ video_message.natural_size().height()),
+ std::vector<uint8_t>(video_message.extra_data().begin(),
+ video_message.extra_data().end()),
+ ConvertProtoToEncryptionScheme(video_message.encryption_scheme()));
+ return video_config->IsValidConfig();
+}
+
+void ConvertCdmKeyInfoToProto(
+ const ::media::CdmKeysInfo& keys_information,
+ pb::CdmClientOnSessionKeysChange* key_change_message) {
+ for (const auto& info : keys_information) {
+ pb::CdmKeyInformation* key = key_change_message->add_key_information();
+ key->set_key_id(info->key_id.data(), info->key_id.size());
+ key->set_status(ToProtoCdmKeyInformation(info->status).value());
+ key->set_system_code(info->system_code);
+ }
+}
+
+void ConvertProtoToCdmKeyInfo(
+ const pb::CdmClientOnSessionKeysChange keychange_message,
+ CdmKeysInfo* key_information) {
+ DCHECK(key_information);
+ key_information->reserve(keychange_message.key_information_size());
+ for (int i = 0; i < keychange_message.key_information_size(); ++i) {
+ const pb::CdmKeyInformation key_info_msg =
+ keychange_message.key_information(i);
+
+ std::unique_ptr<::media::CdmKeyInformation> key(
+ new ::media::CdmKeyInformation(
+ key_info_msg.key_id(),
+ ToMediaCdmKeyInformationKeyStatus(key_info_msg.status()).value(),
+ key_info_msg.system_code()));
+ key_information->push_back(std::move(key));
+ }
+}
+
+void ConvertCdmPromiseToProto(const CdmPromiseResult& result,
+ pb::CdmPromise* promise_message) {
+ promise_message->set_success(result.success());
+ if (!result.success()) {
+ promise_message->set_exception(
+ ToProtoMediaKeysException(result.exception()).value());
+ promise_message->set_system_code(result.system_code());
+ promise_message->set_error_message(result.error_message());
+ }
+}
+
+void ConvertCdmPromiseWithSessionIdToProto(const CdmPromiseResult& result,
+ const std::string& session_id,
+ pb::CdmPromise* promise_message) {
+ ConvertCdmPromiseToProto(result, promise_message);
+ promise_message->set_session_id(session_id);
+}
+
+void ConvertCdmPromiseWithCdmIdToProto(const CdmPromiseResult& result,
+ int cdm_id,
+ pb::CdmPromise* promise_message) {
+ ConvertCdmPromiseToProto(result, promise_message);
+ promise_message->set_cdm_id(cdm_id);
+}
+
+bool ConvertProtoToCdmPromise(const pb::CdmPromise& promise_message,
+ CdmPromiseResult* result) {
+ if (!promise_message.has_success())
+ return false;
+
+ bool success = promise_message.success();
+ if (success) {
+ *result = CdmPromiseResult::SuccessResult();
+ return true;
+ }
+
+ ::media::MediaKeys::Exception exception = ::media::MediaKeys::UNKNOWN_ERROR;
+ uint32_t system_code = 0;
+ std::string error_message;
+
+ exception = ToMediaMediaKeysException(promise_message.exception()).value();
+ system_code = promise_message.system_code();
+ error_message = promise_message.error_message();
+ *result = CdmPromiseResult(exception, system_code, error_message);
+ return true;
+}
+
+bool ConvertProtoToCdmPromiseWithCdmIdSessionId(const pb::RpcMessage& message,
+ CdmPromiseResult* result,
+ int* cdm_id,
+ std::string* session_id) {
+ if (!message.has_cdm_promise_rpc())
+ return false;
+
+ const auto& promise_message = message.cdm_promise_rpc();
+ if (!ConvertProtoToCdmPromise(promise_message, result))
+ return false;
+
+ if (cdm_id)
+ *cdm_id = promise_message.cdm_id();
+ if (session_id)
+ *session_id = promise_message.session_id();
+
+ return true;
+}
+
+//==============================================================================
+CdmPromiseResult::CdmPromiseResult()
+ : CdmPromiseResult(::media::MediaKeys::UNKNOWN_ERROR, 0, "") {}
+
+CdmPromiseResult::CdmPromiseResult(::media::MediaKeys::Exception exception,
+ uint32_t system_code,
+ std::string error_message)
+ : success_(false),
+ exception_(exception),
+ system_code_(system_code),
+ error_message_(error_message) {}
+
+CdmPromiseResult::CdmPromiseResult(const CdmPromiseResult& other) = default;
+
+CdmPromiseResult::~CdmPromiseResult() = default;
+
+CdmPromiseResult CdmPromiseResult::SuccessResult() {
+ CdmPromiseResult result(static_cast<::media::MediaKeys::Exception>(0), 0, "");
+ result.success_ = true;
+ return result;
+}
+
+} // namespace remoting
+} // namespace media
diff --git a/media/remoting/rpc/proto_utils.h b/media/remoting/rpc/proto_utils.h
new file mode 100644
index 0000000..6bba860a
--- /dev/null
+++ b/media/remoting/rpc/proto_utils.h
@@ -0,0 +1,137 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_REMOTING_RPC_PROTO_UTILS_H_
+#define MEDIA_REMOTING_RPC_PROTO_UTILS_H_
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "media/base/audio_decoder_config.h"
+#include "media/base/cdm_config.h"
+#include "media/base/cdm_key_information.h"
+#include "media/base/decoder_buffer.h"
+#include "media/base/demuxer_stream.h"
+#include "media/base/eme_constants.h"
+#include "media/base/media_keys.h"
+#include "media/base/pipeline_status.h"
+#include "media/base/video_decoder_config.h"
+#include "media/remoting/remoting_rpc_message.pb.h"
+
+namespace media {
+namespace remoting {
+
+class CdmPromiseResult;
+
+// Predefined invalid handle value RPC message.
+constexpr int kInvalidHandle = -1;
+
+// Predefined handle value for RPC messages related to initialization.
+constexpr int kReceiverHandle = 0;
+
+// Utility class to convert data between ::media::DecoderBuffer and byte array.
+// It is to serialize ::media::DecoderBuffer structure except for actual data
+// into pb::DecoderBuffer followed by byte array of decoder buffer. The reason
+// data is not part of proto buffer because it would cost unnecessary time to
+// wait for whole proto received before conversion given the fact that decoder
+// buffer data can vary from hundred bytes to 3~5MB. Also, it would costs extra
+// CPU to sirealize/de-serialize decoder buffer which is encoded and encrypted
+// as wire format for data transmission.
+//
+// DecoderBufferSegment {
+// // Payload version. Default value is 0.
+// u8 payload_version;
+//
+// // Length of pb::DecoderBuffer (protobuf-encoded of ::media::DecoderBuffer
+// except for data).
+// u16 buffer_segment_size;
+// // pb::DecoderBuffer.
+// u8[buffer_segment_size] buffer_segment;
+//
+// // Length of data in media::DecoderBuffer.
+// u32 data_buffer_size;
+// // media::DecoderBuffer data.
+// u8[data_buffer_size] data_buffer;
+//};
+
+// Converts DecoderBufferSegment into byte array.
+std::vector<uint8_t> DecoderBufferToByteArray(
+ const scoped_refptr<::media::DecoderBuffer>& decoder_buffer);
+
+// Converts byte array into DecoderBufferSegment.
+scoped_refptr<::media::DecoderBuffer> ByteArrayToDecoderBuffer(
+ const uint8_t* data,
+ uint32_t size);
+
+// Data type conversion between ::media::AudioDecoderConfig and proto buffer.
+void ConvertAudioDecoderConfigToProto(
+ const ::media::AudioDecoderConfig& audio_config,
+ pb::AudioDecoderConfig* audio_message);
+bool ConvertProtoToAudioDecoderConfig(
+ const pb::AudioDecoderConfig& audio_message,
+ ::media::AudioDecoderConfig* audio_config);
+
+// Data type conversion between ::media::VideoDecoderConfig and proto buffer.
+void ConvertVideoDecoderConfigToProto(
+ const ::media::VideoDecoderConfig& video_config,
+ pb::VideoDecoderConfig* video_message);
+bool ConvertProtoToVideoDecoderConfig(
+ const pb::VideoDecoderConfig& video_message,
+ ::media::VideoDecoderConfig* video_config);
+
+// Data type conversion between ::media::CdmKeysInfo and proto buffer.
+void ConvertCdmKeyInfoToProto(
+ const ::media::CdmKeysInfo& keys_information,
+ pb::CdmClientOnSessionKeysChange* key_change_message);
+void ConvertProtoToCdmKeyInfo(
+ const pb::CdmClientOnSessionKeysChange keychange_message,
+ CdmKeysInfo* key_information);
+
+// Data type conversion between CdmPromiseResult and proto buffer.
+void ConvertCdmPromiseToProto(const CdmPromiseResult& result,
+ pb::CdmPromise* promise_message);
+void ConvertCdmPromiseWithSessionIdToProto(const CdmPromiseResult& result,
+ const std::string& session_id,
+ pb::CdmPromise* promise_message);
+void ConvertCdmPromiseWithCdmIdToProto(const CdmPromiseResult& result,
+ int cdm_id,
+ pb::CdmPromise* promise_message);
+bool ConvertProtoToCdmPromise(const pb::CdmPromise& promise_message,
+ CdmPromiseResult* result);
+bool ConvertProtoToCdmPromiseWithCdmIdSessionId(const pb::RpcMessage& message,
+ CdmPromiseResult* result,
+ int* cdm_id,
+ std::string* session_id);
+
+//==================================================================
+class CdmPromiseResult {
+ public:
+ CdmPromiseResult();
+ CdmPromiseResult(::media::MediaKeys::Exception exception,
+ uint32_t system_code,
+ std::string error_message);
+ CdmPromiseResult(const CdmPromiseResult& other);
+ ~CdmPromiseResult();
+
+ static CdmPromiseResult SuccessResult();
+
+ bool success() const { return success_; }
+ ::media::MediaKeys::Exception exception() const { return exception_; }
+ uint32_t system_code() const { return system_code_; }
+ const std::string& error_message() const { return error_message_; }
+
+ private:
+ bool success_;
+ ::media::MediaKeys::Exception exception_;
+ uint32_t system_code_;
+ std::string error_message_;
+};
+
+} // namespace remoting
+} // namespace media
+
+#endif // MEDIA_REMOTING_RPC_PROTO_UTILS_H_
diff --git a/media/remoting/rpc/proto_utils_unittest.cc b/media/remoting/rpc/proto_utils_unittest.cc
new file mode 100644
index 0000000..4f78c96
--- /dev/null
+++ b/media/remoting/rpc/proto_utils_unittest.cc
@@ -0,0 +1,166 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/remoting/rpc/proto_utils.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "media/base/audio_decoder_config.h"
+#include "media/base/cdm_config.h"
+#include "media/base/cdm_key_information.h"
+#include "media/base/decoder_buffer.h"
+#include "media/base/demuxer_stream.h"
+#include "media/base/eme_constants.h"
+#include "media/base/media_keys.h"
+#include "media/base/video_decoder_config.h"
+#include "media/remoting/remoting_rpc_message.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Invoke;
+using testing::Return;
+
+namespace media {
+namespace remoting {
+
+class ProtoUtilsTest : public testing::Test {
+ protected:
+ void SetUp() override {}
+};
+
+TEST_F(ProtoUtilsTest, PassEOSDecoderBuffer) {
+ // 1. To DecoderBuffer
+ scoped_refptr<::media::DecoderBuffer> input_buffer =
+ ::media::DecoderBuffer::CreateEOSBuffer();
+
+ // 2. To Byte Array
+ std::vector<uint8_t> data = DecoderBufferToByteArray(input_buffer);
+
+ // 3. To DecoderBuffer
+ scoped_refptr<::media::DecoderBuffer> output_buffer =
+ ByteArrayToDecoderBuffer(data.data(), data.size());
+ DCHECK(output_buffer);
+
+ ASSERT_TRUE(output_buffer->end_of_stream());
+}
+
+TEST_F(ProtoUtilsTest, PassValidDecoderBuffer) {
+ const uint8_t buffer[] = {
+ 0, 0, 0, 1, 9, 224, 0, 0, 0, 1, 103, 77, 64, 21, 217,
+ 1, 177, 254, 78, 16, 0, 0, 62, 144, 0, 11, 184, 0, 241, 98,
+ 228, 128, 0, 0, 0, 1, 104, 235, 143, 32, 0, 0, 0, 1, 103,
+ 77, 64, 21, 217, 1, 177, 254, 78, 16, 0, 0, 62, 144, 0, 11,
+ 184, 0, 241, 98, 228, 128, 0, 0, 0, 1, 104, 235, 143, 32, 0,
+ 0, 0, 1, 101, 136, 132, 25, 255, 0, 191, 98, 0, 6, 29, 63,
+ 252, 65, 246, 207, 255, 235, 63, 172, 35, 112, 198, 115, 222, 243, 159,
+ 232, 208, 32, 0, 0, 3, 0, 0, 203, 255, 149, 20, 71, 203, 213,
+ 40, 0, 0, 139, 0, 24, 117, 166, 249, 227, 68, 230, 177, 134, 161,
+ 162, 1, 22, 105, 78, 66, 183, 130, 158, 108, 252, 112, 113, 58, 159,
+ 72, 116, 78, 141, 133, 76, 225, 209, 13, 221, 49, 187, 83, 123, 193,
+ 112, 123, 112, 74, 121, 133};
+ size_t buffer_size = sizeof(buffer) / sizeof(uint8_t);
+ const uint8_t side_buffer[] = "XX";
+ size_t side_buffer_size = sizeof(side_buffer) / sizeof(uint8_t);
+ base::TimeDelta pts = base::TimeDelta::FromMilliseconds(5);
+
+ // 1. To DecoderBuffer
+ scoped_refptr<::media::DecoderBuffer> input_buffer =
+ ::media::DecoderBuffer::CopyFrom(buffer, buffer_size, side_buffer,
+ side_buffer_size);
+ input_buffer->set_timestamp(pts);
+ input_buffer->set_is_key_frame(true);
+
+ // 2. To Byte Array
+ std::vector<uint8_t> data = DecoderBufferToByteArray(input_buffer);
+
+ // 3. To DecoderBuffer
+ scoped_refptr<::media::DecoderBuffer> output_buffer =
+ ByteArrayToDecoderBuffer(data.data(), data.size());
+ DCHECK(output_buffer);
+
+ ASSERT_FALSE(output_buffer->end_of_stream());
+ ASSERT_TRUE(output_buffer->is_key_frame());
+ ASSERT_EQ(output_buffer->timestamp(), pts);
+ ASSERT_EQ(output_buffer->data_size(), buffer_size);
+ const uint8_t* output_data = output_buffer->data();
+ for (size_t i = 0; i < buffer_size; i++) {
+ ASSERT_EQ(output_data[i], buffer[i]);
+ }
+ ASSERT_EQ(output_buffer->side_data_size(), side_buffer_size);
+ const uint8_t* output_side_data = output_buffer->side_data();
+ for (size_t i = 0; i < side_buffer_size; i++) {
+ ASSERT_EQ(output_side_data[i], side_buffer[i]);
+ }
+}
+
+TEST_F(ProtoUtilsTest, AudioDecoderConfigConversionTest) {
+ const std::string extra_data = "ACEG";
+ const EncryptionScheme encryption_scheme(
+ EncryptionScheme::CIPHER_MODE_AES_CTR, EncryptionScheme::Pattern(20, 40));
+ AudioDecoderConfig audio_config(
+ kCodecAAC, kSampleFormatF32, CHANNEL_LAYOUT_MONO, 48000,
+ std::vector<uint8_t>(extra_data.begin(), extra_data.end()),
+ encryption_scheme);
+ ASSERT_TRUE(audio_config.IsValidConfig());
+
+ pb::AudioDecoderConfig audio_message;
+ ConvertAudioDecoderConfigToProto(audio_config, &audio_message);
+
+ AudioDecoderConfig audio_output_config;
+ ASSERT_TRUE(
+ ConvertProtoToAudioDecoderConfig(audio_message, &audio_output_config));
+
+ ASSERT_TRUE(audio_config.Matches(audio_output_config));
+}
+
+TEST_F(ProtoUtilsTest, CdmPromiseResultConversion) {
+ CdmPromiseResult success_result = CdmPromiseResult::SuccessResult();
+
+ pb::CdmPromise promise_message;
+ ConvertCdmPromiseToProto(success_result, &promise_message);
+
+ CdmPromiseResult output_result;
+ ASSERT_TRUE(ConvertProtoToCdmPromise(promise_message, &output_result));
+
+ ASSERT_EQ(success_result.success(), output_result.success());
+ ASSERT_EQ(success_result.exception(), output_result.exception());
+ ASSERT_EQ(success_result.system_code(), output_result.system_code());
+ ASSERT_EQ(success_result.error_message(), output_result.error_message());
+}
+
+TEST_F(ProtoUtilsTest, CdmKeyInformationConversion) {
+ std::unique_ptr<CdmKeyInformation> cdm_key_info_1(new CdmKeyInformation(
+ "key_1", CdmKeyInformation::OUTPUT_RESTRICTED, 100));
+ std::unique_ptr<CdmKeyInformation> cdm_key_info_2(
+ new CdmKeyInformation("key_2", CdmKeyInformation::EXPIRED, 11));
+ std::unique_ptr<CdmKeyInformation> cdm_key_info_3(
+ new CdmKeyInformation("key_3", CdmKeyInformation::RELEASED, 22));
+ CdmKeysInfo keys_information;
+ keys_information.push_back(std::move(cdm_key_info_1));
+ keys_information.push_back(std::move(cdm_key_info_2));
+ keys_information.push_back(std::move(cdm_key_info_3));
+
+ pb::CdmClientOnSessionKeysChange key_message;
+ ConvertCdmKeyInfoToProto(keys_information, &key_message);
+
+ CdmKeysInfo key_output_information;
+ ConvertProtoToCdmKeyInfo(key_message, &key_output_information);
+
+ ASSERT_EQ(keys_information.size(), key_output_information.size());
+ for (uint32_t i = 0; i < 3; i++) {
+ ASSERT_EQ(keys_information[i]->key_id, key_output_information[i]->key_id);
+ ASSERT_EQ(keys_information[i]->status, key_output_information[i]->status);
+ ASSERT_EQ(keys_information[i]->system_code,
+ key_output_information[i]->system_code);
+ }
+}
+
+} // namespace remoting
+} // namespace media