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