| Index: chrome/test/data/extensions/api_test/media_remoting/test_media_router.js
|
| diff --git a/chrome/test/data/extensions/api_test/media_remoting/test_media_router.js b/chrome/test/data/extensions/api_test/media_remoting/test_media_router.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d2988c6e0638f6f7b61b4154d0f9f911305dbfc7
|
| --- /dev/null
|
| +++ b/chrome/test/data/extensions/api_test/media_remoting/test_media_router.js
|
| @@ -0,0 +1,306 @@
|
| +// Copyright 2017 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.
|
| +
|
| +'use strict';
|
| +
|
| +mrTest.Parameters = class {
|
| + constructor() {
|
| + this.rendererInitSucceed = true;
|
| + this.route_terminate_while_remoting = false;
|
| + }
|
| +};
|
| +
|
| +mrTest.MediaRoute = class {
|
| + constructor(sourceUrn) {
|
| + this.mediaSource = sourceUrn;
|
| + this.sinkId = "2";
|
| + this.presentationId_ = "0";
|
| + this.id = this.getRouteUrn();
|
| + this.isLocal = true;
|
| + this.description = "test route.";
|
| + this.iconUrl = "";
|
| + this.allowStop = true;
|
| + this.forDisplay = true;
|
| + this.offTheRecord = false;
|
| + this.customControllerPath = null;
|
| + this.isOffscreenPresentation = false;
|
| + }
|
| +
|
| + getRouteUrn() {
|
| + return 'urn:x-org.test:media:route:' + this.mediaSource + '-' + this.sinkId;
|
| + }
|
| +
|
| + getSourceId() { return this.mediaSource; }
|
| +
|
| + getID() { return this.id; }
|
| +};
|
| +
|
| +mrTest.RouteMessage = class {
|
| + constructor(routeId, message) {
|
| + this.routeId = routeId;
|
| + this.message = message;
|
| + }
|
| +};
|
| +
|
| +mrTest.ProviderManager = class {
|
| + constructor(mediaRouterService, parameters) {
|
| + this.routes = [];
|
| + this.service = mediaRouterService;
|
| + this.receivers = [];
|
| + this.testParameters = parameters;
|
| + }
|
| +
|
| + sendRouteMessage(routeId, message, opt_extraInfo) {
|
| + this.receivers.forEach(receiver => {
|
| + if (receiver.routeId == routeId) {
|
| + receiver.onReceivedMessageFromSource(message);
|
| + return Promise.resolve();
|
| + }
|
| + });
|
| + return Promise.resolve();
|
| + }
|
| +
|
| + sendRouteBinaryMessage(routeId, data) {
|
| + this.receivers.forEach(receiver => {
|
| + if (receiver.routeId == routeId) {
|
| + receiver.onReceivedBinaryMessageFromSource(data);
|
| + return Promise.resolve();
|
| + }
|
| + });
|
| + return Promise.resolve();
|
| + }
|
| +
|
| + startObservingMediaRoutes(sourceUrn) {
|
| + this.routes.forEach(route => {
|
| + if (route.getSourceId() == sourceUrn) {
|
| + return;
|
| + }
|
| + });
|
| + let newRoute = new mrTest.MediaRoute(sourceUrn);
|
| + let receiver = new mrTest.Receiver(this, newRoute.id);
|
| + this.routes.push(newRoute);
|
| + this.receivers.push(receiver);
|
| + this.service.onRoutesUpdated(this.routes, sourceUrn, []);
|
| + }
|
| +
|
| + stopObservingMediaRoutes(sourceUrn) {
|
| + let routeToRemove = null;
|
| + this.routes.forEach(route => {
|
| + if (route.getSourceId() == sourceUrn) {
|
| + routeToRemove = route;
|
| + }
|
| + });
|
| + if (routeToRemove == null)
|
| + return;
|
| + let receiverToRemove = null;
|
| + this.receivers.forEach(receiver => {
|
| + if (receiver.routeId == routeToRemove.id) {
|
| + receiverToRemove = receiver;
|
| + }
|
| + });
|
| + let index = this.routes.indexOf(routeToRemove);
|
| + if (index > -1)
|
| + this.routes.splice(index, 1);
|
| + index = this.receivers.indexOf(receiverToRemove);
|
| + if (index > -1)
|
| + this.receivers.splice(index, 1);
|
| + }
|
| +
|
| + sendMessageToSource(message, routeId) {
|
| + let routeMessage = new mrTest.RouteMessage(routeId, message);
|
| + this.service.onRouteMessagesReceived(routeId, [routeMessage]);
|
| + }
|
| +
|
| + RemoveRoute(routeId) {
|
| + let routeToRemove = null;
|
| + this.routes.forEach(route => {
|
| + if (route.id == routeId) {
|
| + routeToRemove = route;
|
| + }
|
| + });
|
| + if (routeToRemove == null)
|
| + return;
|
| + this.service.onRoutesUpdated([], routeToRemove.getSourceId(), []);
|
| +
|
| + // Remove the route and corresponding receiver from the list.
|
| + let receiverToRemove = null;
|
| + this.receivers.forEach(receiver => {
|
| + if (receiver.routeId == routeId) {
|
| + receiverToRemove = receiver;
|
| + }
|
| + });
|
| + let index = this.routes.indexOf(routeToRemove);
|
| + if (index > -1)
|
| + this.routes.splice(index, 1);
|
| + index = this.receivers.indexOf(receiverToRemove);
|
| + if (index > -1)
|
| + this.receivers.splice(index, 1);
|
| + }
|
| +
|
| + // Below handlers are not used in the tests.
|
| + onBeforeInvokeHandler() {}
|
| + createRoute(sourceUrn, sinkId, presentationId, opt_origin,
|
| + opt_tabId, opt_timeoutMillis, opt_offTheRecord) {}
|
| + connectRouteByRouteId(sourceUrn, routeId,
|
| + presentationId, origin, tabId, opt_timeoutMillis) {}
|
| + joinRoute(sourceUrn, presentationId, origin,
|
| + tabId, opt_timeoutMillis, opt_offTheRecord) {}
|
| + terminateRoute(routeId) {}
|
| + startObservingMediaSinks(sourceUrn) {}
|
| + stopObservingMediaSinks(sourceUrn) {}
|
| + searchSinks(sinkId, sourceUrn, searchCriteria) {}
|
| + updateMediaSinks(sourceUrn) {}
|
| + startListeningForRouteMessages(routeId) {}
|
| + stopListeningForRouteMessages(routeId) {}
|
| + detachRoute(routeId) {}
|
| + enableMdnsDiscovery() {}
|
| +};
|
| +
|
| +// Simulates a media remoting receiver. Currently only implements the
|
| +// start of remoting and the initialization of renderer.
|
| +mrTest.Receiver = class {
|
| + constructor(provideManager, routeId) {
|
| + this.mrp = provideManager;
|
| + this.routeId = routeId;
|
| + this.sessionId = null;
|
| + // The RPC handle of this receiver.
|
| + this.handle = 3;
|
| + // The RPC handle of the renderer on sender side.
|
| + this.remoteHandle = null;
|
| + // The number of streams to start remoting with.
|
| + this.num_start_streams = 0;
|
| + // The number of stream handles from RPC_R_INITIALIZE message.
|
| + this.num_stream_handle = 0;
|
| + // The number of streams that are initialized.
|
| + this.num_initialized_stream = 0;
|
| + }
|
| +
|
| + onReceivedMessageFromSource(message) {
|
| + // Each control message is a colon-delimited string. The first element is
|
| + // the command instruction, and all successive ones are arguments. See
|
| + // src/chrome/browser/media/cast_remoting_connector_messaging.cc in the
|
| + // Chromium project for further details.
|
| + const instruction = message.split(':');
|
| +
|
| + // All control messages include a control session ID.
|
| + const sessionId =
|
| + (instruction.find(piece => piece.startsWith('session=')) ||
|
| + '').substring(8);
|
| + if (sessionId.length == 0) {
|
| + return Promise.resolve();
|
| + }
|
| +
|
| + switch (instruction[0]) {
|
| + case 'START_CAST_REMOTING':
|
| + // There can only be one remoting session started at one time.
|
| + chrome.test.assertEq(this.sessionId, null);
|
| + this.sessionId = sessionId;
|
| + chrome.test.sendMessage('start_remoting');
|
| + break;
|
| +
|
| + case 'START_CAST_REMOTING_STREAMS':
|
| + chrome.test.assertEq(this.sessionId, sessionId);
|
| + const withAudio = instruction.some(piece => piece == 'audio=Y');
|
| + const withVideo = instruction.some(piece => piece == 'video=Y');
|
| + if (withAudio)
|
| + ++this.num_start_streams;
|
| + if (withVideo)
|
| + ++this.num_start_streams;
|
| + chrome.test.sendMessage('start_remoting_streams');
|
| + if (this.mrp.testParameters.route_terminate_while_remoting)
|
| + this.mrp.RemoveRoute(this.routeId);
|
| + break;
|
| +
|
| + case 'STOP_CAST_REMOTING':
|
| + chrome.test.assertEq(this.sessionId, sessionId);
|
| + this.sessionId = null;
|
| + chrome.test.sendMessage('stop_remoting');
|
| + break;
|
| +
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + return Promise.resolve();
|
| + }
|
| +
|
| + onReceivedBinaryMessageFromSource(message) {
|
| + let rpc = new mrTest.RpcMessage();
|
| + let reader = new mrTest.reader(message);
|
| + reader.deserializeBinary(rpc);
|
| + chrome.test.assertTrue((rpc.getHandle() == this.handle) ||
|
| + (rpc.getHandle() == 0));
|
| + switch(rpc.getProc()) {
|
| + case mrTest.RpcProc.RPC_ACQUIRE_RENDERER:
|
| + this.remoteHandle = rpc.getIntegerValue();
|
| + chrome.test.sendMessage("received_acquire_renderer");
|
| + // Send RPC_ACQUIRE_RENDERER_DONE message.
|
| + let remoteMessage = new mrTest.RpcMessage();
|
| + remoteMessage.setHandle(this.remoteHandle);
|
| + remoteMessage.setProc(mrTest.RpcProc.RPC_ACQUIRE_RENDERER_DONE);
|
| + remoteMessage.setIntegerValue(this.handle);
|
| + let writer = new mrTest.Writer();
|
| + writer.serializeMessage(remoteMessage);
|
| + this.mrp.sendMessageToSource(writer.getResultBuffer(), this.routeId);
|
| + break;
|
| + case mrTest.RpcProc.RPC_R_INITIALIZE:
|
| + chrome.test.sendMessage("received_renderer_initialize");
|
| + this.initializeRenderer(rpc.getRendererInitializeRpc());
|
| + break;
|
| + case mrTest.RpcProc.RPC_DS_INITIALIZE_CALLBACK:
|
| + this.onDemuxerStreamInitialized();
|
| + break;
|
| + case mrTest.RpcProc.RPC_R_STARTPLAYINGFROM:
|
| + chrome.test.sendMessage("received_startplayingfrom_rpc");
|
| + break;
|
| + default:
|
| + // Ignore other messages.
|
| + break;
|
| + }
|
| +
|
| + return Promise.resolve();
|
| + }
|
| +
|
| + initializeRenderer(rendererInitRpc) {
|
| + if (rendererInitRpc.getAudioDemuxerHandle()) {
|
| + ++this.num_stream_handle;
|
| + // Send RPC_DS_INITIALIZE message for audio.
|
| + let remoteMessage = new mrTest.RpcMessage();
|
| + remoteMessage.setHandle(rendererInitRpc.getAudioDemuxerHandle());
|
| + remoteMessage.setProc(mrTest.RpcProc.RPC_DS_INITIALIZE);
|
| + remoteMessage.setIntegerValue(this.handle);
|
| + let writer = new mrTest.Writer();
|
| + writer.serializeMessage(remoteMessage);
|
| + this.mrp.sendMessageToSource(writer.getResultBuffer(), this.routeId);
|
| + }
|
| + if (rendererInitRpc.getVideoDemuxerHandle()) {
|
| + ++this.num_stream_handle;
|
| + // Send RPC_DS_INITIALIZE message for video.
|
| + let remoteMessage = new mrTest.RpcMessage();
|
| + remoteMessage.setHandle(rendererInitRpc.getVideoDemuxerHandle());
|
| + remoteMessage.setProc(mrTest.RpcProc.RPC_DS_INITIALIZE);
|
| + remoteMessage.setIntegerValue(this.handle);
|
| + let writer = new mrTest.Writer();
|
| + writer.serializeMessage(remoteMessage);
|
| + this.mrp.sendMessageToSource(writer.getResultBuffer(), this.routeId);
|
| + }
|
| + chrome.test.assertEq(this.num_stream_handle, this.num_start_streams);
|
| + }
|
| +
|
| + onDemuxerStreamInitialized() {
|
| + ++this.num_initialized_stream;
|
| + if (this.num_stream_handle == this.num_initialized_stream ) {
|
| + chrome.test.sendMessage("demuxer_stream_initialized");
|
| + // Send RPC_R_INITIALIZE_CALLBACK message.
|
| + let remoteMessage = new mrTest.RpcMessage();
|
| + remoteMessage.setHandle(this.remoteHandle);
|
| + remoteMessage.setProc(mrTest.RpcProc.RPC_R_INITIALIZE_CALLBACK);
|
| + remoteMessage.setBool(this.mrp.testParameters.rendererInitSucceed);
|
| + let writer = new mrTest.Writer();
|
| + writer.serializeMessage(remoteMessage);
|
| + this.mrp.sendMessageToSource(writer.getResultBuffer(), this.routeId);
|
| + }
|
| + }
|
| +};
|
| +
|
|
|