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 17 matching lines...) Expand all Loading... | |
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 // Thread-asserting accessors for member variables. |
160 AudioManagerLinux* manager(); | 149 AudioManagerLinux* manager(); |
161 | 150 |
162 // Struct holding all mutable the data that must be shared by the | 151 // Functions to safeguard state transitions. All changes to the object state |
163 // message_loop() and the thread that created the object. | 152 // should go through these functions. |
164 class SharedData { | 153 bool CanTransitionTo(InternalState to); |
165 public: | 154 InternalState TransitionTo(InternalState to); |
166 explicit SharedData(MessageLoop* state_transition_loop); | 155 InternalState state(); |
167 | 156 |
168 // Functions to safeguard state transitions and ensure that transitions are | 157 float volume(); |
169 // only allowed occuring on the thread that created the object. All | 158 void set_volume(float v); |
170 // changes to the object state should go through these functions. | |
171 bool CanTransitionTo(InternalState to); | |
172 bool CanTransitionTo_Locked(InternalState to); | |
173 InternalState TransitionTo(InternalState to); | |
174 InternalState state(); | |
175 | 159 |
176 float volume(); | 160 // API for Proxying calls to the AudioSourceCallback provided during |
177 void set_volume(float v); | 161 // Start(). These APIs are threadsafe. |
162 // | |
163 // TODO(ajwong): This is necessary because the ownership semantics for the | |
164 // |source_callback_| object are incorrect in AudioRenderHost. The callback | |
165 // is passed into the output stream, but ownership is not transfered which | |
166 // requires a synchronization on access of the |source_callback_| to avoid | |
167 // using a deleted callback. | |
168 uint32 OnMoreData(AudioOutputStream* stream, uint8* dest, | |
169 uint32 max_size, AudioBuffersState buffers_state); | |
170 void OnError(AudioOutputStream* stream, int code); | |
178 | 171 |
179 // API for Proxying calls to the AudioSourceCallback provided during | 172 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to |
180 // Start(). These APIs are threadsafe. | 173 // release ownership of the currently registered callback. |
181 // | 174 void set_source_callback(AudioSourceCallback* callback); |
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 | 175 |
208 // Configuration constants from the constructor. Referenceable by all threads | 176 // Configuration constants from the constructor. Referenceable by all threads |
209 // since they are constants. | 177 // since they are constants. |
210 const std::string requested_device_name_; | 178 const std::string requested_device_name_; |
211 const snd_pcm_format_t pcm_format_; | 179 const snd_pcm_format_t pcm_format_; |
212 const uint32 channels_; | 180 const uint32 channels_; |
213 const uint32 sample_rate_; | 181 const uint32 sample_rate_; |
214 const uint32 bytes_per_sample_; | 182 const uint32 bytes_per_sample_; |
215 const uint32 bytes_per_frame_; | 183 const uint32 bytes_per_frame_; |
216 | 184 |
217 // Device configuration data. Populated after OpenTask() completes. | 185 // Device configuration data. Populated after OpenTask() completes. |
218 std::string device_name_; | 186 std::string device_name_; |
219 bool should_downmix_; | 187 bool should_downmix_; |
220 uint32 packet_size_; | 188 uint32 packet_size_; |
221 uint32 micros_per_packet_; | 189 uint32 micros_per_packet_; |
222 uint32 latency_micros_; | 190 uint32 latency_micros_; |
223 uint32 bytes_per_output_frame_; | 191 uint32 bytes_per_output_frame_; |
224 uint32 alsa_buffer_frames_; | 192 uint32 alsa_buffer_frames_; |
225 | 193 |
226 // Flag indicating the code should stop reading from the data source or | 194 // 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 | 195 // writing to the ALSA device. This is set because the device has entered |
228 // an unrecoverable error state, or the ClosedTask() has executed. | 196 // an unrecoverable error state, or the ClosedTask() has executed. |
229 bool stop_stream_; | 197 bool stop_stream_; |
230 | 198 |
231 // Wrapper class to invoke all the ALSA functions. | 199 // Wrapper class to invoke all the ALSA functions. |
232 AlsaWrapper* wrapper_; | 200 AlsaWrapper* wrapper_; |
233 | 201 |
234 // Audio manager that created us. Used to report that we've been closed. | 202 // 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 | 203 // This should only be used on the |client_thread_loop_|. Access via |
scherkus (not reviewing)
2011/06/07 00:19:01
comment is out of date
enal
2011/06/07 17:29:00
Done.
| |
236 // the manager() function. | 204 // the manager() function. |
237 AudioManagerLinux* manager_; | 205 AudioManagerLinux* manager_; |
238 | 206 |
239 // Handle to the actual PCM playback device. | 207 // Handle to the actual PCM playback device. |
240 snd_pcm_t* playback_handle_; | 208 snd_pcm_t* playback_handle_; |
241 | 209 |
242 scoped_ptr<media::SeekableBuffer> buffer_; | 210 scoped_ptr<media::SeekableBuffer> buffer_; |
243 uint32 frames_per_packet_; | 211 uint32 frames_per_packet_; |
244 | 212 |
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 | 213 // The message loop responsible for querying the data source, and writing to |
249 // the output device. | 214 // the output device. |
250 MessageLoop* message_loop_; | 215 MessageLoop* message_loop_; |
251 | 216 |
217 // Allows us to run tasks on the AlsaPcmOutputStream instance which are | |
218 // bound by its lifetime. | |
219 ScopedRunnableMethodFactory<AlsaPcmOutputStream> method_factory_; | |
220 | |
221 InternalState state_; | |
222 float volume_; // Volume level from 0.0 to 1.0. | |
223 | |
224 AudioSourceCallback* source_callback_; | |
225 | |
252 DISALLOW_COPY_AND_ASSIGN(AlsaPcmOutputStream); | 226 DISALLOW_COPY_AND_ASSIGN(AlsaPcmOutputStream); |
253 }; | 227 }; |
254 | 228 |
255 #endif // MEDIA_AUDIO_LINUX_ALSA_OUTPUT_H_ | 229 #endif // MEDIA_AUDIO_LINUX_ALSA_OUTPUT_H_ |
OLD | NEW |