| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 <mmsystem.h> | 6 #include <mmsystem.h> |
| 7 #pragma comment(lib, "winmm.lib") | 7 #pragma comment(lib, "winmm.lib") |
| 8 | 8 |
| 9 #include "media/audio/win/waveout_output_win.h" | 9 #include "media/audio/win/waveout_output_win.h" |
| 10 | 10 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 // thus it forces you to maintain state, which naturally is not exactly | 22 // thus it forces you to maintain state, which naturally is not exactly |
| 23 // synchronized to the actual device state. | 23 // synchronized to the actual device state. |
| 24 // - Some functions, like waveOutReset cannot be called in the callback thread | 24 // - Some functions, like waveOutReset cannot be called in the callback thread |
| 25 // or called in any random state because they deadlock. This results in a | 25 // or called in any random state because they deadlock. This results in a |
| 26 // non- instantaneous Stop() method. waveOutPrepareHeader seems to be in the | 26 // non- instantaneous Stop() method. waveOutPrepareHeader seems to be in the |
| 27 // same boat. | 27 // same boat. |
| 28 // - waveOutReset() will forcefully kill the _waveThread so it is important | 28 // - waveOutReset() will forcefully kill the _waveThread so it is important |
| 29 // to make sure we are not executing inside the audio source's OnMoreData() | 29 // to make sure we are not executing inside the audio source's OnMoreData() |
| 30 // or that we take locks inside WaveCallback() or QueueNextPacket(). | 30 // or that we take locks inside WaveCallback() or QueueNextPacket(). |
| 31 | 31 |
| 32 // Enable or disable software folding |
| 33 #define FOLDING 1 |
| 34 |
| 32 namespace { | 35 namespace { |
| 33 | 36 |
| 34 // We settled for a double buffering scheme. It seems to strike a good balance | 37 // We settled for a double buffering scheme. It seems to strike a good balance |
| 35 // between how fast data needs to be provided versus memory usage. | 38 // between how fast data needs to be provided versus memory usage. |
| 36 const size_t kNumBuffers = 2; | 39 const size_t kNumBuffers = 2; |
| 37 | 40 |
| 38 // Sixty four MB is the maximum buffer size per AudioOutputStream. | 41 // Sixty four MB is the maximum buffer size per AudioOutputStream. |
| 39 const size_t kMaxOpenBufferSize = 1024 * 1024 * 64; | 42 const size_t kMaxOpenBufferSize = 1024 * 1024 * 64; |
| 40 | 43 |
| 41 // Our sound buffers are allocated once and kept in a linked list using the | 44 // Our sound buffers are allocated once and kept in a linked list using the |
| 42 // the WAVEHDR::dwUser variable. The last buffer points to the first buffer. | 45 // the WAVEHDR::dwUser variable. The last buffer points to the first buffer. |
| 43 WAVEHDR* GetNextBuffer(WAVEHDR* current) { | 46 WAVEHDR* GetNextBuffer(WAVEHDR* current) { |
| 44 return reinterpret_cast<WAVEHDR*>(current->dwUser); | 47 return reinterpret_cast<WAVEHDR*>(current->dwUser); |
| 45 } | 48 } |
| 46 | 49 |
| 47 } // namespace | 50 } // namespace |
| 48 | 51 |
| 49 PCMWaveOutAudioOutputStream::PCMWaveOutAudioOutputStream( | 52 PCMWaveOutAudioOutputStream::PCMWaveOutAudioOutputStream( |
| 50 AudioManagerWin* manager, int channels, int sampling_rate, | 53 AudioManagerWin* manager, int channels, int sampling_rate, |
| 51 char bits_per_sample, UINT device_id) | 54 char bits_per_sample, UINT device_id) |
| 52 : state_(PCMA_BRAND_NEW), | 55 : state_(PCMA_BRAND_NEW), |
| 53 manager_(manager), | 56 manager_(manager), |
| 54 device_id_(device_id), | 57 device_id_(device_id), |
| 55 waveout_(NULL), | 58 waveout_(NULL), |
| 56 callback_(NULL), | 59 callback_(NULL), |
| 57 buffer_(NULL), | 60 buffer_(NULL), |
| 58 buffer_size_(0), | 61 buffer_size_(0), |
| 59 volume_(1) { | 62 volume_(1), |
| 63 channels_(channels) { |
| 60 format_.wFormatTag = WAVE_FORMAT_PCM; | 64 format_.wFormatTag = WAVE_FORMAT_PCM; |
| 65 #ifdef FOLDING |
| 66 format_.nChannels = channels > 2 ? 2 : channels; |
| 67 #else |
| 61 format_.nChannels = channels; | 68 format_.nChannels = channels; |
| 69 #endif |
| 62 format_.nSamplesPerSec = sampling_rate; | 70 format_.nSamplesPerSec = sampling_rate; |
| 63 format_.wBitsPerSample = bits_per_sample; | 71 format_.wBitsPerSample = bits_per_sample; |
| 64 format_.cbSize = 0; | 72 format_.cbSize = 0; |
| 65 // The next are computed from above. | 73 // The next are computed from above. |
| 66 format_.nBlockAlign = (format_.nChannels * format_.wBitsPerSample) / 8; | 74 format_.nBlockAlign = (format_.nChannels * format_.wBitsPerSample) / 8; |
| 67 format_.nAvgBytesPerSec = format_.nBlockAlign * format_.nSamplesPerSec; | 75 format_.nAvgBytesPerSec = format_.nBlockAlign * format_.nSamplesPerSec; |
| 68 // The event is auto-reset. | 76 // The event is auto-reset. |
| 69 stopped_event_.Set(::CreateEventW(NULL, FALSE, FALSE, NULL)); | 77 stopped_event_.Set(::CreateEventW(NULL, FALSE, FALSE, NULL)); |
| 70 } | 78 } |
| 71 | 79 |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 DLOG(WARNING) << "PCMWaveOutAudio error " << error; | 227 DLOG(WARNING) << "PCMWaveOutAudio error " << error; |
| 220 callback_->OnError(this, error); | 228 callback_->OnError(this, error); |
| 221 } | 229 } |
| 222 | 230 |
| 223 void PCMWaveOutAudioOutputStream::QueueNextPacket(WAVEHDR *buffer) { | 231 void PCMWaveOutAudioOutputStream::QueueNextPacket(WAVEHDR *buffer) { |
| 224 // Call the source which will fill our buffer with pleasant sounds and | 232 // Call the source which will fill our buffer with pleasant sounds and |
| 225 // return to us how many bytes were used. | 233 // return to us how many bytes were used. |
| 226 // TODO(fbarchard): Handle used 0 by queueing more. | 234 // TODO(fbarchard): Handle used 0 by queueing more. |
| 227 size_t used = callback_->OnMoreData(this, buffer->lpData, buffer_size_); | 235 size_t used = callback_->OnMoreData(this, buffer->lpData, buffer_size_); |
| 228 if (used <= buffer_size_) { | 236 if (used <= buffer_size_) { |
| 229 buffer->dwBufferLength = used; | 237 buffer->dwBufferLength = used * format_.nChannels / channels_; |
| 230 media::AdjustVolume(buffer->lpData, buffer->dwBufferLength, | 238 if (channels_ > 2 && format_.nChannels == 2) { |
| 231 format_.nChannels, format_.wBitsPerSample >> 3, | 239 media::FoldChannels(buffer->lpData, used, |
| 232 volume_); | 240 channels_, format_.wBitsPerSample >> 3, |
| 241 volume_); |
| 242 } else { |
| 243 media::AdjustVolume(buffer->lpData, used, |
| 244 format_.nChannels, format_.wBitsPerSample >> 3, |
| 245 volume_); |
| 246 } |
| 247 |
| 233 } else { | 248 } else { |
| 234 HandleError(0); | 249 HandleError(0); |
| 235 return; | 250 return; |
| 236 } | 251 } |
| 237 buffer->dwFlags = WHDR_PREPARED; | 252 buffer->dwFlags = WHDR_PREPARED; |
| 238 } | 253 } |
| 239 | 254 |
| 240 // Windows call us back in this function when some events happen. Most notably | 255 // Windows call us back in this function when some events happen. Most notably |
| 241 // when it is done playing a buffer. Since we use double buffering it is | 256 // when it is done playing a buffer. Since we use double buffering it is |
| 242 // convenient to think of |buffer| as free and GetNextBuffer(buffer) as in | 257 // convenient to think of |buffer| as free and GetNextBuffer(buffer) as in |
| (...skipping 28 matching lines...) Expand all Loading... |
| 271 if (result != MMSYSERR_NOERROR) | 286 if (result != MMSYSERR_NOERROR) |
| 272 obj->HandleError(result); | 287 obj->HandleError(result); |
| 273 | 288 |
| 274 } else if (msg == WOM_CLOSE) { | 289 } else if (msg == WOM_CLOSE) { |
| 275 // We can be closed before calling Start, so it is possible to have a | 290 // We can be closed before calling Start, so it is possible to have a |
| 276 // null callback at this point. | 291 // null callback at this point. |
| 277 if (obj->callback_) | 292 if (obj->callback_) |
| 278 obj->callback_->OnClose(obj); | 293 obj->callback_->OnClose(obj); |
| 279 } | 294 } |
| 280 } | 295 } |
| OLD | NEW |