OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 // | 4 // |
5 // Creates an output stream based on the ALSA PCM interface. | 5 // Creates an output stream based on the ALSA PCM interface. |
6 // | 6 // |
7 // On device write failure, the stream will move itself to an invalid state. | 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. | 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 | 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() | 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 | 11 // will return false, and Start() will call OnError() immediately on the |
12 // provided callback. | 12 // provided callback. |
13 // | 13 // |
14 // TODO(ajwong): The OnClose() and OnError() calling needing fixing. | 14 // TODO(ajwong): The OnClose() and OnError() calling needing fixing. |
15 // | 15 // |
16 // If the stream is successfully opened, Close() must be called before the | 16 // If the stream is successfully opened, Close() must be called before the |
17 // stream is deleted as Close() is responsible for ensuring resource cleanup | 17 // stream is deleted as Close() is responsible for ensuring resource cleanup |
18 // occurs. | 18 // occurs. |
19 // | 19 // |
20 // This object's thread-safety is a little tricky. This object's public API | 20 // This object's thread-safety is a little tricky. This object's public API |
21 // can only be called from the thread that created the object. Calling the | 21 // can only be called from the thread that created the object. Calling the |
22 // public APIs in any method that may cause concurrent execution will result in | 22 // public APIs in any method that may cause concurrent execution will result in |
23 // a race condition. When modifying the code in this class, please read the | 23 // a race condition. When modifying the code in this class, please read the |
24 // threading assumptions at the top of the implementation file to avoid | 24 // threading assumptions at the top of the implementation file to avoid |
25 // introducing race conditions between tasks posted to the internal | 25 // introducing race conditions between tasks posted to the internal |
26 // message_loop, and the thread calling the public APIs. | 26 // message_loop, and the thread calling the public APIs. |
27 // | |
28 // TODO(sergeyu): AlsaPcmOutputStream is always created and used from the | |
29 // audio thread (i.e. |client_thread_loop_| and |message_loop_| always point | |
30 // to the same thread), so it doesn't need to be thread-safe anymore. | |
31 // | |
32 // TODO(sergeyu): Remove refcounter from AlsaPcmOutputStream and use | |
33 // ScopedRunnableMethodFactory to create tasks. | |
34 | 27 |
35 #ifndef MEDIA_AUDIO_LINUX_ALSA_OUTPUT_H_ | 28 #ifndef MEDIA_AUDIO_LINUX_ALSA_OUTPUT_H_ |
36 #define MEDIA_AUDIO_LINUX_ALSA_OUTPUT_H_ | 29 #define MEDIA_AUDIO_LINUX_ALSA_OUTPUT_H_ |
37 | 30 |
38 #include <alsa/asoundlib.h> | 31 #include <alsa/asoundlib.h> |
39 | 32 |
40 #include <string> | 33 #include <string> |
41 | 34 |
42 #include "base/gtest_prod_util.h" | 35 #include "base/gtest_prod_util.h" |
43 #include "base/memory/ref_counted.h" | |
44 #include "base/memory/scoped_ptr.h" | 36 #include "base/memory/scoped_ptr.h" |
45 #include "base/synchronization/lock.h" | 37 #include "base/task.h" |
46 #include "media/audio/audio_io.h" | 38 #include "media/audio/audio_io.h" |
47 #include "media/audio/audio_parameters.h" | 39 #include "media/audio/audio_parameters.h" |
48 | 40 |
49 namespace media { | 41 namespace media { |
50 class SeekableBuffer; | 42 class SeekableBuffer; |
51 }; // namespace media | 43 }; // namespace media |
52 | 44 |
53 class AlsaWrapper; | 45 class AlsaWrapper; |
54 class AudioManagerLinux; | 46 class AudioManagerLinux; |
55 class MessageLoop; | 47 class MessageLoop; |
56 | 48 |
57 class AlsaPcmOutputStream : | 49 class AlsaPcmOutputStream : public AudioOutputStream { |
58 public AudioOutputStream, | |
59 public base::RefCountedThreadSafe<AlsaPcmOutputStream> { | |
60 public: | 50 public: |
61 // String for the generic "default" ALSA device that has the highest | 51 // String for the generic "default" ALSA device that has the highest |
62 // compatibility and chance of working. | 52 // compatibility and chance of working. |
63 static const char kDefaultDevice[]; | 53 static const char kDefaultDevice[]; |
64 | 54 |
65 // Pass this to the AlsaPcmOutputStream if you want to attempt auto-selection | 55 // Pass this to the AlsaPcmOutputStream if you want to attempt auto-selection |
66 // of the audio device. | 56 // of the audio device. |
67 static const char kAutoSelectDevice[]; | 57 static const char kAutoSelectDevice[]; |
68 | 58 |
69 // Prefix for device names to enable ALSA library resampling. | 59 // Prefix for device names to enable ALSA library resampling. |
70 static const char kPlugPrefix[]; | 60 static const char kPlugPrefix[]; |
71 | 61 |
72 // The minimum latency that is accepted by the device. | 62 // The minimum latency that is accepted by the device. |
73 static const uint32 kMinLatencyMicros; | 63 static const uint32 kMinLatencyMicros; |
74 | 64 |
75 // Create a PCM Output stream for the ALSA device identified by | 65 // Create a PCM Output stream for the ALSA device identified by |
76 // |device_name|. The AlsaPcmOutputStream uses |wrapper| to communicate with | 66 // |device_name|. The AlsaPcmOutputStream uses |wrapper| to communicate with |
77 // the alsa libraries, allowing for dependency injection during testing. All | 67 // the alsa libraries, allowing for dependency injection during testing. All |
78 // requesting of data, and writing to the alsa device will be done on | 68 // requesting of data, and writing to the alsa device will be done on |
79 // |message_loop|. | 69 // |message_loop|. |
80 // | 70 // |
81 // If unsure of what to use for |device_name|, use |kAutoSelectDevice|. | 71 // If unsure of what to use for |device_name|, use |kAutoSelectDevice|. |
82 AlsaPcmOutputStream(const std::string& device_name, | 72 AlsaPcmOutputStream(const std::string& device_name, |
83 AudioParameters params, | 73 AudioParameters params, |
84 AlsaWrapper* wrapper, | 74 AlsaWrapper* wrapper, |
85 AudioManagerLinux* manager, | 75 AudioManagerLinux* manager, |
86 MessageLoop* message_loop); | 76 MessageLoop* message_loop); |
87 | 77 |
| 78 virtual ~AlsaPcmOutputStream(); |
| 79 |
88 // Implementation of AudioOutputStream. | 80 // Implementation of AudioOutputStream. |
89 virtual bool Open(); | 81 virtual bool Open(); |
90 virtual void Close(); | 82 virtual void Close(); |
91 virtual void Start(AudioSourceCallback* callback); | 83 virtual void Start(AudioSourceCallback* callback); |
92 virtual void Stop(); | 84 virtual void Stop(); |
93 virtual void SetVolume(double volume); | 85 virtual void SetVolume(double volume); |
94 virtual void GetVolume(double* volume); | 86 virtual void GetVolume(double* volume); |
95 | 87 |
96 private: | 88 private: |
97 friend class base::RefCountedThreadSafe<AlsaPcmOutputStream>; | |
98 friend class AlsaPcmOutputStreamTest; | 89 friend class AlsaPcmOutputStreamTest; |
99 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, | 90 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, |
100 AutoSelectDevice_DeviceSelect); | 91 AutoSelectDevice_DeviceSelect); |
101 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, | 92 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, |
102 AutoSelectDevice_FallbackDevices); | 93 AutoSelectDevice_FallbackDevices); |
103 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, AutoSelectDevice_HintFail); | 94 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, AutoSelectDevice_HintFail); |
104 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, BufferPacket); | 95 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, BufferPacket); |
105 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, BufferPacket_Negative); | 96 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, BufferPacket_Negative); |
106 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, BufferPacket_StopStream); | 97 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, BufferPacket_StopStream); |
107 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, BufferPacket_Underrun); | 98 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, BufferPacket_Underrun); |
108 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, BufferPacket_FullBuffer); | 99 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, BufferPacket_FullBuffer); |
109 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, ConstructedState); | 100 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, ConstructedState); |
110 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, LatencyFloor); | 101 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, LatencyFloor); |
111 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, OpenClose); | 102 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, OpenClose); |
112 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, PcmOpenFailed); | 103 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, PcmOpenFailed); |
113 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, PcmSetParamsFailed); | 104 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, PcmSetParamsFailed); |
114 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, ScheduleNextWrite); | 105 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, ScheduleNextWrite); |
115 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, | 106 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, |
116 ScheduleNextWrite_StopStream); | 107 ScheduleNextWrite_StopStream); |
117 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, StartStop); | 108 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, StartStop); |
118 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, WritePacket_FinishedPacket); | 109 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, WritePacket_FinishedPacket); |
119 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, WritePacket_NormalPacket); | 110 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, WritePacket_NormalPacket); |
120 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, WritePacket_StopStream); | 111 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, WritePacket_StopStream); |
121 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, WritePacket_WriteFails); | 112 FRIEND_TEST_ALL_PREFIXES(AlsaPcmOutputStreamTest, WritePacket_WriteFails); |
122 | 113 |
123 virtual ~AlsaPcmOutputStream(); | |
124 | |
125 // Flags indicating the state of the stream. | 114 // Flags indicating the state of the stream. |
126 enum InternalState { | 115 enum InternalState { |
127 kInError = 0, | 116 kInError = 0, |
128 kCreated, | 117 kCreated, |
129 kIsOpened, | 118 kIsOpened, |
130 kIsPlaying, | 119 kIsPlaying, |
131 kIsStopped, | 120 kIsStopped, |
132 kIsClosed | 121 kIsClosed |
133 }; | 122 }; |
134 friend std::ostream& operator<<(std::ostream& os, InternalState); | 123 friend std::ostream& operator<<(std::ostream& os, InternalState); |
(...skipping 14 matching lines...) Expand all Loading... |
149 static uint32 FramesToMicros(uint32 frames, uint32 sample_rate); | 138 static uint32 FramesToMicros(uint32 frames, uint32 sample_rate); |
150 static uint32 FramesToMillis(uint32 frames, uint32 sample_rate); | 139 static uint32 FramesToMillis(uint32 frames, uint32 sample_rate); |
151 std::string FindDeviceForChannels(uint32 channels); | 140 std::string FindDeviceForChannels(uint32 channels); |
152 snd_pcm_sframes_t GetAvailableFrames(); | 141 snd_pcm_sframes_t GetAvailableFrames(); |
153 snd_pcm_sframes_t GetCurrentDelay(); | 142 snd_pcm_sframes_t GetCurrentDelay(); |
154 | 143 |
155 // Attempts to find the best matching linux audio device for the given number | 144 // Attempts to find the best matching linux audio device for the given number |
156 // of channels. This function will set |device_name_| and |should_downmix_|. | 145 // of channels. This function will set |device_name_| and |should_downmix_|. |
157 snd_pcm_t* AutoSelectDevice(uint32 latency); | 146 snd_pcm_t* AutoSelectDevice(uint32 latency); |
158 | 147 |
159 // Thread-asserting accessors for member variables. | 148 // Functions to safeguard state transitions. All changes to the object state |
160 AudioManagerLinux* manager(); | 149 // should go through these functions. |
| 150 bool CanTransitionTo(InternalState to); |
| 151 InternalState TransitionTo(InternalState to); |
| 152 InternalState state(); |
161 | 153 |
162 // Struct holding all mutable the data that must be shared by the | 154 // API for Proxying calls to the AudioSourceCallback provided during |
163 // message_loop() and the thread that created the object. | 155 // Start(). |
164 class SharedData { | 156 // |
165 public: | 157 // TODO(ajwong): This is necessary because the ownership semantics for the |
166 explicit SharedData(MessageLoop* state_transition_loop); | 158 // |source_callback_| object are incorrect in AudioRenderHost. The callback |
| 159 // is passed into the output stream, but ownership is not transfered which |
| 160 // requires a synchronization on access of the |source_callback_| to avoid |
| 161 // using a deleted callback. |
| 162 uint32 RunDataCallback(uint8* dest, |
| 163 uint32 max_size, |
| 164 AudioBuffersState buffers_state); |
| 165 void RunErrorCallback(int code); |
167 | 166 |
168 // Functions to safeguard state transitions and ensure that transitions are | 167 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to |
169 // only allowed occuring on the thread that created the object. All | 168 // release ownership of the currently registered callback. |
170 // changes to the object state should go through these functions. | 169 void set_source_callback(AudioSourceCallback* callback); |
171 bool CanTransitionTo(InternalState to); | |
172 bool CanTransitionTo_Locked(InternalState to); | |
173 InternalState TransitionTo(InternalState to); | |
174 InternalState state(); | |
175 | |
176 float volume(); | |
177 void set_volume(float v); | |
178 | |
179 // API for Proxying calls to the AudioSourceCallback provided during | |
180 // Start(). These APIs are threadsafe. | |
181 // | |
182 // TODO(ajwong): This is necessary because the ownership semantics for the | |
183 // |source_callback_| object are incorrect in AudioRenderHost. The callback | |
184 // is passed into the output stream, but ownership is not transfered which | |
185 // requires a synchronization on access of the |source_callback_| to avoid | |
186 // using a deleted callback. | |
187 uint32 OnMoreData(AudioOutputStream* stream, uint8* dest, | |
188 uint32 max_size, AudioBuffersState buffers_state); | |
189 void OnError(AudioOutputStream* stream, int code); | |
190 | |
191 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to | |
192 // release ownership of the currently registered callback. | |
193 void set_source_callback(AudioSourceCallback* callback); | |
194 | |
195 private: | |
196 base::Lock lock_; | |
197 | |
198 InternalState state_; | |
199 float volume_; // Volume level from 0.0 to 1.0. | |
200 | |
201 AudioSourceCallback* source_callback_; | |
202 | |
203 MessageLoop* const state_transition_loop_; | |
204 | |
205 DISALLOW_COPY_AND_ASSIGN(SharedData); | |
206 } shared_data_; | |
207 | 170 |
208 // Configuration constants from the constructor. Referenceable by all threads | 171 // Configuration constants from the constructor. Referenceable by all threads |
209 // since they are constants. | 172 // since they are constants. |
210 const std::string requested_device_name_; | 173 const std::string requested_device_name_; |
211 const snd_pcm_format_t pcm_format_; | 174 const snd_pcm_format_t pcm_format_; |
212 const uint32 channels_; | 175 const uint32 channels_; |
213 const uint32 sample_rate_; | 176 const uint32 sample_rate_; |
214 const uint32 bytes_per_sample_; | 177 const uint32 bytes_per_sample_; |
215 const uint32 bytes_per_frame_; | 178 const uint32 bytes_per_frame_; |
216 | 179 |
217 // Device configuration data. Populated after OpenTask() completes. | 180 // Device configuration data. Populated after OpenTask() completes. |
218 std::string device_name_; | 181 std::string device_name_; |
219 bool should_downmix_; | 182 bool should_downmix_; |
220 uint32 packet_size_; | 183 uint32 packet_size_; |
221 uint32 micros_per_packet_; | 184 uint32 micros_per_packet_; |
222 uint32 latency_micros_; | 185 uint32 latency_micros_; |
223 uint32 bytes_per_output_frame_; | 186 uint32 bytes_per_output_frame_; |
224 uint32 alsa_buffer_frames_; | 187 uint32 alsa_buffer_frames_; |
225 | 188 |
226 // Flag indicating the code should stop reading from the data source or | 189 // Flag indicating the code should stop reading from the data source or |
227 // writing to the ALSA device. This is set because the device has entered | 190 // writing to the ALSA device. This is set because the device has entered |
228 // an unrecoverable error state, or the ClosedTask() has executed. | 191 // an unrecoverable error state, or the ClosedTask() has executed. |
229 bool stop_stream_; | 192 bool stop_stream_; |
230 | 193 |
231 // Wrapper class to invoke all the ALSA functions. | 194 // Wrapper class to invoke all the ALSA functions. |
232 AlsaWrapper* wrapper_; | 195 AlsaWrapper* wrapper_; |
233 | 196 |
234 // Audio manager that created us. Used to report that we've been closed. | 197 // Audio manager that created us. Used to report that we've been closed. |
235 // This should only be used on the |client_thread_loop_|. Access via | |
236 // the manager() function. | |
237 AudioManagerLinux* manager_; | 198 AudioManagerLinux* manager_; |
238 | 199 |
239 // Handle to the actual PCM playback device. | 200 // Handle to the actual PCM playback device. |
240 snd_pcm_t* playback_handle_; | 201 snd_pcm_t* playback_handle_; |
241 | 202 |
242 scoped_ptr<media::SeekableBuffer> buffer_; | 203 scoped_ptr<media::SeekableBuffer> buffer_; |
243 uint32 frames_per_packet_; | 204 uint32 frames_per_packet_; |
244 | 205 |
245 // Used to check which message loop is allowed to call the public APIs. | |
246 MessageLoop* client_thread_loop_; | |
247 | |
248 // The message loop responsible for querying the data source, and writing to | 206 // The message loop responsible for querying the data source, and writing to |
249 // the output device. | 207 // the output device. |
250 MessageLoop* message_loop_; | 208 MessageLoop* message_loop_; |
251 | 209 |
| 210 // Allows us to run tasks on the AlsaPcmOutputStream instance which are |
| 211 // bound by its lifetime. |
| 212 ScopedRunnableMethodFactory<AlsaPcmOutputStream> method_factory_; |
| 213 |
| 214 InternalState state_; |
| 215 float volume_; // Volume level from 0.0 to 1.0. |
| 216 |
| 217 AudioSourceCallback* source_callback_; |
| 218 |
252 DISALLOW_COPY_AND_ASSIGN(AlsaPcmOutputStream); | 219 DISALLOW_COPY_AND_ASSIGN(AlsaPcmOutputStream); |
253 }; | 220 }; |
254 | 221 |
255 #endif // MEDIA_AUDIO_LINUX_ALSA_OUTPUT_H_ | 222 #endif // MEDIA_AUDIO_LINUX_ALSA_OUTPUT_H_ |
OLD | NEW |