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
36namespace base {
37class MessageLoop;
38}
39
40namespace media {
41
42class AlsaWrapper;
43class AudioManagerBase;
44class ChannelMixer;
45class SeekableBuffer;
46
47class 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
223MEDIA_EXPORT std::ostream& operator<<(std::ostream& os,
224                                      AlsaPcmOutputStream::InternalState);
225
226};  // namespace media
227
228#endif  // MEDIA_AUDIO_ALSA_ALSA_OUTPUT_H_
229