• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_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 "content/renderer/render_thread_impl.h"
13 #include "ipc/ipc_logging.h"
14 
15 namespace content {
16 
17 namespace {
18 const int kStreamIDNotSet = -1;
19 }
20 
21 class AudioMessageFilter::AudioOutputIPCImpl
22     : public NON_EXPORTED_BASE(media::AudioOutputIPC) {
23  public:
24   AudioOutputIPCImpl(const scoped_refptr<AudioMessageFilter>& filter,
25                      int render_view_id);
26   virtual ~AudioOutputIPCImpl();
27 
28   // media::AudioOutputIPC implementation.
29   virtual void CreateStream(media::AudioOutputIPCDelegate* delegate,
30                             const media::AudioParameters& params,
31                             int session_id) OVERRIDE;
32   virtual void PlayStream() OVERRIDE;
33   virtual void PauseStream() OVERRIDE;
34   virtual void CloseStream() OVERRIDE;
35   virtual void SetVolume(double volume) OVERRIDE;
36 
37  private:
38   const scoped_refptr<AudioMessageFilter> filter_;
39   const int render_view_id_;
40   int stream_id_;
41 };
42 
43 AudioMessageFilter* AudioMessageFilter::g_filter = NULL;
44 
AudioMessageFilter(const scoped_refptr<base::MessageLoopProxy> & io_message_loop)45 AudioMessageFilter::AudioMessageFilter(
46     const scoped_refptr<base::MessageLoopProxy>& io_message_loop)
47     : channel_(NULL),
48       audio_hardware_config_(NULL),
49       io_message_loop_(io_message_loop) {
50   DCHECK(!g_filter);
51   g_filter = this;
52 }
53 
~AudioMessageFilter()54 AudioMessageFilter::~AudioMessageFilter() {
55   DCHECK_EQ(g_filter, this);
56   g_filter = NULL;
57 }
58 
59 // static
Get()60 AudioMessageFilter* AudioMessageFilter::Get() {
61   return g_filter;
62 }
63 
AudioOutputIPCImpl(const scoped_refptr<AudioMessageFilter> & filter,int render_view_id)64 AudioMessageFilter::AudioOutputIPCImpl::AudioOutputIPCImpl(
65     const scoped_refptr<AudioMessageFilter>& filter, int render_view_id)
66     : filter_(filter),
67       render_view_id_(render_view_id),
68       stream_id_(kStreamIDNotSet) {}
69 
~AudioOutputIPCImpl()70 AudioMessageFilter::AudioOutputIPCImpl::~AudioOutputIPCImpl() {}
71 
CreateAudioOutputIPC(int render_view_id)72 scoped_ptr<media::AudioOutputIPC> AudioMessageFilter::CreateAudioOutputIPC(
73     int render_view_id) {
74   DCHECK_GT(render_view_id, 0);
75   return scoped_ptr<media::AudioOutputIPC>(
76       new AudioOutputIPCImpl(this, render_view_id));
77 }
78 
CreateStream(media::AudioOutputIPCDelegate * delegate,const media::AudioParameters & params,int session_id)79 void AudioMessageFilter::AudioOutputIPCImpl::CreateStream(
80     media::AudioOutputIPCDelegate* delegate,
81     const media::AudioParameters& params,
82     int session_id) {
83   DCHECK(filter_->io_message_loop_->BelongsToCurrentThread());
84   DCHECK(delegate);
85   DCHECK_EQ(stream_id_, kStreamIDNotSet);
86   stream_id_ = filter_->delegates_.Add(delegate);
87   filter_->Send(new AudioHostMsg_CreateStream(
88       stream_id_, render_view_id_, session_id, params));
89 }
90 
PlayStream()91 void AudioMessageFilter::AudioOutputIPCImpl::PlayStream() {
92   DCHECK_NE(stream_id_, kStreamIDNotSet);
93   filter_->Send(new AudioHostMsg_PlayStream(stream_id_));
94 }
95 
PauseStream()96 void AudioMessageFilter::AudioOutputIPCImpl::PauseStream() {
97   DCHECK_NE(stream_id_, kStreamIDNotSet);
98   filter_->Send(new AudioHostMsg_PauseStream(stream_id_));
99 }
100 
CloseStream()101 void AudioMessageFilter::AudioOutputIPCImpl::CloseStream() {
102   DCHECK(filter_->io_message_loop_->BelongsToCurrentThread());
103   DCHECK_NE(stream_id_, kStreamIDNotSet);
104   filter_->Send(new AudioHostMsg_CloseStream(stream_id_));
105   filter_->delegates_.Remove(stream_id_);
106   stream_id_ = kStreamIDNotSet;
107 }
108 
SetVolume(double volume)109 void AudioMessageFilter::AudioOutputIPCImpl::SetVolume(double volume) {
110   DCHECK_NE(stream_id_, kStreamIDNotSet);
111   filter_->Send(new AudioHostMsg_SetVolume(stream_id_, volume));
112 }
113 
Send(IPC::Message * message)114 void AudioMessageFilter::Send(IPC::Message* message) {
115   DCHECK(io_message_loop_->BelongsToCurrentThread());
116   if (!channel_) {
117     delete message;
118   } else {
119     channel_->Send(message);
120   }
121 }
122 
OnMessageReceived(const IPC::Message & message)123 bool AudioMessageFilter::OnMessageReceived(const IPC::Message& message) {
124   DCHECK(io_message_loop_->BelongsToCurrentThread());
125   bool handled = true;
126   IPC_BEGIN_MESSAGE_MAP(AudioMessageFilter, message)
127     IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamCreated, OnStreamCreated)
128     IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamStateChanged, OnStreamStateChanged)
129     IPC_MESSAGE_HANDLER(AudioMsg_NotifyDeviceChanged, OnOutputDeviceChanged)
130     IPC_MESSAGE_UNHANDLED(handled = false)
131   IPC_END_MESSAGE_MAP()
132   return handled;
133 }
134 
OnFilterAdded(IPC::Channel * channel)135 void AudioMessageFilter::OnFilterAdded(IPC::Channel* channel) {
136   DCHECK(io_message_loop_->BelongsToCurrentThread());
137   channel_ = channel;
138 }
139 
OnFilterRemoved()140 void AudioMessageFilter::OnFilterRemoved() {
141   DCHECK(io_message_loop_->BelongsToCurrentThread());
142 
143   // Once removed, a filter will not be used again.  At this time all
144   // delegates must be notified so they release their reference.
145   OnChannelClosing();
146 }
147 
OnChannelClosing()148 void AudioMessageFilter::OnChannelClosing() {
149   DCHECK(io_message_loop_->BelongsToCurrentThread());
150   channel_ = NULL;
151 
152   DLOG_IF(WARNING, !delegates_.IsEmpty())
153       << "Not all audio devices have been closed.";
154 
155   IDMap<media::AudioOutputIPCDelegate>::iterator it(&delegates_);
156   while (!it.IsAtEnd()) {
157     it.GetCurrentValue()->OnIPCClosed();
158     delegates_.Remove(it.GetCurrentKey());
159     it.Advance();
160   }
161 }
162 
OnStreamCreated(int stream_id,base::SharedMemoryHandle handle,base::SyncSocket::Handle socket_handle,uint32 length)163 void AudioMessageFilter::OnStreamCreated(
164     int stream_id,
165     base::SharedMemoryHandle handle,
166 #if defined(OS_WIN)
167     base::SyncSocket::Handle socket_handle,
168 #else
169     base::FileDescriptor socket_descriptor,
170 #endif
171     uint32 length) {
172   DCHECK(io_message_loop_->BelongsToCurrentThread());
173 
174   WebRtcLogMessage(base::StringPrintf(
175       "AMF::OnStreamCreated. stream_id=%d",
176       stream_id));
177 
178 #if !defined(OS_WIN)
179   base::SyncSocket::Handle socket_handle = socket_descriptor.fd;
180 #endif
181 
182   media::AudioOutputIPCDelegate* delegate = delegates_.Lookup(stream_id);
183   if (!delegate) {
184     DLOG(WARNING) << "Got OnStreamCreated() event for a non-existent or removed"
185                   << " audio renderer. (stream_id=" << stream_id << ").";
186     base::SharedMemory::CloseHandle(handle);
187     base::SyncSocket socket(socket_handle);
188     return;
189   }
190   delegate->OnStreamCreated(handle, socket_handle, length);
191 }
192 
OnStreamStateChanged(int stream_id,media::AudioOutputIPCDelegate::State state)193 void AudioMessageFilter::OnStreamStateChanged(
194     int stream_id, media::AudioOutputIPCDelegate::State state) {
195   DCHECK(io_message_loop_->BelongsToCurrentThread());
196   media::AudioOutputIPCDelegate* delegate = delegates_.Lookup(stream_id);
197   if (!delegate) {
198     DLOG(WARNING) << "Got OnStreamStateChanged() event for a non-existent or"
199                   << " removed audio renderer.  State: " << state;
200     return;
201   }
202   delegate->OnStateChanged(state);
203 }
204 
OnOutputDeviceChanged(int stream_id,int new_buffer_size,int new_sample_rate)205 void AudioMessageFilter::OnOutputDeviceChanged(int stream_id,
206                                                int new_buffer_size,
207                                                int new_sample_rate) {
208   DCHECK(io_message_loop_->BelongsToCurrentThread());
209   base::AutoLock auto_lock(lock_);
210 
211   WebRtcLogMessage(base::StringPrintf(
212       "AMF::OnOutputDeviceChanged. stream_id=%d"
213       ", new_buffer_size=%d, new_sample_rate=%d",
214       stream_id,
215       new_buffer_size,
216       new_sample_rate));
217 
218   // Ignore the message if an audio hardware config hasn't been created; this
219   // can occur if the renderer is using the high latency audio path.
220   // TODO(dalecurtis): After http://crbug.com/173435 is fixed, convert to CHECK.
221   if (!audio_hardware_config_)
222     return;
223 
224   // TODO(crogers): fix OnOutputDeviceChanged() to pass AudioParameters.
225   media::ChannelLayout channel_layout =
226       audio_hardware_config_->GetOutputChannelLayout();
227   int channels = audio_hardware_config_->GetOutputChannels();
228 
229   media::AudioParameters output_params;
230   output_params.Reset(
231       media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
232       channel_layout,
233       channels,
234       0,
235       new_sample_rate,
236       16,
237       new_buffer_size);
238 
239   audio_hardware_config_->UpdateOutputConfig(output_params);
240 }
241 
SetAudioHardwareConfig(media::AudioHardwareConfig * config)242 void AudioMessageFilter::SetAudioHardwareConfig(
243     media::AudioHardwareConfig* config) {
244   base::AutoLock auto_lock(lock_);
245   audio_hardware_config_ = config;
246 }
247 
248 }  // namespace content
249