Commit 7673d021 authored by Xiangjun Zhang's avatar Xiangjun Zhang Committed by Commit Bot

Mirroring Service: Create audio loopback stream as requested.

This CL adds the implementation to create an audio loopback stream
through Audio Service as requested.

Bug: 734672
Change-Id: Ifd78a1848c7979438401586c03f41758d996978e
Reviewed-on: https://chromium-review.googlesource.com/1141284
Commit-Queue: Xiangjun Zhang <xjz@chromium.org>
Reviewed-by: default avatarAlex Moshchuk <alexmos@chromium.org>
Reviewed-by: default avatarYuri Wiitala <miu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#581017}
parent 2441a576
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "chrome/browser/media/cast_remoting_connector.h" #include "chrome/browser/media/cast_remoting_connector.h"
#include "chrome/browser/net/default_network_context_params.h" #include "chrome/browser/net/default_network_context_params.h"
#include "components/mirroring/browser/single_client_video_capture_host.h" #include "components/mirroring/browser/single_client_video_capture_host.h"
#include "content/public/browser/audio_loopback_stream_creator.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/network_service_instance.h" #include "content/public/browser/network_service_instance.h"
#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_frame_host.h"
...@@ -111,7 +112,36 @@ void CastMirroringServiceHost::CreateAudioStream( ...@@ -111,7 +112,36 @@ void CastMirroringServiceHost::CreateAudioStream(
mojom::AudioStreamCreatorClientPtr client, mojom::AudioStreamCreatorClientPtr client,
const media::AudioParameters& params, const media::AudioParameters& params,
uint32_t total_segments) { uint32_t total_segments) {
// TODO(xjz): Implementation will be added in a later CL. content::WebContents* source_web_contents = nullptr;
if (source_media_id_.type == content::DesktopMediaID::TYPE_WEB_CONTENTS) {
source_web_contents = content::WebContents::FromRenderFrameHost(
content::RenderFrameHost::FromID(
source_media_id_.web_contents_id.render_process_id,
source_media_id_.web_contents_id.main_render_frame_id));
if (!source_web_contents) {
VLOG(1) << "Failed to create audio stream: Invalid source.";
return;
}
}
if (!audio_stream_creator_) {
audio_stream_creator_ = content::AudioLoopbackStreamCreator::
CreateInProcessAudioLoopbackStreamCreator();
}
audio_stream_creator_->CreateLoopbackStream(
source_web_contents, params, total_segments,
base::BindRepeating(
[](mojom::AudioStreamCreatorClientPtr client,
media::mojom::AudioInputStreamPtr stream,
media::mojom::AudioInputStreamClientRequest client_request,
media::mojom::ReadOnlyAudioDataPipePtr data_pipe) {
// TODO(xjz): Remove |initially_muted| argument from
// mojom::AudioStreamCreatorClient::StreamCreated().
client->StreamCreated(std::move(stream), std::move(client_request),
std::move(data_pipe),
false /* initially_muted */);
},
base::Passed(&client)));
} }
void CastMirroringServiceHost::ConnectToRemotingSource( void CastMirroringServiceHost::ConnectToRemotingSource(
......
...@@ -10,6 +10,10 @@ ...@@ -10,6 +10,10 @@
#include "components/mirroring/mojom/resource_provider.mojom.h" #include "components/mirroring/mojom/resource_provider.mojom.h"
#include "content/public/browser/desktop_media_id.h" #include "content/public/browser/desktop_media_id.h"
namespace content {
class AudioLoopbackStreamCreator;
} // namespace content
namespace mirroring { namespace mirroring {
// CastMirroringServiceHost starts/stops a mirroring session through Mirroring // CastMirroringServiceHost starts/stops a mirroring session through Mirroring
...@@ -19,6 +23,7 @@ namespace mirroring { ...@@ -19,6 +23,7 @@ namespace mirroring {
class CastMirroringServiceHost final : public mojom::MirroringServiceHost, class CastMirroringServiceHost final : public mojom::MirroringServiceHost,
public mojom::ResourceProvider { public mojom::ResourceProvider {
public: public:
// |source_media_id| indicates the mirroring source.
explicit CastMirroringServiceHost(content::DesktopMediaID source_media_id); explicit CastMirroringServiceHost(content::DesktopMediaID source_media_id);
~CastMirroringServiceHost() override; ~CastMirroringServiceHost() override;
...@@ -30,6 +35,8 @@ class CastMirroringServiceHost final : public mojom::MirroringServiceHost, ...@@ -30,6 +35,8 @@ class CastMirroringServiceHost final : public mojom::MirroringServiceHost,
mojom::CastMessageChannelRequest inbound_channel) override; mojom::CastMessageChannelRequest inbound_channel) override;
private: private:
friend class CastMirroringServiceHostBrowserTest;
// ResourceProvider implementation. // ResourceProvider implementation.
void GetVideoCaptureHost( void GetVideoCaptureHost(
media::mojom::VideoCaptureHostRequest request) override; media::mojom::VideoCaptureHostRequest request) override;
...@@ -45,6 +52,8 @@ class CastMirroringServiceHost final : public mojom::MirroringServiceHost, ...@@ -45,6 +52,8 @@ class CastMirroringServiceHost final : public mojom::MirroringServiceHost,
// Describes the media source for this mirroring session. // Describes the media source for this mirroring session.
const content::DesktopMediaID source_media_id_; const content::DesktopMediaID source_media_id_;
std::unique_ptr<content::AudioLoopbackStreamCreator> audio_stream_creator_;
DISALLOW_COPY_AND_ASSIGN(CastMirroringServiceHost); DISALLOW_COPY_AND_ASSIGN(CastMirroringServiceHost);
}; };
......
...@@ -109,12 +109,16 @@ class MockVideoCaptureObserver final ...@@ -109,12 +109,16 @@ class MockVideoCaptureObserver final
} // namespace } // namespace
class CastMirroringServiceHostBrowserTest : public InProcessBrowserTest, class CastMirroringServiceHostBrowserTest
public mojom::SessionObserver, : public InProcessBrowserTest,
public mojom::CastMessageChannel { public mojom::SessionObserver,
public mojom::CastMessageChannel,
public mojom::AudioStreamCreatorClient {
public: public:
CastMirroringServiceHostBrowserTest() CastMirroringServiceHostBrowserTest()
: observer_binding_(this), outbound_channel_binding_(this) {} : observer_binding_(this),
outbound_channel_binding_(this),
audio_client_binding_(this) {}
~CastMirroringServiceHostBrowserTest() override {} ~CastMirroringServiceHostBrowserTest() override {}
protected: protected:
...@@ -152,12 +156,14 @@ class CastMirroringServiceHostBrowserTest : public InProcessBrowserTest, ...@@ -152,12 +156,14 @@ class CastMirroringServiceHostBrowserTest : public InProcessBrowserTest,
} }
void StopMirroring() { void StopMirroring() {
base::RunLoop run_loop; if (video_frame_receiver_) {
EXPECT_CALL(*video_frame_receiver_, base::RunLoop run_loop;
OnStateChanged(media::mojom::VideoCaptureState::ENDED)) EXPECT_CALL(*video_frame_receiver_,
.WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit)); OnStateChanged(media::mojom::VideoCaptureState::ENDED))
video_frame_receiver_->Stop(); .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
run_loop.Run(); video_frame_receiver_->Stop();
run_loop.Run();
}
host_.reset(); host_.reset();
} }
...@@ -169,6 +175,22 @@ class CastMirroringServiceHostBrowserTest : public InProcessBrowserTest, ...@@ -169,6 +175,22 @@ class CastMirroringServiceHostBrowserTest : public InProcessBrowserTest,
run_loop.Run(); run_loop.Run();
} }
void CreateAudioLoopbackStream() {
constexpr int kTotalSegments = 1;
constexpr int kAudioTimebase = 48000;
media::AudioParameters params(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
media::CHANNEL_LAYOUT_STEREO, kAudioTimebase,
kAudioTimebase / 100);
mojom::AudioStreamCreatorClientPtr audio_client_ptr;
audio_client_binding_.Bind(mojo::MakeRequest(&audio_client_ptr));
base::RunLoop run_loop;
EXPECT_CALL(*this, OnAudioStreamCreated())
.WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
host_->CreateAudioStream(std::move(audio_client_ptr), params,
kTotalSegments);
run_loop.Run();
}
// InProcessBrowserTest override. // InProcessBrowserTest override.
void SetUp() override { void SetUp() override {
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
...@@ -186,13 +208,27 @@ class CastMirroringServiceHostBrowserTest : public InProcessBrowserTest, ...@@ -186,13 +208,27 @@ class CastMirroringServiceHostBrowserTest : public InProcessBrowserTest,
// mojom::CastMessageChannel mocks. // mojom::CastMessageChannel mocks.
MOCK_METHOD1(Send, void(mojom::CastMessagePtr)); MOCK_METHOD1(Send, void(mojom::CastMessagePtr));
// mojom::AudioStreamCreatorClient mocks.
MOCK_METHOD0(OnAudioStreamCreated, void());
void StreamCreated(media::mojom::AudioInputStreamPtr stream,
media::mojom::AudioInputStreamClientRequest client_request,
media::mojom::ReadOnlyAudioDataPipePtr data_pipe,
bool initially_muted) override {
EXPECT_TRUE(stream);
EXPECT_TRUE(client_request);
EXPECT_TRUE(data_pipe);
OnAudioStreamCreated();
}
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
base::test::ScopedFeatureList scoped_feature_list_; base::test::ScopedFeatureList scoped_feature_list_;
#endif #endif
mojo::Binding<mojom::SessionObserver> observer_binding_; mojo::Binding<mojom::SessionObserver> observer_binding_;
mojo::Binding<mojom::CastMessageChannel> outbound_channel_binding_; mojo::Binding<mojom::CastMessageChannel> outbound_channel_binding_;
mojo::Binding<mojom::AudioStreamCreatorClient> audio_client_binding_;
mojom::CastMessageChannelPtr inbound_channel_; mojom::CastMessageChannelPtr inbound_channel_;
std::unique_ptr<CastMirroringServiceHost> host_; std::unique_ptr<CastMirroringServiceHost> host_;
std::unique_ptr<MockVideoCaptureObserver> video_frame_receiver_; std::unique_ptr<MockVideoCaptureObserver> video_frame_receiver_;
...@@ -207,4 +243,10 @@ IN_PROC_BROWSER_TEST_F(CastMirroringServiceHostBrowserTest, CaptureTabVideo) { ...@@ -207,4 +243,10 @@ IN_PROC_BROWSER_TEST_F(CastMirroringServiceHostBrowserTest, CaptureTabVideo) {
StopMirroring(); StopMirroring();
} }
IN_PROC_BROWSER_TEST_F(CastMirroringServiceHostBrowserTest, CaptureTabAudio) {
StartTabMirroring();
CreateAudioLoopbackStream();
StopMirroring();
}
} // namespace mirroring } // namespace mirroring
...@@ -1112,6 +1112,8 @@ jumbo_source_set("browser") { ...@@ -1112,6 +1112,8 @@ jumbo_source_set("browser") {
"media/flinging_renderer.h", "media/flinging_renderer.h",
"media/forwarding_audio_stream_factory.cc", "media/forwarding_audio_stream_factory.cc",
"media/forwarding_audio_stream_factory.h", "media/forwarding_audio_stream_factory.h",
"media/in_process_audio_loopback_stream_creator.cc",
"media/in_process_audio_loopback_stream_creator.h",
"media/media_devices_permission_checker.cc", "media/media_devices_permission_checker.cc",
"media/media_devices_permission_checker.h", "media/media_devices_permission_checker.h",
"media/media_devices_util.cc", "media/media_devices_util.cc",
......
...@@ -13,11 +13,49 @@ ...@@ -13,11 +13,49 @@
#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "media/audio/audio_device_description.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/audio/public/mojom/constants.mojom.h" #include "services/audio/public/mojom/constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/connector.h"
namespace content { namespace content {
namespace {
// A mojom::RendererAudioInputStreamFactoryClient that holds a
// AudioLoopbackStreamCreator::StreamCreatedCallback. The callback runs when the
// requested audio stream is created.
class StreamCreatedCallbackAdapter final
: public mojom::RendererAudioInputStreamFactoryClient {
public:
explicit StreamCreatedCallbackAdapter(
const AudioLoopbackStreamCreator::StreamCreatedCallback& callback)
: callback_(callback) {
DCHECK(callback_);
}
~StreamCreatedCallbackAdapter() override {}
// mojom::RendererAudioInputStreamFactoryClient implementation.
void StreamCreated(
media::mojom::AudioInputStreamPtr stream,
media::mojom::AudioInputStreamClientRequest client_request,
media::mojom::ReadOnlyAudioDataPipePtr data_pipe,
bool initially_muted,
const base::Optional<base::UnguessableToken>& stream_id) override {
DCHECK(!initially_muted); // Loopback streams shouldn't be started muted.
callback_.Run(std::move(stream), std::move(client_request),
std::move(data_pipe));
}
private:
const AudioLoopbackStreamCreator::StreamCreatedCallback callback_;
DISALLOW_COPY_AND_ASSIGN(StreamCreatedCallbackAdapter);
};
} // namespace
ForwardingAudioStreamFactory::ForwardingAudioStreamFactory( ForwardingAudioStreamFactory::ForwardingAudioStreamFactory(
WebContents* web_contents, WebContents* web_contents,
std::unique_ptr<service_manager::Connector> connector, std::unique_ptr<service_manager::Connector> connector,
...@@ -27,7 +65,6 @@ ForwardingAudioStreamFactory::ForwardingAudioStreamFactory( ...@@ -27,7 +65,6 @@ ForwardingAudioStreamFactory::ForwardingAudioStreamFactory(
broker_factory_(std::move(broker_factory)), broker_factory_(std::move(broker_factory)),
group_id_(base::UnguessableToken::Create()) { group_id_(base::UnguessableToken::Create()) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(web_contents);
DCHECK(broker_factory_); DCHECK(broker_factory_);
} }
...@@ -57,8 +94,8 @@ void ForwardingAudioStreamFactory::CreateInputStream( ...@@ -57,8 +94,8 @@ void ForwardingAudioStreamFactory::CreateInputStream(
mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client) { mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
const int process_id = frame->GetProcess()->GetID(); const int process_id = frame ? frame->GetProcess()->GetID() : -1;
const int frame_id = frame->GetRoutingID(); const int frame_id = frame ? frame->GetRoutingID() : -1;
inputs_ inputs_
.insert(broker_factory_->CreateAudioInputStreamBroker( .insert(broker_factory_->CreateAudioInputStreamBroker(
process_id, frame_id, device_id, params, shared_memory_count, process_id, frame_id, device_id, params, shared_memory_count,
...@@ -111,7 +148,6 @@ void ForwardingAudioStreamFactory::CreateLoopbackStream( ...@@ -111,7 +148,6 @@ void ForwardingAudioStreamFactory::CreateLoopbackStream(
bool mute_source, bool mute_source,
mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client) { mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(frame);
DCHECK(frame_of_source_web_contents); DCHECK(frame_of_source_web_contents);
TRACE_EVENT_BEGIN1("audio", "CreateLoopbackStream", "group", TRACE_EVENT_BEGIN1("audio", "CreateLoopbackStream", "group",
...@@ -125,8 +161,8 @@ void ForwardingAudioStreamFactory::CreateLoopbackStream( ...@@ -125,8 +161,8 @@ void ForwardingAudioStreamFactory::CreateLoopbackStream(
return; return;
} }
const int process_id = frame->GetProcess()->GetID(); const int process_id = frame ? frame->GetProcess()->GetID() : -1;
const int frame_id = frame->GetRoutingID(); const int frame_id = frame ? frame->GetRoutingID() : -1;
inputs_ inputs_
.insert(broker_factory_->CreateAudioLoopbackStreamBroker( .insert(broker_factory_->CreateAudioLoopbackStreamBroker(
process_id, frame_id, process_id, frame_id,
...@@ -145,6 +181,28 @@ void ForwardingAudioStreamFactory::CreateLoopbackStream( ...@@ -145,6 +181,28 @@ void ForwardingAudioStreamFactory::CreateLoopbackStream(
.GetLowForSerialization()); .GetLowForSerialization());
} }
void ForwardingAudioStreamFactory::CreateInProcessLoopbackStream(
RenderFrameHost* frame_of_source_web_contents,
const media::AudioParameters& params,
uint32_t shared_memory_count,
const AudioLoopbackStreamCreator::StreamCreatedCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
mojom::RendererAudioInputStreamFactoryClientPtr client;
mojo::MakeStrongBinding(
std::make_unique<StreamCreatedCallbackAdapter>(callback),
mojo::MakeRequest(&client));
if (frame_of_source_web_contents) {
CreateLoopbackStream(nullptr, frame_of_source_web_contents, params,
shared_memory_count, true /* mute_source */,
std::move(client));
} else {
// A null |frame_of_source_web_contents| requests system-wide loopback.
CreateInputStream(
nullptr, media::AudioDeviceDescription::kLoopbackWithMuteDeviceId,
params, shared_memory_count, false /* enable_agc*/, std::move(client));
}
}
void ForwardingAudioStreamFactory::SetMuted(bool muted) { void ForwardingAudioStreamFactory::SetMuted(bool muted) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_NE(muted, IsMuted()); DCHECK_NE(muted, IsMuted());
...@@ -176,8 +234,10 @@ void ForwardingAudioStreamFactory::CleanupStreamsBelongingTo( ...@@ -176,8 +234,10 @@ void ForwardingAudioStreamFactory::CleanupStreamsBelongingTo(
RenderFrameHost* render_frame_host) { RenderFrameHost* render_frame_host) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
const int process_id = render_frame_host->GetProcess()->GetID(); const int process_id =
const int frame_id = render_frame_host->GetRoutingID(); render_frame_host ? render_frame_host->GetProcess()->GetID() : -1;
const int frame_id =
render_frame_host ? render_frame_host->GetRoutingID() : -1;
TRACE_EVENT_BEGIN2("audio", "CleanupStreamsBelongingTo", "group", TRACE_EVENT_BEGIN2("audio", "CleanupStreamsBelongingTo", "group",
group_id_.GetLowForSerialization(), "process id", group_id_.GetLowForSerialization(), "process id",
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "content/browser/media/audio_stream_broker.h" #include "content/browser/media/audio_stream_broker.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
#include "content/common/media/renderer_audio_input_stream_factory.mojom.h" #include "content/common/media/renderer_audio_input_stream_factory.mojom.h"
#include "content/public/browser/audio_loopback_stream_creator.h"
#include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_observer.h"
#include "services/audio/public/mojom/stream_factory.mojom.h" #include "services/audio/public/mojom/stream_factory.mojom.h"
...@@ -39,6 +40,8 @@ class WebContents; ...@@ -39,6 +40,8 @@ class WebContents;
class CONTENT_EXPORT ForwardingAudioStreamFactory final class CONTENT_EXPORT ForwardingAudioStreamFactory final
: public WebContentsObserver { : public WebContentsObserver {
public: public:
// |web_contents| is null in the browser-privileged access case, i.e., when
// the streams created with this factory will not be consumed by a renderer.
ForwardingAudioStreamFactory( ForwardingAudioStreamFactory(
WebContents* web_contents, WebContents* web_contents,
std::unique_ptr<service_manager::Connector> connector, std::unique_ptr<service_manager::Connector> connector,
...@@ -81,6 +84,15 @@ class CONTENT_EXPORT ForwardingAudioStreamFactory final ...@@ -81,6 +84,15 @@ class CONTENT_EXPORT ForwardingAudioStreamFactory final
bool mute_source, bool mute_source,
mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client); mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client);
// Creates a loopback stream that captures the audio from
// |frame_of_source_web_contents|, or the default system playback if the
// source is not provided. The source/system audio is muted during capturing.
void CreateInProcessLoopbackStream(
RenderFrameHost* frame_of_source_web_contents,
const media::AudioParameters& params,
uint32_t shared_memory_count,
const AudioLoopbackStreamCreator::StreamCreatedCallback& callback);
// Sets the muting state for all output streams created through this factory. // Sets the muting state for all output streams created through this factory.
void SetMuted(bool muted); void SetMuted(bool muted);
......
// Copyright 2018 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/media/in_process_audio_loopback_stream_creator.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/service_manager_connection.h"
#include "services/service_manager/public/cpp/connector.h"
namespace content {
InProcessAudioLoopbackStreamCreator::InProcessAudioLoopbackStreamCreator()
: factory_(nullptr,
content::ServiceManagerConnection::GetForProcess()
->GetConnector()
->Clone(),
AudioStreamBrokerFactory::CreateImpl()) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
InProcessAudioLoopbackStreamCreator::~InProcessAudioLoopbackStreamCreator() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
factory_.FrameDeleted(nullptr);
}
void InProcessAudioLoopbackStreamCreator::CreateLoopbackStream(
WebContents* loopback_source,
const media::AudioParameters& params,
uint32_t total_segments,
const StreamCreatedCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RenderFrameHost* loopback_source_frame = nullptr;
if (loopback_source) {
loopback_source_frame = loopback_source->GetMainFrame();
DCHECK(loopback_source_frame);
}
factory_.CreateInProcessLoopbackStream(loopback_source_frame, params,
total_segments, callback);
}
} // namespace content
// Copyright 2018 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_MEDIA_IN_PROCESS_AUDIO_LOOPBACK_STREAM_CREATOR_H_
#define CONTENT_BROWSER_MEDIA_IN_PROCESS_AUDIO_LOOPBACK_STREAM_CREATOR_H_
#include "base/macros.h"
#include "content/browser/media/forwarding_audio_stream_factory.h"
#include "content/public/browser/audio_loopback_stream_creator.h"
namespace media {
class AudioParameters;
}
namespace content {
// This class handles creating a loopback stream that either captures audio from
// a WebContents or the system-wide loopback through the Audio Service.
// This class is operated on the UI thread.
class CONTENT_EXPORT InProcessAudioLoopbackStreamCreator final
: public AudioLoopbackStreamCreator {
public:
InProcessAudioLoopbackStreamCreator();
~InProcessAudioLoopbackStreamCreator() override;
private:
// AudioLoopbackStreamCreator implementation.
void CreateLoopbackStream(WebContents* loopback_source,
const media::AudioParameters& params,
uint32_t total_segments,
const StreamCreatedCallback& callback) override;
ForwardingAudioStreamFactory factory_;
DISALLOW_COPY_AND_ASSIGN(InProcessAudioLoopbackStreamCreator);
};
} // namespace content
#endif // CONTENT_BROWSER_MEDIA_IN_PROCESS_AUDIO_LOOPBACK_STREAM_CREATOR_H_
...@@ -36,6 +36,8 @@ jumbo_source_set("browser_sources") { ...@@ -36,6 +36,8 @@ jumbo_source_set("browser_sources") {
"android/synchronous_compositor.h", "android/synchronous_compositor.h",
"android/synchronous_compositor_client.h", "android/synchronous_compositor_client.h",
"appcache_service.h", "appcache_service.h",
"audio_loopback_stream_creator.cc",
"audio_loopback_stream_creator.h",
"audio_service_info.cc", "audio_service_info.cc",
"audio_service_info.h", "audio_service_info.h",
"authenticator_request_client_delegate.cc", "authenticator_request_client_delegate.cc",
......
// Copyright 2018 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/public/browser/audio_loopback_stream_creator.h"
#include "content/browser/media/in_process_audio_loopback_stream_creator.h"
namespace content {
// static
std::unique_ptr<AudioLoopbackStreamCreator>
AudioLoopbackStreamCreator::CreateInProcessAudioLoopbackStreamCreator() {
return std::make_unique<InProcessAudioLoopbackStreamCreator>();
}
AudioLoopbackStreamCreator::~AudioLoopbackStreamCreator() = default;
} // namespace content
// Copyright 2018 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_PUBLIC_BROWSER_AUDIO_LOOPBACK_STREAM_CREATOR_H_
#define CONTENT_PUBLIC_BROWSER_AUDIO_LOOPBACK_STREAM_CREATOR_H_
#include "base/callback.h"
#include "content/common/content_export.h"
#include "media/mojo/interfaces/audio_data_pipe.mojom.h"
#include "media/mojo/interfaces/audio_input_stream.mojom.h"
namespace media {
class AudioParameters;
}
namespace content {
class WebContents;
// This interface is used by the embedder to ask the Audio Service to create a
// loopback stream that either captures audio from a tab or the system-wide
// loopback.
// Note: Use this to request loopback audio for a privileged embedder feature,
// and not for consumption by a renderer. For renderers, use the
// mojom::RendererAudioInputStreamFactory interface instead.
class CONTENT_EXPORT AudioLoopbackStreamCreator {
public:
virtual ~AudioLoopbackStreamCreator();
// The callback that is called when the requested stream is created.
using StreamCreatedCallback = base::RepeatingCallback<void(
media::mojom::AudioInputStreamPtr stream,
media::mojom::AudioInputStreamClientRequest client_request,
media::mojom::ReadOnlyAudioDataPipePtr data_pipe)>;
// Creates an InProcessAudioLoopbackStreamCreator that handles creating audio
// loopback stream through the Audio Service.
static std::unique_ptr<AudioLoopbackStreamCreator>
CreateInProcessAudioLoopbackStreamCreator();
// Creates a loopback stream that captures the audio from |loopback_source|,
// or the default system playback if |loopback_source| is null. Local output
// of the source/system audio is muted during capturing.
virtual void CreateLoopbackStream(WebContents* loopback_source,
const media::AudioParameters& params,
uint32_t total_segments,
const StreamCreatedCallback& callback) = 0;
};
} // namespace content
#endif // CONTENT_PUBLIC_BROWSER_AUDIO_LOOPBACK_STREAM_CREATOR_H_
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