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.
5 chrome
.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
});
12 function getHost(url
) {
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');
20 var origin
= a
.protocol
+ '//' + a
.hostname
;
22 origin
= origin
+ ':' + a
.port
;
23 origin
= origin
+ '/';
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
34 function sendResponseWithCancelId(streamId
) {
35 var value
= {'cancelId': cancelId
, 'streamId': streamId
};
36 doSendResponse(value
);
38 cancelId
= chrome
.desktopCapture
.chooseDesktopMedia(
39 ['screen', 'window'], sender
.tab
, sendResponseWithCancelId
);
41 } else if (method
== 'cancelChooseDesktopMedia') {
42 // TODO(bemasc): Remove this method (see above).
43 var cancelId
= message
['cancelId'];
44 chrome
.desktopCapture
.cancelChooseDesktopMedia(cancelId
);
47 } else if (method
== 'cpu.getInfo') {
48 chrome
.system
.cpu
.getInfo(doSendResponse
);
50 } else if (method
== 'logging.setMetadata') {
51 var metaData
= message
['metaData'];
52 chrome
.webrtcLoggingPrivate
.setMetaData(
53 sender
.tab
.id
, origin
, metaData
, doSendResponse
);
55 } else if (method
== 'logging.start') {
56 chrome
.webrtcLoggingPrivate
.start(
57 sender
.tab
.id
, origin
, doSendResponse
);
59 } else if (method
== 'logging.uploadOnRenderClose') {
60 chrome
.webrtcLoggingPrivate
.setUploadOnRenderClose(
61 sender
.tab
.id
, origin
, true);
64 } else if (method
== 'logging.noUploadOnRenderClose') {
65 chrome
.webrtcLoggingPrivate
.setUploadOnRenderClose(
66 sender
.tab
.id
, origin
, false);
69 } else if (method
== 'logging.stop') {
70 chrome
.webrtcLoggingPrivate
.stop(
71 sender
.tab
.id
, origin
, doSendResponse
);
73 } else if (method
== 'logging.upload') {
74 chrome
.webrtcLoggingPrivate
.upload(
75 sender
.tab
.id
, origin
, doSendResponse
);
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
);
85 } else if (method
== 'logging.discard') {
86 chrome
.webrtcLoggingPrivate
.discard(
87 sender
.tab
.id
, origin
, doSendResponse
);
89 } else if (method
== 'getSinks') {
90 chrome
.webrtcAudioPrivate
.getSinks(doSendResponse
);
92 } else if (method
== 'getActiveSink') {
93 chrome
.webrtcAudioPrivate
.getActiveSink(
94 sender
.tab
.id
, doSendResponse
);
96 } else if (method
== 'setActiveSink') {
97 var sinkId
= message
['sinkId'];
98 chrome
.webrtcAudioPrivate
.setActiveSink(
99 sender
.tab
.id
, sinkId
, doSendResponse
);
101 } else if (method
== 'getAssociatedSink') {
102 var sourceId
= message
['sourceId'];
103 chrome
.webrtcAudioPrivate
.getAssociatedSink(
104 origin
, sourceId
, doSendResponse
);
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.
115 } else if (method
== 'getNaclArchitecture') {
116 chrome
.runtime
.getPlatformInfo(function(obj
) {
117 doSendResponse(obj
.nacl_arch
);
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
);
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
);
133 throw new Error('Unknown method: ' + method
);
135 doSendResponse(null, e
.name
+ ': ' + e
.message
);
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.
143 function onSinksChangedPort(port
) {
144 function clientListener() {
145 port
.postMessage({'eventName': 'onSinksChanged'});
147 chrome
.webrtcAudioPrivate
.onSinksChanged
.addListener(clientListener
);
149 port
.onDisconnect
.addListener(function() {
150 chrome
.webrtcAudioPrivate
.onSinksChanged
.removeListener(
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.
160 function onChooseDesktopMediaPort(port
) {
161 function sendResponse(streamId
) {
162 port
.postMessage({'value': {'streamId': streamId
}});
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
);
181 // A port for continuously reporting relevant CPU usage information to the page.
182 function onProcessCpu(port
) {
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
) {
194 var tabProcess
= processes
[tabPid
];
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
;
212 'tabCpuUsage': tabProcess
.cpu
,
213 'browserCpuUsage': browserProcessCpu
,
214 'gpuCpuUsage': gpuProcessCpu
,
215 'pluginCpuUsage': pluginProcessCpu
219 chrome
.processes
.onUpdated
.addListener(processListener
);
220 port
.onDisconnect
.addListener(function() {
221 chrome
.processes
.onUpdated
.removeListener(processListener
);
225 function 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,
231 chrome
.webrtcLoggingPrivate
.stopRtpDump(
232 tabId
, origin
, false, true, callback
);
236 chrome
.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') {
244 // Unknown port type.