15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/mac/audio_input_mac.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/mac_logging.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/audio_manager_base.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/audio_util.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_IOS) 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <CoreServices/CoreServices.h> 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace media { 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PCMQueueInAudioInputStream::PCMQueueInAudioInputStream( 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AudioManagerBase* manager, const AudioParameters& params) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : manager_(manager), 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_(NULL), 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) audio_queue_(NULL), 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer_size_bytes_(0), 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) started_(false) { 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We must have a manager. 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(manager_); 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A frame is one sample across all channels. In interleaved audio the per 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // frame fields identify the set of n |channels|. In uncompressed audio, a 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // packet is always one frame. 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) format_.mSampleRate = params.sample_rate(); 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) format_.mFormatID = kAudioFormatLinearPCM; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) format_.mFormatFlags = kLinearPCMFormatFlagIsPacked | 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kLinearPCMFormatFlagIsSignedInteger; 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) format_.mBitsPerChannel = params.bits_per_sample(); 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) format_.mChannelsPerFrame = params.channels(); 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) format_.mFramesPerPacket = 1; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) format_.mBytesPerPacket = (params.bits_per_sample() * params.channels()) / 8; 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) format_.mBytesPerFrame = format_.mBytesPerPacket; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) format_.mReserved = 0; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer_size_bytes_ = params.GetBytesPerBuffer(); 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PCMQueueInAudioInputStream::~PCMQueueInAudioInputStream() { 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!callback_); 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!audio_queue_); 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PCMQueueInAudioInputStream::Open() { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OSStatus err = AudioQueueNewInput(&format_, 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &HandleInputBufferStatic, 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this, 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, // Use OS CFRunLoop for |callback| 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kCFRunLoopCommonModes, 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, // Reserved 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &audio_queue_); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (err != noErr) { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleError(err); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SetupBuffers(); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PCMQueueInAudioInputStream::Start(AudioInputCallback* callback) { 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(callback); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG_IF(ERROR, !audio_queue_) << "Open() has not been called successfully"; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (callback_ || !audio_queue_) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_ = callback; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OSStatus err = AudioQueueStart(audio_queue_, NULL); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (err != noErr) { 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleError(err); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) started_ = true; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PCMQueueInAudioInputStream::Stop() { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!audio_queue_ || !started_) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We request a synchronous stop, so the next call can take some time. In 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the windows implementation we block here as well. 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OSStatus err = AudioQueueStop(audio_queue_, true); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (err != noErr) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleError(err); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) started_ = false; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PCMQueueInAudioInputStream::Close() { 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It is valid to call Close() before calling Open() or Start(), thus 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |audio_queue_| and |callback_| might be NULL. 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (audio_queue_) { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OSStatus err = AudioQueueDispose(audio_queue_, true); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) audio_queue_ = NULL; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (err != noErr) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleError(err); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (callback_) { 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_->OnClose(this); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_ = NULL; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) manager_->ReleaseInputStream(this); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // CARE: This object may now be destroyed. 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)double PCMQueueInAudioInputStream::GetMaxVolume() { 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "Only supported for low-latency mode."; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0.0; 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PCMQueueInAudioInputStream::SetVolume(double volume) { 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "Only supported for low-latency mode."; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)double PCMQueueInAudioInputStream::GetVolume() { 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "Only supported for low-latency mode."; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0.0; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PCMQueueInAudioInputStream::SetAutomaticGainControl(bool enabled) { 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "Only supported for low-latency mode."; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PCMQueueInAudioInputStream::GetAutomaticGainControl() { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "Only supported for low-latency mode."; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PCMQueueInAudioInputStream::HandleError(OSStatus err) { 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (callback_) 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback_->OnError(this); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This point should never be reached. 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OSSTATUS_DCHECK(0, err); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PCMQueueInAudioInputStream::SetupBuffers() { 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(buffer_size_bytes_); 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < kNumberBuffers; ++i) { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AudioQueueBufferRef buffer; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OSStatus err = AudioQueueAllocateBuffer(audio_queue_, 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer_size_bytes_, 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &buffer); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (err == noErr) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err = QueueNextBuffer(buffer); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (err != noErr) { 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleError(err); 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |buffer| will automatically be freed when |audio_queue_| is released. 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OSStatus PCMQueueInAudioInputStream::QueueNextBuffer( 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AudioQueueBufferRef audio_buffer) { 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only the first 2 params are needed for recording. 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return AudioQueueEnqueueBuffer(audio_queue_, audio_buffer, 0, NULL); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PCMQueueInAudioInputStream::HandleInputBufferStatic( 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* data, 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AudioQueueRef audio_queue, 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AudioQueueBufferRef audio_buffer, 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AudioTimeStamp* start_time, 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UInt32 num_packets, 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AudioStreamPacketDescription* desc) { 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<PCMQueueInAudioInputStream*>(data)-> 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleInputBuffer(audio_queue, audio_buffer, start_time, 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_packets, desc); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PCMQueueInAudioInputStream::HandleInputBuffer( 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AudioQueueRef audio_queue, 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AudioQueueBufferRef audio_buffer, 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AudioTimeStamp* start_time, 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UInt32 num_packets, 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AudioStreamPacketDescription* packet_desc) { 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(audio_queue_, audio_queue); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(audio_buffer->mAudioData); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!callback_) { 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This can happen if Stop() was called without start. 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(0U, audio_buffer->mAudioDataByteSize); 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (audio_buffer->mAudioDataByteSize) { 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The AudioQueue API may use a large internal buffer and repeatedly call us 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // back to back once that internal buffer is filled. When this happens the 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // renderer client does not have enough time to read data back from the 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // shared memory before the next write comes along. If HandleInputBuffer() 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // is called too frequently, Sleep() at least 5ms to ensure the shared 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // memory doesn't get trampled. 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(dalecurtis): This is a HACK. Long term the AudioQueue path is going 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // away in favor of the AudioUnit based AUAudioInputStream(). Tracked by 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // http://crbug.com/161383. 2007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::TimeDelta elapsed = base::TimeTicks::Now() - last_fill_; 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::TimeDelta kMinDelay = base::TimeDelta::FromMilliseconds(5); 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (elapsed < kMinDelay) 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::PlatformThread::Sleep(kMinDelay - elapsed); 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_->OnData(this, 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<const uint8*>(audio_buffer->mAudioData), 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) audio_buffer->mAudioDataByteSize, 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) audio_buffer->mAudioDataByteSize, 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0.0); 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) last_fill_ = base::TimeTicks::Now(); 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Recycle the buffer. 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OSStatus err = QueueNextBuffer(audio_buffer); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (err != noErr) { 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (err == kAudioQueueErr_EnqueueDuringReset) { 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is the error you get if you try to enqueue a buffer and the 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // queue has been closed. Not really a problem if indeed the queue 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // has been closed. 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(joth): PCMQueueOutAudioOutputStream uses callback_ to provide an 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // extra guard for this situation, but it seems to introduce more 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // complications than it solves (memory barrier issues accessing it from 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // multiple threads, looses the means to indicate OnClosed to client). 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Should determine if we need to do something equivalent here. 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleError(err); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace media 232