Commit 0d5d2e61 authored by Max Morin's avatar Max Morin Committed by Commit Bot

Add loopback support to audio input stream factory.

TBR=miu@chromium.org

Bug: 824019
Change-Id: Ib70a7edf1c42ea2643393611bca81e3b986fb333
Reviewed-on: https://chromium-review.googlesource.com/1059779Reviewed-by: default avatarOlga Sharonova <olka@chromium.org>
Commit-Queue: Olga Sharonova <olka@chromium.org>
Cr-Commit-Position: refs/heads/master@{#558750}
parent 443b70db
......@@ -93,12 +93,18 @@ void ForwardingAudioStreamFactory::CreateOutputStream(
void ForwardingAudioStreamFactory::CreateLoopbackStream(
RenderFrameHost* frame,
WebContents* source_contents,
RenderFrameHost* frame_of_source_web_contents,
const media::AudioParameters& params,
uint32_t shared_memory_count,
bool mute_source,
mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(frame);
DCHECK(frame_of_source_web_contents);
WebContents* source_contents =
WebContents::FromRenderFrameHost(frame_of_source_web_contents);
if (!source_contents)
return;
const int process_id = frame->GetProcess()->GetID();
const int frame_id = frame->GetRoutingID();
......
......@@ -71,7 +71,7 @@ class CONTENT_EXPORT ForwardingAudioStreamFactory final
void CreateLoopbackStream(
RenderFrameHost* frame,
WebContents* source_contents,
RenderFrameHost* frame_of_source_web_contents,
const media::AudioParameters& params,
uint32_t shared_memory_count,
bool mute_source,
......
......@@ -272,8 +272,8 @@ TEST_F(ForwardingAudioStreamFactoryTest,
EXPECT_CALL(*broker, CreateStream(NotNull()));
mojo::MakeRequest(&client);
factory.CreateLoopbackStream(main_rfh(), source_contents.get(), kParams,
kSharedMemoryCount, kMuteSource,
factory.CreateLoopbackStream(main_rfh(), source_contents->GetMainFrame(),
kParams, kSharedMemoryCount, kMuteSource,
std::move(client));
}
......@@ -340,16 +340,16 @@ TEST_F(ForwardingAudioStreamFactoryTest,
{
EXPECT_CALL(*main_rfh_broker, CreateStream(NotNull()));
mojo::MakeRequest(&client);
factory.CreateLoopbackStream(main_rfh(), source_contents.get(), kParams,
kSharedMemoryCount, kMuteSource,
factory.CreateLoopbackStream(main_rfh(), source_contents->GetMainFrame(),
kParams, kSharedMemoryCount, kMuteSource,
std::move(client));
testing::Mock::VerifyAndClear(&*main_rfh_broker);
}
{
EXPECT_CALL(*other_rfh_broker, CreateStream(NotNull()));
mojo::MakeRequest(&client);
factory.CreateLoopbackStream(other_rfh(), source_contents.get(), kParams,
kSharedMemoryCount, kMuteSource,
factory.CreateLoopbackStream(other_rfh(), source_contents->GetMainFrame(),
kParams, kSharedMemoryCount, kMuteSource,
std::move(client));
testing::Mock::VerifyAndClear(&*other_rfh_broker);
}
......@@ -435,16 +435,16 @@ TEST_F(ForwardingAudioStreamFactoryTest, DestroyFrame_DestroysRelatedStreams) {
{
EXPECT_CALL(*main_rfh_loopback_broker, CreateStream(NotNull()));
mojo::MakeRequest(&input_client);
factory.CreateLoopbackStream(main_rfh(), source_contents.get(), kParams,
kSharedMemoryCount, kMuteSource,
factory.CreateLoopbackStream(main_rfh(), source_contents->GetMainFrame(),
kParams, kSharedMemoryCount, kMuteSource,
std::move(input_client));
testing::Mock::VerifyAndClear(&*main_rfh_loopback_broker);
}
{
EXPECT_CALL(*other_rfh_loopback_broker, CreateStream(NotNull()));
mojo::MakeRequest(&input_client);
factory.CreateLoopbackStream(other_rfh(), source_contents.get(), kParams,
kSharedMemoryCount, kMuteSource,
factory.CreateLoopbackStream(other_rfh(), source_contents->GetMainFrame(),
kParams, kSharedMemoryCount, kMuteSource,
std::move(input_client));
testing::Mock::VerifyAndClear(&*other_rfh_loopback_broker);
}
......
......@@ -81,8 +81,25 @@ void RenderFrameAudioInputStreamFactory::CreateStreamAfterLookingUpDevice(
if (!factory)
return;
if (WebContentsMediaCaptureId::Parse(device.id, nullptr)) {
CHECK(false) << "TODO(https://crbug.com/824019) not implemented.";
WebContentsMediaCaptureId capture_id;
if (WebContentsMediaCaptureId::Parse(device.id, &capture_id)) {
// For MEDIA_DESKTOP_AUDIO_CAPTURE, the source is selected from picker
// window, we do not mute the source audio.
// For MEDIA_TAB_AUDIO_CAPTURE, the probable use case is Cast, we mute
// the source audio.
// TODO(qiangchen): Analyze audio constraints to make a duplicating or
// diverting decision. It would give web developer more flexibility.
RenderFrameHost* source_host = RenderFrameHost::FromID(
capture_id.render_process_id, capture_id.main_render_frame_id);
if (!source_host) {
// The source of the capture has already been destroyed, so fail early.
return;
}
factory->CreateLoopbackStream(
render_frame_host_, source_host, audio_params, shared_memory_count,
capture_id.disable_local_echo, std::move(client));
if (device.type == MEDIA_DESKTOP_AUDIO_CAPTURE)
IncrementDesktopCaptureCounter(SYSTEM_LOOPBACK_AUDIO_CAPTURER_CREATED);
......
......@@ -12,6 +12,7 @@
#include "content/browser/renderer_host/media/audio_input_device_manager.h"
#include "content/common/content_export.h"
#include "content/common/media/renderer_audio_input_stream_factory.mojom.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/common/media_stream_request.h"
#include "mojo/public/cpp/bindings/binding.h"
......
......@@ -15,7 +15,10 @@
#include "content/browser/media/forwarding_audio_stream_factory.h"
#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_media_capture_id.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_renderer_host.h"
......@@ -101,7 +104,19 @@ class RenderFrameAudioInputStreamFactoryTest
last_created_callback = std::move(created_callback);
}
void CreateLoopbackStream(
media::mojom::AudioInputStreamRequest stream_request,
media::mojom::AudioInputStreamClientPtr client,
media::mojom::AudioInputStreamObserverPtr observer,
const media::AudioParameters& params,
uint32_t shared_memory_count,
const base::UnguessableToken& group_id,
CreateLoopbackStreamCallback created_callback) override {
last_created_loopback_callback = std::move(created_callback);
}
CreateInputStreamCallback last_created_callback;
CreateLoopbackStreamCallback last_created_loopback_callback;
mojo::Binding<audio::mojom::StreamFactory> binding_;
};
......@@ -189,6 +204,57 @@ TEST_F(RenderFrameAudioInputStreamFactoryTest,
EXPECT_TRUE(!!audio_service_stream_factory_.last_created_callback);
}
TEST_F(RenderFrameAudioInputStreamFactoryTest,
CreateWebContentsCapture_ForwardsCall) {
std::unique_ptr<WebContents> source_contents = CreateTestWebContents();
mojom::RendererAudioInputStreamFactoryPtr factory_ptr;
RenderFrameAudioInputStreamFactory factory(mojo::MakeRequest(&factory_ptr),
audio_input_device_manager(),
main_rfh());
RenderFrameHost* main_frame = source_contents->GetMainFrame();
WebContentsMediaCaptureId capture_id(main_frame->GetProcess()->GetID(),
main_frame->GetRoutingID());
int session_id = audio_input_device_manager()->Open(MediaStreamDevice(
MEDIA_TAB_AUDIO_CAPTURE, capture_id.ToString(), kDeviceName));
base::RunLoop().RunUntilIdle();
mojom::RendererAudioInputStreamFactoryClientPtr client;
mojo::MakeRequest(&client);
factory_ptr->CreateStream(std::move(client), session_id, kParams, kAGC,
kSharedMemoryCount);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(!!audio_service_stream_factory_.last_created_loopback_callback);
}
TEST_F(RenderFrameAudioInputStreamFactoryTest,
CreateWebContentsCaptureAfterCaptureSourceDestructed_Fails) {
std::unique_ptr<WebContents> source_contents = CreateTestWebContents();
mojom::RendererAudioInputStreamFactoryPtr factory_ptr;
RenderFrameAudioInputStreamFactory factory(mojo::MakeRequest(&factory_ptr),
audio_input_device_manager(),
main_rfh());
RenderFrameHost* main_frame = source_contents->GetMainFrame();
WebContentsMediaCaptureId capture_id(main_frame->GetProcess()->GetID(),
main_frame->GetRoutingID());
int session_id = audio_input_device_manager()->Open(MediaStreamDevice(
MEDIA_TAB_AUDIO_CAPTURE, capture_id.ToString(), kDeviceName));
base::RunLoop().RunUntilIdle();
source_contents.reset();
mojom::RendererAudioInputStreamFactoryClientPtr client;
mojo::MakeRequest(&client);
factory_ptr->CreateStream(std::move(client), session_id, kParams, kAGC,
kSharedMemoryCount);
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(!!audio_service_stream_factory_.last_created_loopback_callback);
}
TEST_F(RenderFrameAudioInputStreamFactoryTest,
CreateStreamWithoutValidSessionId_Fails) {
mojom::RendererAudioInputStreamFactoryPtr factory_ptr;
......
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