Commit 77c6128e authored by jiayl's avatar jiayl Committed by Commit bot

Fix webrtcAudioPrivate API to handle requests from <webview>s.

BUG=424762

Review URL: https://codereview.chromium.org/880393002

Cr-Commit-Position: refs/heads/master@{#314036}
parent 9549ee3b
......@@ -23,12 +23,14 @@
namespace extensions {
using content::BrowserThread;
using content::RenderViewHost;
using content::RenderProcessHost;
using media::AudioDeviceNames;
using media::AudioManager;
namespace wap = api::webrtc_audio_private;
using api::webrtc_audio_private::RequestInfo;
static base::LazyInstance<
BrowserContextKeyedAPIFactory<WebrtcAudioPrivateEventService> > g_factory =
LAZY_INSTANCE_INITIALIZER;
......@@ -130,27 +132,38 @@ void WebrtcAudioPrivateFunction::OnOutputDeviceNames(
NOTREACHED();
}
bool WebrtcAudioPrivateFunction::GetControllerList(int tab_id) {
content::WebContents* contents = NULL;
if (!ExtensionTabUtil::GetTabById(
tab_id, GetProfile(), true, NULL, NULL, &contents, NULL)) {
error_ = extensions::ErrorUtils::FormatErrorMessage(
extensions::tabs_constants::kTabNotFoundError,
base::IntToString(tab_id));
bool WebrtcAudioPrivateFunction::GetControllerList(const RequestInfo& request) {
content::RenderProcessHost* rph = nullptr;
// If |guest_process_id| is defined, directly use this id to find the
// corresponding RenderProcessHost.
if (request.guest_process_id.get()) {
rph = content::RenderProcessHost::FromID(*request.guest_process_id.get());
} else if (request.tab_id.get()) {
int tab_id = *request.tab_id.get();
content::WebContents* contents = NULL;
if (!ExtensionTabUtil::GetTabById(tab_id, GetProfile(), true, NULL, NULL,
&contents, NULL)) {
error_ = extensions::ErrorUtils::FormatErrorMessage(
extensions::tabs_constants::kTabNotFoundError,
base::IntToString(tab_id));
return false;
}
rph = contents->GetRenderProcessHost();
} else {
return false;
}
RenderViewHost* rvh = contents->GetRenderViewHost();
if (!rvh)
if (!rph)
return false;
rvh->GetAudioOutputControllers(base::Bind(
&WebrtcAudioPrivateFunction::OnControllerList, this));
rph->GetAudioOutputControllers(
base::Bind(&WebrtcAudioPrivateFunction::OnControllerList, this));
return true;
}
void WebrtcAudioPrivateFunction::OnControllerList(
const content::RenderViewHost::AudioOutputControllerList& list) {
const content::RenderProcessHost::AudioOutputControllerList& list) {
NOTREACHED();
}
......@@ -254,11 +267,11 @@ bool WebrtcAudioPrivateGetActiveSinkFunction::RunAsync() {
wap::GetActiveSink::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
return GetControllerList(params->tab_id);
return GetControllerList(params->request);
}
void WebrtcAudioPrivateGetActiveSinkFunction::OnControllerList(
const RenderViewHost::AudioOutputControllerList& controllers) {
const RenderProcessHost::AudioOutputControllerList& controllers) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (controllers.empty()) {
......@@ -295,9 +308,8 @@ void WebrtcAudioPrivateGetActiveSinkFunction::OnHMACCalculated(
}
WebrtcAudioPrivateSetActiveSinkFunction::
WebrtcAudioPrivateSetActiveSinkFunction()
: tab_id_(0),
num_remaining_sink_ids_(0) {
WebrtcAudioPrivateSetActiveSinkFunction()
: num_remaining_sink_ids_(0) {
}
WebrtcAudioPrivateSetActiveSinkFunction::
......@@ -312,22 +324,40 @@ bool WebrtcAudioPrivateSetActiveSinkFunction::RunAsync() {
InitResourceContext();
tab_id_ = params->tab_id;
if (params->request.guest_process_id.get()) {
request_info_.guest_process_id.reset(
new int(*params->request.guest_process_id.get()));
} else if (params->request.tab_id.get()) {
request_info_.tab_id.reset(new int(*params->request.tab_id.get()));
} else {
return false;
}
sink_id_ = params->sink_id;
return GetControllerList(tab_id_);
return GetControllerList(request_info_);
}
void WebrtcAudioPrivateSetActiveSinkFunction::OnControllerList(
const RenderViewHost::AudioOutputControllerList& controllers) {
const RenderProcessHost::AudioOutputControllerList& controllers) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
std::string requested_process_type;
int requested_process_id;
if (request_info_.guest_process_id.get()) {
requested_process_type = "guestProcessId";
requested_process_id = *request_info_.guest_process_id.get();
} else {
requested_process_type = "tabId";
requested_process_id = *request_info_.tab_id.get();
}
controllers_ = controllers;
num_remaining_sink_ids_ = controllers_.size();
if (num_remaining_sink_ids_ == 0) {
error_ = extensions::ErrorUtils::FormatErrorMessage(
"No active stream for tab with id: *.",
base::IntToString(tab_id_));
"No active stream for " + requested_process_type + " *",
base::IntToString(requested_process_id));
SendResponse(false);
} else {
// We need to get the output device names, and calculate the HMAC
......@@ -359,7 +389,7 @@ void WebrtcAudioPrivateSetActiveSinkFunction::OnOutputDeviceNames(
DVLOG(2) << "Found no matching raw sink ID for HMAC " << sink_id_;
}
RenderViewHost::AudioOutputControllerList::const_iterator it =
RenderProcessHost::AudioOutputControllerList::const_iterator it =
controllers_.begin();
for (; it != controllers_.end(); ++it) {
(*it)->SwitchOutputDevice(raw_sink_id, base::Bind(
......
......@@ -9,7 +9,7 @@
#include "base/system_monitor/system_monitor.h"
#include "chrome/browser/extensions/chrome_extension_function.h"
#include "chrome/common/extensions/api/webrtc_audio_private.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_process_host.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
#include "media/audio/audio_device_name.h"
#include "url/gurl.h"
......@@ -68,11 +68,11 @@ class WebrtcAudioPrivateFunction : public ChromeAsyncExtensionFunction {
// entire function should fail.
//
// Call from any thread. Callback will occur on originating thread.
bool GetControllerList(int tab_id);
bool GetControllerList(const api::webrtc_audio_private::RequestInfo& request);
// Must override this if you call GetControllerList.
virtual void OnControllerList(
const content::RenderViewHost::AudioOutputControllerList& list);
const content::RenderProcessHost::AudioOutputControllerList& list);
// Calculates a single HMAC. Call from any thread. Calls back via
// OnHMACCalculated on UI thread.
......@@ -134,7 +134,7 @@ class WebrtcAudioPrivateGetActiveSinkFunction
bool RunAsync() override;
void OnControllerList(
const content::RenderViewHost::AudioOutputControllerList& controllers)
const content::RenderProcessHost::AudioOutputControllerList& controllers)
override;
void OnHMACCalculated(const std::string& hmac) override;
};
......@@ -153,18 +153,18 @@ class WebrtcAudioPrivateSetActiveSinkFunction
bool RunAsync() override;
void OnControllerList(
const content::RenderViewHost::AudioOutputControllerList& controllers)
const content::RenderProcessHost::AudioOutputControllerList& controllers)
override;
void OnOutputDeviceNames(
scoped_ptr<media::AudioDeviceNames> device_names) override;
void SwitchDone();
void DoneOnUIThread();
int tab_id_;
api::webrtc_audio_private::RequestInfo request_info_;
std::string sink_id_;
// Filled in by OnControllerList.
content::RenderViewHost::AudioOutputControllerList controllers_;
content::RenderProcessHost::AudioOutputControllerList controllers_;
// Number of sink IDs we are still waiting for. Can become greater
// than 0 in OnControllerList, decreases on every OnSinkId call.
......
......@@ -32,7 +32,7 @@
#include "testing/gtest/include/gtest/gtest.h"
using base::JSONWriter;
using content::RenderViewHost;
using content::RenderProcessHost;
using content::WebContents;
using media::AudioDeviceNames;
using media::AudioManager;
......@@ -49,7 +49,7 @@ class AudioWaitingExtensionTest : public ExtensionApiTest {
// or more AudioOutputController objects for our tab.
bool audio_playing = false;
for (size_t remaining_tries = 50; remaining_tries > 0; --remaining_tries) {
tab->GetRenderViewHost()->GetAudioOutputControllers(
tab->GetRenderProcessHost()->GetAudioOutputControllers(
base::Bind(OnAudioControllers, &audio_playing));
base::MessageLoop::current()->RunUntilIdle();
if (audio_playing)
......@@ -65,7 +65,7 @@ class AudioWaitingExtensionTest : public ExtensionApiTest {
// Used by the test above to wait until audio is playing.
static void OnAudioControllers(
bool* audio_playing,
const RenderViewHost::AudioOutputControllerList& list) {
const RenderProcessHost::AudioOutputControllerList& list) {
if (!list.empty())
*audio_playing = true;
}
......@@ -84,9 +84,15 @@ class WebrtcAudioPrivateTest : public AudioWaitingExtensionTest {
}
protected:
void AppendTabIdToRequestInfo(base::ListValue* params, int tab_id) {
base::DictionaryValue* request_info = new base::DictionaryValue();
request_info->SetInteger("tabId", tab_id);
params->Append(request_info);
}
std::string InvokeGetActiveSink(int tab_id) {
base::ListValue parameters;
parameters.AppendInteger(tab_id);
AppendTabIdToRequestInfo(&parameters, tab_id);
std::string parameter_string;
JSONWriter::Write(&parameters, &parameter_string);
......@@ -221,7 +227,7 @@ IN_PROC_BROWSER_TEST_F(WebrtcAudioPrivateTest, GetActiveSinkNoMediaStream) {
WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
int tab_id = ExtensionTabUtil::GetTabId(tab);
base::ListValue parameters;
parameters.AppendInteger(tab_id);
AppendTabIdToRequestInfo(&parameters, tab_id);
std::string parameter_string;
JSONWriter::Write(&parameters, &parameter_string);
......@@ -244,7 +250,7 @@ IN_PROC_BROWSER_TEST_F(WebrtcAudioPrivateTest, SetActiveSinkNoMediaStream) {
WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
int tab_id = ExtensionTabUtil::GetTabId(tab);
base::ListValue parameters;
parameters.AppendInteger(tab_id);
AppendTabIdToRequestInfo(&parameters, tab_id);
parameters.AppendString("no such id");
std::string parameter_string;
JSONWriter::Write(&parameters, &parameter_string);
......@@ -255,7 +261,7 @@ IN_PROC_BROWSER_TEST_F(WebrtcAudioPrivateTest, SetActiveSinkNoMediaStream) {
std::string error(RunFunctionAndReturnError(function.get(),
parameter_string,
browser()));
EXPECT_EQ(base::StringPrintf("No active stream for tab with id: %d.", tab_id),
EXPECT_EQ(base::StringPrintf("No active stream for tabId %d", tab_id),
error);
}
......@@ -290,7 +296,7 @@ IN_PROC_BROWSER_TEST_F(WebrtcAudioPrivateTest, GetAndSetWithMediaStream) {
dict->GetString("sinkId", &target_device);
base::ListValue parameters;
parameters.AppendInteger(tab_id);
AppendTabIdToRequestInfo(&parameters, tab_id);
parameters.AppendString(target_device);
std::string parameter_string;
JSONWriter::Write(&parameters, &parameter_string);
......
......@@ -107,12 +107,12 @@ chrome.runtime.onMessageExternal.addListener(
return true;
} else if (method == 'getActiveSink') {
chrome.webrtcAudioPrivate.getActiveSink(
sender.tab.id, doSendResponse);
requestInfo, doSendResponse);
return true;
} else if (method == 'setActiveSink') {
var sinkId = message['sinkId'];
chrome.webrtcAudioPrivate.setActiveSink(
sender.tab.id, sinkId, doSendResponse);
requestInfo, sinkId, doSendResponse);
return true;
} else if (method == 'getAssociatedSink') {
var sourceId = message['sourceId'];
......
......@@ -4,7 +4,7 @@
// The <code>chrome.webrtcAudioPrivate</code> API allows enumeration
// of audio output (sink) devices as well as getting and setting the
// active device for a given tab.
// active device for a given requesting process.
//
// Note that device IDs as used in this API are opaque (i.e. they are
// not the hardware identifier of the device) and while they are
......@@ -41,16 +41,26 @@ namespace webrtcAudioPrivate {
callback SinkIdCallback = void(DOMString sinkId);
callback CompletionCallback = void();
dictionary RequestInfo {
// The tab identifier from the chrome.tabs API, if the request is from a
// tab.
long? tabId;
// The guest process id for the requester, if the request is from a
// webview.
long? guestProcessId;
};
interface Functions {
// Retrieves a list of available audio sink devices.
static void getSinks(GetSinksCallback callback);
// Retrieves the currently active audio sink for the given tab.
static void getActiveSink(long tabId,
// Retrieves the currently active audio sink for the given requesting
// process.
static void getActiveSink(RequestInfo request,
SinkIdCallback callback);
// Sets the active audio sink device for the specified tab.
static void setActiveSink(long tabId,
// Sets the active audio sink device for the specified requesting process.
static void setActiveSink(RequestInfo request,
DOMString sinkId,
optional CompletionCallback callback);
......@@ -60,7 +70,7 @@ namespace webrtcAudioPrivate {
// sink.
//
// The associated sink ID can be used as a sink ID for
// setActiveSink. It is valid irrespective of which tab you are
// setActiveSink. It is valid irrespective of which process you are
// setting the active sink for.
static void getAssociatedSink(DOMString securityOrigin,
DOMString sourceIdInOrigin,
......
......@@ -146,14 +146,11 @@ AudioRendererHost::~AudioRendererHost() {
}
void AudioRendererHost::GetOutputControllers(
int render_view_id,
const RenderViewHost::GetAudioOutputControllersCallback& callback) const {
const RenderProcessHost::GetAudioOutputControllersCallback&
callback) const {
BrowserThread::PostTaskAndReplyWithResult(
BrowserThread::IO,
FROM_HERE,
base::Bind(&AudioRendererHost::DoGetOutputControllers, this,
render_view_id),
callback);
BrowserThread::IO, FROM_HERE,
base::Bind(&AudioRendererHost::DoGetOutputControllers, this), callback);
}
void AudioRendererHost::OnChannelClosing() {
......@@ -281,17 +278,15 @@ void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id,
UpdateNumPlayingStreams(entry, is_playing);
}
RenderViewHost::AudioOutputControllerList
AudioRendererHost::DoGetOutputControllers(int render_view_id) const {
RenderProcessHost::AudioOutputControllerList
AudioRendererHost::DoGetOutputControllers() const {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
RenderViewHost::AudioOutputControllerList controllers;
RenderProcessHost::AudioOutputControllerList controllers;
for (AudioEntryMap::const_iterator it = audio_entries_.begin();
it != audio_entries_.end();
++it) {
AudioEntry* entry = it->second;
if (entry->render_view_id() == render_view_id)
controllers.push_back(entry->controller());
controllers.push_back(it->second->controller());
}
return controllers;
......
......@@ -48,7 +48,7 @@
#include "content/common/content_export.h"
#include "content/public/browser/browser_message_filter.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_process_host.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_logging.h"
#include "media/audio/audio_output_controller.h"
......@@ -77,8 +77,8 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter {
// Calls |callback| with the list of AudioOutputControllers for this object.
void GetOutputControllers(
int render_view_id,
const RenderViewHost::GetAudioOutputControllersCallback& callback) const;
const RenderProcessHost::GetAudioOutputControllersCallback&
callback) const;
// BrowserMessageFilter implementation.
void OnChannelClosing() override;
......@@ -144,8 +144,7 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter {
// Send playing/paused status to the renderer.
void DoNotifyStreamStateChanged(int stream_id, bool is_playing);
RenderViewHost::AudioOutputControllerList DoGetOutputControllers(
int render_view_id) const;
RenderProcessHost::AudioOutputControllerList DoGetOutputControllers() const;
// Send an error message to the renderer.
void SendErrorMessage(int stream_id);
......
......@@ -2394,4 +2394,9 @@ void RenderProcessHostImpl::DecrementWorkerRefCount() {
Cleanup();
}
void RenderProcessHostImpl::GetAudioOutputControllers(
const GetAudioOutputControllersCallback& callback) const {
audio_renderer_host()->GetOutputControllers(callback);
}
} // namespace content
......@@ -271,6 +271,9 @@ class CONTENT_EXPORT RenderProcessHostImpl
// immediately after receiving response headers.
void ResumeResponseDeferredAtStart(const GlobalRequestID& request_id);
void GetAudioOutputControllers(
const GetAudioOutputControllersCallback& callback) const override;
protected:
// A proxy for our IPC::Channel that lives on the IO thread (see
// browser_process.h)
......
......@@ -1360,13 +1360,6 @@ void RenderViewHostImpl::OnWebkitPreferencesChanged() {
updating_web_preferences_ = false;
}
void RenderViewHostImpl::GetAudioOutputControllers(
const GetAudioOutputControllersCallback& callback) const {
scoped_refptr<AudioRendererHost> audio_host =
static_cast<RenderProcessHostImpl*>(GetProcess())->audio_renderer_host();
audio_host->GetOutputControllers(GetRoutingID(), callback);
}
void RenderViewHostImpl::ClearFocusedElement() {
is_focused_element_editable_ = false;
Send(new ViewMsg_ClearFocusedElement(GetRoutingID()));
......
......@@ -168,8 +168,6 @@ class CONTENT_EXPORT RenderViewHostImpl
WebPreferences GetWebkitPreferences() override;
void UpdateWebkitPreferences(const WebPreferences& prefs) override;
void OnWebkitPreferencesChanged() override;
void GetAudioOutputControllers(
const GetAudioOutputControllersCallback& callback) const override;
void SelectWordAroundCaret() override;
#if defined(OS_ANDROID)
......
......@@ -5,6 +5,8 @@
#ifndef CONTENT_PUBLIC_BROWSER_RENDER_PROCESS_HOST_H_
#define CONTENT_PUBLIC_BROWSER_RENDER_PROCESS_HOST_H_
#include <list>
#include "base/basictypes.h"
#include "base/id_map.h"
#include "base/process/kill.h"
......@@ -26,6 +28,10 @@ namespace gpu {
union ValueState;
}
namespace media {
class AudioOutputController;
}
namespace content {
class BrowserContext;
class BrowserMessageFilter;
......@@ -255,6 +261,16 @@ class CONTENT_EXPORT RenderProcessHost : public IPC::Sender,
virtual void SendUpdateValueState(
unsigned int target, const gpu::ValueState& state) = 0;
// Retrieves the list of AudioOutputController objects associated
// with this object and passes it to the callback you specify, on
// the same thread on which you called the method.
typedef std::list<scoped_refptr<media::AudioOutputController>>
AudioOutputControllerList;
typedef base::Callback<void(const AudioOutputControllerList&)>
GetAudioOutputControllersCallback;
virtual void GetAudioOutputControllers(
const GetAudioOutputControllersCallback& callback) const = 0;
// Static management functions -----------------------------------------------
// Flag to run the renderer in process. This is primarily
......
......@@ -5,8 +5,6 @@
#ifndef CONTENT_PUBLIC_BROWSER_RENDER_VIEW_HOST_H_
#define CONTENT_PUBLIC_BROWSER_RENDER_VIEW_HOST_H_
#include <list>
#include "base/callback_forward.h"
#include "content/common/content_export.h"
#include "content/public/browser/render_widget_host.h"
......@@ -31,10 +29,6 @@ namespace gfx {
class Point;
}
namespace media {
class AudioOutputController;
}
namespace content {
class ChildProcessSecurityPolicy;
......@@ -199,16 +193,6 @@ class CONTENT_EXPORT RenderViewHost : virtual public RenderWidgetHost {
// Passes a list of Webkit preferences to the renderer.
virtual void UpdateWebkitPreferences(const WebPreferences& prefs) = 0;
// Retrieves the list of AudioOutputController objects associated
// with this object and passes it to the callback you specify, on
// the same thread on which you called the method.
typedef std::list<scoped_refptr<media::AudioOutputController> >
AudioOutputControllerList;
typedef base::Callback<void(const AudioOutputControllerList&)>
GetAudioOutputControllersCallback;
virtual void GetAudioOutputControllers(
const GetAudioOutputControllersCallback& callback) const = 0;
// Notify the render view host to select the word around the caret.
virtual void SelectWordAroundCaret() = 0;
......
......@@ -112,6 +112,9 @@ class MockRenderProcessHost : public RenderProcessHost {
process_handle = new_handle.Pass();
}
void GetAudioOutputControllers(
const GetAudioOutputControllersCallback& callback) const override {}
private:
// Stores IPC messages that would have been sent to the renderer.
IPC::TestSink sink_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment