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 "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 #include "ipc/ipc_sender.h"
18 const int kStreamIDNotSet = -1;
21 class AudioInputMessageFilter::AudioInputIPCImpl
22 : public NON_EXPORTED_BASE(media::AudioInputIPC) {
24 AudioInputIPCImpl(const scoped_refptr<AudioInputMessageFilter>& filter,
26 virtual ~AudioInputIPCImpl();
28 // media::AudioInputIPC implementation.
29 virtual void CreateStream(media::AudioInputIPCDelegate* delegate,
31 const media::AudioParameters& params,
32 bool automatic_gain_control,
33 uint32 total_segments) OVERRIDE;
34 virtual void RecordStream() OVERRIDE;
35 virtual void SetVolume(double volume) OVERRIDE;
36 virtual void CloseStream() OVERRIDE;
39 const scoped_refptr<AudioInputMessageFilter> filter_;
40 const int render_view_id_;
44 AudioInputMessageFilter* AudioInputMessageFilter::g_filter = NULL;
46 AudioInputMessageFilter::AudioInputMessageFilter(
47 const scoped_refptr<base::MessageLoopProxy>& io_message_loop)
49 io_message_loop_(io_message_loop) {
54 AudioInputMessageFilter::~AudioInputMessageFilter() {
55 DCHECK_EQ(g_filter, this);
60 AudioInputMessageFilter* AudioInputMessageFilter::Get() {
64 void AudioInputMessageFilter::Send(IPC::Message* message) {
65 DCHECK(io_message_loop_->BelongsToCurrentThread());
69 sender_->Send(message);
73 bool AudioInputMessageFilter::OnMessageReceived(const IPC::Message& message) {
74 DCHECK(io_message_loop_->BelongsToCurrentThread());
76 IPC_BEGIN_MESSAGE_MAP(AudioInputMessageFilter, message)
77 IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamCreated,
79 IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamVolume, OnStreamVolume)
80 IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamStateChanged,
82 IPC_MESSAGE_UNHANDLED(handled = false)
87 void AudioInputMessageFilter::OnFilterAdded(IPC::Sender* sender) {
88 DCHECK(io_message_loop_->BelongsToCurrentThread());
90 // Captures the sender for IPC.
94 void AudioInputMessageFilter::OnFilterRemoved() {
95 DCHECK(io_message_loop_->BelongsToCurrentThread());
97 // Once removed, a filter will not be used again. At this time all
98 // delegates must be notified so they release their reference.
102 void AudioInputMessageFilter::OnChannelClosing() {
103 DCHECK(io_message_loop_->BelongsToCurrentThread());
106 DLOG_IF(WARNING, !delegates_.IsEmpty())
107 << "Not all audio devices have been closed.";
109 IDMap<media::AudioInputIPCDelegate>::iterator it(&delegates_);
110 while (!it.IsAtEnd()) {
111 it.GetCurrentValue()->OnIPCClosed();
112 delegates_.Remove(it.GetCurrentKey());
117 void AudioInputMessageFilter::OnStreamCreated(
119 base::SharedMemoryHandle handle,
121 base::SyncSocket::Handle socket_handle,
123 base::FileDescriptor socket_descriptor,
126 uint32 total_segments) {
127 DCHECK(io_message_loop_->BelongsToCurrentThread());
129 WebRtcLogMessage(base::StringPrintf(
130 "AIMF::OnStreamCreated. stream_id=%d",
134 base::SyncSocket::Handle socket_handle = socket_descriptor.fd;
136 media::AudioInputIPCDelegate* delegate = delegates_.Lookup(stream_id);
138 DLOG(WARNING) << "Got audio stream event for a non-existent or removed"
139 << " audio capturer (stream_id=" << stream_id << ").";
140 base::SharedMemory::CloseHandle(handle);
141 base::SyncSocket socket(socket_handle);
144 // Forward message to the stream delegate.
145 delegate->OnStreamCreated(handle, socket_handle, length, total_segments);
148 void AudioInputMessageFilter::OnStreamVolume(int stream_id, double volume) {
149 DCHECK(io_message_loop_->BelongsToCurrentThread());
150 media::AudioInputIPCDelegate* delegate = delegates_.Lookup(stream_id);
152 DLOG(WARNING) << "Got audio stream event for a non-existent or removed"
153 << " audio capturer.";
156 delegate->OnVolume(volume);
159 void AudioInputMessageFilter::OnStreamStateChanged(
160 int stream_id, media::AudioInputIPCDelegate::State state) {
161 DCHECK(io_message_loop_->BelongsToCurrentThread());
162 media::AudioInputIPCDelegate* delegate = delegates_.Lookup(stream_id);
164 DLOG(WARNING) << "Got audio stream event for a non-existent or removed"
165 << " audio renderer.";
168 delegate->OnStateChanged(state);
171 AudioInputMessageFilter::AudioInputIPCImpl::AudioInputIPCImpl(
172 const scoped_refptr<AudioInputMessageFilter>& filter, int render_view_id)
174 render_view_id_(render_view_id),
175 stream_id_(kStreamIDNotSet) {}
177 AudioInputMessageFilter::AudioInputIPCImpl::~AudioInputIPCImpl() {}
179 scoped_ptr<media::AudioInputIPC> AudioInputMessageFilter::CreateAudioInputIPC(
180 int render_view_id) {
181 DCHECK_GT(render_view_id, 0);
182 return scoped_ptr<media::AudioInputIPC>(
183 new AudioInputIPCImpl(this, render_view_id));
186 void AudioInputMessageFilter::AudioInputIPCImpl::CreateStream(
187 media::AudioInputIPCDelegate* delegate,
189 const media::AudioParameters& params,
190 bool automatic_gain_control,
191 uint32 total_segments) {
192 DCHECK(filter_->io_message_loop_->BelongsToCurrentThread());
195 stream_id_ = filter_->delegates_.Add(delegate);
197 AudioInputHostMsg_CreateStream_Config config;
198 config.params = params;
199 config.automatic_gain_control = automatic_gain_control;
200 config.shared_memory_count = total_segments;
201 filter_->Send(new AudioInputHostMsg_CreateStream(
202 stream_id_, render_view_id_, session_id, config));
205 void AudioInputMessageFilter::AudioInputIPCImpl::RecordStream() {
206 DCHECK_NE(stream_id_, kStreamIDNotSet);
207 filter_->Send(new AudioInputHostMsg_RecordStream(stream_id_));
210 void AudioInputMessageFilter::AudioInputIPCImpl::SetVolume(double volume) {
211 DCHECK_NE(stream_id_, kStreamIDNotSet);
212 filter_->Send(new AudioInputHostMsg_SetVolume(stream_id_, volume));
215 void AudioInputMessageFilter::AudioInputIPCImpl::CloseStream() {
216 DCHECK(filter_->io_message_loop_->BelongsToCurrentThread());
217 DCHECK_NE(stream_id_, kStreamIDNotSet);
218 filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_));
219 filter_->delegates_.Remove(stream_id_);
220 stream_id_ = kStreamIDNotSet;
223 } // namespace content