Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(182)

Side by Side Diff: media/remoting/proto/remoting_rpc_message.proto

Issue 2261503002: Define remote playback proto buffer (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: DecoderBufferSegment more description and change interface name Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // 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 //
5 // Protocol buffer for Media Remoting.
6
7 syntax = "proto2";
8
9 option optimize_for = LITE_RUNTIME;
10
11 package media.remoting.pb;
12
13 enum RpcProc {
miu 2016/09/08 01:07:34 Perhaps this enum should be nested inside of RpcMe
erickung1 2016/09/13 03:52:52 Done.
14 // Remoting setup
15 RPC_INTERNAL = 0;
16 RPC_ACQUIRE_RENDERER = 1;
17 RPC_ACQUIRE_RENDERER_DONE = 2;
18 RPC_ACQUIRE_CDM = 3;
19 RPC_ACQUIRE_CDM_DONE = 4;
20 // Renderer message
21 RPC_R_INITIALIZE = 1000;
22 RPC_R_FLUSHUNTIL = 1001;
23 RPC_R_STARTPLAYINGFROM = 1002;
24 RPC_R_SETPLAYBACKRATE = 1003;
25 RPC_R_SETVOLUME = 1004;
26 RPC_R_SETCDM = 1005;
27 RPC_R_INITIALIZE_CALLBACK = 1100;
28 RPC_R_FLUSHUNTIL_CALLBACK = 1101;
29 RPC_R_SETCDM_CALLBACK = 1102;
30 // Renderer client message
31 RPC_RC_ONTIMEUPDATE = 2000;
32 RPC_RC_ONBUFFERINGSTATECHANGE = 2001;
33 RPC_RC_ONENDED = 2002;
34 RPC_RC_ONERROR = 2003;
35 RPC_RC_ONVIDEONATURALSIZECHANGE = 2004;
36 RPC_RC_ONVIDEOOPACITYCHANGE = 2005;
37 RPC_RC_ONSTATISTICSUPDATE = 2006;
38 RPC_RC_ONWAITINGFORDECRYPTIONKEY = 2007;
39 RPC_RC_ONDURATIONCHANGE = 2008;
40 // DemuxerStream message
41 RPC_DS_INITIALIZE = 3000;
42 RPC_DS_READUNTIL = 3001;
43 RPC_DS_ENABLEBITSTREAMCONVERTER = 3002;
44 // DemuxerStream callbacks
45 RPC_DS_INITIALIZE_CALLBACK = 3100;
46 RPC_DS_READUNTIL_CALLBACK = 3101;
47 // ContentDecryptionModule
48 RPC_CDM_SETCLIENT = 4000;
49 RPC_CDM_INITIALIZE = 4001;
50 RPC_CDM_SETSERVERCERTIFICATE = 4002;
51 RPC_CDM_CREATESESSIONANDGENERATEREQUEST = 4003;
52 RPC_CDM_LOADSESSION = 4004;
53 RPC_CDM_UPDATESESSION = 4005;
54 RPC_CDM_CLOSESESSION = 4006;
55 RPC_CDM_REMOVESESSION = 4007;
56 // ContentDecryptionModule callbacks
57 RPC_CDM_INITIALIZE_CALLBACK = 4100;
58 RPC_CDM_SETSERVERCERTIFICATE_CALLBACK = 4101;
59 RPC_CDM_CREATESESSIONANDGENERATEREQUEST_CALLBACK = 4102;
60 RPC_CDM_LOADSESSION_CALLBACK = 4103;
61 RPC_CDM_UPDATESESSION_CALLBACK = 4104;
62 RPC_CDM_CLOSESESSION_CALLBACK = 4105;
63 RPC_CDM_REMOVESESSION_CALLBACK = 4106;
64 // ContentDecryptionModule client
65 RPC_CDMC_ONSESSIONMESSAGE = 5000;
66 RPC_CDMC_ONSESSIONCLOSED = 5001;
67 RPC_CDMC_ONSESSIONKEYSCHANGE = 5002;
68 RPC_CDMC_ONSESSIONEXPIRATIONUPDATE = 5003;
69 };
70
71 // DecoderBuffer information which will be sent using RTP packets. The actual
72 // decoder buffer is not included in this proto data structure.
73 message DecoderBuffer {
74 optional int64 timestamp_usec = 1;
miu 2016/09/08 01:07:34 Some of these feel like they shouldn't be optional
erickung1 2016/09/08 22:21:50 The reason I use optional for every field in the b
erickung1 2016/09/13 03:52:52 after the discussion, will put every proto field o
miu 2016/09/13 05:40:57 Sounds good. Also, if we do encounter an invalid R
75 optional int64 duration_usec = 2;
76 optional bool is_key_frame = 3;
77 optional DecryptConfig decrypt_config = 4;
78 optional int64 front_discard_usec = 5;
79 optional int64 back_discard_usec = 6;
80 optional int64 splice_timestamp_usec = 7;
81 optional bytes side_data = 8;
82 // To distinguish from valid 0-length buffers
83 optional bool is_eos = 9;
84 }
85
86 // Utility proto data structure
87 message Size {
88 optional int32 width = 1;
miu 2016/09/08 01:07:34 Why are these fields optional? Seems like the Size
erickung1 2016/09/13 03:52:52 after the discussion, will put every proto field o
89 optional int32 height = 2;
90 }
91
92 message EncryptionScheme {
93 // Align with EncryptionScheme::CipherMode
94 enum CipherMode {
95 CIPHER_MODE_UNENCRYPTED = 0;
96 CIPHER_MODE_AES_CTR = 1;
97 CIPHER_MODE_AES_CBC = 2;
98 }
99
100 optional CipherMode mode = 1;
miu 2016/09/08 01:07:34 Mode is optional? Should there be a default value
erickung1 2016/09/13 03:52:52 ditto
101 optional uint32 encrypt_blocks = 2;
102 optional uint32 skip_blocks = 3;
103 }
104
105 message AudioDecoderConfig {
106 // Should align with ::media::Codec
107 enum Codec {
108 kUnknownAudioCodec = 0;
109 kCodecAAC = 1;
110 kCodecMP3 = 2;
111 kCodecPCM = 3;
112 kCodecVorbis = 4;
113 kCodecFLAC = 5;
114 kCodecAMR_NB = 6;
115 kCodecAMR_WB = 7;
116 kCodecPCM_MULAW = 8;
117 kCodecGSM_MS = 9;
118 kCodecPCM_S16BE = 10;
119 kCodecPCM_S24BE = 11;
120 kCodecOpus = 12;
121 kCodecEAC3 = 13;
122 kCodecPCM_ALAW = 14;
123 kCodecALAC = 15;
124 kCodecAC3 = 16;
125 }
126
127 // Should align with ::media::SampleFormat
128 enum SampleFormat {
129 kUnknownSampleFormat = 0;
130 kSampleFormatU8 = 1;
131 kSampleFormatS16 = 2;
132 kSampleFormatS32 = 3;
133 kSampleFormatF32 = 4;
134 kSampleFormatPlanarS16 = 5;
135 kSampleFormatPlanarF32 = 6;
136 kSampleFormatPlanarS32 = 7;
137 kSampleFormatS24 = 8;
138 };
139
140 // Should align with ::media::ChannelLayout
141 enum ChannelLayout {
142 CHANNEL_LAYOUT_NONE = 0;
143 CHANNEL_LAYOUT_UNSUPPORTED = 1;
144 CHANNEL_LAYOUT_MONO = 2;
145 CHANNEL_LAYOUT_STEREO = 3;
146 CHANNEL_LAYOUT_2_1 = 4;
147 CHANNEL_LAYOUT_SURROUND = 5;
148 CHANNEL_LAYOUT_4_0 = 6;
149 CHANNEL_LAYOUT_2_2 = 7;
150 CHANNEL_LAYOUT_QUAD = 8;
151 CHANNEL_LAYOUT_5_0 = 9;
152 CHANNEL_LAYOUT_5_1 = 10;
153 CHANNEL_LAYOUT_5_0_BACK = 11;
154 CHANNEL_LAYOUT_5_1_BACK = 12;
155 CHANNEL_LAYOUT_7_0 = 13;
156 CHANNEL_LAYOUT_7_1 = 14;
157 CHANNEL_LAYOUT_7_1_WIDE = 15;
158 CHANNEL_LAYOUT_STEREO_DOWNMIX = 16;
159 CHANNEL_LAYOUT_2POINT1 = 17;
160 CHANNEL_LAYOUT_3_1 = 18;
161 CHANNEL_LAYOUT_4_1 = 19;
162 CHANNEL_LAYOUT_6_0 = 20;
163 CHANNEL_LAYOUT_6_0_FRONT = 21;
164 CHANNEL_LAYOUT_HEXAGONAL = 22;
165 CHANNEL_LAYOUT_6_1 = 23;
166 CHANNEL_LAYOUT_6_1_BACK = 24;
167 CHANNEL_LAYOUT_6_1_FRONT = 25;
168 CHANNEL_LAYOUT_7_0_FRONT = 26;
169 CHANNEL_LAYOUT_7_1_WIDE_BACK = 27;
170 CHANNEL_LAYOUT_OCTAGONAL = 28;
171 CHANNEL_LAYOUT_DISCRETE = 29;
172 CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC = 30;
173 CHANNEL_LAYOUT_4_1_QUAD_SIDE = 31;
174 };
175
176 optional Codec codec = 1;
177 optional EncryptionScheme encryption_scheme = 2;
178 optional SampleFormat sample_format = 3;
179 optional ChannelLayout channel_layout = 4;
180 optional int32 samples_per_second = 5;
181 optional int64 seek_preroll_usec = 6;
182 optional int32 codec_delay = 7;
183 optional bytes extra_data = 8;
184 }
185
186 message Rect {
187 optional int32 x = 1;
miu 2016/09/08 01:07:34 ditto: Same concern as Size (fields should not be
erickung1 2016/09/13 03:52:52 ditto
188 optional int32 y = 2;
189 optional int32 width = 3;
190 optional int32 height = 4;
191 }
192
193 message VideoDecoderConfig {
194 // Should align with ::media::VideoCodec
195 enum Codec {
196 kUnknownVideoCodec = 0;
197 kCodecH264 = 1;
198 kCodecVC1 = 2;
199 kCodecMPEG2 = 3;
200 kCodecMPEG4 = 4;
201 kCodecTheora = 5;
202 kCodecVP8 = 6;
203 kCodecVP9 = 7;
204 kCodecHEVC = 8;
205 }
206
207 // Should align with ::media::VideoCodecProfile
208 enum Profile {
209 VIDEO_CODEC_PROFILE_UNKNOWN = -1;
210 H264PROFILE_BASELINE = 0;
211 H264PROFILE_MAIN = 1;
212 H264PROFILE_EXTENDED = 2;
213 H264PROFILE_HIGH = 3;
214 H264PROFILE_HIGH10PROFILE = 4;
215 H264PROFILE_HIGH422PROFILE = 5;
216 H264PROFILE_HIGH444PREDICTIVEPROFILE = 6;
217 H264PROFILE_SCALABLEBASELINE = 7;
218 H264PROFILE_SCALABLEHIGH = 8;
219 H264PROFILE_STEREOHIGH = 9;
220 H264PROFILE_MULTIVIEWHIGH = 10;
221 VP8PROFILE_ANY = 11;
222 VP9PROFILE_PROFILE0 = 12;
223 VP9PROFILE_PROFILE1 = 13;
224 VP9PROFILE_PROFILE2 = 14;
225 VP9PROFILE_PROFILE3 = 15;
226 HEVCPROFILE_MAIN = 16;
227 HEVCPROFILE_MAIN10 = 17;
228 HEVCPROFILE_MAIN_STILL_PICTURE = 18;
229 };
230
231 // Should align with ::media::VideoPixelFormat
232 enum Format {
233 PIXEL_FORMAT_UNKNOWN = 0;
234 PIXEL_FORMAT_I420 = 1;
235 PIXEL_FORMAT_YV12 = 2;
236 PIXEL_FORMAT_YV16 = 3;
237 PIXEL_FORMAT_YV12A = 4;
238 PIXEL_FORMAT_YV24 = 5;
239 PIXEL_FORMAT_NV12 = 6;
240 PIXEL_FORMAT_NV21 = 7;
241 PIXEL_FORMAT_UYVY = 8;
242 PIXEL_FORMAT_YUY2 = 9;
243 PIXEL_FORMAT_ARGB = 10;
244 PIXEL_FORMAT_XRGB = 11;
245 PIXEL_FORMAT_RGB24 = 12;
246 PIXEL_FORMAT_RGB32 = 13;
247 PIXEL_FORMAT_MJPEG = 14;
248 PIXEL_FORMAT_MT21 = 15;
249 PIXEL_FORMAT_YUV420P9 = 16;
250 PIXEL_FORMAT_YUV420P10 = 17;
251 PIXEL_FORMAT_YUV422P9 = 18;
252 PIXEL_FORMAT_YUV422P10 = 19;
253 PIXEL_FORMAT_YUV444P9 = 20;
254 PIXEL_FORMAT_YUV444P10 = 21;
255 };
256
257 // Should align with ::media::ColorSpace
258 enum ColorSpace {
259 COLOR_SPACE_UNSPECIFIED = 0;
260 COLOR_SPACE_JPEG = 1;
261 COLOR_SPACE_HD_REC709 = 2;
262 COLOR_SPACE_SD_REC601 = 3;
263 };
264
265 optional Codec codec = 1;
266 optional EncryptionScheme encryption_scheme = 2;
267 optional Profile profile = 3;
268 optional Format format = 4;
269 optional ColorSpace color_space = 5;
270 optional Size coded_size = 6;
271 optional Rect visible_rect = 7;
272 optional Size natural_size = 8;
273 optional bytes extra_data = 9;
274 }
275
276 message DecryptConfig {
277 message SubSample {
278 optional uint32 clear_bytes = 1;
279 optional uint32 cypher_bytes = 2;
280 }
281
282 optional bytes key_id = 1;
283 optional bytes iv = 2;
284 repeated SubSample sub_samples = 3;
285 }
286
287 message PipelineStatistics {
288 optional uint64 audio_bytes_decoded = 1;
289 optional uint64 video_bytes_decoded = 2;
290 optional uint32 video_frames_decoded = 3;
291 optional uint32 video_frames_dropped = 4;
292 optional int64 audio_memory_usage = 5;
293 optional int64 video_memory_usage = 6;
294 };
295
296 message CdmKeyInformation {
297 // Align with CdmKeyInformation::KeyStatus
298 enum KeyStatus {
299 USABLE = 0;
300 INTERNAL_ERROR = 1;
301 EXPIRED = 2;
302 OUTPUT_RESTRICTED = 3;
303 OUTPUT_DOWNSCALED = 4;
304 KEY_STATUS_PENDING = 5;
305 RELEASED = 6;
306 }
307
308 optional bytes key_id = 1;
309 optional KeyStatus status = 2;
310 optional uint32 system_code = 3;
311 }
312
313 // Should align with MediaKeys::Exception
314 enum MediaKeysException {
315 NOT_SUPPORTED_ERROR = 0;
316 INVALID_STATE_ERROR = 1;
317 INVALID_ACCESS_ERROR = 2;
318 QUOTA_EXCEEDED_ERROR = 3;
319 UNKNOWN_ERROR = 4;
320 CLIENT_ERROR = 5;
321 OUTPUT_ERROR = 6;
322 }
323
324 // Should align with MediaKeys::MessageType
325 enum MediaKeysMessageType {
326 LICENSE_REQUEST = 0;
327 LICENSE_RENEWAL = 1;
328 LICENSE_RELEASE = 2;
329 }
330
331 // Custom proto data structure
332 message RendererInitialize {
333 optional int32 client_handle = 1;
334 optional int32 audio_demuxer_handle = 2;
335 optional int32 video_demuxer_handle = 3;
336 optional int32 callback_handle = 4;
337 }
338
339 message RendererFlushUntil {
340 optional uint32 audio_frame_id = 1;
341 optional uint32 video_frame_id = 2;
342 optional int32 callback_handle = 3;
343 }
344
345 message RendererSetCdm {
346 optional int32 cdm_id = 1;
347 optional int32 callback_handle = 2;
348 }
349
350 message RendererClientOnTimeUpdate {
351 optional int64 time_usec = 1;
352 optional int64 max_time_usec = 2;
353 }
354
355 message DemuxerStreamReadUntil {
356 optional int32 callback_handle = 1;
357 optional int32 frame_id = 2;
358 }
359
360 message DemuxerStreamInitializeCallback {
361 optional int32 type = 1;
362 optional AudioDecoderConfig audio_decoder_config = 2;
363 optional VideoDecoderConfig video_decoder_config = 3;
364 }
365
366 message DemuxerStreamReadUntilCallback {
367 optional int32 status = 1;
368 optional int32 frame_id = 2;
369 optional AudioDecoderConfig audio_decoder_config = 3;
370 optional VideoDecoderConfig video_decoder_config = 4;
371 }
372
373 message CdmInitialize {
374 optional string key_system = 1;
375 optional string security_origin = 2;
376 optional bool allow_distinctive_identifier = 3;
377 optional bool allow_persistent_state = 4;
378 optional bool use_hw_secure_codecs = 5;
379 optional int32 callback_handle = 6;
380 }
381
382 message CdmSetServerCertificate {
383 optional int32 callback_handle = 1;
384 optional bytes certificate_data = 2;
385 }
386
387 message CdmCreateSessionAndGenerateRequest {
388 optional int32 session_type = 1;
389 optional int32 init_data_type = 2;
390 optional int32 callback_handle = 3;
391 optional bytes init_data = 4;
392 }
393
394 message CdmLoadSession {
395 optional int32 session_type = 1;
396 optional string session_id = 2;
397 optional int32 callback_handle = 3;
398 }
399
400 message CdmUpdateSession {
401 optional string session_id = 1;
402 optional int32 callback_handle = 2;
403 optional bytes response = 3;
404 }
405
406 message CdmCloseSession {
407 optional string session_id = 1;
408 optional int32 callback_handle = 2;
409 }
410
411 message CdmRemoveSession {
412 optional string session_id = 1;
413 optional int32 callback_handle = 2;
414 }
415
416 message CdmPromise {
417 // These two fields are used only for RPC_CDM_INITIALIZE_CALLBACK
418 optional int32 cdm_id = 1;
419 optional int32 decryptor_handle = 2;
420
421 optional string session_id = 3;
422 optional bool success = 4;
423 optional MediaKeysException exception = 5;
424 optional uint32 system_code = 6;
425 optional string error_message = 7;
426 }
427
428 message CdmClientOnSessionMessage {
429 optional string session_id = 1;
430 optional MediaKeysMessageType message_type = 2;
431 optional bytes message = 3;
432 }
433
434 message CdmClientOnSessionKeysChange {
435 optional string session_id = 1;
436 optional bool has_additional_usable_key = 2;
437 repeated CdmKeyInformation key_information = 3;
438 }
439
440 message CdmClientOnSessionExpirationUpdate {
441 optional string session_id = 1;
442 optional double new_expiry_time_sec = 2;
443 }
444
445 message RpcMessage {
446 // Handle of this RPC message
447 optional int32 handle = 1;
miu 2016/09/08 01:07:34 Is this a session handle, or does it change per-me
erickung1 2016/09/13 03:52:52 Done.
448
449 // RpcProc of this RPC message
450 optional RpcProc proc = 2;
miu 2016/09/08 01:07:34 I'm probably repeating myself a lot here, so I'll
erickung1 2016/09/13 03:52:52 ditto
451
452 oneof rpc_oneof {
453 // For simple RPC which only passes one parameters can use the following
454 // various data type variables without using specific proto data structure.
455 // RPC_ACQUIRE_RENDERER
456 // RPC_ACQUIRE_RENDERER_DONE
457 // RPC_ACQUIRE_CDM
458 // RPC_ACQUIRE_CDM_DONE
459 // RPC_RC_ONBUFFERINGSTATECHANGE
460 // RPC_DS_INITIALIZE_CALLBACK
461 // RPC_DS_READ
462 // RPC_CDM_SETCLIENT
463 int32 integer_value = 3;
464
465 // RPC_R_STARTPLAYINGFROM
466 // RPC_RC_ONDURATIONCHANGE
467 int64 integer64_value = 4;
468
469 // RPC_R_SETPLAYBACKRATE
470 // RPC_R_SETVOLUME
471 double double_value = 5;
472
473 // RPC_R_INITIALIZE_CALLBACK
474 // RPC_R_SETCDM_CALLBACK
475 // RPC_RC_ONVIDEOOPACITYCHANGE
476 bool boolean_value = 6;
477
478 // string only:
479 // RPC_CDMC_ONSESSIONCLOSED
480 string string_value = 7;
miu 2016/09/08 01:07:34 Should this be of type |string| or |bytes|? I'm th
erickung1 2016/09/13 03:52:52 This message is to send "session id" as a string b
miu 2016/09/13 05:40:57 Could you please check this? Seems like it should
erickung1 2016/09/15 02:13:32 Here is the EME definition https://www.w3.org/TR/e
481
482 // RPC_R_INITIALIZE
483 RendererInitialize renderer_initialize_rpc = 100;
484
485 // RPC_R_FLUSHUNTIL
486 RendererFlushUntil renderer_flushuntil_rpc = 101;
487
488 // RPC_R_SETCDM
489 RendererSetCdm renderer_set_cdm_rpc = 102;
490
491 // RPC_RC_ONTIMEUPDATE
492 RendererClientOnTimeUpdate rendererclient_ontimeupdate_rpc = 200;
493 // RPC_RC_ONVIDEONATURALSIZECHANGE
494 Size rendererclient_onvideonatualsizechange_rpc = 201;
495 // RPC_RC_ONSTATISTICSUPDATE
496 PipelineStatistics rendererclient_onstatisticsupdate_rpc = 202;
497
498 // RPC_DS_READUNTIL
499 DemuxerStreamReadUntil demuxerstream_readuntil_rpc = 300;
500
501 // RPC_DS_INITIALIZE_CALLBACK
502 DemuxerStreamInitializeCallback demuxerstream_initializecb_rpc = 400;
503 // RPC_DS_READUNTIL_CALLBACK
504 DemuxerStreamReadUntilCallback demuxerstream_readuntilcb_rpc = 401;
505
506 // RPC_CDM_INITIALIZE
507 CdmInitialize cdm_initialize_rpc = 500;
508 // RPC_CDM_SETSERVERCERTIFICATE
509 CdmSetServerCertificate cdm_setservercertificate_rpc = 501;
510 // RPC_CDM_CREATESESSIONANDGENERATEREQUEST
511 CdmCreateSessionAndGenerateRequest cdm_createsessionandgeneraterequest_rpc =
512 502;
513 // RPC_CDM_LOADSESSION
514 CdmLoadSession cdm_loadsession_rpc = 503;
515 // RPC_CDM_UPDATESESSION
516 CdmUpdateSession cdm_updatesession_rpc = 504;
517 // RPC_CDM_CLOSESESSION
518 CdmCloseSession cdm_closesession_rpc = 505;
519 // RPC_CDM_REMOVESESSION
520 CdmRemoveSession cdm_removesession_rpc = 506;
521
522 // CdmPromise message type used for the following procedure
523 // RPC_CDM_INITIALIZE_CALLBACK
524 // RPC_CDM_SETSERVERCERTIFICATE_CALLBACK
525 // RPC_CDM_CREATESESSIONANDGENERATEREQUEST_CALLBACK
526 // RPC_CDM_LOADSESSION_CALLBACK
527 // RPC_CDM_UPDATESESSION_CALLBACK
528 // RPC_CDM_CLOSESESSION_CALLBACK
529 // RPC_CDM_REMOVESESSION_CALLBACK
530 CdmPromise cdm_promise_rpc = 600;
531
532 // RPC_CDMC_ONSESSIONMESSAGE
533 CdmClientOnSessionMessage cdmclient_onsessionmessage_rpc = 601;
534 // RPC_CDMC_ONSESSIONKEYSCHANGE
535 CdmClientOnSessionKeysChange cdmclient_onsessionkeychange_rpc = 602;
536 // RPC_CDMC_ONSESSIONEXPIRATIONUPDATE
537 CdmClientOnSessionExpirationUpdate cdmclient_onsessionexpirationupdate_rpc =
538 603;
539 };
540 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698