Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / browser / media / capture / web_contents_audio_muter.cc
blob6d25d550d1878cbc4bee48b442cc6a345013e538
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/media/capture/web_contents_audio_muter.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "content/browser/media/capture/audio_mirroring_manager.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "content/public/browser/render_frame_host.h"
12 #include "content/public/browser/web_contents.h"
13 #include "media/audio/audio_io.h"
14 #include "media/audio/audio_manager.h"
15 #include "media/audio/fake_audio_worker.h"
16 #include "media/base/bind_to_current_loop.h"
18 namespace content {
20 namespace {
22 // An AudioOutputStream that pumps audio data, but does nothing with it.
23 // Pumping the audio data is necessary because video playback is synchronized to
24 // the audio stream and will freeze otherwise.
26 // TODO(miu): media::FakeAudioOutputStream does pretty much the same thing as
27 // this class, but requires construction/destruction via media::AudioManagerBase
28 // on the audio thread. Once that's fixed, this class will no longer be needed.
29 // http://crbug.com/416278
30 class AudioDiscarder : public media::AudioOutputStream {
31 public:
32 explicit AudioDiscarder(const media::AudioParameters& params)
33 : worker_(media::AudioManager::Get()->GetWorkerTaskRunner(), params),
34 audio_bus_(media::AudioBus::Create(params)) {}
36 // AudioOutputStream implementation.
37 bool Open() override { return true; }
38 void Start(AudioSourceCallback* callback) override {
39 worker_.Start(base::Bind(&AudioDiscarder::FetchAudioData,
40 base::Unretained(this),
41 callback));
43 void Stop() override { worker_.Stop(); }
44 void SetVolume(double volume) override {}
45 void GetVolume(double* volume) override { *volume = 0; }
46 void Close() override { delete this; }
48 private:
49 ~AudioDiscarder() override {}
51 void FetchAudioData(AudioSourceCallback* callback) {
52 callback->OnMoreData(audio_bus_.get(), 0);
55 // Calls FetchAudioData() at regular intervals and discards the data.
56 media::FakeAudioWorker worker_;
57 scoped_ptr<media::AudioBus> audio_bus_;
59 DISALLOW_COPY_AND_ASSIGN(AudioDiscarder);
62 } // namespace
64 // A simple AudioMirroringManager::MirroringDestination implementation that
65 // identifies the audio streams rendered by a WebContents and provides
66 // AudioDiscarders to AudioMirroringManager.
67 class WebContentsAudioMuter::MuteDestination
68 : public base::RefCountedThreadSafe<MuteDestination>,
69 public AudioMirroringManager::MirroringDestination {
70 public:
71 explicit MuteDestination(WebContents* web_contents)
72 : web_contents_(web_contents) {}
74 private:
75 friend class base::RefCountedThreadSafe<MuteDestination>;
77 typedef AudioMirroringManager::SourceFrameRef SourceFrameRef;
79 ~MuteDestination() override {}
81 void QueryForMatches(const std::set<SourceFrameRef>& candidates,
82 const MatchesCallback& results_callback) override {
83 BrowserThread::PostTask(
84 BrowserThread::UI,
85 FROM_HERE,
86 base::Bind(&MuteDestination::QueryForMatchesOnUIThread,
87 this,
88 candidates,
89 media::BindToCurrentLoop(results_callback)));
92 void QueryForMatchesOnUIThread(const std::set<SourceFrameRef>& candidates,
93 const MatchesCallback& results_callback) {
94 DCHECK_CURRENTLY_ON(BrowserThread::UI);
95 std::set<SourceFrameRef> matches;
96 // Add each ID to |matches| if it maps to a RenderFrameHost that maps to the
97 // WebContents being muted.
98 for (std::set<SourceFrameRef>::const_iterator i = candidates.begin();
99 i != candidates.end(); ++i) {
100 WebContents* const contents_containing_frame =
101 WebContents::FromRenderFrameHost(
102 RenderFrameHost::FromID(i->first, i->second));
103 if (contents_containing_frame == web_contents_)
104 matches.insert(*i);
106 results_callback.Run(matches);
109 media::AudioOutputStream* AddInput(
110 const media::AudioParameters& params) override {
111 return new AudioDiscarder(params);
114 WebContents* const web_contents_;
116 DISALLOW_COPY_AND_ASSIGN(MuteDestination);
119 WebContentsAudioMuter::WebContentsAudioMuter(WebContents* web_contents)
120 : destination_(new MuteDestination(web_contents)), is_muting_(false) {
121 DCHECK_CURRENTLY_ON(BrowserThread::UI);
124 WebContentsAudioMuter::~WebContentsAudioMuter() {
125 DCHECK_CURRENTLY_ON(BrowserThread::UI);
126 StopMuting();
129 void WebContentsAudioMuter::StartMuting() {
130 DCHECK_CURRENTLY_ON(BrowserThread::UI);
131 if (is_muting_)
132 return;
133 is_muting_ = true;
134 BrowserThread::PostTask(
135 BrowserThread::IO,
136 FROM_HERE,
137 base::Bind(&AudioMirroringManager::StartMirroring,
138 base::Unretained(AudioMirroringManager::GetInstance()),
139 destination_));
142 void WebContentsAudioMuter::StopMuting() {
143 DCHECK_CURRENTLY_ON(BrowserThread::UI);
144 if (!is_muting_)
145 return;
146 is_muting_ = false;
147 BrowserThread::PostTask(
148 BrowserThread::IO,
149 FROM_HERE,
150 base::Bind(&AudioMirroringManager::StopMirroring,
151 base::Unretained(AudioMirroringManager::GetInstance()),
152 destination_));
155 } // namespace content