1// Copyright 2013 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 5chrome.runtime.onMessageExternal.addListener( 6 function(message, sender, sendResponse) { 7 function doSendResponse(value, error) { 8 var errorMessage = error || chrome.extension.lastError; 9 sendResponse({'value': value, 'error': errorMessage}); 10 } 11 12 function getHost(url) { 13 if (!url) 14 return ''; 15 // Use the DOM to parse the URL. Since we don't add the anchor to 16 // the page, this is the only reference to it and it will be 17 // deleted once it's gone out of scope. 18 var a = document.createElement('a'); 19 a.href = url; 20 var origin = a.protocol + '//' + a.hostname; 21 if (a.port != '') 22 origin = origin + ':' + a.port; 23 origin = origin + '/'; 24 return origin; 25 } 26 27 try { 28 var method = message['method']; 29 var origin = getHost(sender.url); 30 if (method == 'chooseDesktopMedia') { 31 // TODO(bemasc): Remove this method once the caller has transitioned 32 // to using the port. 33 var cancelId; 34 function sendResponseWithCancelId(streamId) { 35 var value = {'cancelId': cancelId, 'streamId': streamId}; 36 doSendResponse(value); 37 } 38 cancelId = chrome.desktopCapture.chooseDesktopMedia( 39 ['screen', 'window'], sender.tab, sendResponseWithCancelId); 40 return true; 41 } else if (method == 'cancelChooseDesktopMedia') { 42 // TODO(bemasc): Remove this method (see above). 43 var cancelId = message['cancelId']; 44 chrome.desktopCapture.cancelChooseDesktopMedia(cancelId); 45 doSendResponse(); 46 return false; 47 } else if (method == 'cpu.getInfo') { 48 chrome.system.cpu.getInfo(doSendResponse); 49 return true; 50 } else if (method == 'logging.setMetadata') { 51 var metaData = message['metaData']; 52 chrome.webrtcLoggingPrivate.setMetaData( 53 sender.tab.id, origin, metaData, doSendResponse); 54 return true; 55 } else if (method == 'logging.start') { 56 chrome.webrtcLoggingPrivate.start( 57 sender.tab.id, origin, doSendResponse); 58 return true; 59 } else if (method == 'logging.uploadOnRenderClose') { 60 chrome.webrtcLoggingPrivate.setUploadOnRenderClose( 61 sender.tab.id, origin, true); 62 doSendResponse(); 63 return false; 64 } else if (method == 'logging.noUploadOnRenderClose') { 65 chrome.webrtcLoggingPrivate.setUploadOnRenderClose( 66 sender.tab.id, origin, false); 67 doSendResponse(); 68 return false; 69 } else if (method == 'logging.stop') { 70 chrome.webrtcLoggingPrivate.stop( 71 sender.tab.id, origin, doSendResponse); 72 return true; 73 } else if (method == 'logging.upload') { 74 chrome.webrtcLoggingPrivate.upload( 75 sender.tab.id, origin, doSendResponse); 76 return true; 77 } else if (method == 'logging.stopAndUpload') { 78 stopAllRtpDump(sender.tab.id, origin, function() { 79 chrome.webrtcLoggingPrivate.stop(sender.tab.id, origin, function() { 80 chrome.webrtcLoggingPrivate.upload( 81 sender.tab.id, origin, doSendResponse); 82 }); 83 }); 84 return true; 85 } else if (method == 'logging.discard') { 86 chrome.webrtcLoggingPrivate.discard( 87 sender.tab.id, origin, doSendResponse); 88 return true; 89 } else if (method == 'getSinks') { 90 chrome.webrtcAudioPrivate.getSinks(doSendResponse); 91 return true; 92 } else if (method == 'getActiveSink') { 93 chrome.webrtcAudioPrivate.getActiveSink( 94 sender.tab.id, doSendResponse); 95 return true; 96 } else if (method == 'setActiveSink') { 97 var sinkId = message['sinkId']; 98 chrome.webrtcAudioPrivate.setActiveSink( 99 sender.tab.id, sinkId, doSendResponse); 100 return true; 101 } else if (method == 'getAssociatedSink') { 102 var sourceId = message['sourceId']; 103 chrome.webrtcAudioPrivate.getAssociatedSink( 104 origin, sourceId, doSendResponse); 105 return true; 106 } else if (method == 'isExtensionEnabled') { 107 // This method is necessary because there may be more than one 108 // version of this extension, under different extension IDs. By 109 // first calling this method on the extension ID, the client can 110 // check if it's loaded; if it's not, the extension system will 111 // call the callback with no arguments and set 112 // chrome.runtime.lastError. 113 doSendResponse(); 114 return false; 115 } else if (method == 'getNaclArchitecture') { 116 chrome.runtime.getPlatformInfo(function(obj) { 117 doSendResponse(obj.nacl_arch); 118 }); 119 return true; 120 } else if (method == 'logging.startRtpDump') { 121 var incoming = message['incoming'] || false; 122 var outgoing = message['outgoing'] || false; 123 chrome.webrtcLoggingPrivate.startRtpDump( 124 sender.tab.id, origin, incoming, outgoing, doSendResponse); 125 return true; 126 } else if (method == 'logging.stopRtpDump') { 127 var incoming = message['incoming'] || false; 128 var outgoing = message['outgoing'] || false; 129 chrome.webrtcLoggingPrivate.stopRtpDump( 130 sender.tab.id, origin, incoming, outgoing, doSendResponse); 131 return true; 132 } 133 throw new Error('Unknown method: ' + method); 134 } catch (e) { 135 doSendResponse(null, e.name + ': ' + e.message); 136 } 137 } 138); 139 140// If Hangouts connects with a port named 'onSinksChangedListener', we 141// will register a listener and send it a message {'eventName': 142// 'onSinksChanged'} whenever the event fires. 143function onSinksChangedPort(port) { 144 function clientListener() { 145 port.postMessage({'eventName': 'onSinksChanged'}); 146 } 147 chrome.webrtcAudioPrivate.onSinksChanged.addListener(clientListener); 148 149 port.onDisconnect.addListener(function() { 150 chrome.webrtcAudioPrivate.onSinksChanged.removeListener( 151 clientListener); 152 }); 153} 154 155// This is a one-time-use port for calling chooseDesktopMedia. The page 156// sends one message, identifying the requested source types, and the 157// extension sends a single reply, with the user's selected streamId. A port 158// is used so that if the page is closed before that message is sent, the 159// window picker dialog will be closed. 160function onChooseDesktopMediaPort(port) { 161 function sendResponse(streamId) { 162 port.postMessage({'value': {'streamId': streamId}}); 163 port.disconnect(); 164 } 165 166 port.onMessage.addListener(function(message) { 167 var method = message['method']; 168 if (method == 'chooseDesktopMedia') { 169 var sources = message['sources']; 170 var cancelId = chrome.desktopCapture.chooseDesktopMedia( 171 sources, port.sender.tab, sendResponse); 172 port.onDisconnect.addListener(function() { 173 // This method has no effect if called after the user has selected a 174 // desktop media source, so it does not need to be conditional. 175 chrome.desktopCapture.cancelChooseDesktopMedia(cancelId); 176 }); 177 } 178 }); 179} 180 181// A port for continuously reporting relevant CPU usage information to the page. 182function onProcessCpu(port) { 183 var tabPid; 184 function processListener(processes) { 185 if (tabPid == undefined) { 186 // getProcessIdForTab sometimes fails, and does not call the callback. 187 // (Tracked at https://crbug.com/368855.) 188 // This call retries it on each process update until it succeeds. 189 chrome.processes.getProcessIdForTab(port.sender.tab.id, function(x) { 190 tabPid = x; 191 }); 192 return; 193 } 194 var tabProcess = processes[tabPid]; 195 if (!tabProcess) { 196 return; 197 } 198 var pluginProcessCpu = 0, browserProcessCpu = 0, gpuProcessCpu = 0; 199 for (var pid in processes) { 200 var process = processes[pid]; 201 if (process.type == 'browser') { 202 browserProcessCpu = process.cpu; 203 } else if (process.type == 'gpu') { 204 gpuProcessCpu = process.cpu; 205 } else if ((process.type == 'plugin' || process.type == 'nacl') && 206 process.title.toLowerCase().indexOf('hangouts') > 0) { 207 pluginProcessCpu = process.cpu; 208 } 209 } 210 211 port.postMessage({ 212 'tabCpuUsage': tabProcess.cpu, 213 'browserCpuUsage': browserProcessCpu, 214 'gpuCpuUsage': gpuProcessCpu, 215 'pluginCpuUsage': pluginProcessCpu 216 }); 217 } 218 219 chrome.processes.onUpdated.addListener(processListener); 220 port.onDisconnect.addListener(function() { 221 chrome.processes.onUpdated.removeListener(processListener); 222 }); 223} 224 225function stopAllRtpDump(tabId, origin, callback) { 226 // Stops incoming and outgoing separately, otherwise stopRtpDump will fail if 227 // either type of dump has not been started. 228 chrome.webrtcLoggingPrivate.stopRtpDump( 229 tabId, origin, true, false, 230 function() { 231 chrome.webrtcLoggingPrivate.stopRtpDump( 232 tabId, origin, false, true, callback); 233 }); 234} 235 236chrome.runtime.onConnectExternal.addListener(function(port) { 237 if (port.name == 'onSinksChangedListener') { 238 onSinksChangedPort(port); 239 } else if (port.name == 'chooseDesktopMedia') { 240 onChooseDesktopMediaPort(port); 241 } else if (port.name == 'processCpu') { 242 onProcessCpu(port); 243 } else { 244 // Unknown port type. 245 port.disconnect(); 246 } 247}); 248