Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(33)

Side by Side Diff: media/audio/linux/alsa_output.h

Issue 7117001: Simplify AlsaPcmOutputStream and AudioManagerLinux. Code was thread-safe, but now (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | media/audio/linux/alsa_output.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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_
OLDNEW
« no previous file with comments | « no previous file | media/audio/linux/alsa_output.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698