// Copyright 2013 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. chrome.runtime.onMessageExternal.addListener( function(message, sender, sendResponse) { function doSendResponse(value, error) { var errorMessage = error || chrome.extension.lastError; sendResponse({'value': value, 'error': errorMessage}); } function getHost(url) { if (!url) return ''; // Use the DOM to parse the URL. Since we don't add the anchor to // the page, this is the only reference to it and it will be // deleted once it's gone out of scope. var a = document.createElement('a'); a.href = url; var origin = a.protocol + '//' + a.hostname; if (a.port != '') origin = origin + ':' + a.port; origin = origin + '/'; return origin; } try { var method = message['method']; var origin = getHost(sender.url); if (method == 'chooseDesktopMedia') { // TODO(bemasc): Remove this method once the caller has transitioned // to using the port. var cancelId; function sendResponseWithCancelId(streamId) { var value = {'cancelId': cancelId, 'streamId': streamId}; doSendResponse(value); } cancelId = chrome.desktopCapture.chooseDesktopMedia( ['screen', 'window'], sender.tab, sendResponseWithCancelId); return true; } else if (method == 'cancelChooseDesktopMedia') { // TODO(bemasc): Remove this method (see above). var cancelId = message['cancelId']; chrome.desktopCapture.cancelChooseDesktopMedia(cancelId); doSendResponse(); return false; } else if (method == 'cpu.getInfo') { chrome.system.cpu.getInfo(doSendResponse); return true; } else if (method == 'logging.setMetadata') { var metaData = message['metaData']; chrome.webrtcLoggingPrivate.setMetaData( sender.tab.id, origin, metaData, doSendResponse); return true; } else if (method == 'logging.start') { chrome.webrtcLoggingPrivate.start( sender.tab.id, origin, doSendResponse); return true; } else if (method == 'logging.uploadOnRenderClose') { chrome.webrtcLoggingPrivate.setUploadOnRenderClose( sender.tab.id, origin, true); doSendResponse(); return false; } else if (method == 'logging.noUploadOnRenderClose') { chrome.webrtcLoggingPrivate.setUploadOnRenderClose( sender.tab.id, origin, false); doSendResponse(); return false; } else if (method == 'logging.stop') { chrome.webrtcLoggingPrivate.stop( sender.tab.id, origin, doSendResponse); return true; } else if (method == 'logging.upload') { chrome.webrtcLoggingPrivate.upload( sender.tab.id, origin, doSendResponse); return true; } else if (method == 'logging.stopAndUpload') { stopAllRtpDump(sender.tab.id, origin, function() { chrome.webrtcLoggingPrivate.stop(sender.tab.id, origin, function() { chrome.webrtcLoggingPrivate.upload( sender.tab.id, origin, doSendResponse); }); }); return true; } else if (method == 'logging.discard') { chrome.webrtcLoggingPrivate.discard( sender.tab.id, origin, doSendResponse); return true; } else if (method == 'getSinks') { chrome.webrtcAudioPrivate.getSinks(doSendResponse); return true; } else if (method == 'getActiveSink') { chrome.webrtcAudioPrivate.getActiveSink( sender.tab.id, doSendResponse); return true; } else if (method == 'setActiveSink') { var sinkId = message['sinkId']; chrome.webrtcAudioPrivate.setActiveSink( sender.tab.id, sinkId, doSendResponse); return true; } else if (method == 'getAssociatedSink') { var sourceId = message['sourceId']; chrome.webrtcAudioPrivate.getAssociatedSink( origin, sourceId, doSendResponse); return true; } else if (method == 'isExtensionEnabled') { // This method is necessary because there may be more than one // version of this extension, under different extension IDs. By // first calling this method on the extension ID, the client can // check if it's loaded; if it's not, the extension system will // call the callback with no arguments and set // chrome.runtime.lastError. doSendResponse(); return false; } else if (method == 'getNaclArchitecture') { chrome.runtime.getPlatformInfo(function(obj) { doSendResponse(obj.nacl_arch); }); return true; } else if (method == 'logging.startRtpDump') { var incoming = message['incoming'] || false; var outgoing = message['outgoing'] || false; chrome.webrtcLoggingPrivate.startRtpDump( sender.tab.id, origin, incoming, outgoing, doSendResponse); return true; } else if (method == 'logging.stopRtpDump') { var incoming = message['incoming'] || false; var outgoing = message['outgoing'] || false; chrome.webrtcLoggingPrivate.stopRtpDump( sender.tab.id, origin, incoming, outgoing, doSendResponse); return true; } throw new Error('Unknown method: ' + method); } catch (e) { doSendResponse(null, e.name + ': ' + e.message); } } ); // If Hangouts connects with a port named 'onSinksChangedListener', we // will register a listener and send it a message {'eventName': // 'onSinksChanged'} whenever the event fires. function onSinksChangedPort(port) { function clientListener() { port.postMessage({'eventName': 'onSinksChanged'}); } chrome.webrtcAudioPrivate.onSinksChanged.addListener(clientListener); port.onDisconnect.addListener(function() { chrome.webrtcAudioPrivate.onSinksChanged.removeListener( clientListener); }); } // This is a one-time-use port for calling chooseDesktopMedia. The page // sends one message, identifying the requested source types, and the // extension sends a single reply, with the user's selected streamId. A port // is used so that if the page is closed before that message is sent, the // window picker dialog will be closed. function onChooseDesktopMediaPort(port) { function sendResponse(streamId) { port.postMessage({'value': {'streamId': streamId}}); port.disconnect(); } port.onMessage.addListener(function(message) { var method = message['method']; if (method == 'chooseDesktopMedia') { var sources = message['sources']; var cancelId = chrome.desktopCapture.chooseDesktopMedia( sources, port.sender.tab, sendResponse); port.onDisconnect.addListener(function() { // This method has no effect if called after the user has selected a // desktop media source, so it does not need to be conditional. chrome.desktopCapture.cancelChooseDesktopMedia(cancelId); }); } }); } // A port for continuously reporting relevant CPU usage information to the page. function onProcessCpu(port) { var tabPid; function processListener(processes) { if (tabPid == undefined) { // getProcessIdForTab sometimes fails, and does not call the callback. // (Tracked at https://crbug.com/368855.) // This call retries it on each process update until it succeeds. chrome.processes.getProcessIdForTab(port.sender.tab.id, function(x) { tabPid = x; }); return; } var tabProcess = processes[tabPid]; if (!tabProcess) { return; } var pluginProcessCpu = 0, browserProcessCpu = 0, gpuProcessCpu = 0; for (var pid in processes) { var process = processes[pid]; if (process.type == 'browser') { browserProcessCpu = process.cpu; } else if (process.type == 'gpu') { gpuProcessCpu = process.cpu; } else if ((process.type == 'plugin' || process.type == 'nacl') && process.title.toLowerCase().indexOf('hangouts') > 0) { pluginProcessCpu = process.cpu; } } port.postMessage({ 'tabCpuUsage': tabProcess.cpu, 'browserCpuUsage': browserProcessCpu, 'gpuCpuUsage': gpuProcessCpu, 'pluginCpuUsage': pluginProcessCpu }); } chrome.processes.onUpdated.addListener(processListener); port.onDisconnect.addListener(function() { chrome.processes.onUpdated.removeListener(processListener); }); } function stopAllRtpDump(tabId, origin, callback) { // Stops incoming and outgoing separately, otherwise stopRtpDump will fail if // either type of dump has not been started. chrome.webrtcLoggingPrivate.stopRtpDump( tabId, origin, true, false, function() { chrome.webrtcLoggingPrivate.stopRtpDump( tabId, origin, false, true, callback); }); } chrome.runtime.onConnectExternal.addListener(function(port) { if (port.name == 'onSinksChangedListener') { onSinksChangedPort(port); } else if (port.name == 'chooseDesktopMedia') { onChooseDesktopMediaPort(port); } else if (port.name == 'processCpu') { onProcessCpu(port); } else { // Unknown port type. port.disconnect(); } });