1 // Copyright (c) 2012 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.
4
5 #include "content/renderer/media/audio_input_message_filter.h"
6
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop_proxy.h"
9 #include "base/strings/stringprintf.h"
10 #include "content/common/media/audio_messages.h"
11 #include "content/renderer/media/webrtc_logging.h"
12 #include "ipc/ipc_logging.h"
13
14 namespace content {
15
16 namespace {
17 const int kStreamIDNotSet = -1;
18 }
19
20 class AudioInputMessageFilter::AudioInputIPCImpl
21 : public NON_EXPORTED_BASE(media::AudioInputIPC) {
22 public:
23 AudioInputIPCImpl(const scoped_refptr<AudioInputMessageFilter>& filter,
24 int render_view_id);
25 virtual ~AudioInputIPCImpl();
26
27 // media::AudioInputIPC implementation.
28 virtual void CreateStream(media::AudioInputIPCDelegate* delegate,
29 int session_id,
30 const media::AudioParameters& params,
31 bool automatic_gain_control,
32 uint32 total_segments) OVERRIDE;
33 virtual void RecordStream() OVERRIDE;
34 virtual void SetVolume(double volume) OVERRIDE;
35 virtual void CloseStream() OVERRIDE;
36
37 private:
38 const scoped_refptr<AudioInputMessageFilter> filter_;
39 const int render_view_id_;
40 int stream_id_;
41 };
42
43 AudioInputMessageFilter* AudioInputMessageFilter::g_filter = NULL;
44
AudioInputMessageFilter(const scoped_refptr<base::MessageLoopProxy> & io_message_loop)45 AudioInputMessageFilter::AudioInputMessageFilter(
46 const scoped_refptr<base::MessageLoopProxy>& io_message_loop)
47 : channel_(NULL),
48 io_message_loop_(io_message_loop) {
49 DCHECK(!g_filter);
50 g_filter = this;
51 }
52
~AudioInputMessageFilter()53 AudioInputMessageFilter::~AudioInputMessageFilter() {
54 DCHECK_EQ(g_filter, this);
55 g_filter = NULL;
56 }
57
58 // static
Get()59 AudioInputMessageFilter* AudioInputMessageFilter::Get() {
60 return g_filter;
61 }
62
Send(IPC::Message * message)63 void AudioInputMessageFilter::Send(IPC::Message* message) {
64 DCHECK(io_message_loop_->BelongsToCurrentThread());
65 if (!channel_) {
66 delete message;
67 } else {
68 channel_->Send(message);
69 }
70 }
71
OnMessageReceived(const IPC::Message & message)72 bool AudioInputMessageFilter::OnMessageReceived(const IPC::Message& message) {
73 DCHECK(io_message_loop_->BelongsToCurrentThread());
74 bool handled = true;
75 IPC_BEGIN_MESSAGE_MAP(AudioInputMessageFilter, message)
76 IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamCreated,
77 OnStreamCreated)
78 IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamVolume, OnStreamVolume)
79 IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamStateChanged,
80 OnStreamStateChanged)
81 IPC_MESSAGE_UNHANDLED(handled = false)
82 IPC_END_MESSAGE_MAP()
83 return handled;
84 }
85
OnFilterAdded(IPC::Channel * channel)86 void AudioInputMessageFilter::OnFilterAdded(IPC::Channel* channel) {
87 DCHECK(io_message_loop_->BelongsToCurrentThread());
88
89 // Captures the channel for IPC.
90 channel_ = channel;
91 }
92
OnFilterRemoved()93 void AudioInputMessageFilter::OnFilterRemoved() {
94 DCHECK(io_message_loop_->BelongsToCurrentThread());
95
96 // Once removed, a filter will not be used again. At this time all
97 // delegates must be notified so they release their reference.
98 OnChannelClosing();
99 }
100
OnChannelClosing()101 void AudioInputMessageFilter::OnChannelClosing() {
102 DCHECK(io_message_loop_->BelongsToCurrentThread());
103 channel_ = NULL;
104
105 DLOG_IF(WARNING, !delegates_.IsEmpty())
106 << "Not all audio devices have been closed.";
107
108 IDMap<media::AudioInputIPCDelegate>::iterator it(&delegates_);
109 while (!it.IsAtEnd()) {
110 it.GetCurrentValue()->OnIPCClosed();
111 delegates_.Remove(it.GetCurrentKey());
112 it.Advance();
113 }
114 }
115
OnStreamCreated(int stream_id,base::SharedMemoryHandle handle,base::SyncSocket::Handle socket_handle,uint32 length,uint32 total_segments)116 void AudioInputMessageFilter::OnStreamCreated(
117 int stream_id,
118 base::SharedMemoryHandle handle,
119 #if defined(OS_WIN)
120 base::SyncSocket::Handle socket_handle,
121 #else
122 base::FileDescriptor socket_descriptor,
123 #endif
124 uint32 length,
125 uint32 total_segments) {
126 DCHECK(io_message_loop_->BelongsToCurrentThread());
127
128 WebRtcLogMessage(base::StringPrintf(
129 "AIMF::OnStreamCreated. stream_id=%d",
130 stream_id));
131
132 #if !defined(OS_WIN)
133 base::SyncSocket::Handle socket_handle = socket_descriptor.fd;
134 #endif
135 media::AudioInputIPCDelegate* delegate = delegates_.Lookup(stream_id);
136 if (!delegate) {
137 DLOG(WARNING) << "Got audio stream event for a non-existent or removed"
138 << " audio capturer (stream_id=" << stream_id << ").";
139 base::SharedMemory::CloseHandle(handle);
140 base::SyncSocket socket(socket_handle);
141 return;
142 }
143 // Forward message to the stream delegate.
144 delegate->OnStreamCreated(handle, socket_handle, length, total_segments);
145 }
146
OnStreamVolume(int stream_id,double volume)147 void AudioInputMessageFilter::OnStreamVolume(int stream_id, double volume) {
148 DCHECK(io_message_loop_->BelongsToCurrentThread());
149 media::AudioInputIPCDelegate* delegate = delegates_.Lookup(stream_id);
150 if (!delegate) {
151 DLOG(WARNING) << "Got audio stream event for a non-existent or removed"
152 << " audio capturer.";
153 return;
154 }
155 delegate->OnVolume(volume);
156 }
157
OnStreamStateChanged(int stream_id,media::AudioInputIPCDelegate::State state)158 void AudioInputMessageFilter::OnStreamStateChanged(
159 int stream_id, media::AudioInputIPCDelegate::State state) {
160 DCHECK(io_message_loop_->BelongsToCurrentThread());
161 media::AudioInputIPCDelegate* delegate = delegates_.Lookup(stream_id);
162 if (!delegate) {
163 DLOG(WARNING) << "Got audio stream event for a non-existent or removed"
164 << " audio renderer.";
165 return;
166 }
167 delegate->OnStateChanged(state);
168 }
169
AudioInputIPCImpl(const scoped_refptr<AudioInputMessageFilter> & filter,int render_view_id)170 AudioInputMessageFilter::AudioInputIPCImpl::AudioInputIPCImpl(
171 const scoped_refptr<AudioInputMessageFilter>& filter, int render_view_id)
172 : filter_(filter),
173 render_view_id_(render_view_id),
174 stream_id_(kStreamIDNotSet) {}
175
~AudioInputIPCImpl()176 AudioInputMessageFilter::AudioInputIPCImpl::~AudioInputIPCImpl() {}
177
CreateAudioInputIPC(int render_view_id)178 scoped_ptr<media::AudioInputIPC> AudioInputMessageFilter::CreateAudioInputIPC(
179 int render_view_id) {
180 DCHECK_GT(render_view_id, 0);
181 return scoped_ptr<media::AudioInputIPC>(
182 new AudioInputIPCImpl(this, render_view_id));
183 }
184
CreateStream(media::AudioInputIPCDelegate * delegate,int session_id,const media::AudioParameters & params,bool automatic_gain_control,uint32 total_segments)185 void AudioInputMessageFilter::AudioInputIPCImpl::CreateStream(
186 media::AudioInputIPCDelegate* delegate,
187 int session_id,
188 const media::AudioParameters& params,
189 bool automatic_gain_control,
190 uint32 total_segments) {
191 DCHECK(filter_->io_message_loop_->BelongsToCurrentThread());
192 DCHECK(delegate);
193
194 stream_id_ = filter_->delegates_.Add(delegate);
195
196 AudioInputHostMsg_CreateStream_Config config;
197 config.params = params;
198 config.automatic_gain_control = automatic_gain_control;
199 config.shared_memory_count = total_segments;
200 filter_->Send(new AudioInputHostMsg_CreateStream(
201 stream_id_, render_view_id_, session_id, config));
202 }
203
RecordStream()204 void AudioInputMessageFilter::AudioInputIPCImpl::RecordStream() {
205 DCHECK_NE(stream_id_, kStreamIDNotSet);
206 filter_->Send(new AudioInputHostMsg_RecordStream(stream_id_));
207 }
208
SetVolume(double volume)209 void AudioInputMessageFilter::AudioInputIPCImpl::SetVolume(double volume) {
210 DCHECK_NE(stream_id_, kStreamIDNotSet);
211 filter_->Send(new AudioInputHostMsg_SetVolume(stream_id_, volume));
212 }
213
CloseStream()214 void AudioInputMessageFilter::AudioInputIPCImpl::CloseStream() {
215 DCHECK(filter_->io_message_loop_->BelongsToCurrentThread());
216 DCHECK_NE(stream_id_, kStreamIDNotSet);
217 filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_));
218 filter_->delegates_.Remove(stream_id_);
219 stream_id_ = kStreamIDNotSet;
220 }
221
222 } // namespace content
223