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