• 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                      int render_frame_id);
27   virtual ~AudioOutputIPCImpl();
28 
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;
37 
38  private:
39   const scoped_refptr<AudioMessageFilter> filter_;
40   const int render_view_id_;
41   const int render_frame_id_;
42   int stream_id_;
43 };
44 
45 AudioMessageFilter* AudioMessageFilter::g_filter = NULL;
46 
AudioMessageFilter(const scoped_refptr<base::MessageLoopProxy> & io_message_loop)47 AudioMessageFilter::AudioMessageFilter(
48     const scoped_refptr<base::MessageLoopProxy>& io_message_loop)
49     : sender_(NULL),
50       audio_hardware_config_(NULL),
51       io_message_loop_(io_message_loop) {
52   DCHECK(!g_filter);
53   g_filter = this;
54 }
55 
~AudioMessageFilter()56 AudioMessageFilter::~AudioMessageFilter() {
57   DCHECK_EQ(g_filter, this);
58   g_filter = NULL;
59 }
60 
61 // static
Get()62 AudioMessageFilter* AudioMessageFilter::Get() {
63   return g_filter;
64 }
65 
AudioOutputIPCImpl(const scoped_refptr<AudioMessageFilter> & filter,int render_view_id,int render_frame_id)66 AudioMessageFilter::AudioOutputIPCImpl::AudioOutputIPCImpl(
67     const scoped_refptr<AudioMessageFilter>& filter,
68     int render_view_id,
69     int render_frame_id)
70     : filter_(filter),
71       render_view_id_(render_view_id),
72       render_frame_id_(render_frame_id),
73       stream_id_(kStreamIDNotSet) {}
74 
~AudioOutputIPCImpl()75 AudioMessageFilter::AudioOutputIPCImpl::~AudioOutputIPCImpl() {}
76 
CreateAudioOutputIPC(int render_view_id,int render_frame_id)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));
82 }
83 
CreateStream(media::AudioOutputIPCDelegate * delegate,const media::AudioParameters & params,int session_id)84 void AudioMessageFilter::AudioOutputIPCImpl::CreateStream(
85     media::AudioOutputIPCDelegate* delegate,
86     const media::AudioParameters& params,
87     int session_id) {
88   DCHECK(filter_->io_message_loop_->BelongsToCurrentThread());
89   DCHECK(delegate);
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));
94 }
95 
PlayStream()96 void AudioMessageFilter::AudioOutputIPCImpl::PlayStream() {
97   DCHECK_NE(stream_id_, kStreamIDNotSet);
98   filter_->Send(new AudioHostMsg_PlayStream(stream_id_));
99 }
100 
PauseStream()101 void AudioMessageFilter::AudioOutputIPCImpl::PauseStream() {
102   DCHECK_NE(stream_id_, kStreamIDNotSet);
103   filter_->Send(new AudioHostMsg_PauseStream(stream_id_));
104 }
105 
CloseStream()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;
112 }
113 
SetVolume(double volume)114 void AudioMessageFilter::AudioOutputIPCImpl::SetVolume(double volume) {
115   DCHECK_NE(stream_id_, kStreamIDNotSet);
116   filter_->Send(new AudioHostMsg_SetVolume(stream_id_, volume));
117 }
118 
Send(IPC::Message * message)119 void AudioMessageFilter::Send(IPC::Message* message) {
120   DCHECK(io_message_loop_->BelongsToCurrentThread());
121   if (!sender_) {
122     delete message;
123   } else {
124     sender_->Send(message);
125   }
126 }
127 
OnMessageReceived(const IPC::Message & message)128 bool AudioMessageFilter::OnMessageReceived(const IPC::Message& message) {
129   DCHECK(io_message_loop_->BelongsToCurrentThread());
130   bool handled = true;
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()
137   return handled;
138 }
139 
OnFilterAdded(IPC::Sender * sender)140 void AudioMessageFilter::OnFilterAdded(IPC::Sender* sender) {
141   DCHECK(io_message_loop_->BelongsToCurrentThread());
142   sender_ = sender;
143 }
144 
OnFilterRemoved()145 void AudioMessageFilter::OnFilterRemoved() {
146   DCHECK(io_message_loop_->BelongsToCurrentThread());
147 
148   // Once removed, a filter will not be used again.  At this time all
149   // delegates must be notified so they release their reference.
150   OnChannelClosing();
151 }
152 
OnChannelClosing()153 void AudioMessageFilter::OnChannelClosing() {
154   DCHECK(io_message_loop_->BelongsToCurrentThread());
155   sender_ = NULL;
156 
157   DLOG_IF(WARNING, !delegates_.IsEmpty())
158       << "Not all audio devices have been closed.";
159 
160   IDMap<media::AudioOutputIPCDelegate>::iterator it(&delegates_);
161   while (!it.IsAtEnd()) {
162     it.GetCurrentValue()->OnIPCClosed();
163     delegates_.Remove(it.GetCurrentKey());
164     it.Advance();
165   }
166 }
167 
OnStreamCreated(int stream_id,base::SharedMemoryHandle handle,base::SyncSocket::TransitDescriptor socket_descriptor,uint32 length)168 void AudioMessageFilter::OnStreamCreated(
169     int stream_id,
170     base::SharedMemoryHandle handle,
171     base::SyncSocket::TransitDescriptor socket_descriptor,
172     uint32 length) {
173   DCHECK(io_message_loop_->BelongsToCurrentThread());
174 
175   WebRtcLogMessage(base::StringPrintf(
176       "AMF::OnStreamCreated. stream_id=%d",
177       stream_id));
178 
179   base::SyncSocket::Handle socket_handle =
180       base::SyncSocket::UnwrapHandle(socket_descriptor);
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   CHECK(audio_hardware_config_);
221 
222   // TODO(crogers): fix OnOutputDeviceChanged() to pass AudioParameters.
223   media::ChannelLayout channel_layout =
224       audio_hardware_config_->GetOutputChannelLayout();
225   int channels = audio_hardware_config_->GetOutputChannels();
226 
227   media::AudioParameters output_params;
228   output_params.Reset(
229       media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
230       channel_layout,
231       channels,
232       new_sample_rate,
233       16,
234       new_buffer_size);
235 
236   audio_hardware_config_->UpdateOutputConfig(output_params);
237 }
238 
SetAudioHardwareConfig(media::AudioHardwareConfig * config)239 void AudioMessageFilter::SetAudioHardwareConfig(
240     media::AudioHardwareConfig* config) {
241   base::AutoLock auto_lock(lock_);
242   audio_hardware_config_ = config;
243 }
244 
245 }  // namespace content
246