11e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
21e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
31e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// found in the LICENSE file.
41e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
51e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.h"
61e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
71e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/lazy_instance.h"
81e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
91e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/task_runner_util.h"
101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/browser/extensions/extension_tab_util.h"
13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "content/public/browser/media_device_id.h"
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/public/browser/resource_context.h"
161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "content/public/browser/web_contents.h"
17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/browser/event_router.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h"
191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "extensions/common/error_utils.h"
2046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "extensions/common/permissions/permissions_data.h"
211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "media/audio/audio_manager_base.h"
221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "media/audio/audio_output_controller.h"
231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)namespace extensions {
251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)using content::BrowserThread;
271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)using content::RenderViewHost;
281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)using media::AudioDeviceNames;
291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)using media::AudioManager;
301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)namespace wap = api::webrtc_audio_private;
321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)static base::LazyInstance<
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    BrowserContextKeyedAPIFactory<WebrtcAudioPrivateEventService> > g_factory =
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LAZY_INSTANCE_INITIALIZER;
361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)WebrtcAudioPrivateEventService::WebrtcAudioPrivateEventService(
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    content::BrowserContext* context)
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : browser_context_(context) {
401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // In unit tests, the SystemMonitor may not be created.
411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  base::SystemMonitor* system_monitor = base::SystemMonitor::Get();
421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (system_monitor)
431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    system_monitor->AddDevicesChangedObserver(this);
441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)WebrtcAudioPrivateEventService::~WebrtcAudioPrivateEventService() {
471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void WebrtcAudioPrivateEventService::Shutdown() {
501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // In unit tests, the SystemMonitor may not be created.
511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  base::SystemMonitor* system_monitor = base::SystemMonitor::Get();
521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (system_monitor)
531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    system_monitor->RemoveDevicesChangedObserver(this);
541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// static
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)BrowserContextKeyedAPIFactory<WebrtcAudioPrivateEventService>*
581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)WebrtcAudioPrivateEventService::GetFactoryInstance() {
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return g_factory.Pointer();
601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// static
631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const char* WebrtcAudioPrivateEventService::service_name() {
641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return "WebrtcAudioPrivateEventService";
651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void WebrtcAudioPrivateEventService::OnDevicesChanged(
681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    base::SystemMonitor::DeviceType device_type) {
691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  switch (device_type) {
701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    case base::SystemMonitor::DEVTYPE_AUDIO_CAPTURE:
711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    case base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE:
721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      SignalEvent();
731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      break;
741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    default:
761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      // No action needed.
771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      break;
781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void WebrtcAudioPrivateEventService::SignalEvent() {
821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  using api::webrtc_audio_private::OnSinksChanged::kEventName;
831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  EventRouter* router = EventRouter::Get(browser_context_);
851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (!router || !router->HasEventListener(kEventName))
861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return;
871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ExtensionService* extension_service =
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ExtensionSystem::Get(browser_context_)->extension_service();
891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  const ExtensionSet* extensions = extension_service->extensions();
901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  for (ExtensionSet::const_iterator it = extensions->begin();
911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)       it != extensions->end(); ++it) {
921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const std::string& extension_id = (*it)->id();
931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (router->ExtensionHasEventListener(extension_id, kEventName) &&
9446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        (*it)->permissions_data()->HasAPIPermission("webrtcAudioPrivate")) {
951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      scoped_ptr<Event> event(
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          new Event(kEventName, make_scoped_ptr(new base::ListValue()).Pass()));
971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      router->DispatchEventToExtension(extension_id, event.Pass());
981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    }
991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
1001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)WebrtcAudioPrivateFunction::WebrtcAudioPrivateFunction()
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : resource_context_(NULL) {
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)WebrtcAudioPrivateFunction::~WebrtcAudioPrivateFunction() {
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void WebrtcAudioPrivateFunction::GetOutputDeviceNames() {
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<base::SingleThreadTaskRunner> audio_manager_runner =
111116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      AudioManager::Get()->GetWorkerTaskRunner();
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!audio_manager_runner->BelongsToCurrentThread()) {
113effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    DCHECK_CURRENTLY_ON(BrowserThread::UI);
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    audio_manager_runner->PostTask(
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        FROM_HERE,
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::Bind(&WebrtcAudioPrivateFunction::GetOutputDeviceNames, this));
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<AudioDeviceNames> device_names(new AudioDeviceNames);
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AudioManager::Get()->GetAudioOutputDeviceNames(device_names.get());
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BrowserThread::PostTask(
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      BrowserThread::IO,
1251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      FROM_HERE,
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&WebrtcAudioPrivateFunction::OnOutputDeviceNames,
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 this,
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 Passed(&device_names)));
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void WebrtcAudioPrivateFunction::OnOutputDeviceNames(
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<AudioDeviceNames> device_names) {
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NOTREACHED();
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool WebrtcAudioPrivateFunction::GetControllerList(int tab_id) {
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  content::WebContents* contents = NULL;
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!ExtensionTabUtil::GetTabById(
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          tab_id, GetProfile(), true, NULL, NULL, &contents, NULL)) {
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    error_ = extensions::ErrorUtils::FormatErrorMessage(
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        extensions::tabs_constants::kTabNotFoundError,
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::IntToString(tab_id));
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RenderViewHost* rvh = contents->GetRenderViewHost();
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!rvh)
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  rvh->GetAudioOutputControllers(base::Bind(
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      &WebrtcAudioPrivateFunction::OnControllerList, this));
1521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return true;
1531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void WebrtcAudioPrivateFunction::OnControllerList(
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const content::RenderViewHost::AudioOutputControllerList& list) {
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NOTREACHED();
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void WebrtcAudioPrivateFunction::CalculateHMAC(const std::string& raw_id) {
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    BrowserThread::PostTask(
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        BrowserThread::IO,
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        FROM_HERE,
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::Bind(&WebrtcAudioPrivateFunction::CalculateHMAC, this, raw_id));
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string hmac = CalculateHMACImpl(raw_id);
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BrowserThread::PostTask(
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      BrowserThread::UI,
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&WebrtcAudioPrivateFunction::OnHMACCalculated, this, hmac));
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void WebrtcAudioPrivateFunction::OnHMACCalculated(const std::string& hmac) {
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NOTREACHED();
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string WebrtcAudioPrivateFunction::CalculateHMACImpl(
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& raw_id) {
182effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // We don't hash the default device name, and we always return
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // "default" for the default device. There is code in SetActiveSink
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // that transforms "default" to the empty string, and code in
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // GetActiveSink that ensures we return "default" if we get the
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // empty string as the current device ID.
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (raw_id.empty() || raw_id == media::AudioManagerBase::kDefaultDeviceId)
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return media::AudioManagerBase::kDefaultDeviceId;
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GURL security_origin(source_url().GetOrigin());
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return content::GetHMACForMediaDeviceID(
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      resource_context()->GetMediaDeviceIDSalt(),
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      security_origin,
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      raw_id);
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void WebrtcAudioPrivateFunction::InitResourceContext() {
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  resource_context_ = GetProfile()->GetResourceContext();
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)content::ResourceContext* WebrtcAudioPrivateFunction::resource_context() const {
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(resource_context_);  // Did you forget to InitResourceContext()?
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return resource_context_;
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
208010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool WebrtcAudioPrivateGetSinksFunction::RunAsync() {
209effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  InitResourceContext();
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GetOutputDeviceNames();
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void WebrtcAudioPrivateGetSinksFunction::OnOutputDeviceNames(
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<AudioDeviceNames> raw_ids) {
219effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
2201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  std::vector<linked_ptr<wap::SinkInfo> > results;
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (AudioDeviceNames::const_iterator it = raw_ids->begin();
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it != raw_ids->end();
2241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)       ++it) {
2251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    linked_ptr<wap::SinkInfo> info(new wap::SinkInfo);
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    info->sink_id = CalculateHMACImpl(it->unique_id);
2271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    info->sink_label = it->device_name;
2281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // TODO(joi): Add other parameters.
2291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    results.push_back(info);
2301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
2311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // It's safe to directly set the results here (from a thread other
2331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // than the UI thread, on which an AsyncExtensionFunction otherwise
2341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // normally runs) because there is one instance of this object per
2351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // function call, no actor outside of this object is modifying the
2361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // results_ member, and the different method invocations on this
237010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // object run strictly in sequence; first RunAsync on the UI thread,
2381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // then DoQuery on the audio IO thread, then DoneOnUIThread on the
2391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // UI thread.
2401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  results_.reset(wap::GetSinks::Results::Create(results).release());
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BrowserThread::PostTask(
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      BrowserThread::UI,
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FROM_HERE,
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&WebrtcAudioPrivateGetSinksFunction::DoneOnUIThread, this));
2461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void WebrtcAudioPrivateGetSinksFunction::DoneOnUIThread() {
2491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SendResponse(true);
2501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
252010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool WebrtcAudioPrivateGetActiveSinkFunction::RunAsync() {
253effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  InitResourceContext();
2551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  scoped_ptr<wap::GetActiveSink::Params> params(
2571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      wap::GetActiveSink::Params::Create(*args_));
2581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params.get());
2591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return GetControllerList(params->tab_id);
2611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void WebrtcAudioPrivateGetActiveSinkFunction::OnControllerList(
2641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const RenderViewHost::AudioOutputControllerList& controllers) {
265effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (controllers.empty()) {
2681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // If there is no current audio stream for the rvh, we return an
2691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // empty string as the sink ID.
2701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    DVLOG(2) << "chrome.webrtcAudioPrivate.getActiveSink: No controllers.";
2711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    results_.reset(
2721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        wap::GetActiveSink::Results::Create(std::string()).release());
2731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    SendResponse(true);
2741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  } else {
2751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    DVLOG(2) << "chrome.webrtcAudioPrivate.getActiveSink: "
2761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)             << controllers.size() << " controllers.";
2771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // TODO(joi): Debug-only, DCHECK that all items have the same ID.
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Send the raw ID through CalculateHMAC, and send the result in
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // OnHMACCalculated.
2811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    (*controllers.begin())->GetOutputDeviceId(
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::Bind(&WebrtcAudioPrivateGetActiveSinkFunction::CalculateHMAC,
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   this));
2841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
2851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void WebrtcAudioPrivateGetActiveSinkFunction::OnHMACCalculated(
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& hmac_id) {
289effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string result = hmac_id;
2921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (result.empty()) {
2931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    DVLOG(2) << "Received empty ID, replacing with default ID.";
2941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    result = media::AudioManagerBase::kDefaultDeviceId;
2951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
2961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  results_.reset(wap::GetActiveSink::Results::Create(result).release());
2971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SendResponse(true);
2981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)WebrtcAudioPrivateSetActiveSinkFunction::
3011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)WebrtcAudioPrivateSetActiveSinkFunction()
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : tab_id_(0),
3031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      num_remaining_sink_ids_(0) {
3041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)WebrtcAudioPrivateSetActiveSinkFunction::
3071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)~WebrtcAudioPrivateSetActiveSinkFunction() {
3081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
310010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool WebrtcAudioPrivateSetActiveSinkFunction::RunAsync() {
311effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
3121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  scoped_ptr<wap::SetActiveSink::Params> params(
3131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      wap::SetActiveSink::Params::Create(*args_));
3141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params.get());
3151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  InitResourceContext();
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  tab_id_ = params->tab_id;
3191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  sink_id_ = params->sink_id;
3201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return GetControllerList(tab_id_);
3221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void WebrtcAudioPrivateSetActiveSinkFunction::OnControllerList(
3251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const RenderViewHost::AudioOutputControllerList& controllers) {
326effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  controllers_ = controllers;
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  num_remaining_sink_ids_ = controllers_.size();
3301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (num_remaining_sink_ids_ == 0) {
3311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    error_ = extensions::ErrorUtils::FormatErrorMessage(
3321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        "No active stream for tab with id: *.",
3331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        base::IntToString(tab_id_));
3341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    SendResponse(false);
3351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  } else {
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // We need to get the output device names, and calculate the HMAC
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // for each, to find the raw ID for the ID provided to this API
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // function call.
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    GetOutputDeviceNames();
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void WebrtcAudioPrivateSetActiveSinkFunction::OnOutputDeviceNames(
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<AudioDeviceNames> device_names) {
345effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string raw_sink_id;
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (sink_id_ == media::AudioManagerBase::kDefaultDeviceId) {
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(2) << "Received default ID, replacing with empty ID.";
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    raw_sink_id = "";
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (AudioDeviceNames::const_iterator it = device_names->begin();
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         it != device_names->end();
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         ++it) {
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (sink_id_ == CalculateHMACImpl(it->unique_id)) {
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        raw_sink_id = it->unique_id;
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        break;
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
3591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    }
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (raw_sink_id.empty())
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DVLOG(2) << "Found no matching raw sink ID for HMAC " << sink_id_;
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RenderViewHost::AudioOutputControllerList::const_iterator it =
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      controllers_.begin();
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (; it != controllers_.end(); ++it) {
3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    (*it)->SwitchOutputDevice(raw_sink_id, base::Bind(
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        &WebrtcAudioPrivateSetActiveSinkFunction::SwitchDone, this));
3701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
3711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void WebrtcAudioPrivateSetActiveSinkFunction::SwitchDone() {
3741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (--num_remaining_sink_ids_ == 0) {
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    BrowserThread::PostTask(
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        BrowserThread::UI,
3771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        FROM_HERE,
3781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        base::Bind(&WebrtcAudioPrivateSetActiveSinkFunction::DoneOnUIThread,
3791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                   this));
3801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
3811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void WebrtcAudioPrivateSetActiveSinkFunction::DoneOnUIThread() {
3841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SendResponse(true);
3851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)WebrtcAudioPrivateGetAssociatedSinkFunction::
388a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)WebrtcAudioPrivateGetAssociatedSinkFunction() {
389a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
390a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
391a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)WebrtcAudioPrivateGetAssociatedSinkFunction::
3921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)~WebrtcAudioPrivateGetAssociatedSinkFunction() {
3931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
395010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool WebrtcAudioPrivateGetAssociatedSinkFunction::RunAsync() {
396a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  params_ = wap::GetAssociatedSink::Params::Create(*args_);
397effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
398a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params_.get());
3991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  InitResourceContext();
4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
402116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  AudioManager::Get()->GetWorkerTaskRunner()->PostTask(
4031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      FROM_HERE,
404a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::Bind(&WebrtcAudioPrivateGetAssociatedSinkFunction::
4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 GetDevicesOnDeviceThread, this));
4061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
4071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return true;
4081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
4091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
410a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void WebrtcAudioPrivateGetAssociatedSinkFunction::GetDevicesOnDeviceThread() {
411116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(AudioManager::Get()->GetWorkerTaskRunner()->BelongsToCurrentThread());
412a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  AudioManager::Get()->GetAudioInputDeviceNames(&source_devices_);
413a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BrowserThread::PostTask(
415a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      BrowserThread::IO,
416a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      FROM_HERE,
417a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::Bind(&WebrtcAudioPrivateGetAssociatedSinkFunction::
418a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                 GetRawSourceIDOnIOThread,
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 this));
4205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void
4235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)WebrtcAudioPrivateGetAssociatedSinkFunction::GetRawSourceIDOnIOThread() {
424effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::IO);
4251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GURL security_origin(params_->security_origin);
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string source_id_in_origin(params_->source_id_in_origin);
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Find the raw source ID for source_id_in_origin.
4301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  std::string raw_source_id;
431a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  for (AudioDeviceNames::const_iterator it = source_devices_.begin();
432a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)       it != source_devices_.end();
4331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)       ++it) {
4341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const std::string& id = it->unique_id;
4351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (content::DoesMediaDeviceIDMatchHMAC(
4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            resource_context()->GetMediaDeviceIDSalt(),
437a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            security_origin,
438a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            source_id_in_origin,
439a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            id)) {
4401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      raw_source_id = id;
4411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      DVLOG(2) << "Found raw ID " << raw_source_id
4421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)               << " for source ID in origin " << source_id_in_origin;
4431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      break;
4441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    }
4451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
4461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
447116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  AudioManager::Get()->GetWorkerTaskRunner()->PostTask(
448a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      FROM_HERE,
449a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::Bind(&WebrtcAudioPrivateGetAssociatedSinkFunction::
450a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                 GetAssociatedSinkOnDeviceThread,
451a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                 this,
4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 raw_source_id));
453a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
454a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
4555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void
456a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)WebrtcAudioPrivateGetAssociatedSinkFunction::GetAssociatedSinkOnDeviceThread(
457a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const std::string& raw_source_id) {
458116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(AudioManager::Get()->GetWorkerTaskRunner()->BelongsToCurrentThread());
459a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
4601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // We return an empty string if there is no associated output device.
4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string raw_sink_id;
4621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (!raw_source_id.empty()) {
4635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    raw_sink_id =
4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        AudioManager::Get()->GetAssociatedOutputDeviceID(raw_source_id);
4651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
4661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CalculateHMAC(raw_sink_id);
4681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
4691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
4705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void WebrtcAudioPrivateGetAssociatedSinkFunction::OnHMACCalculated(
4711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const std::string& associated_sink_id) {
472effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
4731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (associated_sink_id == media::AudioManagerBase::kDefaultDeviceId) {
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(2) << "Got default ID, replacing with empty ID.";
4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    results_.reset(wap::GetAssociatedSink::Results::Create("").release());
4775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
4785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    results_.reset(
4795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        wap::GetAssociatedSink::Results::Create(associated_sink_id).release());
4805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SendResponse(true);
4831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
4841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
4851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}  // namespace extensions
486