Skip to content

Commit

Permalink
Add a new RenderFrameAudioOutputStreamFactory
Browse files Browse the repository at this point in the history
It checks that the stream is allowed and forwards the request to the
relevant ForwardingAudioOutputStreamFactory if so. This will cause
the stream to be served by the audio service.
The old RenderFrameAudioOutputStreamFactory which creates streams
living in content/ is renamed to
OldRenderFrameAudioOutputStreamFactory. Since the class was renamed,
the files were moved (by adding "old_" to the beginning). No need to
review those files. Also note that replacement is diffed against
the previous implementation. It's probably best to just ignore the diff
and review render_frame_audio_output_stream_factory{.cc,.h,_unittest.cc}
as new files.

A flag is added to switch between the old factory and the new one.

Approximate diagram of stuff:
https://docs.google.com/drawings/d/1_ZIKj6lihGKRjq4Mflduitmkn_REqpHFeqVNelBGHHk/edit

Tbr since there was a "verbal" LGTM in cl comments.

Tbr: nasko
Bug: 830493
Change-Id: I38887bb97c817cc9182d71edd89d5ff0193b2504
Reviewed-on: https://chromium-review.googlesource.com/1032751
Commit-Queue: Max Morin <maxmorin@chromium.org>
Reviewed-by: Olga Sharonova <olka@chromium.org>
Cr-Commit-Position: refs/heads/master@{#557492}
  • Loading branch information
Max Morin authored and Commit Bot committed May 10, 2018
1 parent 74fa71a commit 59f892f
Show file tree
Hide file tree
Showing 20 changed files with 1,039 additions and 428 deletions.
2 changes: 2 additions & 0 deletions content/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -1365,6 +1365,8 @@ jumbo_source_set("browser") {
"renderer_host/media/media_stream_track_metrics_host.h",
"renderer_host/media/media_stream_ui_proxy.cc",
"renderer_host/media/media_stream_ui_proxy.h",
"renderer_host/media/old_render_frame_audio_output_stream_factory.cc",
"renderer_host/media/old_render_frame_audio_output_stream_factory.h",
"renderer_host/media/peer_connection_tracker_host.cc",
"renderer_host/media/peer_connection_tracker_host.h",
"renderer_host/media/render_frame_audio_input_stream_factory.cc",
Expand Down
21 changes: 15 additions & 6 deletions content/browser/frame_host/render_frame_host_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4587,12 +4587,21 @@ void RenderFrameHostImpl::CreateAudioInputStreamFactory(

void RenderFrameHostImpl::CreateAudioOutputStreamFactory(
mojom::RendererAudioOutputStreamFactoryRequest request) {
RendererAudioOutputStreamFactoryContext* factory_context =
GetProcess()->GetRendererAudioOutputStreamFactoryContext();
DCHECK(factory_context);
audio_output_stream_factory_ =
RenderFrameAudioOutputStreamFactoryHandle::CreateFactory(
factory_context, GetRoutingID(), std::move(request));
if (base::FeatureList::IsEnabled(features::kAudioServiceAudioStreams)) {
media::AudioSystem* audio_system =
BrowserMainLoop::GetInstance()->audio_system();
MediaStreamManager* media_stream_manager =
BrowserMainLoop::GetInstance()->media_stream_manager();
audio_service_audio_output_stream_factory_.emplace(
this, audio_system, media_stream_manager, std::move(request));
} else {
RendererAudioOutputStreamFactoryContext* factory_context =
GetProcess()->GetRendererAudioOutputStreamFactoryContext();
DCHECK(factory_context);
in_content_audio_output_stream_factory_ =
RenderFrameAudioOutputStreamFactoryHandle::CreateFactory(
factory_context, GetRoutingID(), std::move(request));
}
}

#if BUILDFLAG(ENABLE_WEBRTC)
Expand Down
9 changes: 8 additions & 1 deletion content/browser/frame_host/render_frame_host_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/bad_message.h"
#include "content/browser/loader/global_routing_id.h"
#include "content/browser/renderer_host/media/old_render_frame_audio_output_stream_factory.h"
#include "content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h"
#include "content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h"
#include "content/browser/site_instance_impl.h"
Expand Down Expand Up @@ -1421,7 +1422,13 @@ class CONTENT_EXPORT RenderFrameHostImpl
TextSurroundingSelectionCallback text_surrounding_selection_callback_;

UniqueAudioInputStreamFactoryPtr audio_input_stream_factory_;
UniqueAudioOutputStreamFactoryPtr audio_output_stream_factory_;

// We switch between |audio_service_audio_output_stream_factory_| and
// |in_content_audio_output_stream_factory_| based on
// features::kAudioServiceAudioStreams status.
base::Optional<RenderFrameAudioOutputStreamFactory>
audio_service_audio_output_stream_factory_;
UniqueAudioOutputStreamFactoryPtr in_content_audio_output_stream_factory_;

#if BUILDFLAG(ENABLE_WEBRTC)
std::unique_ptr<MediaStreamDispatcherHost, BrowserThread::DeleteOnIOThread>
Expand Down
5 changes: 5 additions & 0 deletions content/browser/media/forwarding_audio_stream_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ class CONTENT_EXPORT ForwardingAudioStreamFactory final
void FrameDeleted(RenderFrameHost* render_frame_host) final;
void WebContentsDestroyed() final;

// E.g. to override binder.
service_manager::Connector* get_connector_for_testing() {
return connector_.get();
}

private:
using StreamBrokerSet = base::flat_set<std::unique_ptr<AudioStreamBroker>,
base::UniquePtrComparator>;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Copyright 2017 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.

#include "content/browser/renderer_host/media/old_render_frame_audio_output_stream_factory.h"

#include <memory>
#include <utility>

#include "base/metrics/histogram_macros.h"
#include "base/task_runner_util.h"
#include "content/browser/renderer_host/media/audio_output_authorization_handler.h"
#include "content/browser/renderer_host/media/audio_output_stream_observer_impl.h"
#include "content/browser/renderer_host/media/renderer_audio_output_stream_factory_context.h"
#include "content/public/browser/render_frame_host.h"
#include "media/base/audio_parameters.h"
#include "media/mojo/services/mojo_audio_output_stream_provider.h"
#include "mojo/public/cpp/bindings/message.h"

namespace content {

// static
std::unique_ptr<RenderFrameAudioOutputStreamFactoryHandle,
BrowserThread::DeleteOnIOThread>
RenderFrameAudioOutputStreamFactoryHandle::CreateFactory(
RendererAudioOutputStreamFactoryContext* context,
int render_frame_id,
mojom::RendererAudioOutputStreamFactoryRequest request) {
std::unique_ptr<RenderFrameAudioOutputStreamFactoryHandle,
BrowserThread::DeleteOnIOThread>
handle(new RenderFrameAudioOutputStreamFactoryHandle(context,
render_frame_id));
// Unretained is safe since |*handle| must be posted to the IO thread prior to
// deletion.
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::BindOnce(&RenderFrameAudioOutputStreamFactoryHandle::Init,
base::Unretained(handle.get()), std::move(request)));
return handle;
}

RenderFrameAudioOutputStreamFactoryHandle::
~RenderFrameAudioOutputStreamFactoryHandle() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
}

RenderFrameAudioOutputStreamFactoryHandle::
RenderFrameAudioOutputStreamFactoryHandle(
RendererAudioOutputStreamFactoryContext* context,
int render_frame_id)
: impl_(render_frame_id, context), binding_(&impl_) {}

void RenderFrameAudioOutputStreamFactoryHandle::Init(
mojom::RendererAudioOutputStreamFactoryRequest request) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
binding_.Bind(std::move(request));
}

OldRenderFrameAudioOutputStreamFactory::OldRenderFrameAudioOutputStreamFactory(
int render_frame_id,
RendererAudioOutputStreamFactoryContext* context)
: render_frame_id_(render_frame_id),
context_(context),
weak_ptr_factory_(this) {
DCHECK(context_);
}

OldRenderFrameAudioOutputStreamFactory::
~OldRenderFrameAudioOutputStreamFactory() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
UMA_HISTOGRAM_EXACT_LINEAR("Media.Audio.OutputStreamsCanceledByBrowser",
stream_providers_.size(), 50);
// Make sure to close all streams.
stream_providers_.clear();
}

void OldRenderFrameAudioOutputStreamFactory::RequestDeviceAuthorization(
media::mojom::AudioOutputStreamProviderRequest stream_provider_request,
int32_t session_id,
const std::string& device_id,
RequestDeviceAuthorizationCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
const base::TimeTicks auth_start_time = base::TimeTicks::Now();

context_->RequestDeviceAuthorization(
render_frame_id_, session_id, device_id,
base::BindOnce(
&OldRenderFrameAudioOutputStreamFactory::AuthorizationCompleted,
weak_ptr_factory_.GetWeakPtr(), auth_start_time,
std::move(stream_provider_request), std::move(callback)));
}

void OldRenderFrameAudioOutputStreamFactory::AuthorizationCompleted(
base::TimeTicks auth_start_time,
media::mojom::AudioOutputStreamProviderRequest request,
RequestDeviceAuthorizationCallback callback,
media::OutputDeviceStatus status,
const media::AudioParameters& params,
const std::string& raw_device_id,
const std::string& device_id_for_renderer) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
AudioOutputAuthorizationHandler::UMALogDeviceAuthorizationTime(
auth_start_time);

if (status != media::OUTPUT_DEVICE_STATUS_OK) {
std::move(callback).Run(media::OutputDeviceStatus(status),
media::AudioParameters::UnavailableDeviceParams(),
std::string());
return;
}

int stream_id = next_stream_id_++;
std::unique_ptr<media::mojom::AudioOutputStreamObserver> observer =
std::make_unique<AudioOutputStreamObserverImpl>(
context_->GetRenderProcessId(), render_frame_id_, stream_id);
// Since |context_| outlives |this| and |this| outlives |stream_providers_|,
// unretained is safe.
stream_providers_.insert(
std::make_unique<media::MojoAudioOutputStreamProvider>(
std::move(request),
base::BindOnce(
&RendererAudioOutputStreamFactoryContext::CreateDelegate,
base::Unretained(context_), raw_device_id, render_frame_id_,
stream_id),
base::BindOnce(&OldRenderFrameAudioOutputStreamFactory::RemoveStream,
base::Unretained(this)),
std::move(observer)));

std::move(callback).Run(media::OutputDeviceStatus(status), params,
device_id_for_renderer);
}

void OldRenderFrameAudioOutputStreamFactory::RemoveStream(
media::mojom::AudioOutputStreamProvider* stream_provider) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);

stream_providers_.erase(stream_provider);
}

} // namespace content
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright 2017 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.

#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_OLD_RENDER_FRAME_AUDIO_OUTPUT_STREAM_FACTORY_H_
#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_OLD_RENDER_FRAME_AUDIO_OUTPUT_STREAM_FACTORY_H_

#include <memory>
#include <string>

#include "base/containers/flat_set.h"
#include "base/containers/unique_ptr_adapters.h"
#include "content/common/content_export.h"
#include "content/common/media/renderer_audio_output_stream_factory.mojom.h"
#include "content/public/browser/browser_thread.h"
#include "mojo/public/cpp/bindings/binding.h"

namespace content {

class RendererAudioOutputStreamFactoryContext;

// Handles a RendererAudioOutputStreamFactory request for a render frame host,
// using the provided RendererAudioOutputStreamFactoryContext. This class may
// be constructed on any thread, but must be used on the IO thread after that.
// This class is used for creating streams hosted by the browser. It is being
// replaced by RenderFrameAudioOutputStreamFactory, which forwards stream
// requests to the audio service (https://crbug.com/830493).
class CONTENT_EXPORT OldRenderFrameAudioOutputStreamFactory
: public mojom::RendererAudioOutputStreamFactory {
public:
OldRenderFrameAudioOutputStreamFactory(
int render_frame_id,
RendererAudioOutputStreamFactoryContext* context);

~OldRenderFrameAudioOutputStreamFactory() override;

private:
using OutputStreamProviderSet =
base::flat_set<std::unique_ptr<media::mojom::AudioOutputStreamProvider>,
base::UniquePtrComparator>;

// mojom::RendererAudioOutputStreamFactory implementation.
void RequestDeviceAuthorization(
media::mojom::AudioOutputStreamProviderRequest stream_provider,
int32_t session_id,
const std::string& device_id,
RequestDeviceAuthorizationCallback callback) override;

// Here, the |raw_device_id| is used to create the stream, and
// |device_id_for_renderer| is nonempty in the case when the renderer
// requested a device using a |session_id|, to let it know which device was
// chosen. This id is hashed.
void AuthorizationCompleted(
base::TimeTicks auth_start_time,
media::mojom::AudioOutputStreamProviderRequest request,
RequestDeviceAuthorizationCallback callback,
media::OutputDeviceStatus status,
const media::AudioParameters& params,
const std::string& raw_device_id,
const std::string& device_id_for_renderer);

void RemoveStream(media::mojom::AudioOutputStreamProvider* stream_provider);

const int render_frame_id_;
RendererAudioOutputStreamFactoryContext* const context_;

// The stream providers will contain the corresponding streams.
OutputStreamProviderSet stream_providers_;

// All streams require IDs. Use a counter to generate them.
int next_stream_id_ = 0;

base::WeakPtrFactory<OldRenderFrameAudioOutputStreamFactory>
weak_ptr_factory_;

DISALLOW_COPY_AND_ASSIGN(OldRenderFrameAudioOutputStreamFactory);
};

// This class is a convenient bundle of factory and binding.
class CONTENT_EXPORT RenderFrameAudioOutputStreamFactoryHandle {
public:
static std::unique_ptr<RenderFrameAudioOutputStreamFactoryHandle,
BrowserThread::DeleteOnIOThread>
CreateFactory(RendererAudioOutputStreamFactoryContext* context,
int render_frame_id,
mojom::RendererAudioOutputStreamFactoryRequest request);

~RenderFrameAudioOutputStreamFactoryHandle();

private:
RenderFrameAudioOutputStreamFactoryHandle(
RendererAudioOutputStreamFactoryContext* context,
int render_frame_id);

void Init(mojom::RendererAudioOutputStreamFactoryRequest request);

OldRenderFrameAudioOutputStreamFactory impl_;
mojo::Binding<mojom::RendererAudioOutputStreamFactory> binding_;

DISALLOW_COPY_AND_ASSIGN(RenderFrameAudioOutputStreamFactoryHandle);
};

using UniqueAudioOutputStreamFactoryPtr =
std::unique_ptr<RenderFrameAudioOutputStreamFactoryHandle,
BrowserThread::DeleteOnIOThread>;

} // namespace content

#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_OLD_RENDER_FRAME_AUDIO_OUTPUT_STREAM_FACTORY_H_
Loading

0 comments on commit 59f892f

Please sign in to comment.