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 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
65 // - It is recommended to first acquire the native sample rate of the default | 65 // - It is recommended to first acquire the native sample rate of the default |
66 // input device and then use the same rate when creating this object. Use | 66 // input device and then use the same rate when creating this object. Use |
67 // WASAPIAudioOutputStream::HardwareSampleRate() to retrieve the sample rate. | 67 // WASAPIAudioOutputStream::HardwareSampleRate() to retrieve the sample rate. |
68 // - Calling Close() also leads to self destruction. | 68 // - Calling Close() also leads to self destruction. |
69 // - Stream switching is not supported if the user shifts the audio device | 69 // - Stream switching is not supported if the user shifts the audio device |
70 // after Open() is called but before Start() has been called. | 70 // after Open() is called but before Start() has been called. |
71 // - Stream switching can fail if streaming starts on one device with a | 71 // - Stream switching can fail if streaming starts on one device with a |
72 // supported format (X) and the new default device - to which we would like | 72 // supported format (X) and the new default device - to which we would like |
73 // to switch - uses another format (Y), which is not supported given the | 73 // to switch - uses another format (Y), which is not supported given the |
74 // configured audio parameters. | 74 // configured audio parameters. |
| 75 // - The audio device is always opened with the same number of channels as |
| 76 // it supports natively (see HardwareChannelCount()). Channel up-mixing will |
| 77 // take place if the |params| parameter in the constructor contains a lower |
| 78 // number of channels than the number of native channels. As an example: if |
| 79 // the clients provides a channel count of 2 and a 7.1 headset is detected, |
| 80 // then 2 -> 7.1 up-mixing will take place for each OnMoreData() callback. |
| 81 // - Channel down-mixing is currently not supported. It is possible to create |
| 82 // an instance for this case but calls to Open() will fail. |
| 83 // - Support for 8-bit audio has not yet been verified and tested. |
| 84 // - Open() will fail if channel up-mixing is done for 8-bit audio. |
| 85 // - Supported channel up-mixing cases (client config -> endpoint config): |
| 86 // o 1 -> 2 |
| 87 // o 1 -> 7.1 |
| 88 // o 2 -> 5.1 |
| 89 // o 2 -> 7.1 |
75 // | 90 // |
76 // Core Audio API details: | 91 // Core Audio API details: |
77 // | 92 // |
78 // - CoInitializeEx() is called on the creating thread and on the internal | 93 // - CoInitializeEx() is called on the creating thread and on the internal |
79 // capture thread. Each thread's concurrency model and apartment is set | 94 // capture thread. Each thread's concurrency model and apartment is set |
80 // to multi-threaded (MTA). CHECK() is called to ensure that we crash if | 95 // to multi-threaded (MTA). CHECK() is called to ensure that we crash if |
81 // CoInitializeEx(MTA) fails. | 96 // CoInitializeEx(MTA) fails. |
82 // - The public API methods (Open(), Start(), Stop() and Close()) must be | 97 // - The public API methods (Open(), Start(), Stop() and Close()) must be |
83 // called on constructing thread. The reason is that we want to ensure that | 98 // called on constructing thread. The reason is that we want to ensure that |
84 // the COM environment is the same for all API implementations. | 99 // the COM environment is the same for all API implementations. |
(...skipping 23 matching lines...) Expand all Loading... |
108 // - Audio rendering is performed on the audio render thread, owned by this | 123 // - Audio rendering is performed on the audio render thread, owned by this |
109 // class, and the AudioSourceCallback::OnMoreData() method will be called | 124 // class, and the AudioSourceCallback::OnMoreData() method will be called |
110 // from this thread. Stream switching also takes place on the audio-render | 125 // from this thread. Stream switching also takes place on the audio-render |
111 // thread. | 126 // thread. |
112 // - All callback methods from the IMMNotificationClient interface will be | 127 // - All callback methods from the IMMNotificationClient interface will be |
113 // called on a Windows-internal MMDevice thread. | 128 // called on a Windows-internal MMDevice thread. |
114 // | 129 // |
115 // Experimental exclusive mode: | 130 // Experimental exclusive mode: |
116 // | 131 // |
117 // - It is possible to open up a stream in exclusive mode by using the | 132 // - It is possible to open up a stream in exclusive mode by using the |
118 // --enable-exclusive-mode command line flag. | 133 // --enable-exclusive-audio command line flag. |
119 // - The internal buffering scheme is less flexible for exclusive streams. | 134 // - The internal buffering scheme is less flexible for exclusive streams. |
120 // Hence, some manual tuning will be required before deciding what frame | 135 // Hence, some manual tuning will be required before deciding what frame |
121 // size to use. See the WinAudioOutputTest unit test for more details. | 136 // size to use. See the WinAudioOutputTest unit test for more details. |
122 // - If an application opens a stream in exclusive mode, the application has | 137 // - If an application opens a stream in exclusive mode, the application has |
123 // exclusive use of the audio endpoint device that plays the stream. | 138 // exclusive use of the audio endpoint device that plays the stream. |
124 // - Exclusive-mode should only be utilized when the lowest possible latency | 139 // - Exclusive-mode should only be utilized when the lowest possible latency |
125 // is important. | 140 // is important. |
126 // - In exclusive mode, the client can choose to open the stream in any audio | 141 // - In exclusive mode, the client can choose to open the stream in any audio |
127 // format that the endpoint device supports, i.e. not limited to the device's | 142 // format that the endpoint device supports, i.e. not limited to the device's |
128 // current (default) configuration. | 143 // current (default) configuration. |
129 // - Initial measurements on Windows 7 (HP Z600 workstation) have shown that | 144 // - Initial measurements on Windows 7 (HP Z600 workstation) have shown that |
130 // the lowest possible latencies we can achieve on this machine are: | 145 // the lowest possible latencies we can achieve on this machine are: |
131 // o ~3.3333ms @ 48kHz <=> 160 audio frames per buffer. | 146 // o ~3.3333ms @ 48kHz <=> 160 audio frames per buffer. |
132 // o ~3.6281ms @ 44.1kHz <=> 160 audio frames per buffer. | 147 // o ~3.6281ms @ 44.1kHz <=> 160 audio frames per buffer. |
133 // - See http://msdn.microsoft.com/en-us/library/windows/desktop/dd370844(v=vs.8
5).aspx | 148 // - See http://msdn.microsoft.com/en-us/library/windows/desktop/dd370844(v=vs.8
5).aspx |
134 // for more details. | 149 // for more details. |
135 | 150 |
136 #ifndef MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_OUTPUT_WIN_H_ | 151 #ifndef MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_OUTPUT_WIN_H_ |
137 #define MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_OUTPUT_WIN_H_ | 152 #define MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_OUTPUT_WIN_H_ |
138 | 153 |
139 #include <Audioclient.h> | 154 #include <Audioclient.h> |
140 #include <audiopolicy.h> | 155 #include <audiopolicy.h> |
141 #include <MMDeviceAPI.h> | 156 #include <MMDeviceAPI.h> |
142 | 157 |
143 #include <string> | 158 #include <string> |
144 | 159 |
145 #include "base/compiler_specific.h" | 160 #include "base/compiler_specific.h" |
| 161 #include "base/gtest_prod_util.h" |
146 #include "base/threading/platform_thread.h" | 162 #include "base/threading/platform_thread.h" |
147 #include "base/threading/simple_thread.h" | 163 #include "base/threading/simple_thread.h" |
148 #include "base/win/scoped_co_mem.h" | 164 #include "base/win/scoped_co_mem.h" |
149 #include "base/win/scoped_com_initializer.h" | 165 #include "base/win/scoped_com_initializer.h" |
150 #include "base/win/scoped_comptr.h" | 166 #include "base/win/scoped_comptr.h" |
151 #include "base/win/scoped_handle.h" | 167 #include "base/win/scoped_handle.h" |
152 #include "media/audio/audio_io.h" | 168 #include "media/audio/audio_io.h" |
153 #include "media/audio/audio_parameters.h" | 169 #include "media/audio/audio_parameters.h" |
154 #include "media/base/media_export.h" | 170 #include "media/base/media_export.h" |
155 | 171 |
(...skipping 19 matching lines...) Expand all Loading... |
175 virtual ~WASAPIAudioOutputStream(); | 191 virtual ~WASAPIAudioOutputStream(); |
176 | 192 |
177 // Implementation of AudioOutputStream. | 193 // Implementation of AudioOutputStream. |
178 virtual bool Open() OVERRIDE; | 194 virtual bool Open() OVERRIDE; |
179 virtual void Start(AudioSourceCallback* callback) OVERRIDE; | 195 virtual void Start(AudioSourceCallback* callback) OVERRIDE; |
180 virtual void Stop() OVERRIDE; | 196 virtual void Stop() OVERRIDE; |
181 virtual void Close() OVERRIDE; | 197 virtual void Close() OVERRIDE; |
182 virtual void SetVolume(double volume) OVERRIDE; | 198 virtual void SetVolume(double volume) OVERRIDE; |
183 virtual void GetVolume(double* volume) OVERRIDE; | 199 virtual void GetVolume(double* volume) OVERRIDE; |
184 | 200 |
185 // Retrieves the stream format that the audio engine uses for its internal | 201 // Retrieves the number of channels the audio engine uses for its internal |
186 // processing/mixing of shared-mode streams. | 202 // processing/mixing of shared-mode streams for the default endpoint device. |
187 // This method should not be used in combination with exclusive-mode streams. | 203 static int HardwareChannelCount(); |
| 204 |
| 205 // Retrieves the channel layout the audio engine uses for its internal |
| 206 // processing/mixing of shared-mode streams for the default endpoint device. |
| 207 // Note that we convert an internal channel layout mask (see ChannelMask()) |
| 208 // into a Chrome-specific channel layout enumerator in this method, hence |
| 209 // the match might not be perfect. |
| 210 static ChannelLayout HardwareChannelLayout(); |
| 211 |
| 212 // Retrieves the sample rate the audio engine uses for its internal |
| 213 // processing/mixing of shared-mode streams for the default endpoint device. |
188 static int HardwareSampleRate(ERole device_role); | 214 static int HardwareSampleRate(ERole device_role); |
189 | 215 |
190 // Returns AUDCLNT_SHAREMODE_EXCLUSIVE if --enable-exclusive-mode is used | 216 // Returns AUDCLNT_SHAREMODE_EXCLUSIVE if --enable-exclusive-mode is used |
191 // as command-line flag and AUDCLNT_SHAREMODE_SHARED otherwise (default). | 217 // as command-line flag and AUDCLNT_SHAREMODE_SHARED otherwise (default). |
192 static AUDCLNT_SHAREMODE GetShareMode(); | 218 static AUDCLNT_SHAREMODE GetShareMode(); |
193 | 219 |
194 bool started() const { return started_; } | 220 bool started() const { return started_; } |
195 | 221 |
196 private: | 222 private: |
| 223 FRIEND_TEST_ALL_PREFIXES(WASAPIAudioOutputStreamTest, HardwareChannelCount); |
| 224 |
197 // Implementation of IUnknown (trivial in this case). See | 225 // Implementation of IUnknown (trivial in this case). See |
198 // msdn.microsoft.com/en-us/library/windows/desktop/dd371403(v=vs.85).aspx | 226 // msdn.microsoft.com/en-us/library/windows/desktop/dd371403(v=vs.85).aspx |
199 // for details regarding why proper implementations of AddRef(), Release() | 227 // for details regarding why proper implementations of AddRef(), Release() |
200 // and QueryInterface() are not needed here. | 228 // and QueryInterface() are not needed here. |
201 STDMETHOD_(ULONG, AddRef)(); | 229 STDMETHOD_(ULONG, AddRef)(); |
202 STDMETHOD_(ULONG, Release)(); | 230 STDMETHOD_(ULONG, Release)(); |
203 STDMETHOD(QueryInterface)(REFIID iid, void** object); | 231 STDMETHOD(QueryInterface)(REFIID iid, void** object); |
204 | 232 |
205 // Implementation of the abstract interface IMMNotificationClient. | 233 // Implementation of the abstract interface IMMNotificationClient. |
206 // Provides notifications when an audio endpoint device is added or removed, | 234 // Provides notifications when an audio endpoint device is added or removed, |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
248 // Converts unique endpoint ID to user-friendly device name. | 276 // Converts unique endpoint ID to user-friendly device name. |
249 std::string GetDeviceName(LPCWSTR device_id) const; | 277 std::string GetDeviceName(LPCWSTR device_id) const; |
250 | 278 |
251 // Called on the audio render thread when the current audio stream must | 279 // Called on the audio render thread when the current audio stream must |
252 // be re-initialized because the default audio device has changed. This | 280 // be re-initialized because the default audio device has changed. This |
253 // method: stops the current renderer, releases and re-creates all WASAPI | 281 // method: stops the current renderer, releases and re-creates all WASAPI |
254 // interfaces, creates a new IMMDevice and re-starts rendering using the | 282 // interfaces, creates a new IMMDevice and re-starts rendering using the |
255 // new default audio device. | 283 // new default audio device. |
256 bool RestartRenderingUsingNewDefaultDevice(); | 284 bool RestartRenderingUsingNewDefaultDevice(); |
257 | 285 |
258 AUDCLNT_SHAREMODE share_mode() const { return share_mode_; } | 286 // Returns the number of channels the audio engine uses for its internal |
| 287 // processing/mixing of shared-mode streams for the default endpoint device. |
| 288 int endpoint_channel_count() { return format_.Format.nChannels; } |
| 289 |
| 290 // The ratio between the the number of native audio channels used by the |
| 291 // audio device and the number of audio channels from the client. |
| 292 // TODO(henrika): using int as indicator of the required type of channel |
| 293 // mixing is not a perfect solution. E.g. 2->2.1 will result in a ratio of |
| 294 // 2/3 which is truncated to 1 and 1 means "no mixing is required". |
| 295 int channel_factor() const { |
| 296 return (format_.Format.nChannels / client_channel_count_); |
| 297 } |
259 | 298 |
260 // Initializes the COM library for use by the calling thread and sets the | 299 // Initializes the COM library for use by the calling thread and sets the |
261 // thread's concurrency model to multi-threaded. | 300 // thread's concurrency model to multi-threaded. |
262 base::win::ScopedCOMInitializer com_init_; | 301 base::win::ScopedCOMInitializer com_init_; |
263 | 302 |
264 // Contains the thread ID of the creating thread. | 303 // Contains the thread ID of the creating thread. |
265 base::PlatformThreadId creating_thread_id_; | 304 base::PlatformThreadId creating_thread_id_; |
266 | 305 |
267 // Our creator, the audio manager needs to be notified when we close. | 306 // Our creator, the audio manager needs to be notified when we close. |
268 AudioManagerWin* manager_; | 307 AudioManagerWin* manager_; |
269 | 308 |
270 // Rendering is driven by this thread (which has no message loop). | 309 // Rendering is driven by this thread (which has no message loop). |
271 // All OnMoreData() callbacks will be called from this thread. | 310 // All OnMoreData() callbacks will be called from this thread. |
272 base::DelegateSimpleThread* render_thread_; | 311 base::DelegateSimpleThread* render_thread_; |
273 | 312 |
274 // Contains the desired audio format which is set up at construction. | 313 // Contains the desired audio format which is set up at construction. |
275 WAVEFORMATEX format_; | 314 // Extended PCM waveform format structure based on WAVEFORMATEXTENSIBLE. |
| 315 // Use this for multiple channel and hi-resolution PCM data. |
| 316 WAVEFORMATPCMEX format_; |
276 | 317 |
277 // Copy of the audio format which we know the audio engine supports. | 318 // Copy of the audio format which we know the audio engine supports. |
278 // It is recommended to ensure that the sample rate in |format_| is identical | 319 // It is recommended to ensure that the sample rate in |format_| is identical |
279 // to the sample rate in |audio_engine_mix_format_|. | 320 // to the sample rate in |audio_engine_mix_format_|. |
280 base::win::ScopedCoMem<WAVEFORMATEX> audio_engine_mix_format_; | 321 base::win::ScopedCoMem<WAVEFORMATPCMEX> audio_engine_mix_format_; |
281 | 322 |
282 bool opened_; | 323 bool opened_; |
283 bool started_; | 324 bool started_; |
284 | 325 |
285 // Set to true as soon as a new default device is detected, and cleared when | 326 // Set to true as soon as a new default device is detected, and cleared when |
286 // the streaming has switched from using the old device to the new device. | 327 // the streaming has switched from using the old device to the new device. |
287 // All additional device detections during an active state are ignored to | 328 // All additional device detections during an active state are ignored to |
288 // ensure that the ongoing switch can finalize without disruptions. | 329 // ensure that the ongoing switch can finalize without disruptions. |
289 bool restart_rendering_mode_; | 330 bool restart_rendering_mode_; |
290 | 331 |
(...skipping 18 matching lines...) Expand all Loading... |
309 size_t endpoint_buffer_size_frames_; | 350 size_t endpoint_buffer_size_frames_; |
310 | 351 |
311 // Defines the role that the system has assigned to an audio endpoint device. | 352 // Defines the role that the system has assigned to an audio endpoint device. |
312 ERole device_role_; | 353 ERole device_role_; |
313 | 354 |
314 // The sharing mode for the connection. | 355 // The sharing mode for the connection. |
315 // Valid values are AUDCLNT_SHAREMODE_SHARED and AUDCLNT_SHAREMODE_EXCLUSIVE | 356 // Valid values are AUDCLNT_SHAREMODE_SHARED and AUDCLNT_SHAREMODE_EXCLUSIVE |
316 // where AUDCLNT_SHAREMODE_SHARED is the default. | 357 // where AUDCLNT_SHAREMODE_SHARED is the default. |
317 AUDCLNT_SHAREMODE share_mode_; | 358 AUDCLNT_SHAREMODE share_mode_; |
318 | 359 |
| 360 // The channel count set by the client in |params| which is provided to the |
| 361 // constructor. The client must feed the AudioSourceCallback::OnMoreData() |
| 362 // callback with PCM-data that contains this number of channels. |
| 363 int client_channel_count_; |
| 364 |
319 // Counts the number of audio frames written to the endpoint buffer. | 365 // Counts the number of audio frames written to the endpoint buffer. |
320 UINT64 num_written_frames_; | 366 UINT64 num_written_frames_; |
321 | 367 |
322 // Pointer to the client that will deliver audio samples to be played out. | 368 // Pointer to the client that will deliver audio samples to be played out. |
323 AudioSourceCallback* source_; | 369 AudioSourceCallback* source_; |
324 | 370 |
325 // An IMMDeviceEnumerator interface which represents a device enumerator. | 371 // An IMMDeviceEnumerator interface which represents a device enumerator. |
326 base::win::ScopedComPtr<IMMDeviceEnumerator> device_enumerator_; | 372 base::win::ScopedComPtr<IMMDeviceEnumerator> device_enumerator_; |
327 | 373 |
328 // An IMMDevice interface which represents an audio endpoint device. | 374 // An IMMDevice interface which represents an audio endpoint device. |
(...skipping 16 matching lines...) Expand all Loading... |
345 | 391 |
346 // This event will be signaled when stream switching shall take place. | 392 // This event will be signaled when stream switching shall take place. |
347 base::win::ScopedHandle stream_switch_event_; | 393 base::win::ScopedHandle stream_switch_event_; |
348 | 394 |
349 DISALLOW_COPY_AND_ASSIGN(WASAPIAudioOutputStream); | 395 DISALLOW_COPY_AND_ASSIGN(WASAPIAudioOutputStream); |
350 }; | 396 }; |
351 | 397 |
352 } // namespace media | 398 } // namespace media |
353 | 399 |
354 #endif // MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_OUTPUT_WIN_H_ | 400 #endif // MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_OUTPUT_WIN_H_ |
OLD | NEW |