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.
5 #include "content/renderer/media/audio_input_message_filter.h"
8 #include "base/message_loop/message_loop_proxy.h"
9 #include "content/common/media/audio_messages.h"
10 #include "ipc/ipc_logging.h"
15 const int kStreamIDNotSet = -1;
18 class AudioInputMessageFilter::AudioInputIPCImpl
19 : public NON_EXPORTED_BASE(media::AudioInputIPC) {
21 AudioInputIPCImpl(const scoped_refptr<AudioInputMessageFilter>& filter,
23 virtual ~AudioInputIPCImpl();
25 // media::AudioInputIPC implementation.
26 virtual void CreateStream(media::AudioInputIPCDelegate* delegate,
28 const media::AudioParameters& params,
29 bool automatic_gain_control,
30 uint32 total_segments) OVERRIDE;
31 virtual void RecordStream() OVERRIDE;
32 virtual void SetVolume(double volume) OVERRIDE;
33 virtual void CloseStream() OVERRIDE;
36 const scoped_refptr<AudioInputMessageFilter> filter_;
37 const int render_view_id_;
41 AudioInputMessageFilter* AudioInputMessageFilter::g_filter = NULL;
43 AudioInputMessageFilter::AudioInputMessageFilter(
44 const scoped_refptr<base::MessageLoopProxy>& io_message_loop)
46 io_message_loop_(io_message_loop) {
51 AudioInputMessageFilter::~AudioInputMessageFilter() {
52 DCHECK_EQ(g_filter, this);
57 AudioInputMessageFilter* AudioInputMessageFilter::Get() {
61 void AudioInputMessageFilter::Send(IPC::Message* message) {
62 DCHECK(io_message_loop_->BelongsToCurrentThread());
66 channel_->Send(message);
70 bool AudioInputMessageFilter::OnMessageReceived(const IPC::Message& message) {
71 DCHECK(io_message_loop_->BelongsToCurrentThread());
73 IPC_BEGIN_MESSAGE_MAP(AudioInputMessageFilter, message)
74 IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamCreated,
76 IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamVolume, OnStreamVolume)
77 IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamStateChanged,
79 IPC_MESSAGE_UNHANDLED(handled = false)
84 void AudioInputMessageFilter::OnFilterAdded(IPC::Channel* channel) {
85 DCHECK(io_message_loop_->BelongsToCurrentThread());
87 // Captures the channel for IPC.
91 void AudioInputMessageFilter::OnFilterRemoved() {
92 DCHECK(io_message_loop_->BelongsToCurrentThread());
94 // Once removed, a filter will not be used again. At this time all
95 // delegates must be notified so they release their reference.
99 void AudioInputMessageFilter::OnChannelClosing() {
100 DCHECK(io_message_loop_->BelongsToCurrentThread());
103 DLOG_IF(WARNING, !delegates_.IsEmpty())
104 << "Not all audio devices have been closed.";
106 IDMap<media::AudioInputIPCDelegate>::iterator it(&delegates_);
107 while (!it.IsAtEnd()) {
108 it.GetCurrentValue()->OnIPCClosed();
109 delegates_.Remove(it.GetCurrentKey());
114 void AudioInputMessageFilter::OnStreamCreated(
116 base::SharedMemoryHandle handle,
118 base::SyncSocket::Handle socket_handle,
120 base::FileDescriptor socket_descriptor,
123 uint32 total_segments) {
124 DCHECK(io_message_loop_->BelongsToCurrentThread());
127 base::SyncSocket::Handle socket_handle = socket_descriptor.fd;
129 media::AudioInputIPCDelegate* delegate = delegates_.Lookup(stream_id);
131 DLOG(WARNING) << "Got audio stream event for a non-existent or removed"
132 << " audio capturer (stream_id=" << stream_id << ").";
133 base::SharedMemory::CloseHandle(handle);
134 base::SyncSocket socket(socket_handle);
137 // Forward message to the stream delegate.
138 delegate->OnStreamCreated(handle, socket_handle, length, total_segments);
141 void AudioInputMessageFilter::OnStreamVolume(int stream_id, double volume) {
142 DCHECK(io_message_loop_->BelongsToCurrentThread());
143 media::AudioInputIPCDelegate* delegate = delegates_.Lookup(stream_id);
145 DLOG(WARNING) << "Got audio stream event for a non-existent or removed"
146 << " audio capturer.";
149 delegate->OnVolume(volume);
152 void AudioInputMessageFilter::OnStreamStateChanged(
153 int stream_id, media::AudioInputIPCDelegate::State state) {
154 DCHECK(io_message_loop_->BelongsToCurrentThread());
155 media::AudioInputIPCDelegate* delegate = delegates_.Lookup(stream_id);
157 DLOG(WARNING) << "Got audio stream event for a non-existent or removed"
158 << " audio renderer.";
161 delegate->OnStateChanged(state);
164 AudioInputMessageFilter::AudioInputIPCImpl::AudioInputIPCImpl(
165 const scoped_refptr<AudioInputMessageFilter>& filter, int render_view_id)
167 render_view_id_(render_view_id),
168 stream_id_(kStreamIDNotSet) {}
170 AudioInputMessageFilter::AudioInputIPCImpl::~AudioInputIPCImpl() {}
172 scoped_ptr<media::AudioInputIPC> AudioInputMessageFilter::CreateAudioInputIPC(
173 int render_view_id) {
174 DCHECK_GT(render_view_id, 0);
175 return scoped_ptr<media::AudioInputIPC>(
176 new AudioInputIPCImpl(this, render_view_id));
179 void AudioInputMessageFilter::AudioInputIPCImpl::CreateStream(
180 media::AudioInputIPCDelegate* delegate,
182 const media::AudioParameters& params,
183 bool automatic_gain_control,
184 uint32 total_segments) {
185 DCHECK(filter_->io_message_loop_->BelongsToCurrentThread());
188 stream_id_ = filter_->delegates_.Add(delegate);
190 AudioInputHostMsg_CreateStream_Config config;
191 config.params = params;
192 config.automatic_gain_control = automatic_gain_control;
193 config.shared_memory_count = total_segments;
194 filter_->Send(new AudioInputHostMsg_CreateStream(
195 stream_id_, render_view_id_, session_id, config));
198 void AudioInputMessageFilter::AudioInputIPCImpl::RecordStream() {
199 DCHECK_NE(stream_id_, kStreamIDNotSet);
200 filter_->Send(new AudioInputHostMsg_RecordStream(stream_id_));
203 void AudioInputMessageFilter::AudioInputIPCImpl::SetVolume(double volume) {
204 DCHECK_NE(stream_id_, kStreamIDNotSet);
205 filter_->Send(new AudioInputHostMsg_SetVolume(stream_id_, volume));
208 void AudioInputMessageFilter::AudioInputIPCImpl::CloseStream() {
209 DCHECK(filter_->io_message_loop_->BelongsToCurrentThread());
210 DCHECK_NE(stream_id_, kStreamIDNotSet);
211 filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_));
212 filter_->delegates_.Remove(stream_id_);
213 stream_id_ = kStreamIDNotSet;
216 } // namespace content