ACodecBufferChannel::BufferInfo::BufferInfo(
        const sp<MediaCodecBuffer> &buffer,
        IOMX::buffer_id bufferId,
        const sp<IMemory> &sharedEncryptedBuffer)
    : mClientBuffer(
          (sharedEncryptedBuffer == nullptr)
          ? buffer
          : new SharedMemoryBuffer(buffer->format(), sharedEncryptedBuffer)),
      mCodecBuffer(buffer),
      mBufferId(bufferId),
      mSharedEncryptedBuffer(sharedEncryptedBuffer) {
}
SourceAudioBufferProvider::SourceAudioBufferProvider(const sp<NBAIO_Source>& source) :
    mSource(source),
    // mFrameBitShiftFormat below
    mAllocated(NULL), mSize(0), mOffset(0), mRemaining(0), mGetCount(0)
{
    ALOG_ASSERT(source != 0);

    // negotiate with source
    NBAIO_Format counterOffers[1];
    size_t numCounterOffers = 1;
    ssize_t index = source->negotiate(NULL, 0, counterOffers, numCounterOffers);
    ALOG_ASSERT(index == (ssize_t) NEGOTIATE && numCounterOffers > 0);
    numCounterOffers = 0;
    index = source->negotiate(counterOffers, 1, NULL, numCounterOffers);
    ALOG_ASSERT(index == 0);
    mFrameBitShift = Format_frameBitShift(source->format());
}
// call with sound pool lock held
void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftVolume,
        float rightVolume, int priority, int loop, float rate)
{
    sp<AudioTrack> oldTrack;
    sp<AudioTrack> newTrack;
    status_t status;

    { // scope for the lock
        Mutex::Autolock lock(&mLock);

        ALOGV("SoundChannel::play %p: sampleID=%d, channelID=%d, leftVolume=%f, rightVolume=%f,"
                " priority=%d, loop=%d, rate=%f",
                this, sample->sampleID(), nextChannelID, leftVolume, rightVolume,
                priority, loop, rate);

        // if not idle, this voice is being stolen
        if (mState != IDLE) {
            ALOGV("channel %d stolen - event queued for channel %d", channelID(), nextChannelID);
            mNextEvent.set(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate);
            stop_l();
            return;
        }

        // initialize track
        size_t afFrameCount;
        uint32_t afSampleRate;
        audio_stream_type_t streamType = mSoundPool->streamType();
        if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
            afFrameCount = kDefaultFrameCount;
        }
        if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
            afSampleRate = kDefaultSampleRate;
        }
        int numChannels = sample->numChannels();
        uint32_t sampleRate = uint32_t(float(sample->sampleRate()) * rate + 0.5);
        uint32_t totalFrames = (kDefaultBufferCount * afFrameCount * sampleRate) / afSampleRate;
        uint32_t bufferFrames = (totalFrames + (kDefaultBufferCount - 1)) / kDefaultBufferCount;
        uint32_t frameCount = 0;

        if (loop) {
            frameCount = sample->size()/numChannels/
                ((sample->format() == AUDIO_FORMAT_PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t));
        }

#ifndef USE_SHARED_MEM_BUFFER
        // Ensure minimum audio buffer size in case of short looped sample
        if(frameCount < totalFrames) {
            frameCount = totalFrames;
        }
#endif

        // mToggle toggles each time a track is started on a given channel.
        // The toggle is concatenated with the SoundChannel address and passed to AudioTrack
        // as callback user data. This enables the detection of callbacks received from the old
        // audio track while the new one is being started and avoids processing them with
        // wrong audio audio buffer size  (mAudioBufferSize)
        unsigned long toggle = mToggle ^ 1;
        void *userData = (void *)((unsigned long)this | toggle);
        uint32_t channels = (numChannels == 2) ?
                AUDIO_CHANNEL_OUT_STEREO : AUDIO_CHANNEL_OUT_MONO;

        // do not create a new audio track if current track is compatible with sample parameters
#ifdef USE_SHARED_MEM_BUFFER
        newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
                channels, sample->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, callback, userData);
#else
        newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
                channels, frameCount, AUDIO_OUTPUT_FLAG_FAST, callback, userData,
                bufferFrames);
#endif
        oldTrack = mAudioTrack;
        status = newTrack->initCheck();
        if (status != NO_ERROR) {
            ALOGE("Error creating AudioTrack");
            goto exit;
        }
        ALOGV("setVolume %p", newTrack.get());
        newTrack->setVolume(leftVolume, rightVolume);
        newTrack->setLoop(0, frameCount, loop);

        // From now on, AudioTrack callbacks received with previous toggle value will be ignored.
        mToggle = toggle;
        mAudioTrack = newTrack;
        mPos = 0;
        mSample = sample;
        mChannelID = nextChannelID;
        mPriority = priority;
        mLoop = loop;
        mLeftVolume = leftVolume;
        mRightVolume = rightVolume;
        mNumChannels = numChannels;
        mRate = rate;
        clearNextEvent();
        mState = PLAYING;
        mAudioTrack->start();
        mAudioBufferSize = newTrack->frameCount()*newTrack->frameSize();
    }

exit:
    ALOGV("delete oldTrack %p", oldTrack.get());
    if (status != NO_ERROR) {
        mAudioTrack.clear();
    }
}
void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftVolume,
        float rightVolume, int priority, int loop, float rate)
{
    AudioTrack* oldTrack;

    LOGV("play %p: sampleID=%d, channelID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f",
            this, sample->sampleID(), nextChannelID, leftVolume, rightVolume, priority, loop, rate);

    // if not idle, this voice is being stolen
    if (mState != IDLE) {
        LOGV("channel %d stolen - event queued for channel %d", channelID(), nextChannelID);
        mNextEvent.set(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate);
        stop();
        return;
    }

    // initialize track
    int afFrameCount;
    int afSampleRate;
    int streamType = mSoundPool->streamType();
    if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
        afFrameCount = kDefaultFrameCount;
    }
    if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
        afSampleRate = kDefaultSampleRate;
    }
    int numChannels = sample->numChannels();
    uint32_t sampleRate = uint32_t(float(sample->sampleRate()) * rate + 0.5);
    uint32_t bufferFrames = (afFrameCount * sampleRate) / afSampleRate;
    uint32_t frameCount = 0;

    if (loop) {
        frameCount = sample->size()/numChannels/((sample->format() == AudioSystem::PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t));
    }

#ifndef USE_SHARED_MEM_BUFFER
    // Ensure minimum audio buffer size in case of short looped sample
    if(frameCount < kDefaultBufferCount * bufferFrames) {
        frameCount = kDefaultBufferCount * bufferFrames;
    }
#endif

    AudioTrack* newTrack;
    
    // mToggle toggles each time a track is started on a given channel.
    // The toggle is concatenated with the SoundChannel address and passed to AudioTrack
    // as callback user data. This enables the detection of callbacks received from the old
    // audio track while the new one is being started and avoids processing them with 
    // wrong audio audio buffer size  (mAudioBufferSize)
    unsigned long toggle = mToggle ^ 1;
    void *userData = (void *)((unsigned long)this | toggle);
    
#ifdef USE_SHARED_MEM_BUFFER
    newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
            numChannels, sample->getIMemory(), 0, callback, userData);
#else
    newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
            numChannels, frameCount, 0, callback, userData, bufferFrames);
#endif
    if (newTrack->initCheck() != NO_ERROR) {
        LOGE("Error creating AudioTrack");
        delete newTrack;
        return;
    }
    LOGV("setVolume %p", newTrack);
    newTrack->setVolume(leftVolume, rightVolume);
    newTrack->setLoop(0, frameCount, loop);

    {
        Mutex::Autolock lock(&mLock);
        // From now on, AudioTrack callbacks recevieved with previous toggle value will be ignored.
        mToggle = toggle;
        oldTrack = mAudioTrack;
        mAudioTrack = newTrack;
        mPos = 0;
        mSample = sample;
        mChannelID = nextChannelID;
        mPriority = priority;
        mLoop = loop;
        mLeftVolume = leftVolume;
        mRightVolume = rightVolume;
        mNumChannels = numChannels;
        mRate = rate;
        clearNextEvent();
        mState = PLAYING;
        mAudioTrack->start();
        mAudioBufferSize = newTrack->frameCount()*newTrack->frameSize();
    }

    LOGV("delete oldTrack %p", oldTrack);
    delete oldTrack;
}