// Copyright (c) 2010 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. // // AudioRendererHost serves audio related requests from AudioRenderer which // lives inside the render process and provide access to audio hardware. It maps // an internal ID to AudioRendererHost::IPCAudioSource in a map, which is the // actual object providing audio packets through IPC. It creates the actual // AudioOutputStream object when requested by the renderer provided with // render view id and stream id. // // This class is owned by BrowserRenderProcessHost, and instantiated on UI // thread, but all other operations and method calls (except Destroy()) happens // in IO thread, so we need to be extra careful about the lifetime of this // object. AudioManager is a singleton and created in IO thread, audio output // streams are also created in the IO thread, so we need to destroy them also // in IO thread. After this class is created, a task of OnInitialized() is // posted on IO thread in which singleton of AudioManager is created and // AddRef() is called to increase one ref count of this object. Owner of this // class should call Destroy() before decrementing the ref count to this object, // which essentially post a task of OnDestroyed() on IO thread. Inside // OnDestroyed(), audio output streams are destroyed and Release() is called // which may result in self-destruction. // // AudioRendererHost::IPCAudioSource is a container of AudioOutputStream and // provide audio packets to the associated AudioOutputStream through IPC. It // performs the logic for buffering and controlling the AudioOutputStream. // // Here is a state diagram for the IPCAudioSource: // // .---------> [ Stopped ] <--------. // | ^ | // | | | // *[ Created ] --> [ Playing ] --> [ Paused ] // ^ | // | | // `-----------------' // // Here's an example of a typical IPC dialog for audio: // // Renderer AudioRendererHost // | | // | CreateStream > | // | < Created | // | | // | Play > | // | < Playing | time // | | // | < RequestAudioPacket | // | AudioPacketReady > | // | ... | // | < RequestAudioPacket | // | AudioPacketReady > | // | | // | ... | // | < RequestAudioPacket | // | AudioPacketReady > | // | ... | // | Pause > | // | < Paused | // | ... | // | Start > | // | < Started | // | ... | // | Close > | // v v // The above mode of operation uses relatively big buffers and has latencies // of 50 ms or more. There is a second mode of operation which is low latency. // For low latency audio, the picture above is modified by not having the // RequestAudioPacket and the AudioPacketReady messages, instead a SyncSocket // pair is used to signal buffer readiness without having to route messages // using the IO thread. #ifndef CHROME_BROWSER_RENDERER_HOST_AUDIO_RENDERER_HOST_H_ #define CHROME_BROWSER_RENDERER_HOST_AUDIO_RENDERER_HOST_H_ #include #include "base/lock.h" #include "base/process.h" #include "base/ref_counted.h" #include "base/scoped_ptr.h" #include "base/shared_memory.h" #include "base/sync_socket.h" #include "base/waitable_event.h" #include "chrome/browser/chrome_thread.h" #include "ipc/ipc_message.h" #include "media/audio/audio_output.h" #include "media/audio/simple_sources.h" #include "testing/gtest/include/gtest/gtest_prod.h" class AudioManager; struct ViewHostMsg_Audio_CreateStream_Params; class AudioRendererHost : public base::RefCountedThreadSafe< AudioRendererHost, ChromeThread::DeleteOnIOThread> { private: class IPCAudioSource; public: // Called from UI thread from the owner of this object. AudioRendererHost(); // Called from UI thread from the owner of this object to kick start // destruction of streams in IO thread. void Destroy(); //--------------------------------------------------------------------------- // The following public methods are called from ResourceMessageFilter in the // IO thread. // Event received when IPC channel is connected with the renderer process. void IPCChannelConnected(int process_id, base::ProcessHandle process_handle, IPC::Message::Sender* ipc_sender); // Event received when IPC channel is closing. void IPCChannelClosing(); // Returns true if the message is a audio related message and was processed. // If it was, message_was_ok will be false iff the message was corrupt. bool OnMessageReceived(const IPC::Message& message, bool* message_was_ok); protected: friend class ChromeThread; friend class DeleteTask; // Destruction always happens on the IO thread (see DeleteOnIOThread above). virtual ~AudioRendererHost(); //--------------------------------------------------------------------------- // Helper methods called from IPCAudioSource or from this class, since // methods in IPCAudioSource maybe called from hardware audio threads, these // methods make sure the actual tasks happen on IO thread. // These methods are virtual protected so we can mock these methods to test // IPCAudioSource. // A helper method to send an IPC message to renderer process on IO thread. virtual void Send(IPC::Message* message); // A helper method for sending error IPC messages. virtual void SendErrorMessage(int32 render_view_id, int32 stream_id); // A helper method for calling OnDestroySource on IO thread. virtual void DestroySource(IPCAudioSource* source); private: friend class AudioRendererHost::IPCAudioSource; friend class AudioRendererHostTest; FRIEND_TEST(AudioRendererHostTest, CreateMockStream); FRIEND_TEST(AudioRendererHostTest, MockStreamDataConversation); // The container for AudioOutputStream and serves the audio packet received // via IPC. class IPCAudioSource : public AudioOutputStream::AudioSourceCallback { public: // Internal state of the source. enum State { kCreated, kPlaying, kPaused, kClosed, kError, }; // Factory method for creating an IPCAudioSource, returns NULL if failed. // The IPCAudioSource object will have an internal state of // AudioOutputStream::STATE_CREATED after creation. // If an IPCAudioSource is created successfully, a // ViewMsg_NotifyAudioStreamCreated message is sent to the renderer. // This factory method also starts requesting audio packet from the renderer // after creation. The renderer will thus receive // ViewMsg_RequestAudioPacket message. static IPCAudioSource* CreateIPCAudioSource( AudioRendererHost* host, // Host of this source. int process_id, // Process ID of renderer. int route_id, // Routing ID to RenderView. int stream_id, // ID of this source. base::ProcessHandle process_handle, // Process handle of renderer. AudioManager::Format format, // Format of the stream. int channels, // Number of channels. int sample_rate, // Sampling frequency/rate. char bits_per_sample, // Number of bits per sample. uint32 decoded_packet_size, // Number of bytes per packet. uint32 buffer_capacity, // Number of bytes in the buffer. bool low_latency // Use low-latency (socket) code ); ~IPCAudioSource(); // Methods to control playback of the stream. // Starts the playback of this audio output stream. The internal state will // be updated to AudioOutputStream::STATE_STARTED and the state update is // sent to the renderer. void Play(); // Pause this audio output stream. The audio output stream will stop // reading from the |push_source_|. The internal state will be updated // to AudioOutputStream::STATE_PAUSED and the state update is sent to // the renderer. void Pause(); // Discard all audio data buffered in this output stream. This method only // has effect when the stream is paused. void Flush(); // Closes the audio output stream. After calling this method all activities // of the audio output stream are stopped. void Close(); // Sets the volume of the audio output stream. There's no IPC messages // sent back to the renderer upon success and failure. void SetVolume(double volume); // Gets the volume of the audio output stream. // ViewMsg_NotifyAudioStreamVolume is sent back to renderer with volume // information if succeeded. void GetVolume(); // Notify this source that buffer has been filled and is ready to be // consumed. void NotifyPacketReady(uint32 packet_size); // AudioSourceCallback methods. virtual uint32 OnMoreData(AudioOutputStream* stream, void* dest, uint32 max_size, uint32 pending_bytes); virtual void OnClose(AudioOutputStream* stream); virtual void OnError(AudioOutputStream* stream, int code); int process_id() { return process_id_; } int route_id() { return route_id_; } int stream_id() { return stream_id_; } private: IPCAudioSource(AudioRendererHost* host, // Host of this source. int process_id, // Process ID of renderer. int route_id, // Routing ID to RenderView. int stream_id, // ID of this source. AudioOutputStream* stream, // Stream associated. uint32 hardware_packet_size, uint32 decoded_packet_size, // Size of shared memory // buffer for writing. uint32 buffer_capacity); // Capacity of transportation // buffer. // Check the condition of |outstanding_request_| and |push_source_| to // determine if we should submit a new packet request. void SubmitPacketRequest_Locked(); void SubmitPacketRequest(AutoLock* alock); // A helper method to start buffering. This method is used by // CreateIPCAudioSource to submit a packet request. void StartBuffering(); AudioRendererHost* host_; int process_id_; int route_id_; int stream_id_; AudioOutputStream* stream_; uint32 hardware_packet_size_; uint32 decoded_packet_size_; uint32 buffer_capacity_; State state_; base::SharedMemory shared_memory_; scoped_ptr shared_socket_; // PushSource role is to buffer and it's only used in regular latency mode. PushSource push_source_; // Flag that indicates there is an outstanding request. bool outstanding_request_; // Number of bytes copied in the last OnMoreData call. uint32 pending_bytes_; base::Time last_callback_time_; // Protects: // - |outstanding_requests_| // - |last_copied_bytes_| // - |push_source_| Lock lock_; }; //--------------------------------------------------------------------------- // Methods called on IO thread. // Returns true if the message is an audio related message and should be // handled by this class. bool IsAudioRendererHostMessage(const IPC::Message& message); // Audio related IPC message handlers. // Creates an audio output stream with the specified format. If this call is // successful this object would keep an internal entry of the stream for the // required properties. See IPCAudioSource::CreateIPCAudioSource() for more // details. void OnCreateStream(const IPC::Message& msg, int stream_id, const ViewHostMsg_Audio_CreateStream_Params& params, bool low_latency); // Starts buffering for the audio output stream. Delegates the start method // call to the corresponding IPCAudioSource::Play(). // ViewMsg_NotifyAudioStreamStateChanged with // AudioOutputStream::AUDIO_STREAM_ERROR is sent back to renderer if the // required IPCAudioSource is not found. void OnPlayStream(const IPC::Message& msg, int stream_id); // Pauses the audio output stream. Delegates the pause method call to the // corresponding IPCAudioSource::Pause(), // ViewMsg_NotifyAudioStreamStateChanged with // AudioOutputStream::AUDIO_STREAM_ERROR is sent back to renderer if the // required IPCAudioSource is not found. void OnPauseStream(const IPC::Message& msg, int stream_id); // Discard all audio data buffered. void OnFlushStream(const IPC::Message& msg, int stream_id); // Closes the audio output stream, delegates the close method call to the // corresponding IPCAudioSource::Close(), no returning IPC message to renderer // upon success and failure. void OnCloseStream(const IPC::Message& msg, int stream_id); // Set the volume for the stream specified. Delegates the SetVolume() method // call to IPCAudioSource. No returning IPC message to renderer upon success. // ViewMsg_NotifyAudioStreamStateChanged with // AudioOutputStream::AUDIO_STREAM_ERROR is sent back to renderer if the // required IPCAudioSource is not found. void OnSetVolume(const IPC::Message& msg, int stream_id, double volume); // Gets the volume of the stream specified, delegates to corresponding // IPCAudioSource::GetVolume(), see the method for more details. // ViewMsg_NotifyAudioStreamStateChanged with // AudioOutputStream::AUDIO_STREAM_ERROR is sent back to renderer if the // required IPCAudioSource is not found. void OnGetVolume(const IPC::Message& msg, int stream_id); // Notify packet has been prepared for stream, delegates to corresponding // IPCAudioSource::NotifyPacketReady(), see the method for more details. // ViewMsg_NotifyAudioStreamStateChanged with // AudioOutputStream::AUDIO_STREAM_ERROR is sent back to renderer if the // required IPCAudioSource is not found. void OnNotifyPacketReady(const IPC::Message& msg, int stream_id, uint32 packet_size); // Called on IO thread when this object needs to be destroyed and after // Destroy() is called from owner of this class in UI thread. void OnDestroyed(); // Sends IPC messages using ipc_sender_. void OnSend(IPC::Message* message); // Closes the source, deletes it and removes it from the internal map. // Destruction of source and associated stream should always be done by this // method. *DO NOT* call this method from other than IPCAudioSource and from // this class. void OnDestroySource(IPCAudioSource* source); // A helper method that destroy all IPCAudioSource and associated audio // output streams. void DestroyAllSources(); // A helper method to look up a IPCAudioSource with a tuple of render view id // and stream id. Returns NULL if not found. IPCAudioSource* Lookup(int render_view_id, int stream_id); int process_id_; base::ProcessHandle process_handle_; IPC::Message::Sender* ipc_sender_; // A map of id to audio sources. typedef std::pair SourceID; typedef std::map SourceMap; SourceMap sources_; DISALLOW_COPY_AND_ASSIGN(AudioRendererHost); }; #endif // CHROME_BROWSER_RENDERER_HOST_AUDIO_RENDERER_HOST_H_