123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- // 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.
- //
- // Audio rendering unit utilizing audio output stream provided by browser
- // process through IPC.
- //
- // Relationship of classes.
- //
- // AudioOutputController AudioOutputDevice
- // ^ ^
- // | |
- // v IPC v
- // MojoAudioOutputStream <---------> AudioOutputIPC (MojoAudioOutputIPC)
- //
- // Transportation of audio samples from the render to the browser process
- // is done by using shared memory in combination with a sync socket pair
- // to generate a low latency transport. The AudioOutputDevice user registers an
- // AudioOutputDevice::RenderCallback at construction and will be polled by the
- // AudioOutputController for audio to be played out by the underlying audio
- // layers.
- //
- // State sequences.
- //
- // Task [IO thread] IPC [IO thread]
- // RequestDeviceAuthorization -> RequestDeviceAuthorizationOnIOThread ------>
- // RequestDeviceAuthorization ->
- // <- OnDeviceAuthorized <- AudioMsg_NotifyDeviceAuthorized <-
- //
- // Start -> CreateStreamOnIOThread -----> CreateStream ------>
- // <- OnStreamCreated <- AudioMsg_NotifyStreamCreated <-
- // ---> PlayOnIOThread -----------> PlayStream -------->
- //
- // Optionally Play() / Pause() sequences may occur:
- // Play -> PlayOnIOThread --------------> PlayStream --------->
- // Pause -> PauseOnIOThread ------------> PauseStream -------->
- // (note that Play() / Pause() sequences before
- // OnStreamCreated are deferred until OnStreamCreated, with the last valid
- // state being used)
- //
- // AudioOutputDevice::Render => audio transport on audio thread =>
- // |
- // Stop --> ShutDownOnIOThread --------> CloseStream -> Close
- //
- // This class utilizes several threads during its lifetime, namely:
- // 1. Creating thread.
- // Must be the main render thread.
- // 2. Control thread (may be the main render thread or another thread).
- // The methods: Start(), Stop(), Play(), Pause(), SetVolume()
- // must be called on the same thread.
- // 3. IO thread (internal implementation detail - not exposed to public API)
- // The thread within which this class receives all the IPC messages and
- // IPC communications can only happen in this thread.
- // 4. Audio transport thread (See AudioDeviceThread).
- // Responsible for calling the AudioOutputDeviceThreadCallback
- // implementation that in turn calls AudioRendererSink::RenderCallback
- // which feeds audio samples to the audio layer in the browser process using
- // sync sockets and shared memory.
- //
- // Implementation notes:
- // - The user must call Stop() before deleting the class instance.
- #ifndef MEDIA_AUDIO_AUDIO_OUTPUT_DEVICE_H_
- #define MEDIA_AUDIO_AUDIO_OUTPUT_DEVICE_H_
- #include <memory>
- #include <string>
- #include "base/bind.h"
- #include "base/memory/raw_ptr.h"
- #include "base/memory/unsafe_shared_memory_region.h"
- #include "base/synchronization/waitable_event.h"
- #include "base/thread_annotations.h"
- #include "base/time/time.h"
- #include "media/audio/audio_device_thread.h"
- #include "media/audio/audio_output_ipc.h"
- #include "media/audio/audio_sink_parameters.h"
- #include "media/base/audio_parameters.h"
- #include "media/base/audio_renderer_sink.h"
- #include "media/base/media_export.h"
- #include "media/base/output_device_info.h"
- namespace base {
- class OneShotTimer;
- class SingleThreadTaskRunner;
- }
- namespace media {
- class AudioOutputDeviceThreadCallback;
- class MEDIA_EXPORT AudioOutputDevice : public AudioRendererSink,
- public AudioOutputIPCDelegate {
- public:
- // NOTE: Clients must call Initialize() before using.
- AudioOutputDevice(
- std::unique_ptr<AudioOutputIPC> ipc,
- const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
- const AudioSinkParameters& sink_params,
- base::TimeDelta authorization_timeout);
- AudioOutputDevice(const AudioOutputDevice&) = delete;
- AudioOutputDevice& operator=(const AudioOutputDevice&) = delete;
- // Request authorization to use the device specified in the constructor.
- void RequestDeviceAuthorization();
- // AudioRendererSink implementation.
- void Initialize(const AudioParameters& params,
- RenderCallback* callback) override;
- void Start() override;
- void Stop() override;
- void Play() override;
- void Pause() override;
- void Flush() override;
- bool SetVolume(double volume) override;
- OutputDeviceInfo GetOutputDeviceInfo() override;
- void GetOutputDeviceInfoAsync(OutputDeviceInfoCB info_cb) override;
- bool IsOptimizedForHardwareParameters() override;
- bool CurrentThreadIsRenderingThread() override;
- // Methods called on IO thread ----------------------------------------------
- // AudioOutputIPCDelegate methods.
- void OnError() override;
- void OnDeviceAuthorized(OutputDeviceStatus device_status,
- const AudioParameters& output_params,
- const std::string& matched_device_id) override;
- void OnStreamCreated(base::UnsafeSharedMemoryRegion shared_memory_region,
- base::SyncSocket::ScopedHandle socket_handle,
- bool play_automatically) override;
- void OnIPCClosed() override;
- protected:
- // Magic required by ref_counted.h to avoid any code deleting the object
- // accidentally while there are references to it.
- friend class base::RefCountedThreadSafe<AudioOutputDevice>;
- ~AudioOutputDevice() override;
- private:
- enum StartupState {
- IDLE, // Authorization not requested.
- AUTHORIZATION_REQUESTED, // Sent (possibly completed) device
- // authorization request.
- STREAM_CREATION_REQUESTED, // Sent (possibly completed) device creation
- // request. Can Play()/Pause()/Stop().
- };
- // This enum is used for UMA, so the only allowed operation on this definition
- // is to add new states to the bottom, update kMaxValue, and update the
- // histogram "Media.Audio.Render.StreamCallbackError2".
- enum Error {
- kNoError = 0,
- kErrorDuringCreation = 1,
- kErrorDuringRendering = 2,
- kMaxValue = kErrorDuringRendering
- };
- // Methods called on IO thread ----------------------------------------------
- // The following methods are tasks posted on the IO thread that need to
- // be executed on that thread. They use AudioOutputIPC to send IPC messages
- // upon state changes.
- void RequestDeviceAuthorizationOnIOThread();
- void InitializeOnIOThread(const AudioParameters& params,
- RenderCallback* callback);
- void CreateStreamOnIOThread();
- void PlayOnIOThread();
- void PauseOnIOThread();
- void FlushOnIOThread();
- void ShutDownOnIOThread();
- void SetVolumeOnIOThread(double volume);
- // Process device authorization result on the IO thread.
- void ProcessDeviceAuthorizationOnIOThread(
- OutputDeviceStatus device_status,
- const AudioParameters& output_params,
- const std::string& matched_device_id,
- bool timed_out);
- void NotifyRenderCallbackOfError();
- OutputDeviceInfo GetOutputDeviceInfo_Signaled();
- void OnAuthSignal();
- const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
- AudioParameters audio_parameters_;
- raw_ptr<RenderCallback> callback_;
- // A pointer to the IPC layer that takes care of sending requests over to
- // the implementation. May be set to nullptr after errors.
- std::unique_ptr<AudioOutputIPC> ipc_;
- // Current state (must only be accessed from the IO thread). See comments for
- // State enum above.
- StartupState state_;
- // For UMA stats. May only be accessed on the IO thread.
- Error had_error_ = kNoError;
- // Last set volume.
- double volume_ = 1.0;
- // The media session ID used to identify which input device to be started.
- // Only used by Unified IO.
- base::UnguessableToken session_id_;
- // ID of hardware output device to be used (provided |session_id_| is zero)
- const std::string device_id_;
- // If |device_id_| is empty and |session_id_| is not, |matched_device_id_| is
- // received in OnDeviceAuthorized().
- std::string matched_device_id_;
- // In order to avoid a race between OnStreamCreated and Stop(), we use this
- // guard to control stopping and starting the audio thread.
- base::Lock audio_thread_lock_;
- std::unique_ptr<AudioOutputDeviceThreadCallback> audio_callback_;
- std::unique_ptr<AudioDeviceThread> audio_thread_
- GUARDED_BY(audio_thread_lock_);
- // Temporary hack to ignore OnStreamCreated() due to the user calling Stop()
- // so we don't start the audio thread pointing to a potentially freed
- // |callback_|.
- //
- // TODO(scherkus): Replace this by changing AudioRendererSink to either accept
- // the callback via Start(). See http://crbug.com/151051 for details.
- bool stopping_hack_ GUARDED_BY(audio_thread_lock_);
- base::WaitableEvent did_receive_auth_;
- AudioParameters output_params_;
- OutputDeviceStatus device_status_;
- const base::TimeDelta auth_timeout_;
- std::unique_ptr<base::OneShotTimer> auth_timeout_action_;
- // Pending callback for OutputDeviceInfo if it has not been received by the
- // time a call to GetGetOutputDeviceInfoAsync() is called.
- //
- // Lock for use ONLY with |pending_device_info_cb_| and |did_receive_auth_|,
- // if you add more usage of this lock ensure you have not added a deadlock.
- base::Lock device_info_lock_;
- OutputDeviceInfoCB pending_device_info_cb_ GUARDED_BY(device_info_lock_);
- };
- } // namespace media
- #endif // MEDIA_AUDIO_AUDIO_OUTPUT_DEVICE_H_
|