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

Side by Side Diff: remoting/host/audio_capturer_win.cc

Issue 10818010: Added support for multiple sampling rates on Windows. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 5 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 #include <windows.h> 5 #include <windows.h>
6 #include <audioclient.h> 6 #include <audioclient.h>
7 #include <avrt.h> 7 #include <avrt.h>
8 #include <mmdeviceapi.h> 8 #include <mmdeviceapi.h>
9 #include <mmreg.h> 9 #include <mmreg.h>
10 #include <mmsystem.h> 10 #include <mmsystem.h>
11 11
12 #include "base/basictypes.h" 12 #include "base/basictypes.h"
13 #include "base/logging.h" 13 #include "base/logging.h"
14 #include "base/memory/scoped_ptr.h" 14 #include "base/memory/scoped_ptr.h"
15 #include "base/message_loop.h" 15 #include "base/message_loop.h"
16 #include "base/timer.h" 16 #include "base/timer.h"
17 #include "base/win/scoped_co_mem.h" 17 #include "base/win/scoped_co_mem.h"
18 #include "base/win/scoped_com_initializer.h" 18 #include "base/win/scoped_com_initializer.h"
19 #include "base/win/scoped_comptr.h" 19 #include "base/win/scoped_comptr.h"
20 #include "remoting/host/audio_capturer.h" 20 #include "remoting/host/audio_capturer.h"
21 #include "remoting/proto/audio.pb.h" 21 #include "remoting/proto/audio.pb.h"
22 22
23 namespace { 23 namespace {
24 const int kChannels = 2; 24 const int kChannels = 2;
25 const int kBitsPerSample = 16; 25 const int kBitsPerSample = 16;
26 const int kSamplesPerSecond = 44100;
27 const int kBitsPerByte = 8; 26 const int kBitsPerByte = 8;
28 // Conversion factor from 100ns to 1ms. 27 // Conversion factor from 100ns to 1ms.
29 const int kHnsToMs = 10000; 28 const int kHnsToMs = 10000;
30 } // namespace 29 } // namespace
31 30
32 namespace remoting { 31 namespace remoting {
33 32
34 class AudioCapturerWin : public AudioCapturer { 33 class AudioCapturerWin : public AudioCapturer {
35 public: 34 public:
36 AudioCapturerWin(); 35 AudioCapturerWin();
37 virtual ~AudioCapturerWin(); 36 virtual ~AudioCapturerWin();
38 37
39 // AudioCapturer interface. 38 // AudioCapturer interface.
40 virtual bool Start(const PacketCapturedCallback& callback) OVERRIDE; 39 virtual bool Start(const PacketCapturedCallback& callback) OVERRIDE;
41 virtual void Stop() OVERRIDE; 40 virtual void Stop() OVERRIDE;
42 virtual bool IsRunning() OVERRIDE; 41 virtual bool IsRunning() OVERRIDE;
43 42
44 private: 43 private:
45 // Receives all packets from the audio capture endpoint buffer and pushes them 44 // Receives all packets from the audio capture endpoint buffer and pushes them
46 // to the network. 45 // to the network.
47 void DoCapture(); 46 void DoCapture();
48 47
49 PacketCapturedCallback callback_; 48 PacketCapturedCallback callback_;
50 49
50 AudioPacket::SamplingRate sampling_rate_;
51
51 scoped_ptr<base::RepeatingTimer<AudioCapturerWin> > capture_timer_; 52 scoped_ptr<base::RepeatingTimer<AudioCapturerWin> > capture_timer_;
52 base::TimeDelta audio_device_period_; 53 base::TimeDelta audio_device_period_;
53 54
54 base::win::ScopedCoMem<WAVEFORMATEX> wave_format_ex_; 55 base::win::ScopedCoMem<WAVEFORMATEX> wave_format_ex_;
55 base::win::ScopedComPtr<IAudioCaptureClient> audio_capture_client_; 56 base::win::ScopedComPtr<IAudioCaptureClient> audio_capture_client_;
56 base::win::ScopedComPtr<IAudioClient> audio_client_; 57 base::win::ScopedComPtr<IAudioClient> audio_client_;
57 base::win::ScopedComPtr<IMMDevice> mm_device_; 58 base::win::ScopedComPtr<IMMDevice> mm_device_;
58 scoped_ptr<base::win::ScopedCOMInitializer> com_initializer_; 59 scoped_ptr<base::win::ScopedCOMInitializer> com_initializer_;
59 60
60 base::ThreadChecker thread_checker_; 61 base::ThreadChecker thread_checker_;
61 62
62 DISALLOW_COPY_AND_ASSIGN(AudioCapturerWin); 63 DISALLOW_COPY_AND_ASSIGN(AudioCapturerWin);
63 }; 64 };
64 65
65 AudioCapturerWin::AudioCapturerWin() { 66 AudioCapturerWin::AudioCapturerWin()
67 : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID) {
Sergey Ulanov 2012/07/26 03:40:24 nit: initializer list should be indented 4 spaces
kxing 2012/07/26 22:47:17 Done.
66 thread_checker_.DetachFromThread(); 68 thread_checker_.DetachFromThread();
67 } 69 }
68 70
69 AudioCapturerWin::~AudioCapturerWin() { 71 AudioCapturerWin::~AudioCapturerWin() {
70 } 72 }
71 73
72 bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) { 74 bool AudioCapturerWin::Start(const PacketCapturedCallback& callback) {
73 DCHECK(!audio_capture_client_.get()); 75 DCHECK(!audio_capture_client_.get());
74 DCHECK(!audio_client_.get()); 76 DCHECK(!audio_client_.get());
75 DCHECK(!mm_device_.get()); 77 DCHECK(!mm_device_.get());
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 if (FAILED(hr)) { 126 if (FAILED(hr)) {
125 LOG(ERROR) << "Failed to get WAVEFORMATEX. Error " << hr; 127 LOG(ERROR) << "Failed to get WAVEFORMATEX. Error " << hr;
126 return false; 128 return false;
127 } 129 }
128 130
129 // Set the wave format 131 // Set the wave format
130 switch (wave_format_ex_->wFormatTag) { 132 switch (wave_format_ex_->wFormatTag) {
131 case WAVE_FORMAT_IEEE_FLOAT: 133 case WAVE_FORMAT_IEEE_FLOAT:
132 // Intentional fall-through. 134 // Intentional fall-through.
133 case WAVE_FORMAT_PCM: 135 case WAVE_FORMAT_PCM:
136 if (!AudioCapturer::IsValidSampleRate(wave_format_ex_->nSamplesPerSec)) {
Wez 2012/07/25 09:23:48 Rather than have a static test for validity, why n
kxing 2012/07/26 22:47:17 The set of valid sampling rates is the same across
Sergey Ulanov 2012/07/27 04:22:38 I discussed this with Kerry. This might be useful
137 LOG(ERROR) << "Host sampling rate is neither 44.1 kHz nor 48 kHz.";
138 return false;
Sergey Ulanov 2012/07/26 03:40:24 Can we still try to request some known sampling ra
kxing 2012/07/26 22:47:17 No, Pepper only supports 44.1 kHz and 48 kHz, and
139 }
140 sampling_rate_ =
141 static_cast<AudioPacket::SamplingRate>(
142 wave_format_ex_->nSamplesPerSec);
143
134 wave_format_ex_->wFormatTag = WAVE_FORMAT_PCM; 144 wave_format_ex_->wFormatTag = WAVE_FORMAT_PCM;
135 wave_format_ex_->nChannels = kChannels; 145 wave_format_ex_->nChannels = kChannels;
136 wave_format_ex_->nSamplesPerSec = kSamplesPerSecond;
137 wave_format_ex_->wBitsPerSample = kBitsPerSample; 146 wave_format_ex_->wBitsPerSample = kBitsPerSample;
138 wave_format_ex_->nBlockAlign = kChannels * kBitsPerSample / kBitsPerByte; 147 wave_format_ex_->nBlockAlign = kChannels * kBitsPerSample / kBitsPerByte;
139 wave_format_ex_->nAvgBytesPerSec = 148 wave_format_ex_->nAvgBytesPerSec =
140 kSamplesPerSecond * kChannels * kBitsPerSample / kBitsPerByte; 149 sampling_rate_ * kChannels * kBitsPerSample / kBitsPerByte;
141 break; 150 break;
142 case WAVE_FORMAT_EXTENSIBLE: { 151 case WAVE_FORMAT_EXTENSIBLE: {
143 PWAVEFORMATEXTENSIBLE wave_format_extensible = 152 PWAVEFORMATEXTENSIBLE wave_format_extensible =
144 reinterpret_cast<WAVEFORMATEXTENSIBLE*>( 153 reinterpret_cast<WAVEFORMATEXTENSIBLE*>(
145 static_cast<WAVEFORMATEX*>(wave_format_ex_)); 154 static_cast<WAVEFORMATEX*>(wave_format_ex_));
146 if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 155 if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
147 wave_format_extensible->SubFormat)) { 156 wave_format_extensible->SubFormat)) {
157 if (!AudioCapturer::IsValidSampleRate(
158 wave_format_extensible->Format.nSamplesPerSec)) {
Sergey Ulanov 2012/07/26 03:40:24 nit: incorrect indentation. move it four spaces to
kxing 2012/07/26 22:47:17 Done.
159 LOG(ERROR) << "Host sampling rate is neither 44.1 kHz nor 48 kHz.";
160 return false;
161 }
162 sampling_rate_ =
163 static_cast<AudioPacket::SamplingRate>(
164 wave_format_extensible->Format.nSamplesPerSec);
Sergey Ulanov 2012/07/26 03:40:24 nit: indent 4 spaces relative to the previous line
kxing 2012/07/26 22:47:17 Done.
165
148 wave_format_extensible->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; 166 wave_format_extensible->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
149 wave_format_extensible->Samples.wValidBitsPerSample = kBitsPerSample; 167 wave_format_extensible->Samples.wValidBitsPerSample = kBitsPerSample;
150 168
151 wave_format_extensible->Format.nChannels = kChannels; 169 wave_format_extensible->Format.nChannels = kChannels;
152 wave_format_extensible->Format.nSamplesPerSec = kSamplesPerSecond; 170 wave_format_extensible->Format.nSamplesPerSec = sampling_rate_;
153 wave_format_extensible->Format.wBitsPerSample = kBitsPerSample; 171 wave_format_extensible->Format.wBitsPerSample = kBitsPerSample;
154 wave_format_extensible->Format.nBlockAlign = 172 wave_format_extensible->Format.nBlockAlign =
155 kChannels * kBitsPerSample / kBitsPerByte; 173 kChannels * kBitsPerSample / kBitsPerByte;
156 wave_format_extensible->Format.nAvgBytesPerSec = 174 wave_format_extensible->Format.nAvgBytesPerSec =
157 kSamplesPerSecond * kChannels * kBitsPerSample / kBitsPerByte; 175 sampling_rate_ * kChannels * kBitsPerSample / kBitsPerByte;
158 } else { 176 } else {
159 LOG(ERROR) << "Failed to force 16-bit samples"; 177 LOG(ERROR) << "Failed to force 16-bit samples";
160 return false; 178 return false;
161 } 179 }
162 break; 180 break;
163 } 181 }
164 default: 182 default:
165 LOG(ERROR) << "Failed to force 16-bit samples"; 183 LOG(ERROR) << "Failed to force 16-bit samples";
Sergey Ulanov 2012/07/26 03:40:24 is this a correct error message?
kxing 2012/07/26 22:47:17 Done.
166 return false; 184 return false;
167 } 185 }
168 186
169 // Initialize the IAudioClient. 187 // Initialize the IAudioClient.
170 hr = audio_client_->Initialize(AUDCLNT_SHAREMODE_SHARED, 188 hr = audio_client_->Initialize(AUDCLNT_SHAREMODE_SHARED,
171 AUDCLNT_STREAMFLAGS_LOOPBACK, 189 AUDCLNT_STREAMFLAGS_LOOPBACK,
172 0, 190 0,
173 0, 191 0,
174 wave_format_ex_, 192 wave_format_ex_,
175 NULL); 193 NULL);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 232
215 thread_checker_.DetachFromThread(); 233 thread_checker_.DetachFromThread();
216 } 234 }
217 235
218 bool AudioCapturerWin::IsRunning() { 236 bool AudioCapturerWin::IsRunning() {
219 DCHECK(thread_checker_.CalledOnValidThread()); 237 DCHECK(thread_checker_.CalledOnValidThread());
220 return capture_timer_.get() != NULL; 238 return capture_timer_.get() != NULL;
221 } 239 }
222 240
223 void AudioCapturerWin::DoCapture() { 241 void AudioCapturerWin::DoCapture() {
242 DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_));
224 DCHECK(thread_checker_.CalledOnValidThread()); 243 DCHECK(thread_checker_.CalledOnValidThread());
225 DCHECK(IsRunning()); 244 DCHECK(IsRunning());
226 245
227 // Fetch all packets from the audio capture endpoint buffer. 246 // Fetch all packets from the audio capture endpoint buffer.
228 while (true) { 247 while (true) {
229 UINT32 next_packet_size; 248 UINT32 next_packet_size;
230 HRESULT hr = audio_capture_client_->GetNextPacketSize(&next_packet_size); 249 HRESULT hr = audio_capture_client_->GetNextPacketSize(&next_packet_size);
231 if (FAILED(hr)) { 250 if (FAILED(hr)) {
232 LOG(ERROR) << "Failed to GetNextPacketSize. Error " << hr; 251 LOG(ERROR) << "Failed to GetNextPacketSize. Error " << hr;
233 return; 252 return;
234 } 253 }
235 254
236 if (next_packet_size <= 0) { 255 if (next_packet_size <= 0) {
237 return; 256 return;
238 } 257 }
239 258
240 BYTE* data; 259 BYTE* data;
241 UINT32 frames; 260 UINT32 frames;
242 DWORD flags; 261 DWORD flags;
243 hr = audio_capture_client_->GetBuffer( 262 hr = audio_capture_client_->GetBuffer(
244 &data, &frames, &flags, NULL, NULL); 263 &data, &frames, &flags, NULL, NULL);
245 if (FAILED(hr)) { 264 if (FAILED(hr)) {
246 LOG(ERROR) << "Failed to GetBuffer. Error " << hr; 265 LOG(ERROR) << "Failed to GetBuffer. Error " << hr;
247 return; 266 return;
248 } 267 }
249 268
250 scoped_ptr<AudioPacket> packet = scoped_ptr<AudioPacket>(new AudioPacket()); 269 scoped_ptr<AudioPacket> packet = scoped_ptr<AudioPacket>(new AudioPacket());
251 packet->set_data(data, frames * wave_format_ex_->nBlockAlign); 270 packet->set_data(data, frames * wave_format_ex_->nBlockAlign);
271 packet->set_sampling_rate(sampling_rate_);
252 272
253 callback_.Run(packet.Pass()); 273 callback_.Run(packet.Pass());
254 274
255 hr = audio_capture_client_->ReleaseBuffer(frames); 275 hr = audio_capture_client_->ReleaseBuffer(frames);
256 if (FAILED(hr)) { 276 if (FAILED(hr)) {
257 LOG(ERROR) << "Failed to ReleaseBuffer. Error " << hr; 277 LOG(ERROR) << "Failed to ReleaseBuffer. Error " << hr;
258 return; 278 return;
259 } 279 }
260 } 280 }
261 } 281 }
262 282
263 scoped_ptr<AudioCapturer> AudioCapturer::Create() { 283 scoped_ptr<AudioCapturer> AudioCapturer::Create() {
264 return scoped_ptr<AudioCapturer>(new AudioCapturerWin()); 284 return scoped_ptr<AudioCapturer>(new AudioCapturerWin());
265 } 285 }
266 286
267 } // namespace remoting 287 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698