OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 // Implementation of AudioOutputStream for Windows using Windows Core Audio | 5 // Implementation of AudioOutputStream for Windows using Windows Core Audio |
6 // WASAPI for low latency rendering. | 6 // WASAPI for low latency rendering. |
7 // | 7 // |
8 // Overview of operation and performance: | 8 // Overview of operation and performance: |
9 // | 9 // |
10 // - An object of WASAPIAudioOutputStream is created by the AudioManager | 10 // - An object of WASAPIAudioOutputStream is created by the AudioManager |
11 // factory. | 11 // factory. |
12 // - Next some thread will call Open(), at that point the underlying | 12 // - Next some thread will call Open(), at that point the underlying |
13 // Core Audio APIs are utilized to create two WASAPI interfaces called | 13 // Core Audio APIs are utilized to create two WASAPI interfaces called |
14 // IAudioClient and IAudioRenderClient. | 14 // IAudioClient and IAudioRenderClient. |
15 // - Then some thread will call Start(source). | 15 // - Then some thread will call Start(source). |
16 // A thread called "wasapi_render_thread" is started and this thread listens | 16 // A thread called "wasapi_render_thread" is started and this thread listens |
17 // on an event signal which is set periodically by the audio engine to signal | 17 // on an event signal which is set periodically by the audio engine to signal |
18 // render events. As a result, OnMoreData() will be called and the registered | 18 // render events. As a result, OnMoreData() will be called and the registered |
19 // client is then expected to provide data samples to be played out. | 19 // client is then expected to provide data samples to be played out. |
20 // - At some point, a thread will call Stop(), which stops and joins the | 20 // - At some point, a thread will call Stop(), which stops and joins the |
21 // render thread and at the same time stops audio streaming. | 21 // render thread and at the same time stops audio streaming. |
22 // - The same thread that called stop will call Close() where we cleanup | 22 // - The same thread that called stop will call Close() where we cleanup |
23 // and notify the audio manager, which likely will destroy this object. | 23 // and notify the audio manager, which likely will destroy this object. |
24 // - Initial tests on Windows 7 shows that this implementation results in a | |
25 // latency of approximately 35 ms if the selected packet size is less than | |
26 // or equal to 20 ms. Using a packet size of 10 ms does not result in a | |
27 // lower latency but only affects the size of the data buffer in each | |
28 // OnMoreData() callback. | |
29 // - A total typical delay of 35 ms contains three parts: | 24 // - A total typical delay of 35 ms contains three parts: |
30 // o Audio endpoint device period (~10 ms). | 25 // o Audio endpoint device period (~10 ms). |
31 // o Stream latency between the buffer and endpoint device (~5 ms). | 26 // o Stream latency between the buffer and endpoint device (~5 ms). |
32 // o Endpoint buffer (~20 ms to ensure glitch-free rendering). | 27 // o Endpoint buffer (~20 ms to ensure glitch-free rendering). |
33 // - Note that, if the user selects a packet size of e.g. 100 ms, the total | |
34 // delay will be approximately 115 ms (10 + 5 + 100). | |
35 // | 28 // |
36 // Implementation notes: | 29 // Implementation notes: |
37 // | 30 // |
38 // - The minimum supported client is Windows Vista. | 31 // - The minimum supported client is Windows Vista. |
39 // - This implementation is single-threaded, hence: | 32 // - This implementation is single-threaded, hence: |
40 // o Construction and destruction must take place from the same thread. | 33 // o Construction and destruction must take place from the same thread. |
41 // o All APIs must be called from the creating thread as well. | 34 // o All APIs must be called from the creating thread as well. |
42 // - It is recommended to first acquire the native sample rate of the default | 35 // - It is required to first acquire the native audio parameters of the default |
43 // input device and then use the same rate when creating this object. Use | 36 // output device and then use the same rate when creating this object. Use |
44 // WASAPIAudioOutputStream::HardwareSampleRate() to retrieve the sample rate. | 37 // e.g. WASAPIAudioOutputStream::HardwareSampleRate() to retrieve the sample |
| 38 // rate. Open() will fail unless "perfect" audio parameters are utilized. |
45 // - Calling Close() also leads to self destruction. | 39 // - Calling Close() also leads to self destruction. |
46 // - Stream switching is not supported if the user shifts the audio device | |
47 // after Open() is called but before Start() has been called. | |
48 // - Stream switching can fail if streaming starts on one device with a | |
49 // supported format (X) and the new default device - to which we would like | |
50 // to switch - uses another format (Y), which is not supported given the | |
51 // configured audio parameters. | |
52 // - The audio device must be opened with the same number of channels as it | |
53 // supports natively (see HardwareChannelCount()) otherwise Open() will fail. | |
54 // - Support for 8-bit audio has not yet been verified and tested. | 40 // - Support for 8-bit audio has not yet been verified and tested. |
55 // | 41 // |
56 // Core Audio API details: | 42 // Core Audio API details: |
57 // | 43 // |
58 // - The public API methods (Open(), Start(), Stop() and Close()) must be | 44 // - The public API methods (Open(), Start(), Stop() and Close()) must be |
59 // called on constructing thread. The reason is that we want to ensure that | 45 // called on constructing thread. The reason is that we want to ensure that |
60 // the COM environment is the same for all API implementations. | 46 // the COM environment is the same for all API implementations. |
61 // - Utilized MMDevice interfaces: | 47 // - Utilized MMDevice interfaces: |
62 // o IMMDeviceEnumerator | 48 // o IMMDeviceEnumerator |
63 // o IMMDevice | 49 // o IMMDevice |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
176 // processing/mixing of shared-mode streams for the default endpoint device. | 162 // processing/mixing of shared-mode streams for the default endpoint device. |
177 int GetEndpointChannelCountForTesting() { return format_.Format.nChannels; } | 163 int GetEndpointChannelCountForTesting() { return format_.Format.nChannels; } |
178 | 164 |
179 private: | 165 private: |
180 // DelegateSimpleThread::Delegate implementation. | 166 // DelegateSimpleThread::Delegate implementation. |
181 virtual void Run() OVERRIDE; | 167 virtual void Run() OVERRIDE; |
182 | 168 |
183 // Issues the OnError() callback to the |sink_|. | 169 // Issues the OnError() callback to the |sink_|. |
184 void HandleError(HRESULT err); | 170 void HandleError(HRESULT err); |
185 | 171 |
186 // The Open() method is divided into these sub methods. | |
187 HRESULT SetRenderDevice(); | |
188 HRESULT ActivateRenderDevice(); | |
189 bool DesiredFormatIsSupported(); | |
190 HRESULT InitializeAudioEngine(); | |
191 | |
192 // Called when the device will be opened in shared mode and use the | |
193 // internal audio engine's mix format. | |
194 HRESULT SharedModeInitialization(); | |
195 | |
196 // Called when the device will be opened in exclusive mode and use the | 172 // Called when the device will be opened in exclusive mode and use the |
197 // application specified format. | 173 // application specified format. |
198 HRESULT ExclusiveModeInitialization(); | 174 // TODO(henrika): rewrite and move to CoreAudioUtil when removing flag |
| 175 // for exclusive audio mode. |
| 176 HRESULT ExclusiveModeInitialization(IAudioClient* client, |
| 177 HANDLE event_handle, |
| 178 size_t* endpoint_buffer_size); |
199 | 179 |
200 // Converts unique endpoint ID to user-friendly device name. | 180 // Fills up the endpoint rendering buffer with silence. |
201 std::string GetDeviceName(LPCWSTR device_id) const; | 181 bool FillEndpointBufferWithSilence(UINT32* num_written_frames); |
202 | 182 |
203 // Contains the thread ID of the creating thread. | 183 // Contains the thread ID of the creating thread. |
204 base::PlatformThreadId creating_thread_id_; | 184 base::PlatformThreadId creating_thread_id_; |
205 | 185 |
206 // Our creator, the audio manager needs to be notified when we close. | 186 // Our creator, the audio manager needs to be notified when we close. |
207 AudioManagerWin* manager_; | 187 AudioManagerWin* manager_; |
208 | 188 |
209 // Rendering is driven by this thread (which has no message loop). | 189 // Rendering is driven by this thread (which has no message loop). |
210 // All OnMoreData() callbacks will be called from this thread. | 190 // All OnMoreData() callbacks will be called from this thread. |
211 scoped_ptr<base::DelegateSimpleThread> render_thread_; | 191 scoped_ptr<base::DelegateSimpleThread> render_thread_; |
212 | 192 |
213 // Contains the desired audio format which is set up at construction. | 193 // Contains the desired audio format which is set up at construction. |
214 // Extended PCM waveform format structure based on WAVEFORMATEXTENSIBLE. | 194 // Extended PCM waveform format structure based on WAVEFORMATEXTENSIBLE. |
215 // Use this for multiple channel and hi-resolution PCM data. | 195 // Use this for multiple channel and hi-resolution PCM data. |
216 WAVEFORMATPCMEX format_; | 196 WAVEFORMATPCMEX format_; |
217 | 197 |
218 // Copy of the audio format which we know the audio engine supports. | 198 // Set to true when stream is successfully opened. |
219 // It is recommended to ensure that the sample rate in |format_| is identical | |
220 // to the sample rate in |audio_engine_mix_format_|. | |
221 base::win::ScopedCoMem<WAVEFORMATPCMEX> audio_engine_mix_format_; | |
222 | |
223 bool opened_; | 199 bool opened_; |
224 | 200 |
225 // Set to true as soon as a new default device is detected, and cleared when | 201 // We check if the input audio parameters are identical (bit depth is |
226 // the streaming has switched from using the old device to the new device. | 202 // excluded) to the preferred (native) audio parameters during construction. |
227 // All additional device detections during an active state are ignored to | 203 // Open() will fail if |audio_parmeters_are_valid_| is false. |
228 // ensure that the ongoing switch can finalize without disruptions. | 204 bool audio_parmeters_are_valid_; |
229 bool restart_rendering_mode_; | |
230 | 205 |
231 // Volume level from 0 to 1. | 206 // Volume level from 0 to 1. |
232 float volume_; | 207 float volume_; |
233 | 208 |
234 // Size in bytes of each audio frame (4 bytes for 16-bit stereo PCM). | |
235 size_t frame_size_; | |
236 | |
237 // Size in audio frames of each audio packet where an audio packet | 209 // Size in audio frames of each audio packet where an audio packet |
238 // is defined as the block of data which the source is expected to deliver | 210 // is defined as the block of data which the source is expected to deliver |
239 // in each OnMoreData() callback. | 211 // in each OnMoreData() callback. |
240 size_t packet_size_frames_; | 212 size_t packet_size_frames_; |
241 | 213 |
242 // Size in bytes of each audio packet. | 214 // Size in bytes of each audio packet. |
243 size_t packet_size_bytes_; | 215 size_t packet_size_bytes_; |
244 | 216 |
245 // Size in milliseconds of each audio packet. | 217 // Size in milliseconds of each audio packet. |
246 float packet_size_ms_; | 218 float packet_size_ms_; |
247 | 219 |
248 // Length of the audio endpoint buffer. | 220 // Length of the audio endpoint buffer. |
249 size_t endpoint_buffer_size_frames_; | 221 size_t endpoint_buffer_size_frames_; |
250 | 222 |
251 // Defines the role that the system has assigned to an audio endpoint device. | 223 // Defines the role that the system has assigned to an audio endpoint device. |
252 ERole device_role_; | 224 ERole device_role_; |
253 | 225 |
254 // The sharing mode for the connection. | 226 // The sharing mode for the connection. |
255 // Valid values are AUDCLNT_SHAREMODE_SHARED and AUDCLNT_SHAREMODE_EXCLUSIVE | 227 // Valid values are AUDCLNT_SHAREMODE_SHARED and AUDCLNT_SHAREMODE_EXCLUSIVE |
256 // where AUDCLNT_SHAREMODE_SHARED is the default. | 228 // where AUDCLNT_SHAREMODE_SHARED is the default. |
257 AUDCLNT_SHAREMODE share_mode_; | 229 AUDCLNT_SHAREMODE share_mode_; |
258 | 230 |
259 // The channel count set by the client in |params| which is provided to the | |
260 // constructor. The client must feed the AudioSourceCallback::OnMoreData() | |
261 // callback with PCM-data that contains this number of channels. | |
262 int client_channel_count_; | |
263 | |
264 // Counts the number of audio frames written to the endpoint buffer. | 231 // Counts the number of audio frames written to the endpoint buffer. |
265 UINT64 num_written_frames_; | 232 UINT64 num_written_frames_; |
266 | 233 |
267 // Pointer to the client that will deliver audio samples to be played out. | 234 // Pointer to the client that will deliver audio samples to be played out. |
268 AudioSourceCallback* source_; | 235 AudioSourceCallback* source_; |
269 | 236 |
270 // An IMMDeviceEnumerator interface which represents a device enumerator. | 237 // An IMMDeviceEnumerator interface which represents a device enumerator. |
271 base::win::ScopedComPtr<IMMDeviceEnumerator> device_enumerator_; | 238 base::win::ScopedComPtr<IMMDeviceEnumerator> device_enumerator_; |
272 | 239 |
273 // An IMMDevice interface which represents an audio endpoint device. | |
274 base::win::ScopedComPtr<IMMDevice> endpoint_device_; | |
275 | |
276 // An IAudioClient interface which enables a client to create and initialize | 240 // An IAudioClient interface which enables a client to create and initialize |
277 // an audio stream between an audio application and the audio engine. | 241 // an audio stream between an audio application and the audio engine. |
278 base::win::ScopedComPtr<IAudioClient> audio_client_; | 242 base::win::ScopedComPtr<IAudioClient> audio_client_; |
279 | 243 |
280 // The IAudioRenderClient interface enables a client to write output | 244 // The IAudioRenderClient interface enables a client to write output |
281 // data to a rendering endpoint buffer. | 245 // data to a rendering endpoint buffer. |
282 base::win::ScopedComPtr<IAudioRenderClient> audio_render_client_; | 246 base::win::ScopedComPtr<IAudioRenderClient> audio_render_client_; |
283 | 247 |
284 // The audio engine will signal this event each time a buffer becomes | 248 // The audio engine will signal this event each time a buffer becomes |
285 // ready to be filled by the client. | 249 // ready to be filled by the client. |
286 base::win::ScopedHandle audio_samples_render_event_; | 250 base::win::ScopedHandle audio_samples_render_event_; |
287 | 251 |
288 // This event will be signaled when rendering shall stop. | 252 // This event will be signaled when rendering shall stop. |
289 base::win::ScopedHandle stop_render_event_; | 253 base::win::ScopedHandle stop_render_event_; |
290 | 254 |
291 // Container for retrieving data from AudioSourceCallback::OnMoreData(). | 255 // Container for retrieving data from AudioSourceCallback::OnMoreData(). |
292 scoped_ptr<AudioBus> audio_bus_; | 256 scoped_ptr<AudioBus> audio_bus_; |
293 | 257 |
294 DISALLOW_COPY_AND_ASSIGN(WASAPIAudioOutputStream); | 258 DISALLOW_COPY_AND_ASSIGN(WASAPIAudioOutputStream); |
295 }; | 259 }; |
296 | 260 |
297 } // namespace media | 261 } // namespace media |
298 | 262 |
299 #endif // MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_OUTPUT_WIN_H_ | 263 #endif // MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_OUTPUT_WIN_H_ |
OLD | NEW |