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

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

Issue 11366241: Removed IMMNotification from WASAPIAudioOutputStream. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 1 month 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
« no previous file with comments | « no previous file | media/audio/win/audio_low_latency_output_win.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 14 matching lines...) Expand all
25 // latency of approximately 35 ms if the selected packet size is less than 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 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 27 // lower latency but only affects the size of the data buffer in each
28 // OnMoreData() callback. 28 // OnMoreData() callback.
29 // - A total typical delay of 35 ms contains three parts: 29 // - A total typical delay of 35 ms contains three parts:
30 // o Audio endpoint device period (~10 ms). 30 // o Audio endpoint device period (~10 ms).
31 // o Stream latency between the buffer and endpoint device (~5 ms). 31 // o Stream latency between the buffer and endpoint device (~5 ms).
32 // o Endpoint buffer (~20 ms to ensure glitch-free rendering). 32 // 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 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). 34 // delay will be approximately 115 ms (10 + 5 + 100).
35 // - Supports device events using the IMMNotificationClient Interface. If
36 // streaming has started, a so-called stream switch will take place in the
37 // following situations:
38 // o The user enables or disables an audio endpoint device from Device
39 // Manager or from the Windows multimedia control panel, Mmsys.cpl.
40 // o The user adds an audio adapter to the system or removes an audio
41 // adapter from the system.
42 // o The user plugs an audio endpoint device into an audio jack with
43 // jack-presence detection, or removes an audio endpoint device from
44 // such a jack.
45 // o The user changes the device role that is assigned to a device.
46 // o The value of a property of a device changes.
47 // Practical/typical example: A user has two audio devices A and B where
48 // A is a built-in device configured as Default Communication and B is a
49 // USB device set as Default device. Audio rendering starts and audio is
50 // played through the device B since the eConsole role is used by the audio
51 // manager in Chrome today. If the user now removes the USB device (B), it
52 // will be detected and device A will instead be defined as the new default
53 // device. Rendering will automatically stop, all resources will be released
54 // and a new session will be initialized and started using device A instead.
55 // The net effect for the user is that audio will automatically switch from
56 // device B to device A. Same thing will happen if the user now re-inserts
57 // the USB device again.
58 // 35 //
59 // Implementation notes: 36 // Implementation notes:
60 // 37 //
61 // - The minimum supported client is Windows Vista. 38 // - The minimum supported client is Windows Vista.
62 // - This implementation is single-threaded, hence: 39 // - This implementation is single-threaded, hence:
63 // o Construction and destruction must take place from the same thread. 40 // o Construction and destruction must take place from the same thread.
64 // o All APIs must be called from the creating thread as well. 41 // o All APIs must be called from the creating thread as well.
65 // - It is recommended to first acquire the native sample rate of the default 42 // - 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 43 // input device and then use the same rate when creating this object. Use
67 // WASAPIAudioOutputStream::HardwareSampleRate() to retrieve the sample rate. 44 // WASAPIAudioOutputStream::HardwareSampleRate() to retrieve the sample rate.
(...skipping 19 matching lines...) Expand all
87 // - Utilized WASAPI interfaces: 64 // - Utilized WASAPI interfaces:
88 // o IAudioClient 65 // o IAudioClient
89 // o IAudioRenderClient 66 // o IAudioRenderClient
90 // - The stream is initialized in shared mode and the processing of the 67 // - The stream is initialized in shared mode and the processing of the
91 // audio buffer is event driven. 68 // audio buffer is event driven.
92 // - The Multimedia Class Scheduler service (MMCSS) is utilized to boost 69 // - The Multimedia Class Scheduler service (MMCSS) is utilized to boost
93 // the priority of the render thread. 70 // the priority of the render thread.
94 // - Audio-rendering endpoint devices can have three roles: 71 // - Audio-rendering endpoint devices can have three roles:
95 // Console (eConsole), Communications (eCommunications), and Multimedia 72 // Console (eConsole), Communications (eCommunications), and Multimedia
96 // (eMultimedia). Search for "Device Roles" on MSDN for more details. 73 // (eMultimedia). Search for "Device Roles" on MSDN for more details.
97 // - The actual stream-switch is executed on the audio-render thread but it
98 // is triggered by an internal MMDevice thread using callback methods
99 // in the IMMNotificationClient interface.
100 // 74 //
101 // Threading details: 75 // Threading details:
102 // 76 //
103 // - It is assumed that this class is created on the audio thread owned 77 // - It is assumed that this class is created on the audio thread owned
104 // by the AudioManager. 78 // by the AudioManager.
105 // - It is a requirement to call the following methods on the same audio 79 // - It is a requirement to call the following methods on the same audio
106 // thread: Open(), Start(), Stop(), and Close(). 80 // thread: Open(), Start(), Stop(), and Close().
107 // - Audio rendering is performed on the audio render thread, owned by this 81 // - Audio rendering is performed on the audio render thread, owned by this
108 // class, and the AudioSourceCallback::OnMoreData() method will be called 82 // class, and the AudioSourceCallback::OnMoreData() method will be called
109 // from this thread. Stream switching also takes place on the audio-render 83 // from this thread. Stream switching also takes place on the audio-render
110 // thread. 84 // thread.
111 // - All callback methods from the IMMNotificationClient interface will be
112 // called on a Windows-internal MMDevice thread.
113 // 85 //
114 // Experimental exclusive mode: 86 // Experimental exclusive mode:
115 // 87 //
116 // - It is possible to open up a stream in exclusive mode by using the 88 // - It is possible to open up a stream in exclusive mode by using the
117 // --enable-exclusive-audio command line flag. 89 // --enable-exclusive-audio command line flag.
118 // - The internal buffering scheme is less flexible for exclusive streams. 90 // - The internal buffering scheme is less flexible for exclusive streams.
119 // Hence, some manual tuning will be required before deciding what frame 91 // Hence, some manual tuning will be required before deciding what frame
120 // size to use. See the WinAudioOutputTest unit test for more details. 92 // size to use. See the WinAudioOutputTest unit test for more details.
121 // - If an application opens a stream in exclusive mode, the application has 93 // - If an application opens a stream in exclusive mode, the application has
122 // exclusive use of the audio endpoint device that plays the stream. 94 // exclusive use of the audio endpoint device that plays the stream.
123 // - Exclusive-mode should only be utilized when the lowest possible latency 95 // - Exclusive-mode should only be utilized when the lowest possible latency
124 // is important. 96 // is important.
125 // - In exclusive mode, the client can choose to open the stream in any audio 97 // - In exclusive mode, the client can choose to open the stream in any audio
126 // format that the endpoint device supports, i.e. not limited to the device's 98 // format that the endpoint device supports, i.e. not limited to the device's
127 // current (default) configuration. 99 // current (default) configuration.
128 // - Initial measurements on Windows 7 (HP Z600 workstation) have shown that 100 // - Initial measurements on Windows 7 (HP Z600 workstation) have shown that
129 // the lowest possible latencies we can achieve on this machine are: 101 // the lowest possible latencies we can achieve on this machine are:
130 // o ~3.3333ms @ 48kHz <=> 160 audio frames per buffer. 102 // o ~3.3333ms @ 48kHz <=> 160 audio frames per buffer.
131 // o ~3.6281ms @ 44.1kHz <=> 160 audio frames per buffer. 103 // o ~3.6281ms @ 44.1kHz <=> 160 audio frames per buffer.
132 // - See http://msdn.microsoft.com/en-us/library/windows/desktop/dd370844(v=vs.8 5).aspx 104 // - See http://msdn.microsoft.com/en-us/library/windows/desktop/dd370844(v=vs.8 5).aspx
133 // for more details. 105 // for more details.
134 106
135 #ifndef MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_OUTPUT_WIN_H_ 107 #ifndef MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_OUTPUT_WIN_H_
136 #define MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_OUTPUT_WIN_H_ 108 #define MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_OUTPUT_WIN_H_
137 109
138 #include <Audioclient.h> 110 #include <Audioclient.h>
139 #include <audiopolicy.h>
140 #include <MMDeviceAPI.h> 111 #include <MMDeviceAPI.h>
141 112
142 #include <string> 113 #include <string>
143 114
144 #include "base/compiler_specific.h" 115 #include "base/compiler_specific.h"
145 #include "base/memory/scoped_ptr.h" 116 #include "base/memory/scoped_ptr.h"
146 #include "base/threading/platform_thread.h" 117 #include "base/threading/platform_thread.h"
147 #include "base/threading/simple_thread.h" 118 #include "base/threading/simple_thread.h"
148 #include "base/win/scoped_co_mem.h" 119 #include "base/win/scoped_co_mem.h"
149 #include "base/win/scoped_com_initializer.h" 120 #include "base/win/scoped_com_initializer.h"
150 #include "base/win/scoped_comptr.h" 121 #include "base/win/scoped_comptr.h"
151 #include "base/win/scoped_handle.h" 122 #include "base/win/scoped_handle.h"
152 #include "media/audio/audio_io.h" 123 #include "media/audio/audio_io.h"
153 #include "media/audio/audio_parameters.h" 124 #include "media/audio/audio_parameters.h"
154 #include "media/base/media_export.h" 125 #include "media/base/media_export.h"
155 126
156 namespace media { 127 namespace media {
157 128
158 class AudioManagerWin; 129 class AudioManagerWin;
159 130
160 // AudioOutputStream implementation using Windows Core Audio APIs. 131 // AudioOutputStream implementation using Windows Core Audio APIs.
161 // TODO(henrika): Remove IMMNotificationClient implementation now that we have 132 class MEDIA_EXPORT WASAPIAudioOutputStream :
162 // AudioDeviceListenerWin; currently just disabled since extraction is extremely
163 // advanced.
164 class MEDIA_EXPORT WASAPIAudioOutputStream
165 : public IMMNotificationClient,
166 public AudioOutputStream, 133 public AudioOutputStream,
167 public base::DelegateSimpleThread::Delegate { 134 public base::DelegateSimpleThread::Delegate {
168 public: 135 public:
169 // The ctor takes all the usual parameters, plus |manager| which is the 136 // The ctor takes all the usual parameters, plus |manager| which is the
170 // the audio manager who is creating this object. 137 // the audio manager who is creating this object.
171 WASAPIAudioOutputStream(AudioManagerWin* manager, 138 WASAPIAudioOutputStream(AudioManagerWin* manager,
172 const AudioParameters& params, 139 const AudioParameters& params,
173 ERole device_role); 140 ERole device_role);
141
174 // The dtor is typically called by the AudioManager only and it is usually 142 // The dtor is typically called by the AudioManager only and it is usually
175 // triggered by calling AudioOutputStream::Close(). 143 // triggered by calling AudioOutputStream::Close().
176 virtual ~WASAPIAudioOutputStream(); 144 virtual ~WASAPIAudioOutputStream();
177 145
178 // Implementation of AudioOutputStream. 146 // Implementation of AudioOutputStream.
179 virtual bool Open() OVERRIDE; 147 virtual bool Open() OVERRIDE;
180 virtual void Start(AudioSourceCallback* callback) OVERRIDE; 148 virtual void Start(AudioSourceCallback* callback) OVERRIDE;
181 virtual void Stop() OVERRIDE; 149 virtual void Stop() OVERRIDE;
182 virtual void Close() OVERRIDE; 150 virtual void Close() OVERRIDE;
183 virtual void SetVolume(double volume) OVERRIDE; 151 virtual void SetVolume(double volume) OVERRIDE;
(...skipping 18 matching lines...) Expand all
202 // as command-line flag and AUDCLNT_SHAREMODE_SHARED otherwise (default). 170 // as command-line flag and AUDCLNT_SHAREMODE_SHARED otherwise (default).
203 static AUDCLNT_SHAREMODE GetShareMode(); 171 static AUDCLNT_SHAREMODE GetShareMode();
204 172
205 bool started() const { return render_thread_.get() != NULL; } 173 bool started() const { return render_thread_.get() != NULL; }
206 174
207 // Returns the number of channels the audio engine uses for its internal 175 // Returns the number of channels the audio engine uses for its internal
208 // processing/mixing of shared-mode streams for the default endpoint device. 176 // processing/mixing of shared-mode streams for the default endpoint device.
209 int GetEndpointChannelCountForTesting() { return format_.Format.nChannels; } 177 int GetEndpointChannelCountForTesting() { return format_.Format.nChannels; }
210 178
211 private: 179 private:
212 // Implementation of IUnknown (trivial in this case). See
213 // msdn.microsoft.com/en-us/library/windows/desktop/dd371403(v=vs.85).aspx
214 // for details regarding why proper implementations of AddRef(), Release()
215 // and QueryInterface() are not needed here.
216 STDMETHOD_(ULONG, AddRef)();
217 STDMETHOD_(ULONG, Release)();
218 STDMETHOD(QueryInterface)(REFIID iid, void** object);
219
220 // Implementation of the abstract interface IMMNotificationClient.
221 // Provides notifications when an audio endpoint device is added or removed,
222 // when the state or properties of a device change, or when there is a
223 // change in the default role assigned to a device. See
224 // msdn.microsoft.com/en-us/library/windows/desktop/dd371417(v=vs.85).aspx
225 // for more details about the IMMNotificationClient interface.
226
227 // The default audio endpoint device for a particular role has changed.
228 // This method is only used for diagnostic purposes.
229 STDMETHOD(OnDeviceStateChanged)(LPCWSTR device_id, DWORD new_state);
230
231 // Indicates that the state of an audio endpoint device has changed.
232 STDMETHOD(OnDefaultDeviceChanged)(EDataFlow flow, ERole role,
233 LPCWSTR new_default_device_id);
234
235 // These IMMNotificationClient methods are currently not utilized.
236 STDMETHOD(OnDeviceAdded)(LPCWSTR device_id) { return S_OK; }
237 STDMETHOD(OnDeviceRemoved)(LPCWSTR device_id) { return S_OK; }
238 STDMETHOD(OnPropertyValueChanged)(LPCWSTR device_id,
239 const PROPERTYKEY key) {
240 return S_OK;
241 }
242
243 // DelegateSimpleThread::Delegate implementation. 180 // DelegateSimpleThread::Delegate implementation.
244 virtual void Run() OVERRIDE; 181 virtual void Run() OVERRIDE;
245 182
246 // Issues the OnError() callback to the |sink_|. 183 // Issues the OnError() callback to the |sink_|.
247 void HandleError(HRESULT err); 184 void HandleError(HRESULT err);
248 185
249 // The Open() method is divided into these sub methods. 186 // The Open() method is divided into these sub methods.
250 HRESULT SetRenderDevice(); 187 HRESULT SetRenderDevice();
251 HRESULT ActivateRenderDevice(); 188 HRESULT ActivateRenderDevice();
252 bool DesiredFormatIsSupported(); 189 bool DesiredFormatIsSupported();
253 HRESULT InitializeAudioEngine(); 190 HRESULT InitializeAudioEngine();
254 191
255 // Called when the device will be opened in shared mode and use the 192 // Called when the device will be opened in shared mode and use the
256 // internal audio engine's mix format. 193 // internal audio engine's mix format.
257 HRESULT SharedModeInitialization(); 194 HRESULT SharedModeInitialization();
258 195
259 // Called when the device will be opened in exclusive mode and use the 196 // Called when the device will be opened in exclusive mode and use the
260 // application specified format. 197 // application specified format.
261 HRESULT ExclusiveModeInitialization(); 198 HRESULT ExclusiveModeInitialization();
262 199
263 // Converts unique endpoint ID to user-friendly device name. 200 // Converts unique endpoint ID to user-friendly device name.
264 std::string GetDeviceName(LPCWSTR device_id) const; 201 std::string GetDeviceName(LPCWSTR device_id) const;
265 202
266 // Called on the audio render thread when the current audio stream must
267 // be re-initialized because the default audio device has changed. This
268 // method: stops the current renderer, releases and re-creates all WASAPI
269 // interfaces, creates a new IMMDevice and re-starts rendering using the
270 // new default audio device.
271 bool RestartRenderingUsingNewDefaultDevice();
272
273 // Contains the thread ID of the creating thread. 203 // Contains the thread ID of the creating thread.
274 base::PlatformThreadId creating_thread_id_; 204 base::PlatformThreadId creating_thread_id_;
275 205
276 // Our creator, the audio manager needs to be notified when we close. 206 // Our creator, the audio manager needs to be notified when we close.
277 AudioManagerWin* manager_; 207 AudioManagerWin* manager_;
278 208
279 // Rendering is driven by this thread (which has no message loop). 209 // Rendering is driven by this thread (which has no message loop).
280 // All OnMoreData() callbacks will be called from this thread. 210 // All OnMoreData() callbacks will be called from this thread.
281 scoped_ptr<base::DelegateSimpleThread> render_thread_; 211 scoped_ptr<base::DelegateSimpleThread> render_thread_;
282 212
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
351 // data to a rendering endpoint buffer. 281 // data to a rendering endpoint buffer.
352 base::win::ScopedComPtr<IAudioRenderClient> audio_render_client_; 282 base::win::ScopedComPtr<IAudioRenderClient> audio_render_client_;
353 283
354 // The audio engine will signal this event each time a buffer becomes 284 // The audio engine will signal this event each time a buffer becomes
355 // ready to be filled by the client. 285 // ready to be filled by the client.
356 base::win::ScopedHandle audio_samples_render_event_; 286 base::win::ScopedHandle audio_samples_render_event_;
357 287
358 // This event will be signaled when rendering shall stop. 288 // This event will be signaled when rendering shall stop.
359 base::win::ScopedHandle stop_render_event_; 289 base::win::ScopedHandle stop_render_event_;
360 290
361 // This event will be signaled when stream switching shall take place.
362 base::win::ScopedHandle stream_switch_event_;
363
364 // Container for retrieving data from AudioSourceCallback::OnMoreData(). 291 // Container for retrieving data from AudioSourceCallback::OnMoreData().
365 scoped_ptr<AudioBus> audio_bus_; 292 scoped_ptr<AudioBus> audio_bus_;
366 293
367 DISALLOW_COPY_AND_ASSIGN(WASAPIAudioOutputStream); 294 DISALLOW_COPY_AND_ASSIGN(WASAPIAudioOutputStream);
368 }; 295 };
369 296
370 } // namespace media 297 } // namespace media
371 298
372 #endif // MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_OUTPUT_WIN_H_ 299 #endif // MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_OUTPUT_WIN_H_
OLDNEW
« no previous file with comments | « no previous file | media/audio/win/audio_low_latency_output_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698