| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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_ |
| OLD | NEW |