• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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_ALSA_ALSA_OUTPUT_H_
22 #define MEDIA_AUDIO_ALSA_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 AudioManagerBase;
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                       AudioManagerBase* 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   AudioManagerBase* 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_ALSA_ALSA_OUTPUT_H_
229