|
OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 // | |
5 // Implementation of AudioInputStream for Windows using Windows Core Audio | |
6 // WASAPI for low latency capturing. | |
7 // | |
8 // Overview of operation: | |
9 // | |
10 // - An object of WASAPIAudioInputStream is created by the AudioManager | |
11 // factory. | |
12 // - Next some thread will call Open(), at that point the underlying | |
13 // Core Audio APIs are utilized to create two WASAPI interfaces called | |
14 // IAudioClient and IAudioCaptureClient. | |
15 // - Then some thread will call Start(sink). | |
16 // A thread called "wasapi_capture_thread" is started and this thread listens | |
17 // on an event signal which is set periodically by the audio engine for | |
18 // each recorded data packet. As a result, data samples will be provided | |
19 // to the registered sink. | |
20 // - At some point, a thread will call Stop(), which stops and joins the | |
21 // capture thread and at the same time stops audio streaming. | |
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. | |
24 // | |
25 // Implementation notes: | |
26 // | |
27 // - The minimum supported client is Windows Vista. | |
28 // - This implementation is single-threaded, hence: | |
29 // o Construction and destruction must take place from the same thread. | |
30 // o It is recommended to call all APIs from the same thread as well. | |
31 // - It is recommended to first acquire the native sample rate of the default | |
32 // input device and then use the same rate when creating this object. Use | |
33 // WASAPIAudioInputStream::HardwareSampleRate() to retrieve the sample rate. | |
34 // - Calling Close() also leads to self destruction. | |
35 // | |
36 // Core Audio API details: | |
37 // | |
38 // - CoInitializeEx() is called on the creating thread and on the internal | |
39 // capture thread. Each thread's concurrency model and apartment is set | |
40 // to multi-threaded (MTA). CHECK() is called to ensure that we crash if | |
41 // CoInitializeEx(MTA) fails. | |
42 // - Utilized MMDevice interfaces: | |
43 // o IMMDeviceEnumerator | |
44 // o IMMDevice | |
45 // - Utilized WASAPI interfaces: | |
46 // o IAudioClient | |
47 // o IAudioCaptureClient | |
48 // - The stream is initialized in shared mode and the processing of the | |
49 // audio buffer is event driven. | |
50 // - The Multimedia Class Scheduler service (MMCSS) is utilized to boost | |
51 // the priority of the capture thread. | |
52 // | |
53 #ifndef MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_INPUT_WIN_H_ | |
54 #define MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_INPUT_WIN_H_ | |
55 | |
56 #include <Audioclient.h> | |
57 #include <MMDeviceAPI.h> | |
58 | |
59 #include "base/compiler_specific.h" | |
60 #include "base/threading/platform_thread.h" | |
61 #include "base/threading/simple_thread.h" | |
62 #include "base/win/scoped_comptr.h" | |
63 #include "base/win/scoped_handle.h" | |
64 #include "media/audio/audio_io.h" | |
65 #include "media/audio/audio_parameters.h" | |
66 #include "media/audio/win/avrt_wrapper_win.h" | |
67 | |
68 class AudioManagerWin; | |
69 | |
70 // Initializes COM in the constructor (MTA), and uninitializes COM in the | |
71 // destructor. | |
72 class ScopedCOMInitializerMTA { | |
scherkus (not reviewing)
2011/10/18 21:12:30
would base/win/scoped_com_initializer.h suit your
henrika (OOO until Aug 14)
2011/10/19 15:42:43
Modified. Now uses base::win::ScopedCOMInitializer
| |
73 public: | |
74 ScopedCOMInitializerMTA() : hr_(CoInitializeEx(NULL, COINIT_MULTITHREADED)) { | |
75 CHECK(SUCCEEDED(hr_)); | |
76 #ifndef NDEBUG | |
77 creating_thread_id_ = base::PlatformThread::CurrentId(); | |
78 #endif | |
79 } | |
80 | |
81 ScopedCOMInitializerMTA::~ScopedCOMInitializerMTA() { | |
82 #ifndef NDEBUG | |
83 DCHECK_EQ(base::PlatformThread::CurrentId(), creating_thread_id_); | |
84 #endif | |
85 if (SUCCEEDED(hr_)) | |
86 CoUninitialize(); | |
87 } | |
88 | |
89 private: | |
90 HRESULT hr_; | |
91 #ifndef NDEBUG | |
92 base::PlatformThreadId creating_thread_id_; | |
93 #endif | |
94 DISALLOW_COPY_AND_ASSIGN(ScopedCOMInitializerMTA); | |
95 }; | |
96 | |
97 // A convenience class for COM memory handling. | |
98 template <class T> | |
99 class ScopedComMem { | |
scherkus (not reviewing)
2011/10/18 21:12:30
this appears nearly identical to chrome/common/sco
henrika (OOO until Aug 14)
2011/10/19 15:42:43
Thanks Andrew. I was able to refactor using your p
| |
100 public: | |
101 ScopedComMem() : ptr_(NULL) {} | |
102 ~ScopedComMem() { | |
103 Free(); | |
104 } | |
105 | |
106 T* operator->() { | |
107 DCHECK(ptr_ != NULL); | |
108 return ptr_; | |
109 } | |
110 | |
111 T* get() const { return ptr_; } | |
112 | |
113 T** Receive() { | |
114 DCHECK(ptr_ == NULL); | |
115 return &ptr_; | |
116 } | |
117 | |
118 void Free() { | |
119 if (ptr_) { | |
120 ::CoTaskMemFree(ptr_); | |
121 ptr_ = NULL; | |
122 } | |
123 } | |
124 | |
125 bool valid() const { return ptr_ != NULL; } | |
126 | |
127 protected: | |
128 T* ptr_; | |
129 | |
130 private: | |
131 DISALLOW_COPY_AND_ASSIGN(ScopedComMem); | |
132 }; | |
133 | |
134 // AudioInputStream implementation using Windows Core Audio APIs. | |
135 class WASAPIAudioInputStream : public AudioInputStream, | |
scherkus (not reviewing)
2011/10/18 21:12:30
nit: inititalizer list format
henrika (OOO until Aug 14)
2011/10/19 15:42:43
Done.
| |
136 public base::DelegateSimpleThread::Delegate { | |
137 public: | |
138 // The ctor takes all the usual parameters, plus |manager| which is the | |
139 // the audio manager who is creating this object. | |
140 WASAPIAudioInputStream(AudioManagerWin* manager, | |
141 const AudioParameters& params, | |
142 ERole device_role); | |
143 // The dtor is typically called by the AudioManager only and it is usually | |
144 // triggered by calling AudioInputStream::Close(). | |
145 virtual ~WASAPIAudioInputStream(); | |
146 | |
147 // Implementation of AudioInputStream. | |
148 virtual bool Open() OVERRIDE; | |
149 virtual void Start(AudioInputCallback* callback) OVERRIDE; | |
150 virtual void Stop() OVERRIDE; | |
151 virtual void Close() OVERRIDE; | |
152 | |
153 // Retrieve the stream format that the audio engine uses for its internal | |
154 // processing/mixing of shared-mode streams. | |
155 static double HardwareSampleRate(ERole device_role); | |
156 | |
157 bool started() const { return started_; } | |
158 | |
159 private: | |
160 // DelegateSimpleThread::Delegate implementation. | |
161 virtual void Run() OVERRIDE; | |
162 | |
163 // Issues the OnError() callback to the |sink_|. | |
164 void HandleError(HRESULT err); | |
165 | |
166 // The Open() method is divided into these sub methods. | |
167 HRESULT SetCaptureDevice(ERole device_role); | |
168 HRESULT ActivateCaptureDevice(); | |
169 HRESULT GetAudioEngineStreamFormat(); | |
170 bool DesiredFormatIsSupported(); | |
171 HRESULT InitializeAudioEngine(); | |
172 | |
173 // Initializes the COM library for use by the calling thread and set the | |
174 // thread's concurrency model to multi-threaded. | |
175 ScopedCOMInitializerMTA com_init_; | |
176 | |
177 // Contains the functions required to support MMCSS. | |
178 AvrtWrapper avrt_; | |
179 | |
180 // Our creator, the audio manager needs to be notified when we close. | |
181 AudioManagerWin* manager_; | |
182 | |
183 // Capturing is driven by this thread (which has no message loop). | |
184 // All OnData() callbacks will be called from this thread. | |
185 base::DelegateSimpleThread* capture_thread_; | |
186 | |
187 // Contains the desired audio format which is set up at construction. | |
188 WAVEFORMATEX format_; | |
189 | |
190 // Copy of the audio format which we know the audio engine supports. | |
191 // It is recommended to ensure that the sample rate in |format_| is identical | |
192 // to the sample rate in |audio_engine_mix_format_|. | |
193 ScopedComMem<WAVEFORMATEX> audio_engine_mix_format_; | |
194 | |
195 bool opened_; | |
196 bool started_; | |
197 | |
198 // Size in bytes of each audio frame (4 bytes for 16-bit stereo PCM) | |
199 size_t frame_size_; | |
200 | |
201 // Size in audio frames of each audio packet where an audio packet | |
202 // is defined as the block of data which the user received in each | |
203 // OnData() callback. | |
204 size_t packet_size_frames_; | |
205 | |
206 // Size in bytes of each audio packet. | |
207 size_t packet_size_bytes_; | |
208 | |
209 // Length of the audio endpoint buffer. | |
210 size_t endpoint_buffer_size_frames_; | |
211 | |
212 // Defines the role that the system has assigned to an audio endpoint device. | |
213 ERole device_role_; | |
214 | |
215 // Conversion factor used in delay-estimation calculations. | |
216 // Converts a raw performance counter value to 100-nanosecond unit. | |
217 double perf_count_to_100ns_units_; | |
218 | |
219 // Conversion factor used in delay-estimation calculations. | |
220 // Converts from milliseconds to audio frames. | |
221 double ms_to_frame_count_; | |
222 | |
223 // Pointer to the object that will receive the recorded audio samples. | |
224 AudioInputCallback* sink_; | |
225 | |
226 // An IMMDevice interface which represents an audio endpoint device. | |
227 base::win::ScopedComPtr<IMMDevice> endpoint_device_; | |
228 | |
229 // An IAudioClient interface which enables a client to create and initialize | |
230 // an audio stream between an audio application and the audio engine. | |
231 base::win::ScopedComPtr<IAudioClient> audio_client_; | |
232 | |
233 // The IAudioCaptureClient interface enables a client to read input data | |
234 // from a capture endpoint buffer. | |
235 base::win::ScopedComPtr<IAudioCaptureClient> audio_capture_client_; | |
236 | |
237 // The audio engine will signal this event each time a buffer has been | |
238 // recorded. | |
239 base::win::ScopedHandle audio_samples_ready_event_; | |
240 | |
241 // This event will be signaled when capturing shall stop. | |
242 base::win::ScopedHandle stop_capture_event_; | |
243 | |
244 DISALLOW_COPY_AND_ASSIGN(WASAPIAudioInputStream); | |
245 }; | |
246 | |
247 #endif // MEDIA_AUDIO_WIN_AUDIO_LOW_LATENCY_INPUT_WIN_H_ | |
OLD | NEW |