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

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: Fixed bug in GetMixFormat 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.
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
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
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
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 int channel_factor() const {
293 return (format_.Format.nChannels / client_channel_count_);
scherkus (not reviewing) 2012/08/03 21:20:55 OOC and something we can TODO for now, but do we a
henrika (OOO until Aug 14) 2012/08/04 16:42:23 We only support the mixing modes listed in the "Ov
294 }
259 295
260 // Initializes the COM library for use by the calling thread and sets the 296 // Initializes the COM library for use by the calling thread and sets the
261 // thread's concurrency model to multi-threaded. 297 // thread's concurrency model to multi-threaded.
262 base::win::ScopedCOMInitializer com_init_; 298 base::win::ScopedCOMInitializer com_init_;
263 299
264 // Contains the thread ID of the creating thread. 300 // Contains the thread ID of the creating thread.
265 base::PlatformThreadId creating_thread_id_; 301 base::PlatformThreadId creating_thread_id_;
266 302
267 // Our creator, the audio manager needs to be notified when we close. 303 // Our creator, the audio manager needs to be notified when we close.
268 AudioManagerWin* manager_; 304 AudioManagerWin* manager_;
269 305
270 // Rendering is driven by this thread (which has no message loop). 306 // Rendering is driven by this thread (which has no message loop).
271 // All OnMoreData() callbacks will be called from this thread. 307 // All OnMoreData() callbacks will be called from this thread.
272 base::DelegateSimpleThread* render_thread_; 308 base::DelegateSimpleThread* render_thread_;
273 309
274 // Contains the desired audio format which is set up at construction. 310 // Contains the desired audio format which is set up at construction.
275 WAVEFORMATEX format_; 311 // Extended PCM waveform format structure based on WAVEFORMATEXTENSIBLE.
312 // Use this for multiple channel and hi-resolution PCM data.
313 WAVEFORMATPCMEX format_;
276 314
277 // Copy of the audio format which we know the audio engine supports. 315 // 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 316 // It is recommended to ensure that the sample rate in |format_| is identical
279 // to the sample rate in |audio_engine_mix_format_|. 317 // to the sample rate in |audio_engine_mix_format_|.
280 base::win::ScopedCoMem<WAVEFORMATEX> audio_engine_mix_format_; 318 base::win::ScopedCoMem<WAVEFORMATPCMEX> audio_engine_mix_format_;
281 319
282 bool opened_; 320 bool opened_;
283 bool started_; 321 bool started_;
284 322
285 // Set to true as soon as a new default device is detected, and cleared when 323 // 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. 324 // 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 325 // All additional device detections during an active state are ignored to
288 // ensure that the ongoing switch can finalize without disruptions. 326 // ensure that the ongoing switch can finalize without disruptions.
289 bool restart_rendering_mode_; 327 bool restart_rendering_mode_;
290 328
(...skipping 18 matching lines...) Expand all
309 size_t endpoint_buffer_size_frames_; 347 size_t endpoint_buffer_size_frames_;
310 348
311 // Defines the role that the system has assigned to an audio endpoint device. 349 // Defines the role that the system has assigned to an audio endpoint device.
312 ERole device_role_; 350 ERole device_role_;
313 351
314 // The sharing mode for the connection. 352 // The sharing mode for the connection.
315 // Valid values are AUDCLNT_SHAREMODE_SHARED and AUDCLNT_SHAREMODE_EXCLUSIVE 353 // Valid values are AUDCLNT_SHAREMODE_SHARED and AUDCLNT_SHAREMODE_EXCLUSIVE
316 // where AUDCLNT_SHAREMODE_SHARED is the default. 354 // where AUDCLNT_SHAREMODE_SHARED is the default.
317 AUDCLNT_SHAREMODE share_mode_; 355 AUDCLNT_SHAREMODE share_mode_;
318 356
357 // The channel count set by the client in |params| which is provided to the
358 // constructor. The client must feed the AudioSourceCallback::OnMoreData()
359 // callback with PCM-data that contains this number of channels.
360 int client_channel_count_;
361
319 // Counts the number of audio frames written to the endpoint buffer. 362 // Counts the number of audio frames written to the endpoint buffer.
320 UINT64 num_written_frames_; 363 UINT64 num_written_frames_;
321 364
322 // Pointer to the client that will deliver audio samples to be played out. 365 // Pointer to the client that will deliver audio samples to be played out.
323 AudioSourceCallback* source_; 366 AudioSourceCallback* source_;
324 367
325 // An IMMDeviceEnumerator interface which represents a device enumerator. 368 // An IMMDeviceEnumerator interface which represents a device enumerator.
326 base::win::ScopedComPtr<IMMDeviceEnumerator> device_enumerator_; 369 base::win::ScopedComPtr<IMMDeviceEnumerator> device_enumerator_;
327 370
328 // An IMMDevice interface which represents an audio endpoint device. 371 // An IMMDevice interface which represents an audio endpoint device.
(...skipping 16 matching lines...) Expand all
345 388
346 // This event will be signaled when stream switching shall take place. 389 // This event will be signaled when stream switching shall take place.
347 base::win::ScopedHandle stream_switch_event_; 390 base::win::ScopedHandle stream_switch_event_;
348 391
349 DISALLOW_COPY_AND_ASSIGN(WASAPIAudioOutputStream); 392 DISALLOW_COPY_AND_ASSIGN(WASAPIAudioOutputStream);
350 }; 393 };
351 394
352 } // namespace media 395 } // namespace media
353 396
354 #endif // MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_OUTPUT_WIN_H_ 397 #endif // MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_OUTPUT_WIN_H_
OLDNEW
« no previous file with comments | « media/audio/win/audio_low_latency_input_win.h ('k') | media/audio/win/audio_low_latency_output_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698