Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 "media/audio/mac/audio_manager_mac.h" | 5 #include "media/audio/mac/audio_manager_mac.h" |
| 6 #include "media/audio/mac/audio_output_mac.h" | 6 #include "media/audio/mac/audio_output_mac.h" |
| 7 | 7 |
| 8 #include "base/basictypes.h" | 8 #include "base/basictypes.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 | 10 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 30 kAudioQueueErr_EnqueueDuringReset = -66632 | 30 kAudioQueueErr_EnqueueDuringReset = -66632 |
| 31 }; | 31 }; |
| 32 | 32 |
| 33 PCMQueueOutAudioOutputStream::PCMQueueOutAudioOutputStream( | 33 PCMQueueOutAudioOutputStream::PCMQueueOutAudioOutputStream( |
| 34 AudioManagerMac* manager, int channels, int sampling_rate, | 34 AudioManagerMac* manager, int channels, int sampling_rate, |
| 35 char bits_per_sample) | 35 char bits_per_sample) |
| 36 : format_(), | 36 : format_(), |
| 37 audio_queue_(NULL), | 37 audio_queue_(NULL), |
| 38 buffer_(), | 38 buffer_(), |
| 39 source_(NULL), | 39 source_(NULL), |
| 40 manager_(manager) { | 40 manager_(manager), |
| 41 silence_bytes_(0), | |
| 42 pending_bytes_(0) { | |
| 41 // We must have a manager. | 43 // We must have a manager. |
| 42 DCHECK(manager_); | 44 DCHECK(manager_); |
| 43 // A frame is one sample across all channels. In interleaved audio the per | 45 // A frame is one sample across all channels. In interleaved audio the per |
| 44 // frame fields identify the set of n |channels|. In uncompressed audio, a | 46 // frame fields identify the set of n |channels|. In uncompressed audio, a |
| 45 // packet is always one frame. | 47 // packet is always one frame. |
| 46 format_.mSampleRate = sampling_rate; | 48 format_.mSampleRate = sampling_rate; |
| 47 format_.mFormatID = kAudioFormatLinearPCM; | 49 format_.mFormatID = kAudioFormatLinearPCM; |
| 48 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked | | 50 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked | |
| 49 kLinearPCMFormatFlagIsSignedInteger; | 51 kLinearPCMFormatFlagIsSignedInteger; |
| 50 format_.mBitsPerChannel = bits_per_sample; | 52 format_.mBitsPerChannel = bits_per_sample; |
| 51 format_.mChannelsPerFrame = channels; | 53 format_.mChannelsPerFrame = channels; |
| 52 format_.mFramesPerPacket = 1; | 54 format_.mFramesPerPacket = 1; |
| 53 format_.mBytesPerPacket = (format_.mBitsPerChannel * channels) / 8; | 55 format_.mBytesPerPacket = (format_.mBitsPerChannel * channels) / 8; |
| 54 format_.mBytesPerFrame = format_.mBytesPerPacket; | 56 format_.mBytesPerFrame = format_.mBytesPerPacket; |
| 57 | |
| 58 // Silence buffer has a duration of 6ms to simulate the behavior of Windows. | |
| 59 // This value is choosen by experiments and macs cannot keep up with | |
| 60 // anything less than 6ms. | |
| 61 silence_bytes_ = format_.mBytesPerFrame * sampling_rate * 6 / 1000; | |
| 55 } | 62 } |
| 56 | 63 |
| 57 PCMQueueOutAudioOutputStream::~PCMQueueOutAudioOutputStream() { | 64 PCMQueueOutAudioOutputStream::~PCMQueueOutAudioOutputStream() { |
| 58 } | 65 } |
| 59 | 66 |
| 60 void PCMQueueOutAudioOutputStream::HandleError(OSStatus err) { | 67 void PCMQueueOutAudioOutputStream::HandleError(OSStatus err) { |
| 61 // source_ can be set to NULL from another thread. We need to cache its | 68 // source_ can be set to NULL from another thread. We need to cache its |
| 62 // pointer while we operate here. Note that does not mean that the source | 69 // pointer while we operate here. Note that does not mean that the source |
| 63 // has been destroyed. | 70 // has been destroyed. |
| 64 AudioSourceCallback* source = source_; | 71 AudioSourceCallback* source = source_; |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 152 void PCMQueueOutAudioOutputStream::RenderCallback(void* p_this, | 159 void PCMQueueOutAudioOutputStream::RenderCallback(void* p_this, |
| 153 AudioQueueRef queue, | 160 AudioQueueRef queue, |
| 154 AudioQueueBufferRef buffer) { | 161 AudioQueueBufferRef buffer) { |
| 155 PCMQueueOutAudioOutputStream* audio_stream = | 162 PCMQueueOutAudioOutputStream* audio_stream = |
| 156 static_cast<PCMQueueOutAudioOutputStream*>(p_this); | 163 static_cast<PCMQueueOutAudioOutputStream*>(p_this); |
| 157 // Call the audio source to fill the free buffer with data. Not having a | 164 // Call the audio source to fill the free buffer with data. Not having a |
| 158 // source means that the queue has been closed. This is not an error. | 165 // source means that the queue has been closed. This is not an error. |
| 159 AudioSourceCallback* source = audio_stream->source_; | 166 AudioSourceCallback* source = audio_stream->source_; |
| 160 if (!source) | 167 if (!source) |
| 161 return; | 168 return; |
| 169 | |
| 170 // Adjust the number of pending bytes by subtracting the amount played. | |
| 171 audio_stream->pending_bytes_ -= buffer->mAudioDataByteSize; | |
| 162 size_t capacity = buffer->mAudioDataBytesCapacity; | 172 size_t capacity = buffer->mAudioDataBytesCapacity; |
| 163 // TODO(hclam): Provide pending bytes. | |
| 164 size_t filled = source->OnMoreData(audio_stream, buffer->mAudioData, | 173 size_t filled = source->OnMoreData(audio_stream, buffer->mAudioData, |
| 165 capacity, 0); | 174 capacity, audio_stream->pending_bytes_); |
| 175 | |
| 176 // In order to keep the callback running, we need to provide a positive amount | |
| 177 // of data to the audio queue. To simulate the behavior of Windows, we write | |
| 178 // a buffer of silence. | |
| 179 if (!filled) { | |
| 180 CHECK(audio_stream->silence_bytes_ <= static_cast<int>(capacity)); | |
| 181 filled = audio_stream->silence_bytes_; | |
| 182 memset(buffer->mAudioData, 0, filled); | |
| 183 } | |
| 184 | |
|
cpu_(ooo_6.6-7.5)
2009/09/16 18:06:26
Won't it be much easier we just simply don't call
Alpha Left Google
2009/09/16 18:25:34
AudioQueue works as a circular buffer, if we don't
| |
| 166 if (filled > capacity) { | 185 if (filled > capacity) { |
| 167 // User probably overran our buffer. | 186 // User probably overran our buffer. |
| 168 audio_stream->HandleError(0); | 187 audio_stream->HandleError(0); |
| 169 return; | 188 return; |
| 170 } | 189 } |
| 171 buffer->mAudioDataByteSize = filled; | 190 buffer->mAudioDataByteSize = filled; |
| 191 // Incremnet bytes by amount filled into audio buffer. | |
| 192 audio_stream->pending_bytes_ += filled; | |
| 172 if (NULL == queue) | 193 if (NULL == queue) |
| 173 return; | 194 return; |
| 174 // Queue the audio data to the audio driver. | 195 // Queue the audio data to the audio driver. |
| 175 OSStatus err = AudioQueueEnqueueBuffer(queue, buffer, 0, NULL); | 196 OSStatus err = AudioQueueEnqueueBuffer(queue, buffer, 0, NULL); |
| 176 if (err != noErr) { | 197 if (err != noErr) { |
| 177 if (err == kAudioQueueErr_EnqueueDuringReset) { | 198 if (err == kAudioQueueErr_EnqueueDuringReset) { |
| 178 // This is the error you get if you try to enqueue a buffer and the | 199 // This is the error you get if you try to enqueue a buffer and the |
| 179 // queue has been closed. Not really a problem if indeed the queue | 200 // queue has been closed. Not really a problem if indeed the queue |
| 180 // has been closed. | 201 // has been closed. |
| 181 if (!audio_stream->source_) | 202 if (!audio_stream->source_) |
| 182 return; | 203 return; |
| 183 } | 204 } |
| 184 audio_stream->HandleError(err); | 205 audio_stream->HandleError(err); |
| 185 } | 206 } |
| 186 } | 207 } |
| 187 | 208 |
| 188 void PCMQueueOutAudioOutputStream::Start(AudioSourceCallback* callback) { | 209 void PCMQueueOutAudioOutputStream::Start(AudioSourceCallback* callback) { |
| 189 DCHECK(callback); | 210 DCHECK(callback); |
| 190 OSStatus err = AudioQueueStart(audio_queue_, NULL); | 211 OSStatus err = noErr; |
| 191 if (err != noErr) { | |
| 192 HandleError(err); | |
| 193 return; | |
| 194 } | |
| 195 source_ = callback; | 212 source_ = callback; |
| 213 pending_bytes_ = 0; | |
| 196 // Ask the source to pre-fill all our buffers before playing. | 214 // Ask the source to pre-fill all our buffers before playing. |
| 197 for(size_t ix = 0; ix != kNumBuffers; ++ix) { | 215 for(size_t ix = 0; ix != kNumBuffers; ++ix) { |
| 216 buffer_[ix]->mAudioDataByteSize = 0; | |
| 198 RenderCallback(this, NULL, buffer_[ix]); | 217 RenderCallback(this, NULL, buffer_[ix]); |
| 199 } | 218 } |
| 200 // Queue the buffers to the audio driver, sounds starts now. | 219 // Queue the buffers to the audio driver, sounds starts now. |
| 201 for(size_t ix = 0; ix != kNumBuffers; ++ix) { | 220 for(size_t ix = 0; ix != kNumBuffers; ++ix) { |
| 202 err = AudioQueueEnqueueBuffer(audio_queue_, buffer_[ix], 0, NULL); | 221 err = AudioQueueEnqueueBuffer(audio_queue_, buffer_[ix], 0, NULL); |
| 203 if (err != noErr) { | 222 if (err != noErr) { |
| 204 HandleError(err); | 223 HandleError(err); |
| 205 return; | 224 return; |
| 206 } | 225 } |
| 207 } | 226 } |
| 227 err = AudioQueueStart(audio_queue_, NULL); | |
| 228 if (err != noErr) { | |
| 229 HandleError(err); | |
| 230 return; | |
| 231 } | |
| 208 } | 232 } |
| 209 | 233 |
| OLD | NEW |