Home | History | Annotate | Download | only in linux
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 //
      5 // Creates an output stream based on the ALSA PCM interface.
      6 //
      7 // On device write failure, the stream will move itself to an invalid state.
      8 // No more data will be pulled from the data source, or written to the device.
      9 // All calls to public API functions will either no-op themselves, or return an
     10 // error if possible.  Specifically, If the stream is in an error state, Open()
     11 // will return false, and Start() will call OnError() immediately on the
     12 // provided callback.
     13 //
     14 // If the stream is successfully opened, Close() must be called.  After Close
     15 // has been called, the object should be regarded as deleted and not touched.
     16 //
     17 // AlsaPcmOutputStream is a single threaded class that should only be used from
     18 // the audio thread. When modifying the code in this class, please read the
     19 // threading assumptions at the top of the implementation.
     20 
     21 #ifndef MEDIA_AUDIO_LINUX_ALSA_OUTPUT_H_
     22 #define MEDIA_AUDIO_LINUX_ALSA_OUTPUT_H_
     23 
     24 #include <alsa/asoundlib.h>
     25 
     26 #include <string>
     27 
     28 #include "base/compiler_specific.h"
     29 #include "base/gtest_prod_util.h"
     30 #include "base/memory/scoped_ptr.h"
     31 #include "base/memory/weak_ptr.h"
     32 #include "base/time/time.h"
     33 #include "media/audio/audio_io.h"
     34 #include "media/audio/audio_parameters.h"
     35 
     36 namespace base {
     37 class MessageLoop;
     38 }
     39 
     40 namespace media {
     41 
     42 class AlsaWrapper;
     43 class AudioManagerLinux;
     44 class ChannelMixer;
     45 class SeekableBuffer;
     46 
     47 class MEDIA_EXPORT AlsaPcmOutputStream : public AudioOutputStream {
     48  public:
     49   // String for the generic "default" ALSA device that has the highest
     50   // compatibility and chance of working.
     51   static const char kDefaultDevice[];
     52 
     53   // Pass this to the AlsaPcmOutputStream if you want to attempt auto-selection
     54   // of the audio device.
     55   static const char kAutoSelectDevice[];
     56 
     57   // Prefix for device names to enable ALSA library resampling.
     58   static const char kPlugPrefix[];
     59 
     60   // The minimum latency that is accepted by the device.
     61   static const uint32 kMinLatencyMicros;
     62 
     63   // Create a PCM Output stream for the ALSA device identified by
     64   // |device_name|.  The AlsaPcmOutputStream uses |wrapper| to communicate with
     65   // the alsa libraries, allowing for dependency injection during testing.  All
     66   // requesting of data, and writing to the alsa device will be done on
     67   // |message_loop|.
     68   //
     69   // If unsure of what to use for |device_name|, use |kAutoSelectDevice|.
     70   AlsaPcmOutputStream(const std::string& device_name,
     71                       const AudioParameters& params,
     72                       AlsaWrapper* wrapper,
     73                       AudioManagerLinux* manager);
     74 
     75   virtual ~AlsaPcmOutputStream();
     76 
     77   // Implementation of AudioOutputStream.
     78   virtual bool Open() OVERRIDE;
     79   virtual void Close() OVERRIDE;
     80   virtual void Start(AudioSourceCallback* callback) OVERRIDE;
     81   virtual void Stop() OVERRIDE;
     82   virtual void SetVolume(double volume) OVERRIDE;
     83   virtual void GetVolume(double* volume) OVERRIDE;
     84 
     85  private:
     86   friend class AlsaPcmOutputStreamTest;
     87   FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest,
     88                            AutoSelectDevice_DeviceSelect);
     89   FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest,
     90                            AutoSelectDevice_FallbackDevices);
     91   FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, AutoSelectDevice_HintFail);
     92   FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, BufferPacket);
     93   FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, BufferPacket_Negative);
     94   FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, BufferPacket_StopStream);
     95   FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, BufferPacket_Underrun);
     96   FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, BufferPacket_FullBuffer);
     97   FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, ConstructedState);
     98   FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, LatencyFloor);
     99   FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, OpenClose);
    100   FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, PcmOpenFailed);
    101   FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, PcmSetParamsFailed);
    102   FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, ScheduleNextWrite);
    103   FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest,
    104                            ScheduleNextWrite_StopStream);
    105   FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, StartStop);
    106   FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, WritePacket_FinishedPacket);
    107   FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, WritePacket_NormalPacket);
    108   FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, WritePacket_StopStream);
    109   FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, WritePacket_WriteFails);
    110 
    111   // Flags indicating the state of the stream.
    112   enum InternalState {
    113     kInError = 0,
    114     kCreated,
    115     kIsOpened,
    116     kIsPlaying,
    117     kIsStopped,
    118     kIsClosed
    119   };
    120   friend std::ostream& operator<<(std::ostream& os, InternalState);
    121 
    122   // Functions to get another packet from the data source and write it into the
    123   // ALSA device.
    124   void BufferPacket(bool* source_exhausted);
    125   void WritePacket();
    126   void WriteTask();
    127   void ScheduleNextWrite(bool source_exhausted);
    128 
    129   // Utility functions for talking with the ALSA API.
    130   static base::TimeDelta FramesToTimeDelta(int frames, double sample_rate);
    131   std::string FindDeviceForChannels(uint32 channels);
    132   snd_pcm_sframes_t GetAvailableFrames();
    133   snd_pcm_sframes_t GetCurrentDelay();
    134 
    135   // Attempts to find the best matching linux audio device for the given number
    136   // of channels.  This function will set |device_name_| and |channel_mixer_|.
    137   snd_pcm_t* AutoSelectDevice(uint32 latency);
    138 
    139   // Functions to safeguard state transitions.  All changes to the object state
    140   // should go through these functions.
    141   bool CanTransitionTo(InternalState to);
    142   InternalState TransitionTo(InternalState to);
    143   InternalState state();
    144 
    145   // Returns true when we're on the audio thread or if the audio thread's
    146   // message loop is NULL (which will happen during shutdown).
    147   bool IsOnAudioThread() const;
    148 
    149   // API for Proxying calls to the AudioSourceCallback provided during
    150   // Start().
    151   //
    152   // TODO(ajwong): This is necessary because the ownership semantics for the
    153   // |source_callback_| object are incorrect in AudioRenderHost. The callback
    154   // is passed into the output stream, but ownership is not transfered which
    155   // requires a synchronization on access of the |source_callback_| to avoid
    156   // using a deleted callback.
    157   int RunDataCallback(AudioBus* audio_bus, AudioBuffersState buffers_state);
    158   void RunErrorCallback(int code);
    159 
    160   // Changes the AudioSourceCallback to proxy calls to.  Pass in NULL to
    161   // release ownership of the currently registered callback.
    162   void set_source_callback(AudioSourceCallback* callback);
    163 
    164   // Configuration constants from the constructor.  Referenceable by all threads
    165   // since they are constants.
    166   const std::string requested_device_name_;
    167   const snd_pcm_format_t pcm_format_;
    168   const uint32 channels_;
    169   const ChannelLayout channel_layout_;
    170   const uint32 sample_rate_;
    171   const uint32 bytes_per_sample_;
    172   const uint32 bytes_per_frame_;
    173 
    174   // Device configuration data. Populated after OpenTask() completes.
    175   std::string device_name_;
    176   uint32 packet_size_;
    177   base::TimeDelta latency_;
    178   uint32 bytes_per_output_frame_;
    179   uint32 alsa_buffer_frames_;
    180 
    181   // Flag indicating the code should stop reading from the data source or
    182   // writing to the ALSA device.  This is set because the device has entered
    183   // an unrecoverable error state, or the ClosedTask() has executed.
    184   bool stop_stream_;
    185 
    186   // Wrapper class to invoke all the ALSA functions.
    187   AlsaWrapper* wrapper_;
    188 
    189   // Audio manager that created us.  Used to report that we've been closed.
    190   AudioManagerLinux* manager_;
    191 
    192   // Message loop to use for polling. The object is owned by the AudioManager.
    193   // We hold a reference to the audio thread message loop since
    194   // AudioManagerBase::ShutDown() can invalidate the message loop pointer
    195   // before the stream gets deleted.
    196   base::MessageLoop* message_loop_;
    197 
    198   // Handle to the actual PCM playback device.
    199   snd_pcm_t* playback_handle_;
    200 
    201   scoped_ptr<media::SeekableBuffer> buffer_;
    202   uint32 frames_per_packet_;
    203 
    204   // Allows us to run tasks on the AlsaPcmOutputStream instance which are
    205   // bound by its lifetime.
    206   base::WeakPtrFactory<AlsaPcmOutputStream> weak_factory_;
    207 
    208   InternalState state_;
    209   float volume_;  // Volume level from 0.0 to 1.0.
    210 
    211   AudioSourceCallback* source_callback_;
    212 
    213   // Container for retrieving data from AudioSourceCallback::OnMoreData().
    214   scoped_ptr<AudioBus> audio_bus_;
    215 
    216   // Channel mixer and temporary bus for the final mixed channel data.
    217   scoped_ptr<ChannelMixer> channel_mixer_;
    218   scoped_ptr<AudioBus> mixed_audio_bus_;
    219 
    220   DISALLOW_COPY_AND_ASSIGN(AlsaPcmOutputStream);
    221 };
    222 
    223 MEDIA_EXPORT std::ostream& operator<<(std::ostream& os,
    224                                       AlsaPcmOutputStream::InternalState);
    225 
    226 };  // namespace media
    227 
    228 #endif  // MEDIA_AUDIO_LINUX_ALSA_OUTPUT_H_
    229