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

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: Uploaded the correct set of changes 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
« no previous file with comments | « remoting/host/audio_capturer.cc ('k') | remoting/remoting.gyp » ('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 #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()
66 thread_checker_.DetachFromThread(); 67 : sampling_rate_(AudioPacket::SAMPLING_RATE_INVALID) {
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());
76 DCHECK(static_cast<PWAVEFORMATEX>(wave_format_ex_) == NULL); 78 DCHECK(static_cast<PWAVEFORMATEX>(wave_format_ex_) == NULL);
(...skipping 47 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)) {
137 LOG(ERROR) << "Host sampling rate is neither 44.1 kHz nor 48 kHz.";
138 return false;
139 }
140 sampling_rate_ = static_cast<AudioPacket::SamplingRate>(
141 wave_format_ex_->nSamplesPerSec);
142
134 wave_format_ex_->wFormatTag = WAVE_FORMAT_PCM; 143 wave_format_ex_->wFormatTag = WAVE_FORMAT_PCM;
135 wave_format_ex_->nChannels = kChannels; 144 wave_format_ex_->nChannels = kChannels;
136 wave_format_ex_->nSamplesPerSec = kSamplesPerSecond;
137 wave_format_ex_->wBitsPerSample = kBitsPerSample; 145 wave_format_ex_->wBitsPerSample = kBitsPerSample;
138 wave_format_ex_->nBlockAlign = kChannels * kBitsPerSample / kBitsPerByte; 146 wave_format_ex_->nBlockAlign = kChannels * kBitsPerSample / kBitsPerByte;
139 wave_format_ex_->nAvgBytesPerSec = 147 wave_format_ex_->nAvgBytesPerSec =
140 kSamplesPerSecond * kChannels * kBitsPerSample / kBitsPerByte; 148 sampling_rate_ * kChannels * kBitsPerSample / kBitsPerByte;
141 break; 149 break;
142 case WAVE_FORMAT_EXTENSIBLE: { 150 case WAVE_FORMAT_EXTENSIBLE: {
143 PWAVEFORMATEXTENSIBLE wave_format_extensible = 151 PWAVEFORMATEXTENSIBLE wave_format_extensible =
144 reinterpret_cast<WAVEFORMATEXTENSIBLE*>( 152 reinterpret_cast<WAVEFORMATEXTENSIBLE*>(
145 static_cast<WAVEFORMATEX*>(wave_format_ex_)); 153 static_cast<WAVEFORMATEX*>(wave_format_ex_));
146 if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 154 if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
147 wave_format_extensible->SubFormat)) { 155 wave_format_extensible->SubFormat)) {
156 if (!AudioCapturer::IsValidSampleRate(
157 wave_format_extensible->Format.nSamplesPerSec)) {
158 LOG(ERROR) << "Host sampling rate is neither 44.1 kHz nor 48 kHz.";
159 return false;
160 }
161 sampling_rate_ = static_cast<AudioPacket::SamplingRate>(
162 wave_format_extensible->Format.nSamplesPerSec);
163
148 wave_format_extensible->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; 164 wave_format_extensible->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
149 wave_format_extensible->Samples.wValidBitsPerSample = kBitsPerSample; 165 wave_format_extensible->Samples.wValidBitsPerSample = kBitsPerSample;
150 166
151 wave_format_extensible->Format.nChannels = kChannels; 167 wave_format_extensible->Format.nChannels = kChannels;
152 wave_format_extensible->Format.nSamplesPerSec = kSamplesPerSecond; 168 wave_format_extensible->Format.nSamplesPerSec = sampling_rate_;
153 wave_format_extensible->Format.wBitsPerSample = kBitsPerSample; 169 wave_format_extensible->Format.wBitsPerSample = kBitsPerSample;
154 wave_format_extensible->Format.nBlockAlign = 170 wave_format_extensible->Format.nBlockAlign =
155 kChannels * kBitsPerSample / kBitsPerByte; 171 kChannels * kBitsPerSample / kBitsPerByte;
156 wave_format_extensible->Format.nAvgBytesPerSec = 172 wave_format_extensible->Format.nAvgBytesPerSec =
157 kSamplesPerSecond * kChannels * kBitsPerSample / kBitsPerByte; 173 sampling_rate_ * kChannels * kBitsPerSample / kBitsPerByte;
158 } else { 174 } else {
159 LOG(ERROR) << "Failed to force 16-bit samples"; 175 LOG(ERROR) << "Failed to force 16-bit samples";
160 return false; 176 return false;
161 } 177 }
162 break; 178 break;
163 } 179 }
164 default: 180 default:
165 LOG(ERROR) << "Failed to force 16-bit samples"; 181 LOG(ERROR) << "Failed to force 16-bit PCM";
166 return false; 182 return false;
167 } 183 }
168 184
169 // Initialize the IAudioClient. 185 // Initialize the IAudioClient.
170 hr = audio_client_->Initialize(AUDCLNT_SHAREMODE_SHARED, 186 hr = audio_client_->Initialize(AUDCLNT_SHAREMODE_SHARED,
171 AUDCLNT_STREAMFLAGS_LOOPBACK, 187 AUDCLNT_STREAMFLAGS_LOOPBACK,
172 0, 188 0,
173 0, 189 0,
174 wave_format_ex_, 190 wave_format_ex_,
175 NULL); 191 NULL);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 230
215 thread_checker_.DetachFromThread(); 231 thread_checker_.DetachFromThread();
216 } 232 }
217 233
218 bool AudioCapturerWin::IsRunning() { 234 bool AudioCapturerWin::IsRunning() {
219 DCHECK(thread_checker_.CalledOnValidThread()); 235 DCHECK(thread_checker_.CalledOnValidThread());
220 return capture_timer_.get() != NULL; 236 return capture_timer_.get() != NULL;
221 } 237 }
222 238
223 void AudioCapturerWin::DoCapture() { 239 void AudioCapturerWin::DoCapture() {
240 DCHECK(AudioCapturer::IsValidSampleRate(sampling_rate_));
224 DCHECK(thread_checker_.CalledOnValidThread()); 241 DCHECK(thread_checker_.CalledOnValidThread());
225 DCHECK(IsRunning()); 242 DCHECK(IsRunning());
226 243
227 // Fetch all packets from the audio capture endpoint buffer. 244 // Fetch all packets from the audio capture endpoint buffer.
228 while (true) { 245 while (true) {
229 UINT32 next_packet_size; 246 UINT32 next_packet_size;
230 HRESULT hr = audio_capture_client_->GetNextPacketSize(&next_packet_size); 247 HRESULT hr = audio_capture_client_->GetNextPacketSize(&next_packet_size);
231 if (FAILED(hr)) { 248 if (FAILED(hr)) {
232 LOG(ERROR) << "Failed to GetNextPacketSize. Error " << hr; 249 LOG(ERROR) << "Failed to GetNextPacketSize. Error " << hr;
233 return; 250 return;
234 } 251 }
235 252
236 if (next_packet_size <= 0) { 253 if (next_packet_size <= 0) {
237 return; 254 return;
238 } 255 }
239 256
240 BYTE* data; 257 BYTE* data;
241 UINT32 frames; 258 UINT32 frames;
242 DWORD flags; 259 DWORD flags;
243 hr = audio_capture_client_->GetBuffer( 260 hr = audio_capture_client_->GetBuffer(
244 &data, &frames, &flags, NULL, NULL); 261 &data, &frames, &flags, NULL, NULL);
245 if (FAILED(hr)) { 262 if (FAILED(hr)) {
246 LOG(ERROR) << "Failed to GetBuffer. Error " << hr; 263 LOG(ERROR) << "Failed to GetBuffer. Error " << hr;
247 return; 264 return;
248 } 265 }
249 266
250 scoped_ptr<AudioPacket> packet = scoped_ptr<AudioPacket>(new AudioPacket()); 267 scoped_ptr<AudioPacket> packet = scoped_ptr<AudioPacket>(new AudioPacket());
251 packet->set_data(data, frames * wave_format_ex_->nBlockAlign); 268 packet->set_data(data, frames * wave_format_ex_->nBlockAlign);
269 packet->set_sampling_rate(sampling_rate_);
252 270
253 callback_.Run(packet.Pass()); 271 callback_.Run(packet.Pass());
254 272
255 hr = audio_capture_client_->ReleaseBuffer(frames); 273 hr = audio_capture_client_->ReleaseBuffer(frames);
256 if (FAILED(hr)) { 274 if (FAILED(hr)) {
257 LOG(ERROR) << "Failed to ReleaseBuffer. Error " << hr; 275 LOG(ERROR) << "Failed to ReleaseBuffer. Error " << hr;
258 return; 276 return;
259 } 277 }
260 } 278 }
261 } 279 }
262 280
263 scoped_ptr<AudioCapturer> AudioCapturer::Create() { 281 scoped_ptr<AudioCapturer> AudioCapturer::Create() {
264 return scoped_ptr<AudioCapturer>(new AudioCapturerWin()); 282 return scoped_ptr<AudioCapturer>(new AudioCapturerWin());
265 } 283 }
266 284
267 } // namespace remoting 285 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/audio_capturer.cc ('k') | remoting/remoting.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698