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

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

Issue 275022: Move Alsa device opening into the audio thread, and add in support for multi-channel audio. (Closed)
Patch Set: Fix up the unittests since we not only downmix for a very small set of channels. Created 11 years, 2 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
« 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) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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()
(...skipping 28 matching lines...) Expand all
39 #include "media/audio/audio_output.h" 39 #include "media/audio/audio_output.h"
40 #include "testing/gtest/include/gtest/gtest_prod.h" 40 #include "testing/gtest/include/gtest/gtest_prod.h"
41 41
42 class AlsaWrapper; 42 class AlsaWrapper;
43 class AudioManagerLinux; 43 class AudioManagerLinux;
44 44
45 class AlsaPcmOutputStream : 45 class AlsaPcmOutputStream :
46 public AudioOutputStream, 46 public AudioOutputStream,
47 public base::RefCountedThreadSafe<AlsaPcmOutputStream> { 47 public base::RefCountedThreadSafe<AlsaPcmOutputStream> {
48 public: 48 public:
49 // Set to "default" which should avoid locking the sound device and allow 49 // String for the generic "default" ALSA device that has the highest
50 // ALSA to multiplex sound from different processes that want to write PCM 50 // compatibility and chance of working.
51 // data.
52 static const char kDefaultDevice[]; 51 static const char kDefaultDevice[];
53 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 int kMinLatencyMicros;
62
54 // Create a PCM Output stream for the ALSA device identified by 63 // Create a PCM Output stream for the ALSA device identified by
55 // |device_name|. The AlsaPcmOutputStream uses |wrapper| to communicate with 64 // |device_name|. The AlsaPcmOutputStream uses |wrapper| to communicate with
56 // the alsa libraries, allowing for dependency injection during testing. All 65 // the alsa libraries, allowing for dependency injection during testing. All
57 // requesting of data, and writing to the alsa device will be done on 66 // requesting of data, and writing to the alsa device will be done on
58 // |message_loop|. 67 // |message_loop|.
59 // 68 //
60 // If unsure of what to use for |device_name|, use |kDefaultDevice|. 69 // If unsure of what to use for |device_name|, use |kAutoSelectDevice|.
61 AlsaPcmOutputStream(const std::string& device_name, 70 AlsaPcmOutputStream(const std::string& device_name,
62 AudioManager::Format format, 71 AudioManager::Format format,
63 int channels, 72 int channels,
64 int sample_rate, 73 int sample_rate,
65 int bits_per_sample, 74 int bits_per_sample,
66 AlsaWrapper* wrapper, 75 AlsaWrapper* wrapper,
67 AudioManagerLinux* manager, 76 AudioManagerLinux* manager,
68 MessageLoop* message_loop); 77 MessageLoop* message_loop);
69 virtual ~AlsaPcmOutputStream(); 78 virtual ~AlsaPcmOutputStream();
70 79
71 // Implementation of AudioOutputStream. 80 // Implementation of AudioOutputStream.
72 virtual bool Open(size_t packet_size); 81 virtual bool Open(size_t packet_size);
73 virtual void Close(); 82 virtual void Close();
74 virtual void Start(AudioSourceCallback* callback); 83 virtual void Start(AudioSourceCallback* callback);
75 virtual void Stop(); 84 virtual void Stop();
76 virtual void SetVolume(double left_level, double right_level); 85 virtual void SetVolume(double left_level, double right_level);
77 virtual void GetVolume(double* left_level, double* right_level); 86 virtual void GetVolume(double* left_level, double* right_level);
78 87
79 private: 88 private:
80 friend class AlsaPcmOutputStreamTest; 89 friend class AlsaPcmOutputStreamTest;
90 FRIEND_TEST(AlsaPcmOutputStreamTest, AutoSelectDevice_DeviceSelect);
91 FRIEND_TEST(AlsaPcmOutputStreamTest, AutoSelectDevice_FallbackDevices);
92 FRIEND_TEST(AlsaPcmOutputStreamTest, AutoSelectDevice_HintFail);
81 FRIEND_TEST(AlsaPcmOutputStreamTest, BufferPacket); 93 FRIEND_TEST(AlsaPcmOutputStreamTest, BufferPacket);
82 FRIEND_TEST(AlsaPcmOutputStreamTest, BufferPacket_StopStream); 94 FRIEND_TEST(AlsaPcmOutputStreamTest, BufferPacket_StopStream);
83 FRIEND_TEST(AlsaPcmOutputStreamTest, BufferPacket_UnfinishedPacket); 95 FRIEND_TEST(AlsaPcmOutputStreamTest, BufferPacket_UnfinishedPacket);
84 FRIEND_TEST(AlsaPcmOutputStreamTest, ConstructedState); 96 FRIEND_TEST(AlsaPcmOutputStreamTest, ConstructedState);
97 FRIEND_TEST(AlsaPcmOutputStreamTest, LatencyFloor);
85 FRIEND_TEST(AlsaPcmOutputStreamTest, OpenClose); 98 FRIEND_TEST(AlsaPcmOutputStreamTest, OpenClose);
86 FRIEND_TEST(AlsaPcmOutputStreamTest, PcmOpenFailed); 99 FRIEND_TEST(AlsaPcmOutputStreamTest, PcmOpenFailed);
87 FRIEND_TEST(AlsaPcmOutputStreamTest, PcmSetParamsFailed); 100 FRIEND_TEST(AlsaPcmOutputStreamTest, PcmSetParamsFailed);
88 FRIEND_TEST(AlsaPcmOutputStreamTest, ScheduleNextWrite); 101 FRIEND_TEST(AlsaPcmOutputStreamTest, ScheduleNextWrite);
89 FRIEND_TEST(AlsaPcmOutputStreamTest, ScheduleNextWrite_StopStream); 102 FRIEND_TEST(AlsaPcmOutputStreamTest, ScheduleNextWrite_StopStream);
90 FRIEND_TEST(AlsaPcmOutputStreamTest, StartStop); 103 FRIEND_TEST(AlsaPcmOutputStreamTest, StartStop);
91 FRIEND_TEST(AlsaPcmOutputStreamTest, WritePacket_FinishedPacket); 104 FRIEND_TEST(AlsaPcmOutputStreamTest, WritePacket_FinishedPacket);
92 FRIEND_TEST(AlsaPcmOutputStreamTest, WritePacket_NormalPacket); 105 FRIEND_TEST(AlsaPcmOutputStreamTest, WritePacket_NormalPacket);
93 FRIEND_TEST(AlsaPcmOutputStreamTest, WritePacket_StopStream); 106 FRIEND_TEST(AlsaPcmOutputStreamTest, WritePacket_StopStream);
94 FRIEND_TEST(AlsaPcmOutputStreamTest, WritePacket_WriteFails); 107 FRIEND_TEST(AlsaPcmOutputStreamTest, WritePacket_WriteFails);
(...skipping 19 matching lines...) Expand all
114 kInError = 0, 127 kInError = 0,
115 kCreated, 128 kCreated,
116 kIsOpened, 129 kIsOpened,
117 kIsPlaying, 130 kIsPlaying,
118 kIsStopped, 131 kIsStopped,
119 kIsClosed 132 kIsClosed
120 }; 133 };
121 friend std::ostream& ::operator<<(std::ostream& os, InternalState); 134 friend std::ostream& ::operator<<(std::ostream& os, InternalState);
122 135
123 // Various tasks that complete actions started in the public API. 136 // Various tasks that complete actions started in the public API.
124 void FinishOpen(snd_pcm_t* playback_handle, size_t packet_size); 137 void OpenTask(size_t packet_size);
125 void StartTask(); 138 void StartTask();
126 void CloseTask(); 139 void CloseTask();
127 140
128 // Functions to get another packet from the data source and write it into the 141 // Functions to get another packet from the data source and write it into the
129 // ALSA device. 142 // ALSA device.
130 void BufferPacket(Packet* packet); 143 void BufferPacket(Packet* packet);
131 void WritePacket(Packet* packet); 144 void WritePacket(Packet* packet);
132 void WriteTask(); 145 void WriteTask();
133 void ScheduleNextWrite(Packet* current_packet); 146 void ScheduleNextWrite(Packet* current_packet);
134 147
135 // Utility functions for talking with the ALSA API. 148 // Utility functions for talking with the ALSA API.
136 static snd_pcm_sframes_t FramesInPacket(const Packet& packet, 149 static snd_pcm_sframes_t FramesInPacket(const Packet& packet,
137 int bytes_per_frame); 150 int bytes_per_frame);
138 static int64 FramesToMicros(int frames, int sample_rate); 151 static int64 FramesToMicros(int frames, int sample_rate);
139 static int64 FramesToMillis(int frames, int sample_rate); 152 static int64 FramesToMillis(int frames, int sample_rate);
153 std::string FindDeviceForChannels(int channels);
154 snd_pcm_t* OpenDevice(const std::string& device_name,
155 int channels,
156 unsigned int latency);
140 bool CloseDevice(snd_pcm_t* handle); 157 bool CloseDevice(snd_pcm_t* handle);
141 snd_pcm_sframes_t GetAvailableFrames(); 158 snd_pcm_sframes_t GetAvailableFrames();
142 159
160 // Attempts to find the best matching linux audio device for the given number
161 // of channels. This function will set |device_name_| and |should_downmix_|.
162 snd_pcm_t* AutoSelectDevice(unsigned int latency);
163
143 // Thread-asserting accessors for member variables. 164 // Thread-asserting accessors for member variables.
144 AudioManagerLinux* manager(); 165 AudioManagerLinux* manager();
145 166
146 // Struct holding all mutable the data that must be shared by the 167 // Struct holding all mutable the data that must be shared by the
147 // message_loop() and the thread that created the object. 168 // message_loop() and the thread that created the object.
148 class SharedData { 169 class SharedData {
149 public: 170 public:
150 explicit SharedData(MessageLoop* state_transition_loop); 171 explicit SharedData(MessageLoop* state_transition_loop);
151 172
152 // Functions to safeguard state transitions and ensure that transitions are 173 // Functions to safeguard state transitions and ensure that transitions are
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
185 206
186 AudioSourceCallback* source_callback_; 207 AudioSourceCallback* source_callback_;
187 208
188 MessageLoop* const state_transition_loop_; 209 MessageLoop* const state_transition_loop_;
189 210
190 DISALLOW_COPY_AND_ASSIGN(SharedData); 211 DISALLOW_COPY_AND_ASSIGN(SharedData);
191 } shared_data_; 212 } shared_data_;
192 213
193 // Configuration constants from the constructor. Referenceable by all threads 214 // Configuration constants from the constructor. Referenceable by all threads
194 // since they are constants. 215 // since they are constants.
195 const std::string device_name_; 216 const std::string requested_device_name_;
196 const snd_pcm_format_t pcm_format_; 217 const snd_pcm_format_t pcm_format_;
197 const int channels_; 218 const int channels_;
198 const int sample_rate_; 219 const int sample_rate_;
199 const int bytes_per_sample_; 220 const int bytes_per_sample_;
200 const int bytes_per_frame_; 221 const int bytes_per_frame_;
201 222
223 // Device configuration data. Populated after OpenTask() completes.
224 std::string device_name_;
225 bool should_downmix_;
226 int latency_micros_;
227 int micros_per_packet_;
228 int bytes_per_output_frame_;
229
202 // Flag indicating the code should stop reading from the data source or 230 // Flag indicating the code should stop reading from the data source or
203 // writing to the ALSA device. This is set because the device has entered 231 // writing to the ALSA device. This is set because the device has entered
204 // an unrecoverable error state, or the ClosedTask() has executed. 232 // an unrecoverable error state, or the ClosedTask() has executed.
205 bool stop_stream_; 233 bool stop_stream_;
206 234
207 // Wrapper class to invoke all the ALSA functions. 235 // Wrapper class to invoke all the ALSA functions.
208 AlsaWrapper* wrapper_; 236 AlsaWrapper* wrapper_;
209 237
210 // Audio manager that created us. Used to report that we've been closed. 238 // Audio manager that created us. Used to report that we've been closed.
211 // This should only be used on the |client_thread_loop_|. Access via 239 // This should only be used on the |client_thread_loop_|. Access via
(...skipping 10 matching lines...) Expand all
222 MessageLoop* client_thread_loop_; 250 MessageLoop* client_thread_loop_;
223 251
224 // The message loop responsible for querying the data source, and writing to 252 // The message loop responsible for querying the data source, and writing to
225 // the output device. 253 // the output device.
226 MessageLoop* message_loop_; 254 MessageLoop* message_loop_;
227 255
228 DISALLOW_COPY_AND_ASSIGN(AlsaPcmOutputStream); 256 DISALLOW_COPY_AND_ASSIGN(AlsaPcmOutputStream);
229 }; 257 };
230 258
231 #endif // MEDIA_AUDIO_LINUX_ALSA_OUTPUT_H_ 259 #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