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

Side by Side Diff: media/audio/win/audio_low_latency_output_win.h

Issue 10823100: Adds support for multi-channel output audio for the low-latency path in Windows. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Added more mixing cases and improved the tests Created 8 years, 4 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
OLDNEW
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
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.
scherkus (not reviewing) 2012/08/02 17:14:14 what about opening up 8 channels when HardwareChan
henrika (OOO until Aug 14) 2012/08/03 14:55:56 Added comment about that we don't support it. Als
75 // 81 //
76 // Core Audio API details: 82 // Core Audio API details:
77 // 83 //
78 // - CoInitializeEx() is called on the creating thread and on the internal 84 // - CoInitializeEx() is called on the creating thread and on the internal
79 // capture thread. Each thread's concurrency model and apartment is set 85 // 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 86 // to multi-threaded (MTA). CHECK() is called to ensure that we crash if
81 // CoInitializeEx(MTA) fails. 87 // CoInitializeEx(MTA) fails.
82 // - The public API methods (Open(), Start(), Stop() and Close()) must be 88 // - 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 89 // called on constructing thread. The reason is that we want to ensure that
84 // the COM environment is the same for all API implementations. 90 // the COM environment is the same for all API implementations.
(...skipping 23 matching lines...) Expand all
108 // - Audio rendering is performed on the audio render thread, owned by this 114 // - Audio rendering is performed on the audio render thread, owned by this
109 // class, and the AudioSourceCallback::OnMoreData() method will be called 115 // class, and the AudioSourceCallback::OnMoreData() method will be called
110 // from this thread. Stream switching also takes place on the audio-render 116 // from this thread. Stream switching also takes place on the audio-render
111 // thread. 117 // thread.
112 // - All callback methods from the IMMNotificationClient interface will be 118 // - All callback methods from the IMMNotificationClient interface will be
113 // called on a Windows-internal MMDevice thread. 119 // called on a Windows-internal MMDevice thread.
114 // 120 //
115 // Experimental exclusive mode: 121 // Experimental exclusive mode:
116 // 122 //
117 // - It is possible to open up a stream in exclusive mode by using the 123 // - It is possible to open up a stream in exclusive mode by using the
118 // --enable-exclusive-mode command line flag. 124 // --enable-exclusive-audio command line flag.
119 // - The internal buffering scheme is less flexible for exclusive streams. 125 // - The internal buffering scheme is less flexible for exclusive streams.
120 // Hence, some manual tuning will be required before deciding what frame 126 // Hence, some manual tuning will be required before deciding what frame
121 // size to use. See the WinAudioOutputTest unit test for more details. 127 // size to use. See the WinAudioOutputTest unit test for more details.
122 // - If an application opens a stream in exclusive mode, the application has 128 // - If an application opens a stream in exclusive mode, the application has
123 // exclusive use of the audio endpoint device that plays the stream. 129 // exclusive use of the audio endpoint device that plays the stream.
124 // - Exclusive-mode should only be utilized when the lowest possible latency 130 // - Exclusive-mode should only be utilized when the lowest possible latency
125 // is important. 131 // is important.
126 // - In exclusive mode, the client can choose to open the stream in any audio 132 // - 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 133 // format that the endpoint device supports, i.e. not limited to the device's
128 // current (default) configuration. 134 // current (default) configuration.
129 // - Initial measurements on Windows 7 (HP Z600 workstation) have shown that 135 // - Initial measurements on Windows 7 (HP Z600 workstation) have shown that
130 // the lowest possible latencies we can achieve on this machine are: 136 // the lowest possible latencies we can achieve on this machine are:
131 // o ~3.3333ms @ 48kHz <=> 160 audio frames per buffer. 137 // o ~3.3333ms @ 48kHz <=> 160 audio frames per buffer.
132 // o ~3.6281ms @ 44.1kHz <=> 160 audio frames per buffer. 138 // 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 139 // - See http://msdn.microsoft.com/en-us/library/windows/desktop/dd370844(v=vs.8 5).aspx
134 // for more details. 140 // for more details.
135 141
136 #ifndef MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_OUTPUT_WIN_H_ 142 #ifndef MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_OUTPUT_WIN_H_
137 #define MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_OUTPUT_WIN_H_ 143 #define MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_OUTPUT_WIN_H_
138 144
139 #include <Audioclient.h> 145 #include <Audioclient.h>
140 #include <audiopolicy.h> 146 #include <audiopolicy.h>
141 #include <MMDeviceAPI.h> 147 #include <MMDeviceAPI.h>
142 148
143 #include <string> 149 #include <string>
144 150
145 #include "base/compiler_specific.h" 151 #include "base/compiler_specific.h"
152 #include "base/gtest_prod_util.h"
146 #include "base/threading/platform_thread.h" 153 #include "base/threading/platform_thread.h"
147 #include "base/threading/simple_thread.h" 154 #include "base/threading/simple_thread.h"
148 #include "base/win/scoped_co_mem.h" 155 #include "base/win/scoped_co_mem.h"
149 #include "base/win/scoped_com_initializer.h" 156 #include "base/win/scoped_com_initializer.h"
150 #include "base/win/scoped_comptr.h" 157 #include "base/win/scoped_comptr.h"
151 #include "base/win/scoped_handle.h" 158 #include "base/win/scoped_handle.h"
152 #include "media/audio/audio_io.h" 159 #include "media/audio/audio_io.h"
153 #include "media/audio/audio_parameters.h" 160 #include "media/audio/audio_parameters.h"
154 #include "media/base/media_export.h" 161 #include "media/base/media_export.h"
155 162
156 namespace media { 163 namespace media {
157 164
158 class AudioManagerWin; 165 class AudioManagerWin;
166 class WASAPIAudioOutputStreamTest;
scherkus (not reviewing) 2012/08/02 17:14:14 AFAIK you don't need to fwd decl this for FRIEND_T
henrika (OOO until Aug 14) 2012/08/03 14:55:56 Correct. Thanks ;-)
159 167
160 // AudioOutputStream implementation using Windows Core Audio APIs. 168 // AudioOutputStream implementation using Windows Core Audio APIs.
161 // The IMMNotificationClient interface enables device event notifications 169 // The IMMNotificationClient interface enables device event notifications
162 // related to changes in the status of an audio endpoint device. 170 // related to changes in the status of an audio endpoint device.
163 class MEDIA_EXPORT WASAPIAudioOutputStream 171 class MEDIA_EXPORT WASAPIAudioOutputStream
164 : public IMMNotificationClient, 172 : public IMMNotificationClient,
165 public AudioOutputStream, 173 public AudioOutputStream,
166 public base::DelegateSimpleThread::Delegate { 174 public base::DelegateSimpleThread::Delegate {
167 public: 175 public:
168 // The ctor takes all the usual parameters, plus |manager| which is the 176 // The ctor takes all the usual parameters, plus |manager| which is the
169 // the audio manager who is creating this object. 177 // the audio manager who is creating this object.
170 WASAPIAudioOutputStream(AudioManagerWin* manager, 178 WASAPIAudioOutputStream(AudioManagerWin* manager,
171 const AudioParameters& params, 179 const AudioParameters& params,
172 ERole device_role); 180 ERole device_role);
173 // The dtor is typically called by the AudioManager only and it is usually 181 // The dtor is typically called by the AudioManager only and it is usually
174 // triggered by calling AudioOutputStream::Close(). 182 // triggered by calling AudioOutputStream::Close().
175 virtual ~WASAPIAudioOutputStream(); 183 virtual ~WASAPIAudioOutputStream();
176 184
177 // Implementation of AudioOutputStream. 185 // Implementation of AudioOutputStream.
178 virtual bool Open() OVERRIDE; 186 virtual bool Open() OVERRIDE;
179 virtual void Start(AudioSourceCallback* callback) OVERRIDE; 187 virtual void Start(AudioSourceCallback* callback) OVERRIDE;
180 virtual void Stop() OVERRIDE; 188 virtual void Stop() OVERRIDE;
181 virtual void Close() OVERRIDE; 189 virtual void Close() OVERRIDE;
182 virtual void SetVolume(double volume) OVERRIDE; 190 virtual void SetVolume(double volume) OVERRIDE;
183 virtual void GetVolume(double* volume) OVERRIDE; 191 virtual void GetVolume(double* volume) OVERRIDE;
184 192
185 // Retrieves the stream format that the audio engine uses for its internal 193 // Retrieves the number of channels the audio engine uses for its internal
186 // processing/mixing of shared-mode streams. 194 // processing/mixing of shared-mode streams for the default endpoint device.
187 // This method should not be used in combination with exclusive-mode streams. 195 static int HardwareChannelCount();
196
197 // Retrieves the channel layout the audio engine uses for its internal
198 // processing/mixing of shared-mode streams for the default endpoint device.
199 // Note that we convert an internal channel layout mask (see ChannelMask())
200 // into a Chrome-specific channel layout enumerator in this method, hence
201 // the match might not be perfect.
202 static ChannelLayout HardwareChannelLayout();
203
204 // Retrieves the sample rate the audio engine uses for its internal
205 // processing/mixing of shared-mode streams for the default endpoint device.
188 static int HardwareSampleRate(ERole device_role); 206 static int HardwareSampleRate(ERole device_role);
189 207
190 // Returns AUDCLNT_SHAREMODE_EXCLUSIVE if --enable-exclusive-mode is used 208 // Returns AUDCLNT_SHAREMODE_EXCLUSIVE if --enable-exclusive-mode is used
191 // as command-line flag and AUDCLNT_SHAREMODE_SHARED otherwise (default). 209 // as command-line flag and AUDCLNT_SHAREMODE_SHARED otherwise (default).
192 static AUDCLNT_SHAREMODE GetShareMode(); 210 static AUDCLNT_SHAREMODE GetShareMode();
193 211
194 bool started() const { return started_; } 212 bool started() const { return started_; }
195 213
196 private: 214 private:
215 FRIEND_TEST_ALL_PREFIXES(WASAPIAudioOutputStreamTest, HardwareChannelCount);
216
197 // Implementation of IUnknown (trivial in this case). See 217 // Implementation of IUnknown (trivial in this case). See
198 // msdn.microsoft.com/en-us/library/windows/desktop/dd371403(v=vs.85).aspx 218 // msdn.microsoft.com/en-us/library/windows/desktop/dd371403(v=vs.85).aspx
199 // for details regarding why proper implementations of AddRef(), Release() 219 // for details regarding why proper implementations of AddRef(), Release()
200 // and QueryInterface() are not needed here. 220 // and QueryInterface() are not needed here.
201 STDMETHOD_(ULONG, AddRef)(); 221 STDMETHOD_(ULONG, AddRef)();
202 STDMETHOD_(ULONG, Release)(); 222 STDMETHOD_(ULONG, Release)();
203 STDMETHOD(QueryInterface)(REFIID iid, void** object); 223 STDMETHOD(QueryInterface)(REFIID iid, void** object);
204 224
205 // Implementation of the abstract interface IMMNotificationClient. 225 // Implementation of the abstract interface IMMNotificationClient.
206 // Provides notifications when an audio endpoint device is added or removed, 226 // Provides notifications when an audio endpoint device is added or removed,
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
248 // Converts unique endpoint ID to user-friendly device name. 268 // Converts unique endpoint ID to user-friendly device name.
249 std::string GetDeviceName(LPCWSTR device_id) const; 269 std::string GetDeviceName(LPCWSTR device_id) const;
250 270
251 // Called on the audio render thread when the current audio stream must 271 // Called on the audio render thread when the current audio stream must
252 // be re-initialized because the default audio device has changed. This 272 // be re-initialized because the default audio device has changed. This
253 // method: stops the current renderer, releases and re-creates all WASAPI 273 // method: stops the current renderer, releases and re-creates all WASAPI
254 // interfaces, creates a new IMMDevice and re-starts rendering using the 274 // interfaces, creates a new IMMDevice and re-starts rendering using the
255 // new default audio device. 275 // new default audio device.
256 bool RestartRenderingUsingNewDefaultDevice(); 276 bool RestartRenderingUsingNewDefaultDevice();
257 277
258 AUDCLNT_SHAREMODE share_mode() const { return share_mode_; } 278 // Returns the number of channels the audio engine uses for its internal
279 // processing/mixing of shared-mode streams for the default endpoint device.
280 int endpoint_channel_count() { return format_.Format.nChannels; }
281
282 // The ratio between the the number of native audio channels used by the
283 // audio device and the number of audio channels from the client.
284 int channel_factor() const {
285 return (format_.Format.nChannels / client_channel_count_);
286 }
259 287
260 // Initializes the COM library for use by the calling thread and sets the 288 // Initializes the COM library for use by the calling thread and sets the
261 // thread's concurrency model to multi-threaded. 289 // thread's concurrency model to multi-threaded.
262 base::win::ScopedCOMInitializer com_init_; 290 base::win::ScopedCOMInitializer com_init_;
263 291
264 // Contains the thread ID of the creating thread. 292 // Contains the thread ID of the creating thread.
265 base::PlatformThreadId creating_thread_id_; 293 base::PlatformThreadId creating_thread_id_;
266 294
267 // Our creator, the audio manager needs to be notified when we close. 295 // Our creator, the audio manager needs to be notified when we close.
268 AudioManagerWin* manager_; 296 AudioManagerWin* manager_;
269 297
270 // Rendering is driven by this thread (which has no message loop). 298 // Rendering is driven by this thread (which has no message loop).
271 // All OnMoreData() callbacks will be called from this thread. 299 // All OnMoreData() callbacks will be called from this thread.
272 base::DelegateSimpleThread* render_thread_; 300 base::DelegateSimpleThread* render_thread_;
273 301
274 // Contains the desired audio format which is set up at construction. 302 // Contains the desired audio format which is set up at construction.
275 WAVEFORMATEX format_; 303 // Extended PCM waveform format structure based on WAVEFORMATEXTENSIBLE.
304 // Use this for multiple channel and hi-resolution PCM data.
305 WAVEFORMATPCMEX format_;
276 306
277 // Copy of the audio format which we know the audio engine supports. 307 // 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 308 // It is recommended to ensure that the sample rate in |format_| is identical
279 // to the sample rate in |audio_engine_mix_format_|. 309 // to the sample rate in |audio_engine_mix_format_|.
280 base::win::ScopedCoMem<WAVEFORMATEX> audio_engine_mix_format_; 310 base::win::ScopedCoMem<WAVEFORMATPCMEX> audio_engine_mix_format_;
281 311
282 bool opened_; 312 bool opened_;
283 bool started_; 313 bool started_;
284 314
285 // Set to true as soon as a new default device is detected, and cleared when 315 // 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. 316 // 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 317 // All additional device detections during an active state are ignored to
288 // ensure that the ongoing switch can finalize without disruptions. 318 // ensure that the ongoing switch can finalize without disruptions.
289 bool restart_rendering_mode_; 319 bool restart_rendering_mode_;
290 320
(...skipping 18 matching lines...) Expand all
309 size_t endpoint_buffer_size_frames_; 339 size_t endpoint_buffer_size_frames_;
310 340
311 // Defines the role that the system has assigned to an audio endpoint device. 341 // Defines the role that the system has assigned to an audio endpoint device.
312 ERole device_role_; 342 ERole device_role_;
313 343
314 // The sharing mode for the connection. 344 // The sharing mode for the connection.
315 // Valid values are AUDCLNT_SHAREMODE_SHARED and AUDCLNT_SHAREMODE_EXCLUSIVE 345 // Valid values are AUDCLNT_SHAREMODE_SHARED and AUDCLNT_SHAREMODE_EXCLUSIVE
316 // where AUDCLNT_SHAREMODE_SHARED is the default. 346 // where AUDCLNT_SHAREMODE_SHARED is the default.
317 AUDCLNT_SHAREMODE share_mode_; 347 AUDCLNT_SHAREMODE share_mode_;
318 348
349 // The channel count set by the client in |params| which is provided to the
350 // constructor. The client must feed the AudioSourceCallback::OnMoreData()
351 // callback with PCM-data that contains this number of channels.
352 int client_channel_count_;
353
319 // Counts the number of audio frames written to the endpoint buffer. 354 // Counts the number of audio frames written to the endpoint buffer.
320 UINT64 num_written_frames_; 355 UINT64 num_written_frames_;
321 356
322 // Pointer to the client that will deliver audio samples to be played out. 357 // Pointer to the client that will deliver audio samples to be played out.
323 AudioSourceCallback* source_; 358 AudioSourceCallback* source_;
324 359
325 // An IMMDeviceEnumerator interface which represents a device enumerator. 360 // An IMMDeviceEnumerator interface which represents a device enumerator.
326 base::win::ScopedComPtr<IMMDeviceEnumerator> device_enumerator_; 361 base::win::ScopedComPtr<IMMDeviceEnumerator> device_enumerator_;
327 362
328 // An IMMDevice interface which represents an audio endpoint device. 363 // An IMMDevice interface which represents an audio endpoint device.
(...skipping 16 matching lines...) Expand all
345 380
346 // This event will be signaled when stream switching shall take place. 381 // This event will be signaled when stream switching shall take place.
347 base::win::ScopedHandle stream_switch_event_; 382 base::win::ScopedHandle stream_switch_event_;
348 383
349 DISALLOW_COPY_AND_ASSIGN(WASAPIAudioOutputStream); 384 DISALLOW_COPY_AND_ASSIGN(WASAPIAudioOutputStream);
350 }; 385 };
351 386
352 } // namespace media 387 } // namespace media
353 388
354 #endif // MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_OUTPUT_WIN_H_ 389 #endif // MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_OUTPUT_WIN_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698