| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/renderer/media/audio_input_message_filter.h" |
| |
| #include "base/bind.h" |
| #include "base/message_loop.h" |
| #include "base/time.h" |
| #include "content/common/child_process.h" |
| #include "content/common/media/audio_messages.h" |
| #include "ipc/ipc_logging.h" |
| |
| AudioInputMessageFilter* AudioInputMessageFilter::filter_ = NULL; |
| |
| AudioInputMessageFilter::AudioInputMessageFilter() |
| : channel_(NULL) { |
| DVLOG(1) << "AudioInputMessageFilter()"; |
| DCHECK(!filter_); |
| filter_ = this; |
| } |
| |
| AudioInputMessageFilter::~AudioInputMessageFilter() { |
| DVLOG(1) << "AudioInputMessageFilter::~AudioInputMessageFilter()"; |
| |
| // Just in case the message filter is deleted before the channel |
| // is closed and there are still living audio devices. |
| OnChannelClosing(); |
| |
| DCHECK_EQ(filter_, this); |
| filter_ = NULL; |
| } |
| |
| // static. |
| AudioInputMessageFilter* AudioInputMessageFilter::Get() { |
| return filter_; |
| } |
| |
| bool AudioInputMessageFilter::Send(IPC::Message* message) { |
| if (!channel_) { |
| delete message; |
| return false; |
| } |
| |
| if (MessageLoop::current() != ChildProcess::current()->io_message_loop()) { |
| // Can only access the IPC::Channel on the IPC thread since it's not thread |
| // safe. |
| ChildProcess::current()->io_message_loop()->PostTask( |
| FROM_HERE, |
| base::Bind(base::IgnoreResult(&AudioInputMessageFilter::Send), this, |
| message)); |
| return true; |
| } |
| |
| return channel_->Send(message); |
| } |
| |
| bool AudioInputMessageFilter::OnMessageReceived(const IPC::Message& message) { |
| bool handled = true; |
| IPC_BEGIN_MESSAGE_MAP(AudioInputMessageFilter, message) |
| IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamCreated, |
| OnStreamCreated) |
| IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamVolume, OnStreamVolume) |
| IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyStreamStateChanged, |
| OnStreamStateChanged) |
| IPC_MESSAGE_HANDLER(AudioInputMsg_NotifyDeviceStarted, |
| OnDeviceStarted) |
| IPC_MESSAGE_UNHANDLED(handled = false) |
| IPC_END_MESSAGE_MAP() |
| return handled; |
| } |
| |
| void AudioInputMessageFilter::OnFilterAdded(IPC::Channel* channel) { |
| DVLOG(1) << "AudioInputMessageFilter::OnFilterAdded()"; |
| // Captures the channel for IPC. |
| channel_ = channel; |
| } |
| |
| void AudioInputMessageFilter::OnFilterRemoved() { |
| channel_ = NULL; |
| } |
| |
| void AudioInputMessageFilter::OnChannelClosing() { |
| channel_ = NULL; |
| LOG_IF(WARNING, !delegates_.IsEmpty()) |
| << "Not all audio devices have been closed."; |
| |
| IDMap<media::AudioInputIPCDelegate>::iterator it(&delegates_); |
| while (!it.IsAtEnd()) { |
| it.GetCurrentValue()->OnIPCClosed(); |
| delegates_.Remove(it.GetCurrentKey()); |
| it.Advance(); |
| } |
| } |
| |
| void AudioInputMessageFilter::OnStreamCreated( |
| int stream_id, |
| base::SharedMemoryHandle handle, |
| #if defined(OS_WIN) |
| base::SyncSocket::Handle socket_handle, |
| #else |
| base::FileDescriptor socket_descriptor, |
| #endif |
| uint32 length) { |
| #if !defined(OS_WIN) |
| base::SyncSocket::Handle socket_handle = socket_descriptor.fd; |
| #endif |
| media::AudioInputIPCDelegate* delegate = delegates_.Lookup(stream_id); |
| if (!delegate) { |
| DLOG(WARNING) << "Got audio stream event for a non-existent or removed" |
| " audio capturer (stream_id=" << stream_id << ")."; |
| base::SharedMemory::CloseHandle(handle); |
| base::SyncSocket socket(socket_handle); |
| return; |
| } |
| // Forward message to the stream delegate. |
| delegate->OnStreamCreated(handle, socket_handle, length); |
| } |
| |
| void AudioInputMessageFilter::OnStreamVolume(int stream_id, double volume) { |
| media::AudioInputIPCDelegate* delegate = delegates_.Lookup(stream_id); |
| if (!delegate) { |
| DLOG(WARNING) << "Got audio stream event for a non-existent or removed" |
| " audio capturer."; |
| return; |
| } |
| delegate->OnVolume(volume); |
| } |
| |
| void AudioInputMessageFilter::OnStreamStateChanged( |
| int stream_id, media::AudioInputIPCDelegate::State state) { |
| media::AudioInputIPCDelegate* delegate = delegates_.Lookup(stream_id); |
| if (!delegate) { |
| DLOG(WARNING) << "Got audio stream event for a non-existent or removed" |
| " audio renderer."; |
| return; |
| } |
| delegate->OnStateChanged(state); |
| } |
| |
| void AudioInputMessageFilter::OnDeviceStarted(int stream_id, |
| const std::string& device_id) { |
| media::AudioInputIPCDelegate* delegate = delegates_.Lookup(stream_id); |
| if (!delegate) { |
| NOTREACHED(); |
| return; |
| } |
| delegate->OnDeviceReady(device_id); |
| } |
| |
| int AudioInputMessageFilter::AddDelegate( |
| media::AudioInputIPCDelegate* delegate) { |
| return delegates_.Add(delegate); |
| } |
| |
| void AudioInputMessageFilter::RemoveDelegate(int id) { |
| DVLOG(1) << "AudioInputMessageFilter::RemoveDelegate(id=" << id << ")"; |
| delegates_.Remove(id); |
| } |
| |
| void AudioInputMessageFilter::CreateStream(int stream_id, |
| const media::AudioParameters& params, const std::string& device_id, |
| bool automatic_gain_control) { |
| Send(new AudioInputHostMsg_CreateStream( |
| stream_id, params, device_id, automatic_gain_control)); |
| } |
| |
| void AudioInputMessageFilter::StartDevice(int stream_id, int session_id) { |
| Send(new AudioInputHostMsg_StartDevice(stream_id, session_id)); |
| } |
| |
| void AudioInputMessageFilter::RecordStream(int stream_id) { |
| Send(new AudioInputHostMsg_RecordStream(stream_id)); |
| } |
| |
| void AudioInputMessageFilter::CloseStream(int stream_id) { |
| Send(new AudioInputHostMsg_CloseStream(stream_id)); |
| } |
| |
| void AudioInputMessageFilter::SetVolume(int stream_id, double volume) { |
| Send(new AudioInputHostMsg_SetVolume(stream_id, volume)); |
| } |