C++程序  |  284行  |  10.91 KB

// 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 "base/atomic_ref_count.h"
#include "base/callback.h"
#include "base/cancelable_callback.h"
#include "base/memory/ref_counted.h"
#include "base/timer/timer.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/audio/simple_sources.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.
//
// All the public methods of AudioOutputController are non-blocking.
// The actual operations are performed on the audio manager thread.
//
// 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 {

// Only do power monitoring for non-mobile platforms that need it for the UI.
#if !defined(OS_ANDROID) && !defined(OS_IOS)
#define AUDIO_POWER_MONITORING
#endif

class MEDIA_EXPORT AudioOutputController
    : public base::RefCountedThreadSafe<AudioOutputController>,
      public AudioOutputStream::AudioSourceCallback,
      public AudioSourceDiverter,
      NON_EXPORTED_BASE(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 OnCreated() = 0;
    virtual void OnPlaying() = 0;
    virtual void OnPowerMeasured(float power_dbfs, bool clipped) = 0;
    virtual void OnPaused() = 0;
    virtual void OnError() = 0;
    virtual void OnDeviceChange(int new_buffer_size, int new_sample_rate) = 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() {}

    // Notify the synchronous reader the number of bytes in the
    // AudioOutputController not yet played. This is used by SyncReader to
    // prepare more data and perform synchronization.
    virtual void UpdatePendingBytes(uint32 bytes) = 0;

    // Attempts to completely fill |dest|, zeroing |dest| if the request can not
    // be fulfilled (due to timeout).  |source| may optionally be provided for
    // input data.
    virtual void Read(const AudioBus* source, 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
  // OnCreated() 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.  The |input_device_id| is
  // used only for unified audio when opening up input and output at the same
  // time (controlled by |params.input_channel_count()|).
  static scoped_refptr<AudioOutputController> Create(
      AudioManager* audio_manager, EventHandler* event_handler,
      const AudioParameters& params, const std::string& output_device_id,
      const std::string& input_device_id, SyncReader* sync_reader);

  // 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.
  // Callbacks (EventHandler and SyncReader) must exist until closed_task is
  // called.
  //
  // It is safe to call this method more than once. Calls after the first one
  // will have no effect.
  void Close(const base::Closure& closed_task);

  // Sets the volume of the audio output stream.
  void SetVolume(double volume);

  // Calls |callback| (on the caller's thread) with the current output
  // device ID.
  void GetOutputDeviceId(
      base::Callback<void(const std::string&)> callback) const;

  // Changes which output device to use. If desired, you can provide a
  // callback that will be notified (on the thread you called from)
  // when the function has completed execution.
  //
  // Changing the output device causes the controller to go through
  // the same state transition back to the current state as a call to
  // OnDeviceChange (unless it is currently diverting, see
  // Start/StopDiverting below, in which case the state transition
  // will happen when StopDiverting is called).
  void SwitchOutputDevice(const std::string& output_device_id,
                          const base::Closure& callback);

  // AudioSourceCallback implementation.
  virtual int OnMoreData(AudioBus* dest,
                         AudioBuffersState buffers_state) OVERRIDE;
  virtual int OnMoreIOData(AudioBus* source,
                           AudioBus* dest,
                           AudioBuffersState buffers_state) OVERRIDE;
  virtual void OnError(AudioOutputStream* stream) 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.
  virtual void OnDeviceChange() OVERRIDE;

  // AudioSourceDiverter implementation.
  virtual const AudioParameters& GetAudioParameters() OVERRIDE;
  virtual void StartDiverting(AudioOutputStream* to_stream) OVERRIDE;
  virtual void StopDiverting() OVERRIDE;

 protected:
  // Internal state of the source.
  enum State {
    kEmpty,
    kCreated,
    kPlaying,
    kPaused,
    kClosed,
    kError,
  };

  friend class base::RefCountedThreadSafe<AudioOutputController>;
  virtual ~AudioOutputController();

 private:
  // We are polling sync reader if data became available.
  static const int kPollNumAttempts;
  static const int kPollPauseInMilliseconds;

  AudioOutputController(AudioManager* audio_manager, EventHandler* handler,
                        const AudioParameters& params,
                        const std::string& output_device_id,
                        const std::string& input_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);
  std::string DoGetOutputDeviceId() const;
  void DoSwitchOutputDevice(const std::string& output_device_id);
  void DoReportError();
  void DoStartDiverting(AudioOutputStream* to_stream);
  void DoStopDiverting();

  // Calls EventHandler::OnPowerMeasured() with the current power level and then
  // schedules itself to be called again later.
  void ReportPowerMeasurementPeriodically();

  // Helper method that stops the physical stream.
  void StopStream();

  // Helper method that stops, closes, and NULLs |*stream_|.
  void DoStopCloseAndClearStream();

  // Sanity-check that entry/exit to OnMoreIOData() by the hardware audio thread
  // happens only between AudioOutputStream::Start() and Stop().
  void AllowEntryToOnMoreIOData();
  void DisallowEntryToOnMoreIOData();

  // Checks if a stream was started successfully but never calls OnMoreIOData().
  void WedgeCheck();

  AudioManager* const audio_manager_;
  const AudioParameters params_;
  EventHandler* const handler_;

  // Specifies the device id of the output device to open or empty for the
  // default output device.
  std::string output_device_id_;

  // Used by the unified IO to open the correct input device.
  const std::string input_device_id_;

  AudioOutputStream* stream_;

  // When non-NULL, audio is being diverted to this stream.
  AudioOutputStream* diverting_to_stream_;

  // The current volume of the audio stream.
  double volume_;

  // |state_| is written on the audio manager thread and is read on the
  // hardware audio thread. These operations need to be locked. But lock
  // is not required for reading on the audio manager thread.
  State state_;

  // Binary semaphore, used to ensure that only one thread enters the
  // OnMoreIOData() method, and only when it is valid to do so.  This is for
  // sanity-checking the behavior of platform implementations of
  // AudioOutputStream.  In other words, multiple contention is not expected,
  // nor in the design here.
  base::AtomicRefCount num_allowed_io_;

  // SyncReader is used only in low latency mode for synchronous reading.
  SyncReader* const sync_reader_;

  // The message loop of audio manager thread that this object runs on.
  const scoped_refptr<base::MessageLoopProxy> message_loop_;

#if defined(AUDIO_POWER_MONITORING)
  // Scans audio samples from OnMoreIOData() as input to compute power levels.
  AudioPowerMonitor power_monitor_;

  // Periodic callback to report power levels during playback.
  base::CancelableClosure power_poll_callback_;
#endif

  // Flags when we've asked for a stream to start but it never did.
  base::AtomicRefCount on_more_io_data_called_;
  scoped_ptr<base::OneShotTimer<AudioOutputController> > wedge_timer_;

  DISALLOW_COPY_AND_ASSIGN(AudioOutputController);
};

}  // namespace media

#endif  // MEDIA_AUDIO_AUDIO_OUTPUT_CONTROLLER_H_