blob: d4634e8029b9a1ea702ccbdc9b9ed36ddf70a241 [file] [log] [blame]
// 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.
#ifndef MEDIA_AUDIO_AUDIO_OUTPUT_CONTROLLER_H_
#define MEDIA_AUDIO_AUDIO_OUTPUT_CONTROLLER_H_
#include <stdint.h>
#include <memory>
#include <string>
#include <utility>
#include "base/atomic_ref_count.h"
#include "base/callback.h"
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/strings/string_piece.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_manager.h"
#include "media/audio/audio_power_monitor.h"
#include "media/audio/audio_source_diverter.h"
#include "media/base/media_export.h"
// An AudioOutputController controls an AudioOutputStream and provides data
// to this output stream. It has an important function that it executes
// audio operations like play, pause, stop, etc. on a separate thread,
// namely the audio manager thread.
//
// There are two ways to use this class.
// 1. Do all operations (including Create and Close) from a thread different
// than the Audio Manager thread. In this case, the public methods are
// non-blocking. The actual operations are performed on the audio manager
// thread.
// 2. Do all operations (including Create and Close) on the Audio Manager
// thread. In this case, they are completed synchronously.
// Note: it is not allowed to mix 1. and 2.!
//
// Here is a state transition diagram for the AudioOutputController:
//
// *[ Empty ] --> [ Created ] --> [ Playing ] -------.
// | | | ^ |
// | | | | |
// | | | | v
// | | | `----- [ Paused ]
// | | | |
// | v v |
// `-----------> [ Closed ] <-----------'
//
// * Initial state
//
// At any time after reaching the Created state but before Closed, the
// AudioOutputController may be notified of a device change via
// OnDeviceChange(). As the OnDeviceChange() is processed, state transitions
// will occur, ultimately ending up in an equivalent pre-call state. E.g., if
// the state was Paused, the new state will be Created, since these states are
// all functionally equivalent and require a Play() call to continue to the next
// state.
//
// The AudioOutputStream can request data from the AudioOutputController via the
// AudioSourceCallback interface. AudioOutputController uses the SyncReader
// passed to it via construction to synchronously fulfill this read request.
namespace media {
class MEDIA_EXPORT AudioOutputController
: public base::RefCountedThreadSafe<AudioOutputController>,
public AudioOutputStream::AudioSourceCallback,
public AudioSourceDiverter,
public AudioManager::AudioDeviceListener {
public:
// An event handler that receives events from the AudioOutputController. The
// following methods are called on the audio manager thread.
class MEDIA_EXPORT EventHandler {
public:
virtual void OnControllerCreated() = 0;
virtual void OnControllerPlaying() = 0;
virtual void OnControllerPaused() = 0;
virtual void OnControllerError() = 0;
virtual void OnLog(base::StringPiece message) = 0;
protected:
virtual ~EventHandler() {}
};
// A synchronous reader interface used by AudioOutputController for
// synchronous reading.
// TODO(crogers): find a better name for this class and the Read() method
// now that it can handle synchronized I/O.
class SyncReader {
public:
virtual ~SyncReader() {}
// This is used by SyncReader to prepare more data and perform
// synchronization. Also inform about output delay at a certain moment and
// if any frames have been skipped by the renderer (typically the OS). The
// renderer source can handle this appropriately depending on the type of
// source. An ordinary file playout would ignore this.
virtual void RequestMoreData(base::TimeDelta delay,
base::TimeTicks delay_timestamp,
int prior_frames_skipped) = 0;
// Attempts to completely fill |dest|, zeroing |dest| if the request can not
// be fulfilled (due to timeout).
virtual void Read(AudioBus* dest) = 0;
// Close this synchronous reader.
virtual void Close() = 0;
};
// Factory method for creating an AudioOutputController.
// This also creates and opens an AudioOutputStream on the audio manager
// thread, and if this is successful, the |event_handler| will receive an
// OnControllerCreated() call from the same audio manager thread.
// |audio_manager| must outlive AudioOutputController.
// The |output_device_id| can be either empty (default device) or specify a
// specific hardware device for audio output.
static scoped_refptr<AudioOutputController> Create(
AudioManager* audio_manager, EventHandler* event_handler,
const AudioParameters& params, const std::string& output_device_id,
SyncReader* sync_reader);
// Indicates whether audio power level analysis will be performed. If false,
// ReadCurrentPowerAndClip() can not be called.
static bool will_monitor_audio_levels() {
#if defined(OS_ANDROID) || defined(OS_IOS)
return false;
#else
return true;
#endif
}
// Methods to control playback of the stream.
// Starts the playback of this audio output stream.
void Play();
// Pause this audio output stream.
void Pause();
// Closes the audio output stream. The state is changed and the resources
// are freed on the audio manager thread. |closed_task| is executed after
// that, on the thread on which Close was called. Callbacks (EventHandler and
// SyncReader) must exist until |closed_task| is called, but they are safe
// to delete after that.
//
// When calling this on the audio manager thread, all resources will be
// released synchronously and there is no need for |closed_task|. In this
// case, it must be null.
void Close(base::OnceClosure closed_task);
// Sets the volume of the audio output stream.
void SetVolume(double volume);
// AudioSourceCallback implementation.
int OnMoreData(base::TimeDelta delay,
base::TimeTicks delay_timestamp,
int prior_frames_skipped,
AudioBus* dest) override;
void OnError() override;
// AudioDeviceListener implementation. When called AudioOutputController will
// shutdown the existing |stream_|, transition to the kRecreating state,
// create a new stream, and then transition back to an equivalent state prior
// to being called.
void OnDeviceChange() override;
// AudioSourceDiverter implementation.
const AudioParameters& GetAudioParameters() override;
void StartDiverting(AudioOutputStream* to_stream) override;
void StopDiverting() override;
void StartDuplicating(AudioPushSink* sink) override;
void StopDuplicating(AudioPushSink* sink) override;
// Accessor for AudioPowerMonitor::ReadCurrentPowerAndClip(). See comments in
// audio_power_monitor.h for usage. This may be called on any thread.
std::pair<float, bool> ReadCurrentPowerAndClip();
protected:
// Internal state of the source.
enum State {
kEmpty,
kCreated,
kPlaying,
kPaused,
kClosed,
kError,
};
// Time constant for AudioPowerMonitor. See AudioPowerMonitor ctor comments
// for semantics. This value was arbitrarily chosen, but seems to work well.
enum { kPowerMeasurementTimeConstantMillis = 10 };
friend class base::RefCountedThreadSafe<AudioOutputController>;
~AudioOutputController() override;
private:
// Used to store various stats about a stream. The lifetime of this object is
// from play until pause. The underlying physical stream may be changed when
// resuming playback, hence separate stats are logged for each play/pause
// cycle.
class ErrorStatisticsTracker {
public:
ErrorStatisticsTracker();
// Note: the destructor takes care of logging all of the stats.
~ErrorStatisticsTracker();
// Called to indicate an error callback was fired for the stream.
void RegisterError();
// This function should be called from the stream callback thread.
void OnMoreDataCalled();
private:
void WedgeCheck();
const base::TimeTicks start_time_;
bool error_during_callback_ = false;
// Flags when we've asked for a stream to start but it never did.
base::AtomicRefCount on_more_io_data_called_;
base::OneShotTimer wedge_timer_;
};
AudioOutputController(AudioManager* audio_manager, EventHandler* handler,
const AudioParameters& params,
const std::string& output_device_id,
SyncReader* sync_reader);
// The following methods are executed on the audio manager thread.
void DoCreate(bool is_for_device_change);
void DoPlay();
void DoPause();
void DoClose();
void DoSetVolume(double volume);
void DoReportError();
void DoStartDiverting(AudioOutputStream* to_stream);
void DoStopDiverting();
void DoStartDuplicating(AudioPushSink* sink);
void DoStopDuplicating(AudioPushSink* sink);
// Helper method that stops the physical stream.
void StopStream();
// Helper method that stops, closes, and NULLs |*stream_|.
void DoStopCloseAndClearStream();
// Send audio data to each duplication target.
void BroadcastDataToDuplicationTargets(std::unique_ptr<AudioBus> audio_bus,
base::TimeTicks reference_time);
// Log the current average power level measured by power_monitor_.
void LogAudioPowerLevel(const std::string& call_name);
SEQUENCE_CHECKER(owning_sequence_);
AudioManager* const audio_manager_;
const AudioParameters params_;
EventHandler* const handler_;
// The message loop of audio manager thread that this object runs on.
const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
// Specifies the device id of the output device to open or empty for the
// default output device.
std::string output_device_id_;
AudioOutputStream* stream_;
// When non-NULL, audio is being diverted to this stream.
AudioOutputStream* diverting_to_stream_;
// The targets for audio stream to be copied to. |should_duplicate_| is set to
// 1 when the OnMoreData() call should proxy the data to
// BroadcastDataToDuplicationTargets().
base::flat_set<AudioPushSink*> duplication_targets_;
base::AtomicRefCount should_duplicate_;
// The current volume of the audio stream.
double volume_;
// |state_| may only be used on the audio manager thread.
State state_;
// SyncReader is used only in low latency mode for synchronous reading.
SyncReader* const sync_reader_;
// Scans audio samples from OnMoreData() as input to compute power levels.
AudioPowerMonitor power_monitor_;
// Updated each time a power measurement is logged.
base::TimeTicks last_audio_level_log_time_;
// Used for keeping track of and logging stats. Created when a stream starts
// and destroyed when a stream stops. Also reset every time there is a stream
// being created due to device changes.
base::Optional<ErrorStatisticsTracker> stats_tracker_;
// WeakPtrFactory and WeakPtr for ignoring errors which occur arround a
// Stop/Close cycle; e.g., device changes. These errors are generally harmless
// since a fresh stream is about to be recreated, but if forwarded, renderer
// side clients may consider them catastrophic and abort their operations.
//
// |weak_this_for_errors_| must not be reassigned while a stream is active or
// we'll have concurrent access from different threads. Only the factory may
// be used to invalidate WeakPtrs while the stream is active.
base::WeakPtr<AudioOutputController> weak_this_for_errors_;
base::WeakPtrFactory<AudioOutputController> weak_factory_for_errors_;
DISALLOW_COPY_AND_ASSIGN(AudioOutputController);
};
} // namespace media
#endif // MEDIA_AUDIO_AUDIO_OUTPUT_CONTROLLER_H_