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_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 "content/renderer/render_thread_impl.h"
13 #include "ipc/ipc_logging.h"
18 const int kStreamIDNotSet = -1;
21 class AudioMessageFilter::AudioOutputIPCImpl
22 : public NON_EXPORTED_BASE(media::AudioOutputIPC) {
24 AudioOutputIPCImpl(const scoped_refptr<AudioMessageFilter>& filter,
27 virtual ~AudioOutputIPCImpl();
29 // media::AudioOutputIPC implementation.
30 virtual void CreateStream(media::AudioOutputIPCDelegate* delegate,
31 const media::AudioParameters& params,
32 int session_id) OVERRIDE;
33 virtual void PlayStream() OVERRIDE;
34 virtual void PauseStream() OVERRIDE;
35 virtual void CloseStream() OVERRIDE;
36 virtual void SetVolume(double volume) OVERRIDE;
39 const scoped_refptr<AudioMessageFilter> filter_;
40 const int render_view_id_;
41 const int render_frame_id_;
45 AudioMessageFilter* AudioMessageFilter::g_filter = NULL;
47 AudioMessageFilter::AudioMessageFilter(
48 const scoped_refptr<base::MessageLoopProxy>& io_message_loop)
50 audio_hardware_config_(NULL),
51 io_message_loop_(io_message_loop) {
56 AudioMessageFilter::~AudioMessageFilter() {
57 DCHECK_EQ(g_filter, this);
62 AudioMessageFilter* AudioMessageFilter::Get() {
66 AudioMessageFilter::AudioOutputIPCImpl::AudioOutputIPCImpl(
67 const scoped_refptr<AudioMessageFilter>& filter,
71 render_view_id_(render_view_id),
72 render_frame_id_(render_frame_id),
73 stream_id_(kStreamIDNotSet) {}
75 AudioMessageFilter::AudioOutputIPCImpl::~AudioOutputIPCImpl() {}
77 scoped_ptr<media::AudioOutputIPC> AudioMessageFilter::CreateAudioOutputIPC(
78 int render_view_id, int render_frame_id) {
79 DCHECK_GT(render_view_id, 0);
80 return scoped_ptr<media::AudioOutputIPC>(
81 new AudioOutputIPCImpl(this, render_view_id, render_frame_id));
84 void AudioMessageFilter::AudioOutputIPCImpl::CreateStream(
85 media::AudioOutputIPCDelegate* delegate,
86 const media::AudioParameters& params,
88 DCHECK(filter_->io_message_loop_->BelongsToCurrentThread());
90 DCHECK_EQ(stream_id_, kStreamIDNotSet);
91 stream_id_ = filter_->delegates_.Add(delegate);
92 filter_->Send(new AudioHostMsg_CreateStream(
93 stream_id_, render_view_id_, render_frame_id_, session_id, params));
96 void AudioMessageFilter::AudioOutputIPCImpl::PlayStream() {
97 DCHECK_NE(stream_id_, kStreamIDNotSet);
98 filter_->Send(new AudioHostMsg_PlayStream(stream_id_));
101 void AudioMessageFilter::AudioOutputIPCImpl::PauseStream() {
102 DCHECK_NE(stream_id_, kStreamIDNotSet);
103 filter_->Send(new AudioHostMsg_PauseStream(stream_id_));
106 void AudioMessageFilter::AudioOutputIPCImpl::CloseStream() {
107 DCHECK(filter_->io_message_loop_->BelongsToCurrentThread());
108 DCHECK_NE(stream_id_, kStreamIDNotSet);
109 filter_->Send(new AudioHostMsg_CloseStream(stream_id_));
110 filter_->delegates_.Remove(stream_id_);
111 stream_id_ = kStreamIDNotSet;
114 void AudioMessageFilter::AudioOutputIPCImpl::SetVolume(double volume) {
115 DCHECK_NE(stream_id_, kStreamIDNotSet);
116 filter_->Send(new AudioHostMsg_SetVolume(stream_id_, volume));
119 void AudioMessageFilter::Send(IPC::Message* message) {
120 DCHECK(io_message_loop_->BelongsToCurrentThread());
124 channel_->Send(message);
128 bool AudioMessageFilter::OnMessageReceived(const IPC::Message& message) {
129 DCHECK(io_message_loop_->BelongsToCurrentThread());
131 IPC_BEGIN_MESSAGE_MAP(AudioMessageFilter, message)
132 IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamCreated, OnStreamCreated)
133 IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamStateChanged, OnStreamStateChanged)
134 IPC_MESSAGE_HANDLER(AudioMsg_NotifyDeviceChanged, OnOutputDeviceChanged)
135 IPC_MESSAGE_UNHANDLED(handled = false)
136 IPC_END_MESSAGE_MAP()
140 void AudioMessageFilter::OnFilterAdded(IPC::Channel* channel) {
141 DCHECK(io_message_loop_->BelongsToCurrentThread());
145 void AudioMessageFilter::OnFilterRemoved() {
146 DCHECK(io_message_loop_->BelongsToCurrentThread());
148 // Once removed, a filter will not be used again. At this time all
149 // delegates must be notified so they release their reference.
153 void AudioMessageFilter::OnChannelClosing() {
154 DCHECK(io_message_loop_->BelongsToCurrentThread());
157 DLOG_IF(WARNING, !delegates_.IsEmpty())
158 << "Not all audio devices have been closed.";
160 IDMap<media::AudioOutputIPCDelegate>::iterator it(&delegates_);
161 while (!it.IsAtEnd()) {
162 it.GetCurrentValue()->OnIPCClosed();
163 delegates_.Remove(it.GetCurrentKey());
168 void AudioMessageFilter::OnStreamCreated(
170 base::SharedMemoryHandle handle,
172 base::SyncSocket::Handle socket_handle,
174 base::FileDescriptor socket_descriptor,
177 DCHECK(io_message_loop_->BelongsToCurrentThread());
179 WebRtcLogMessage(base::StringPrintf(
180 "AMF::OnStreamCreated. stream_id=%d",
184 base::SyncSocket::Handle socket_handle = socket_descriptor.fd;
187 media::AudioOutputIPCDelegate* delegate = delegates_.Lookup(stream_id);
189 DLOG(WARNING) << "Got OnStreamCreated() event for a non-existent or removed"
190 << " audio renderer. (stream_id=" << stream_id << ").";
191 base::SharedMemory::CloseHandle(handle);
192 base::SyncSocket socket(socket_handle);
195 delegate->OnStreamCreated(handle, socket_handle, length);
198 void AudioMessageFilter::OnStreamStateChanged(
199 int stream_id, media::AudioOutputIPCDelegate::State state) {
200 DCHECK(io_message_loop_->BelongsToCurrentThread());
201 media::AudioOutputIPCDelegate* delegate = delegates_.Lookup(stream_id);
203 DLOG(WARNING) << "Got OnStreamStateChanged() event for a non-existent or"
204 << " removed audio renderer. State: " << state;
207 delegate->OnStateChanged(state);
210 void AudioMessageFilter::OnOutputDeviceChanged(int stream_id,
212 int new_sample_rate) {
213 DCHECK(io_message_loop_->BelongsToCurrentThread());
214 base::AutoLock auto_lock(lock_);
216 WebRtcLogMessage(base::StringPrintf(
217 "AMF::OnOutputDeviceChanged. stream_id=%d"
218 ", new_buffer_size=%d, new_sample_rate=%d",
223 // Ignore the message if an audio hardware config hasn't been created; this
224 // can occur if the renderer is using the high latency audio path.
225 // TODO(dalecurtis): After http://crbug.com/173435 is fixed, convert to CHECK.
226 if (!audio_hardware_config_)
229 // TODO(crogers): fix OnOutputDeviceChanged() to pass AudioParameters.
230 media::ChannelLayout channel_layout =
231 audio_hardware_config_->GetOutputChannelLayout();
232 int channels = audio_hardware_config_->GetOutputChannels();
234 media::AudioParameters output_params;
236 media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
244 audio_hardware_config_->UpdateOutputConfig(output_params);
247 void AudioMessageFilter::SetAudioHardwareConfig(
248 media::AudioHardwareConfig* config) {
249 base::AutoLock auto_lock(lock_);
250 audio_hardware_config_ = config;
253 } // namespace content