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