Example #1
0
qboolean SNDDMA_Init(void)
{
  if ( ! enableSound() ) {
    return false;
  }

  gDMAByteIndex = 0;

  // Initialize the AudioTrack.

  status_t result = gAudioTrack.set(
    AudioSystem::DEFAULT, // stream type
    SAMPLE_RATE,   // sample rate
    BITS_PER_SAMPLE == 16 ? AudioSystem::PCM_16_BIT : AudioSystem::PCM_8_BIT,      // format (8 or 16)
    (CHANNEL_COUNT > 1) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO,       // channel mask
    0,       // default buffer size
    0, // flags
    AndroidQuakeSoundCallback, // callback
    0,  // user
    0); // default notification size

  LOGI("AudioTrack status  = %d (%s)\n", result, result == NO_ERROR ? "success" : "error");

  if ( result == NO_ERROR ) {
    LOGI("AudioTrack latency = %u ms\n", gAudioTrack.latency());
    LOGI("AudioTrack format = %u bits\n", gAudioTrack.format() == AudioSystem::PCM_16_BIT ? 16 : 8);
    LOGI("AudioTrack sample rate = %u Hz\n", gAudioTrack.getSampleRate());
    LOGI("AudioTrack frame count = %d\n", int(gAudioTrack.frameCount()));
    LOGI("AudioTrack channel count = %d\n", gAudioTrack.channelCount());

    // Initialize Quake's idea of a DMA buffer.

    shm = &sn;
    memset((void*)&sn, 0, sizeof(sn));

    shm->splitbuffer = false;	// Not used.
    shm->samplebits = gAudioTrack.format() == AudioSystem::PCM_16_BIT ? 16 : 8;
    shm->speed = gAudioTrack.getSampleRate();
    shm->channels = gAudioTrack.channelCount();
    shm->samples = TOTAL_BUFFER_SIZE / BYTES_PER_SAMPLE;
    shm->samplepos = 0; // Not used.
    shm->buffer = (unsigned char*) Hunk_AllocName(TOTAL_BUFFER_SIZE, (char*) "shmbuf");
    shm->submission_chunk = 1; // Not used.

    shm->soundalive = true;

    if ( (shm->samples & 0x1ff) != 0 ) {
      LOGE("SNDDDMA_Init: samples must be power of two.");
      return false;
    }

    if ( shm->buffer == 0 ) {
      LOGE("SNDDDMA_Init: Could not allocate sound buffer.");
      return false;
    }

    gAudioTrack.setVolume(1.0f, 1.0f);
    gAudioTrack.start();
  }

  return result == NO_ERROR;
}
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;
}