普通文本  |  858行  |  30.08 KB

/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <variablespeed.h>

#include <unistd.h>
#include <stdlib.h>

#include <sola_time_scaler.h>
#include <ring_buffer.h>

#include <hlogging.h>

#include <vector>

#include <sys/system_properties.h>

// ****************************************************************************
// Constants, utility methods, structures and other miscellany used throughout
// this file.

namespace {

// These variables are used to determine the size of the buffer queue used by
// the decoder.
// This is not the same as the large buffer used to hold the uncompressed data
// - for that see the member variable decodeBuffer_.
// The choice of 1152 corresponds to the number of samples per mp3 frame, so is
// a good choice of size for a decoding buffer in the absence of other
// information (we don't know exactly what formats we will be working with).
const size_t kNumberOfBuffersInQueue = 4;
const size_t kNumberOfSamplesPerBuffer = 1152;
const size_t kBufferSizeInBytes = 2 * kNumberOfSamplesPerBuffer;
const size_t kSampleSizeInBytes = 4;

// When calculating play buffer size before pushing to audio player.
const size_t kNumberOfBytesPerInt16 = 2;

// How long to sleep during the main play loop and the decoding callback loop.
// In due course this should be replaced with the better signal and wait on
// condition rather than busy-looping.
const int kSleepTimeMicros = 1000;

// Used in detecting errors with the OpenSL ES framework.
const SLuint32 kPrefetchErrorCandidate =
    SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE;

// Structure used when we perform a decoding callback.
typedef struct CallbackContext_ {
  // Pointer to local storage buffers for decoded audio data.
  int8_t* pDataBase;
  // Pointer to the current buffer within local storage.
  int8_t* pData;
  // Used to read the sample rate and channels from the decoding stream during
  // the first decoding callback.
  SLMetadataExtractionItf decoderMetadata;
  // The play interface used for reading duration.
  SLPlayItf playItf;
} CallbackContext;

// Local storage for decoded audio data.
int8_t pcmData[kNumberOfBuffersInQueue * kBufferSizeInBytes];

#define CheckSLResult(message, result) \
    CheckSLResult_Real(message, result, __LINE__)

// Helper function for debugging - checks the OpenSL result for success.
void CheckSLResult_Real(const char* message, SLresult result, int line) {
  // This can be helpful when debugging.
  // LOGD("sl result %d for %s", result, message);
  if (SL_RESULT_SUCCESS != result) {
    LOGE("slresult was %d at %s file variablespeed line %d",
        static_cast<int>(result), message, line);
  }
  CHECK(SL_RESULT_SUCCESS == result);
}

// Whether logging should be enabled. Only used if LOG_OPENSL_API_CALL is
// defined to use it.
bool gLogEnabled = false;
// The property to set in order to enable logging.
const char *const kLogTagVariableSpeed = "log.tag.VariableSpeed";

bool ShouldLog() {
  char buffer[PROP_VALUE_MAX];
  __system_property_get(kLogTagVariableSpeed, buffer);
  return strlen(buffer) > 0;
}

}  // namespace

// ****************************************************************************
// Static instance of audio engine, and methods for getting, setting and
// deleting it.

// The single global audio engine instance.
AudioEngine* AudioEngine::audioEngine_ = NULL;
android::Mutex publishEngineLock_;

AudioEngine* AudioEngine::GetEngine() {
  android::Mutex::Autolock autoLock(publishEngineLock_);
  if (audioEngine_ == NULL) {
    LOGE("you haven't initialized the audio engine");
    CHECK(false);
    return NULL;
  }
  return audioEngine_;
}

void AudioEngine::SetEngine(AudioEngine* engine) {
  if (audioEngine_ != NULL) {
    LOGE("you have already set the audio engine");
    CHECK(false);
    return;
  }
  audioEngine_ = engine;
}

void AudioEngine::DeleteEngine() {
  if (audioEngine_ == NULL) {
    LOGE("you haven't initialized the audio engine");
    CHECK(false);
    return;
  }
  delete audioEngine_;
  audioEngine_ = NULL;
}

// ****************************************************************************
// The callbacks from the engine require static callback functions.
// Here are the static functions - they just delegate to instance methods on
// the engine.

static void PlayingBufferQueueCb(SLAndroidSimpleBufferQueueItf, void*) {
  AudioEngine::GetEngine()->PlayingBufferQueueCallback();
}

static void PrefetchEventCb(SLPrefetchStatusItf caller, void*, SLuint32 event) {
  AudioEngine::GetEngine()->PrefetchEventCallback(caller, event);
}

static void DecodingBufferQueueCb(SLAndroidSimpleBufferQueueItf queueItf,
    void *context) {
  AudioEngine::GetEngine()->DecodingBufferQueueCallback(queueItf, context);
}

static void DecodingEventCb(SLPlayItf caller, void*, SLuint32 event) {
  AudioEngine::GetEngine()->DecodingEventCallback(caller, event);
}

// ****************************************************************************
// Macros for making working with OpenSL easier.

// Log based on the value of a property.
#define LOG_OPENSL_API_CALL(string) (gLogEnabled && LOGV(string))

// The regular macro: log an api call, make the api call, check the result.
#define OpenSL(obj, method, ...) \
{ \
  LOG_OPENSL_API_CALL("OpenSL " #method "(" #obj ", " #__VA_ARGS__ ")"); \
  SLresult result = (*obj)->method(obj, __VA_ARGS__); \
  CheckSLResult("OpenSL " #method "(" #obj ", " #__VA_ARGS__ ")", result); \
}

// Special case call for api call that has void return value, can't be checked.
#define VoidOpenSL(obj, method) \
{ \
  LOG_OPENSL_API_CALL("OpenSL (void) " #method "(" #obj ")"); \
  (*obj)->method(obj); \
}

// Special case for api call with checked result but takes no arguments.
#define OpenSL0(obj, method) \
{ \
  LOG_OPENSL_API_CALL("OpenSL " #method "(" #obj ")"); \
  SLresult result = (*obj)->method(obj); \
  CheckSLResult("OpenSL " #method "(" #obj ")", result); \
}

// Special case for api call whose result we want to store, not check.
// We have to encapsulate the two calls in braces, so that this expression
// evaluates to the last expression not the first.
#define ReturnOpenSL(obj, method, ...) \
( \
    LOG_OPENSL_API_CALL("OpenSL (int) " \
        #method "(" #obj ", " #__VA_ARGS__ ")"), \
    (*obj)->method(obj, __VA_ARGS__) \
) \

// ****************************************************************************
// Static utility methods.

// Set the audio stream type for the player.
//
// Must be called before it is realized.
//
// The caller must have requested the SL_IID_ANDROIDCONFIGURATION interface when
// creating the player.
static void setAudioStreamType(SLObjectItf audioPlayer, SLint32 audioStreamType) {
  SLAndroidConfigurationItf playerConfig;
  OpenSL(audioPlayer, GetInterface, SL_IID_ANDROIDCONFIGURATION, &playerConfig);
  // The STREAM_XXX constants defined by android.media.AudioManager match the
  // corresponding SL_ANDROID_STREAM_XXX constants defined by
  // include/SLES/OpenSLES_AndroidConfiguration.h, so we can just pass the
  // value across.
  OpenSL(playerConfig, SetConfiguration, SL_ANDROID_KEY_STREAM_TYPE,
         &audioStreamType, sizeof(audioStreamType));
}

// Must be called with callbackLock_ held.
static void ReadSampleRateAndChannelCount(CallbackContext *pContext,
    SLuint32 *sampleRateOut, SLuint32 *channelsOut) {
  SLMetadataExtractionItf decoderMetadata = pContext->decoderMetadata;
  SLuint32 itemCount;
  OpenSL(decoderMetadata, GetItemCount, &itemCount);
  SLuint32 i, keySize, valueSize;
  SLMetadataInfo *keyInfo, *value;
  for (i = 0; i < itemCount; ++i) {
    keyInfo = value = NULL;
    keySize = valueSize = 0;
    OpenSL(decoderMetadata, GetKeySize, i, &keySize);
    keyInfo = static_cast<SLMetadataInfo*>(malloc(keySize));
    if (keyInfo) {
      OpenSL(decoderMetadata, GetKey, i, keySize, keyInfo);
      if (keyInfo->encoding == SL_CHARACTERENCODING_ASCII
          || keyInfo->encoding == SL_CHARACTERENCODING_UTF8) {
        OpenSL(decoderMetadata, GetValueSize, i, &valueSize);
        value = static_cast<SLMetadataInfo*>(malloc(valueSize));
        if (value) {
          OpenSL(decoderMetadata, GetValue, i, valueSize, value);
          if (strcmp((char*) keyInfo->data, ANDROID_KEY_PCMFORMAT_SAMPLERATE) == 0) {
            SLuint32 sampleRate = *(reinterpret_cast<SLuint32*>(value->data));
            LOGD("sample Rate: %d", sampleRate);
            *sampleRateOut = sampleRate;
          } else if (strcmp((char*) keyInfo->data, ANDROID_KEY_PCMFORMAT_NUMCHANNELS) == 0) {
            SLuint32 channels = *(reinterpret_cast<SLuint32*>(value->data));
            LOGD("channels: %d", channels);
            *channelsOut = channels;
          }
          free(value);
        }
      }
      free(keyInfo);
    }
  }
}

// Must be called with callbackLock_ held.
static void RegisterCallbackContextAndAddEnqueueBuffersToDecoder(
    SLAndroidSimpleBufferQueueItf decoderQueue, CallbackContext* context) {
  // Register a callback on the decoder queue, so that we will be called
  // throughout the decoding process (and can then extract the decoded audio
  // for the next bit of the pipeline).
  OpenSL(decoderQueue, RegisterCallback, DecodingBufferQueueCb, context);

  // Enqueue buffers to map the region of memory allocated to store the
  // decoded data.
  for (size_t i = 0; i < kNumberOfBuffersInQueue; i++) {
    OpenSL(decoderQueue, Enqueue, context->pData, kBufferSizeInBytes);
    context->pData += kBufferSizeInBytes;
  }
  context->pData = context->pDataBase;
}

// ****************************************************************************
// Constructor and Destructor.

AudioEngine::AudioEngine(size_t targetFrames, float windowDuration,
    float windowOverlapDuration, size_t maxPlayBufferCount, float initialRate,
    size_t decodeInitialSize, size_t decodeMaxSize, size_t startPositionMillis,
    int audioStreamType)
    : decodeBuffer_(decodeInitialSize, decodeMaxSize),
      playingBuffers_(), freeBuffers_(), timeScaler_(NULL),
      floatBuffer_(NULL), injectBuffer_(NULL),
      mSampleRate(0), mChannels(0),
      targetFrames_(targetFrames),
      windowDuration_(windowDuration),
      windowOverlapDuration_(windowOverlapDuration),
      maxPlayBufferCount_(maxPlayBufferCount), initialRate_(initialRate),
      startPositionMillis_(startPositionMillis),
      audioStreamType_(audioStreamType),
      totalDurationMs_(0), decoderCurrentPosition_(0), startRequested_(false),
      stopRequested_(false), finishedDecoding_(false) {
  // Determine whether we should log calls.
  gLogEnabled = ShouldLog();
}

AudioEngine::~AudioEngine() {
  // destroy the time scaler
  if (timeScaler_ != NULL) {
    delete timeScaler_;
    timeScaler_ = NULL;
  }

  // delete all outstanding playing and free buffers
  android::Mutex::Autolock autoLock(playBufferLock_);
  while (playingBuffers_.size() > 0) {
    delete[] playingBuffers_.front();
    playingBuffers_.pop();
  }
  while (freeBuffers_.size() > 0) {
    delete[] freeBuffers_.top();
    freeBuffers_.pop();
  }

  delete[] floatBuffer_;
  floatBuffer_ = NULL;
  delete[] injectBuffer_;
  injectBuffer_ = NULL;
}

// ****************************************************************************
// Regular AudioEngine class methods.

void AudioEngine::SetVariableSpeed(float speed) {
  // TODO: Mutex for shared time scaler accesses.
  if (HasSampleRateAndChannels()) {
    GetTimeScaler()->set_speed(speed);
  } else {
    // This is being called at a point where we have not yet processed enough
    // data to determine the sample rate and number of channels.
    // Ignore the call.  See http://b/5140693.
    LOGD("set varaible speed called, sample rate and channels not ready yet");
  }
}

void AudioEngine::RequestStart() {
  android::Mutex::Autolock autoLock(lock_);
  startRequested_ = true;
}

void AudioEngine::ClearRequestStart() {
  android::Mutex::Autolock autoLock(lock_);
  startRequested_ = false;
}

bool AudioEngine::GetWasStartRequested() {
  android::Mutex::Autolock autoLock(lock_);
  return startRequested_;
}

void AudioEngine::RequestStop() {
  android::Mutex::Autolock autoLock(lock_);
  stopRequested_ = true;
}

int AudioEngine::GetCurrentPosition() {
  android::Mutex::Autolock autoLock(decodeBufferLock_);
  double result = decodeBuffer_.GetTotalAdvancedCount();
  // TODO: This is horrible, but should be removed soon once the outstanding
  // issue with get current position on decoder is fixed.
  android::Mutex::Autolock autoLock2(callbackLock_);
  return static_cast<int>(
      (result * 1000) / mSampleRate / mChannels + startPositionMillis_);
}

int AudioEngine::GetTotalDuration() {
  android::Mutex::Autolock autoLock(lock_);
  return static_cast<int>(totalDurationMs_);
}

video_editing::SolaTimeScaler* AudioEngine::GetTimeScaler() {
  if (timeScaler_ == NULL) {
    CHECK(HasSampleRateAndChannels());
    android::Mutex::Autolock autoLock(callbackLock_);
    timeScaler_ = new video_editing::SolaTimeScaler();
    timeScaler_->Init(mSampleRate, mChannels, initialRate_, windowDuration_,
        windowOverlapDuration_);
  }
  return timeScaler_;
}

bool AudioEngine::EnqueueNextBufferOfAudio(
    SLAndroidSimpleBufferQueueItf audioPlayerQueue) {
  size_t channels;
  {
    android::Mutex::Autolock autoLock(callbackLock_);
    channels = mChannels;
  }
  size_t frameSizeInBytes = kSampleSizeInBytes * channels;
  size_t frameCount = 0;
  while (frameCount < targetFrames_) {
    size_t framesLeft = targetFrames_ - frameCount;
    // If there is data already in the time scaler, retrieve it.
    if (GetTimeScaler()->available() > 0) {
      size_t retrieveCount = min(GetTimeScaler()->available(), framesLeft);
      int count = GetTimeScaler()->RetrieveSamples(
          floatBuffer_ + frameCount * channels, retrieveCount);
      if (count <= 0) {
        LOGD("error: count was %d", count);
        break;
      }
      frameCount += count;
      continue;
    }
    // If there is no data in the time scaler, then feed some into it.
    android::Mutex::Autolock autoLock(decodeBufferLock_);
    size_t framesInDecodeBuffer =
        decodeBuffer_.GetSizeInBytes() / frameSizeInBytes;
    size_t framesScalerCanHandle = GetTimeScaler()->input_limit();
    size_t framesToInject = min(framesInDecodeBuffer,
        min(targetFrames_, framesScalerCanHandle));
    if (framesToInject <= 0) {
      // No more frames left to inject.
      break;
    }
    for (size_t i = 0; i < framesToInject * channels; ++i) {
      injectBuffer_[i] = decodeBuffer_.GetAtIndex(i);
    }
    int count = GetTimeScaler()->InjectSamples(injectBuffer_, framesToInject);
    if (count <= 0) {
      LOGD("error: count was %d", count);
      break;
    }
    decodeBuffer_.AdvanceHeadPointerShorts(count * channels);
  }
  if (frameCount <= 0) {
    // We must have finished playback.
    if (GetEndOfDecoderReached()) {
      // If we've finished decoding, clear the buffer - so we will terminate.
      ClearDecodeBuffer();
    }
    return false;
  }

  // Get a free playing buffer.
  int16* playBuffer;
  {
    android::Mutex::Autolock autoLock(playBufferLock_);
    if (freeBuffers_.size() > 0) {
      // If we have a free buffer, recycle it.
      playBuffer = freeBuffers_.top();
      freeBuffers_.pop();
    } else {
      // Otherwise allocate a new one.
      playBuffer = new int16[targetFrames_ * channels];
    }
  }

  // Try to play the buffer.
  for (size_t i = 0; i < frameCount * channels; ++i) {
    playBuffer[i] = floatBuffer_[i];
  }
  size_t sizeOfPlayBufferInBytes =
      frameCount * channels * kNumberOfBytesPerInt16;
  SLresult result = ReturnOpenSL(audioPlayerQueue, Enqueue, playBuffer,
      sizeOfPlayBufferInBytes);
  if (result == SL_RESULT_SUCCESS) {
    android::Mutex::Autolock autoLock(playBufferLock_);
    playingBuffers_.push(playBuffer);
  } else {
    LOGE("could not enqueue audio buffer");
    delete[] playBuffer;
  }

  return (result == SL_RESULT_SUCCESS);
}

bool AudioEngine::GetEndOfDecoderReached() {
  android::Mutex::Autolock autoLock(lock_);
  return finishedDecoding_;
}

void AudioEngine::SetEndOfDecoderReached() {
  android::Mutex::Autolock autoLock(lock_);
  finishedDecoding_ = true;
}

bool AudioEngine::PlayFileDescriptor(int fd, int64 offset, int64 length) {
  SLDataLocator_AndroidFD loc_fd = {
      SL_DATALOCATOR_ANDROIDFD, fd, offset, length };
  SLDataFormat_MIME format_mime = {
      SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED };
  SLDataSource audioSrc = { &loc_fd, &format_mime };
  return PlayFromThisSource(audioSrc);
}

bool AudioEngine::PlayUri(const char* uri) {
  // Source of audio data for the decoding
  SLDataLocator_URI decUri = { SL_DATALOCATOR_URI,
      const_cast<SLchar*>(reinterpret_cast<const SLchar*>(uri)) };
  SLDataFormat_MIME decMime = {
      SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED };
  SLDataSource decSource = { &decUri, &decMime };
  return PlayFromThisSource(decSource);
}

bool AudioEngine::IsDecodeBufferEmpty() {
  android::Mutex::Autolock autoLock(decodeBufferLock_);
  return decodeBuffer_.GetSizeInBytes() <= 0;
}

void AudioEngine::ClearDecodeBuffer() {
  android::Mutex::Autolock autoLock(decodeBufferLock_);
  decodeBuffer_.Clear();
}

static size_t ReadDuration(SLPlayItf playItf) {
  SLmillisecond durationInMsec = SL_TIME_UNKNOWN;
  OpenSL(playItf, GetDuration, &durationInMsec);
  if (durationInMsec == SL_TIME_UNKNOWN) {
    LOGE("can't get duration");
    return 0;
  }
  LOGD("duration: %d", static_cast<int>(durationInMsec));
  return durationInMsec;
}

static size_t ReadPosition(SLPlayItf playItf) {
  SLmillisecond positionInMsec = SL_TIME_UNKNOWN;
  OpenSL(playItf, GetPosition, &positionInMsec);
  if (positionInMsec == SL_TIME_UNKNOWN) {
    LOGE("can't get position");
    return 0;
  }
  LOGW("decoder position: %d", static_cast<int>(positionInMsec));
  return positionInMsec;
}

static void CreateAndRealizeEngine(SLObjectItf &engine,
    SLEngineItf &engineInterface) {
  SLEngineOption EngineOption[] = { {
      SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE } };
  SLresult result = slCreateEngine(&engine, 1, EngineOption, 0, NULL, NULL);
  CheckSLResult("create engine", result);
  OpenSL(engine, Realize, SL_BOOLEAN_FALSE);
  OpenSL(engine, GetInterface, SL_IID_ENGINE, &engineInterface);
}

SLuint32 AudioEngine::GetSLSampleRate() {
  android::Mutex::Autolock autoLock(callbackLock_);
  return mSampleRate * 1000;
}

SLuint32 AudioEngine::GetSLChannels() {
  android::Mutex::Autolock autoLock(callbackLock_);
  switch (mChannels) {
    case 2:
      return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
    case 1:
      return SL_SPEAKER_FRONT_CENTER;
    default:
      LOGE("unknown channels %d, using 2", mChannels);
      return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
  }
}

SLuint32 AudioEngine::GetChannelCount() {
  android::Mutex::Autolock autoLock(callbackLock_);
  return mChannels;
}

static void CreateAndRealizeAudioPlayer(SLuint32 slSampleRate,
    size_t channelCount, SLuint32 slChannels, SLint32 audioStreamType, SLObjectItf &outputMix,
    SLObjectItf &audioPlayer, SLEngineItf &engineInterface) {
  // Define the source and sink for the audio player: comes from a buffer queue
  // and goes to the output mix.
  SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {
      SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2 };
  SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, channelCount, slSampleRate,
      SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
      slChannels, SL_BYTEORDER_LITTLEENDIAN};
  SLDataSource playingSrc = {&loc_bufq, &format_pcm};
  SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMix};
  SLDataSink audioSnk = {&loc_outmix, NULL};

  // Create the audio player, which will play from the buffer queue and send to
  // the output mix.
  const size_t playerInterfaceCount = 2;
  const SLInterfaceID iids[playerInterfaceCount] = {
      SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION };
  const SLboolean reqs[playerInterfaceCount] = { SL_BOOLEAN_TRUE };
  OpenSL(engineInterface, CreateAudioPlayer, &audioPlayer, &playingSrc,
      &audioSnk, playerInterfaceCount, iids, reqs);
  setAudioStreamType(audioPlayer, audioStreamType);
  OpenSL(audioPlayer, Realize, SL_BOOLEAN_FALSE);
}

bool AudioEngine::HasSampleRateAndChannels() {
  android::Mutex::Autolock autoLock(callbackLock_);
  return mChannels != 0 && mSampleRate != 0;
}

bool AudioEngine::PlayFromThisSource(const SLDataSource& audioSrc) {
  ClearDecodeBuffer();

  SLObjectItf engine;
  SLEngineItf engineInterface;
  CreateAndRealizeEngine(engine, engineInterface);

  // Define the source and sink for the decoding player: comes from the source
  // this method was called with, is sent to another buffer queue.
  SLDataLocator_AndroidSimpleBufferQueue decBuffQueue;
  decBuffQueue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
  decBuffQueue.numBuffers = kNumberOfBuffersInQueue;
  // A valid value seems required here but is currently ignored.
  SLDataFormat_PCM pcm = {SL_DATAFORMAT_PCM, 1, SL_SAMPLINGRATE_44_1,
      SL_PCMSAMPLEFORMAT_FIXED_16, 16,
      SL_SPEAKER_FRONT_LEFT, SL_BYTEORDER_LITTLEENDIAN};
  SLDataSink decDest = { &decBuffQueue, &pcm };

  // Create the decoder with the given source and sink.
  const size_t decoderInterfaceCount = 5;
  SLObjectItf decoder;
  const SLInterfaceID decodePlayerInterfaces[decoderInterfaceCount] = {
      SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_PREFETCHSTATUS, SL_IID_SEEK,
      SL_IID_METADATAEXTRACTION, SL_IID_ANDROIDCONFIGURATION };
  const SLboolean decodePlayerRequired[decoderInterfaceCount] = {
      SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
  SLDataSource sourceCopy(audioSrc);
  OpenSL(engineInterface, CreateAudioPlayer, &decoder, &sourceCopy, &decDest,
      decoderInterfaceCount, decodePlayerInterfaces, decodePlayerRequired);
  // Not sure if this is necessary, but just in case.
  setAudioStreamType(decoder, audioStreamType_);
  OpenSL(decoder, Realize, SL_BOOLEAN_FALSE);

  // Get the play interface from the decoder, and register event callbacks.
  // Get the buffer queue, prefetch and seek interfaces.
  SLPlayItf decoderPlay = NULL;
  SLAndroidSimpleBufferQueueItf decoderQueue = NULL;
  SLPrefetchStatusItf decoderPrefetch = NULL;
  SLSeekItf decoderSeek = NULL;
  SLMetadataExtractionItf decoderMetadata = NULL;
  OpenSL(decoder, GetInterface, SL_IID_PLAY, &decoderPlay);
  OpenSL(decoderPlay, SetCallbackEventsMask, SL_PLAYEVENT_HEADATEND);
  OpenSL(decoderPlay, RegisterCallback, DecodingEventCb, NULL);
  OpenSL(decoder, GetInterface, SL_IID_PREFETCHSTATUS, &decoderPrefetch);
  OpenSL(decoder, GetInterface, SL_IID_SEEK, &decoderSeek);
  OpenSL(decoder, GetInterface, SL_IID_METADATAEXTRACTION, &decoderMetadata);
  OpenSL(decoder, GetInterface, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
      &decoderQueue);

  // Initialize the callback structure, used during the decoding.
  CallbackContext callbackContext;
  {
    android::Mutex::Autolock autoLock(callbackLock_);
    callbackContext.pDataBase = pcmData;
    callbackContext.pData = pcmData;
    callbackContext.decoderMetadata = decoderMetadata;
    callbackContext.playItf = decoderPlay;
    RegisterCallbackContextAndAddEnqueueBuffersToDecoder(
        decoderQueue, &callbackContext);
  }

  // Initialize the callback for prefetch errors, if we can't open the
  // resource to decode.
  OpenSL(decoderPrefetch, SetCallbackEventsMask, kPrefetchErrorCandidate);
  OpenSL(decoderPrefetch, RegisterCallback, PrefetchEventCb, &decoderPrefetch);

  // Seek to the start position.
  OpenSL(decoderSeek, SetPosition, startPositionMillis_, SL_SEEKMODE_ACCURATE);

  // Start decoding immediately.
  OpenSL(decoderPlay, SetPlayState, SL_PLAYSTATE_PLAYING);

  // These variables hold the audio player and its output.
  // They will only be constructed once the decoder has invoked the callback,
  // and given us the correct sample rate, number of channels and duration.
  SLObjectItf outputMix = NULL;
  SLObjectItf audioPlayer = NULL;
  SLPlayItf audioPlayerPlay = NULL;
  SLAndroidSimpleBufferQueueItf audioPlayerQueue = NULL;

  // The main loop - until we're told to stop: if there is audio data coming
  // out of the decoder, feed it through the time scaler.
  // As it comes out of the time scaler, feed it into the audio player.
  while (!Finished()) {
    if (GetWasStartRequested() && HasSampleRateAndChannels()) {
      // Build the audio player.
      // TODO: What happens if I maliciously call start lots of times?
      floatBuffer_ = new float[targetFrames_ * mChannels];
      injectBuffer_ = new float[targetFrames_ * mChannels];
      OpenSL(engineInterface, CreateOutputMix, &outputMix, 0, NULL, NULL);
      OpenSL(outputMix, Realize, SL_BOOLEAN_FALSE);
      CreateAndRealizeAudioPlayer(GetSLSampleRate(), GetChannelCount(),
          GetSLChannels(), audioStreamType_, outputMix, audioPlayer,
          engineInterface);
      OpenSL(audioPlayer, GetInterface, SL_IID_PLAY, &audioPlayerPlay);
      OpenSL(audioPlayer, GetInterface, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
          &audioPlayerQueue);
      OpenSL(audioPlayerQueue, RegisterCallback, PlayingBufferQueueCb, NULL);
      ClearRequestStart();
      OpenSL(audioPlayerPlay, SetPlayState, SL_PLAYSTATE_PLAYING);
    }
    EnqueueMoreAudioIfNecessary(audioPlayerQueue);
    usleep(kSleepTimeMicros);
  }

  // Delete the audio player and output mix, iff they have been created.
  if (audioPlayer != NULL) {
    OpenSL(audioPlayerPlay, SetPlayState, SL_PLAYSTATE_STOPPED);
    OpenSL0(audioPlayerQueue, Clear);
    OpenSL(audioPlayerQueue, RegisterCallback, NULL, NULL);
    VoidOpenSL(audioPlayer, AbortAsyncOperation);
    VoidOpenSL(audioPlayer, Destroy);
    VoidOpenSL(outputMix, Destroy);
    audioPlayer = NULL;
    audioPlayerPlay = NULL;
    audioPlayerQueue = NULL;
    outputMix = NULL;
  }

  // Delete the decoder.
  OpenSL(decoderPlay, SetPlayState, SL_PLAYSTATE_STOPPED);
  OpenSL(decoderPrefetch, RegisterCallback, NULL, NULL);
  // This is returning slresult 13 if I do no playback.
  // Repro is to comment out all before this line, and all after enqueueing
  // my buffers.
  // OpenSL0(decoderQueue, Clear);
  OpenSL(decoderQueue, RegisterCallback, NULL, NULL);
  decoderSeek = NULL;
  decoderPrefetch = NULL;
  decoderQueue = NULL;
  OpenSL(decoderPlay, RegisterCallback, NULL, NULL);
  VoidOpenSL(decoder, AbortAsyncOperation);
  VoidOpenSL(decoder, Destroy);
  decoderPlay = NULL;

  // Delete the engine.
  VoidOpenSL(engine, Destroy);
  engineInterface = NULL;

  return true;
}

bool AudioEngine::Finished() {
  if (GetWasStopRequested()) {
    return true;
  }
  android::Mutex::Autolock autoLock(playBufferLock_);
  return playingBuffers_.size() <= 0 &&
      IsDecodeBufferEmpty() &&
      GetEndOfDecoderReached();
}

bool AudioEngine::GetWasStopRequested() {
  android::Mutex::Autolock autoLock(lock_);
  return stopRequested_;
}

bool AudioEngine::GetHasReachedPlayingBuffersLimit() {
  android::Mutex::Autolock autoLock(playBufferLock_);
  return playingBuffers_.size() >= maxPlayBufferCount_;
}

void AudioEngine::EnqueueMoreAudioIfNecessary(
    SLAndroidSimpleBufferQueueItf audioPlayerQueue) {
  bool keepEnqueueing = true;
  while (audioPlayerQueue != NULL &&
         !GetWasStopRequested() &&
         !IsDecodeBufferEmpty() &&
         !GetHasReachedPlayingBuffersLimit() &&
         keepEnqueueing) {
    keepEnqueueing = EnqueueNextBufferOfAudio(audioPlayerQueue);
  }
}

bool AudioEngine::DecodeBufferTooFull() {
  android::Mutex::Autolock autoLock(decodeBufferLock_);
  return decodeBuffer_.IsTooLarge();
}

// ****************************************************************************
// Code for handling the static callbacks.

void AudioEngine::PlayingBufferQueueCallback() {
  // The head playing buffer is done, move it to the free list.
  android::Mutex::Autolock autoLock(playBufferLock_);
  if (playingBuffers_.size() > 0) {
    freeBuffers_.push(playingBuffers_.front());
    playingBuffers_.pop();
  }
}

void AudioEngine::PrefetchEventCallback(
    SLPrefetchStatusItf caller, SLuint32 event) {
  // If there was a problem during decoding, then signal the end.
  SLpermille level = 0;
  SLuint32 status;
  OpenSL(caller, GetFillLevel, &level);
  OpenSL(caller, GetPrefetchStatus, &status);
  if ((kPrefetchErrorCandidate == (event & kPrefetchErrorCandidate)) &&
      (level == 0) &&
      (status == SL_PREFETCHSTATUS_UNDERFLOW)) {
    LOGI("prefetcheventcallback error while prefetching data");
    SetEndOfDecoderReached();
  }
  if (SL_PREFETCHSTATUS_SUFFICIENTDATA == event) {
    // android::Mutex::Autolock autoLock(prefetchLock_);
    // prefetchCondition_.broadcast();
  }
}

void AudioEngine::DecodingBufferQueueCallback(
    SLAndroidSimpleBufferQueueItf queueItf, void *context) {
  if (GetWasStopRequested()) {
    return;
  }

  CallbackContext *pCntxt;
  {
    android::Mutex::Autolock autoLock(callbackLock_);
    pCntxt = reinterpret_cast<CallbackContext*>(context);
  }
  {
    android::Mutex::Autolock autoLock(decodeBufferLock_);
    decodeBuffer_.AddData(pCntxt->pData, kBufferSizeInBytes);
  }

  if (!HasSampleRateAndChannels()) {
    android::Mutex::Autolock autoLock(callbackLock_);
    ReadSampleRateAndChannelCount(pCntxt, &mSampleRate, &mChannels);
  }

  {
    android::Mutex::Autolock autoLock(lock_);
    if (totalDurationMs_ == 0) {
      totalDurationMs_ = ReadDuration(pCntxt->playItf);
    }
    // TODO: This isn't working, it always reports zero.
    // ReadPosition(pCntxt->playItf);
  }

  OpenSL(queueItf, Enqueue, pCntxt->pData, kBufferSizeInBytes);

  // Increase data pointer by buffer size
  pCntxt->pData += kBufferSizeInBytes;
  if (pCntxt->pData >= pCntxt->pDataBase +
      (kNumberOfBuffersInQueue * kBufferSizeInBytes)) {
    pCntxt->pData = pCntxt->pDataBase;
  }

  // If we get too much data into the decoder,
  // sleep until the playback catches up.
  while (!GetWasStopRequested() && DecodeBufferTooFull()) {
    usleep(kSleepTimeMicros);
  }
}

void AudioEngine::DecodingEventCallback(SLPlayItf, SLuint32 event) {
  if (SL_PLAYEVENT_HEADATEND & event) {
    SetEndOfDecoderReached();
  }
}