Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e0fa467e authored by Glenn Kasten's avatar Glenn Kasten
Browse files

Move frame count calculations for fast tracks

For fast tracks: move the default and minimum frame count calculations
from client to server.  If accepted, the default and minimum frame count
is the fast mixer (HAL) frame count.  If denied, the default and minimum
frame count is the same as it currently is for normal tracks.

For normal tracks: there is no change yet, preserve legacy behavior for
now but add a FIXME to change this later.

Bug fix: the test for buffer alignment matches channelCount was wrong.

Bug fix: check for 8-bit data in shared memory, which isn't supported.

Optimizations:
 - in set(), only call AudioSystem::getOutputSamplingRate() when needed
 - in createTrack_l(), only call AudioSystem::getSamplingRate() and
   AudioSystem::getFrameCount() when needed

Change-Id: I79d2fe507db1a8f7bb094c71da8a129951dbb82f
parent e370bb62
Loading
Loading
Loading
Loading
+84 −44
Original line number Diff line number Diff line
@@ -54,6 +54,12 @@ status_t AudioTrack::getMinFrameCount(
        audio_stream_type_t streamType,
        uint32_t sampleRate)
{
    // FIXME merge with similar code in createTrack_l(), except we're missing
    //       some information here that is available in createTrack_l():
    //          audio_io_handle_t output
    //          audio_format_t format
    //          audio_channel_mask_t channelMask
    //          audio_output_flags_t flags
    int afSampleRate;
    if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
        return NO_INIT;
@@ -201,11 +207,11 @@ status_t AudioTrack::set(
        streamType = AUDIO_STREAM_MUSIC;
    }

    if (sampleRate == 0) {
        int afSampleRate;
        if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
            return NO_INIT;
        }
    if (sampleRate == 0) {
        sampleRate = afSampleRate;
    }

@@ -223,6 +229,12 @@ status_t AudioTrack::set(
        return BAD_VALUE;
    }

    // AudioFlinger does not currently support 8-bit data in shared memory
    if (format == AUDIO_FORMAT_PCM_8_BIT && sharedBuffer != 0) {
        ALOGE("8-bit data in shared memory is not supported");
        return BAD_VALUE;
    }

    // force direct flag if format is not linear PCM
    if (!audio_is_linear_pcm(format)) {
        flags = (audio_output_flags_t)
@@ -744,14 +756,6 @@ status_t AudioTrack::createTrack_l(
        return NO_INIT;
    }

    int afSampleRate;
    if (AudioSystem::getSamplingRate(output, streamType, &afSampleRate) != NO_ERROR) {
        return NO_INIT;
    }
    int afFrameCount;
    if (AudioSystem::getFrameCount(output, streamType, &afFrameCount) != NO_ERROR) {
        return NO_INIT;
    }
    uint32_t afLatency;
    if (AudioSystem::getLatency(output, streamType, &afLatency) != NO_ERROR) {
        return NO_INIT;
@@ -768,14 +772,57 @@ status_t AudioTrack::createTrack_l(
        ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client");
        flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_FAST);
    }
    ALOGV("createTrack_l() output %d afFrameCount %d afLatency %d", output, afFrameCount, afLatency);
    ALOGV("createTrack_l() output %d afLatency %d", output, afLatency);

    mNotificationFramesAct = mNotificationFramesReq;

    if (!audio_is_linear_pcm(format)) {

        if (sharedBuffer != 0) {
            // Same comment as below about ignoring frameCount parameter for set()
            frameCount = sharedBuffer->size();
        } else if (frameCount == 0) {
            int afFrameCount;
            if (AudioSystem::getFrameCount(output, streamType, &afFrameCount) != NO_ERROR) {
                return NO_INIT;
            }
    } else {
            frameCount = afFrameCount;
        }

    } else if (sharedBuffer != 0) {

        // Ensure that buffer alignment matches channelCount
        int channelCount = popcount(channelMask);
        // 8-bit data in shared memory is not currently supported by AudioFlinger
        size_t alignment = /* format == AUDIO_FORMAT_PCM_8_BIT ? 1 : */ 2;
        if (channelCount > 1) {
            // More than 2 channels does not require stronger alignment than stereo
            alignment <<= 1;
        }
        if (((uint32_t)sharedBuffer->pointer() & (alignment - 1)) != 0) {
            ALOGE("Invalid buffer alignment: address %p, channelCount %d",
                    sharedBuffer->pointer(), channelCount);
            return BAD_VALUE;
        }

        // When initializing a shared buffer AudioTrack via constructors,
        // there's no frameCount parameter.
        // But when initializing a shared buffer AudioTrack via set(),
        // there _is_ a frameCount parameter.  We silently ignore it.
        frameCount = sharedBuffer->size()/channelCount/sizeof(int16_t);

    } else if (!(flags & AUDIO_OUTPUT_FLAG_FAST)) {

        // FIXME move these calculations and associated checks to server
        int afSampleRate;
        if (AudioSystem::getSamplingRate(output, streamType, &afSampleRate) != NO_ERROR) {
            return NO_INIT;
        }
        int afFrameCount;
        if (AudioSystem::getFrameCount(output, streamType, &afFrameCount) != NO_ERROR) {
            return NO_INIT;
        }

        // Ensure that buffer depth covers at least audio hardware latency
        uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
        if (minBufCount < 2) minBufCount = 2;
@@ -784,12 +831,7 @@ status_t AudioTrack::createTrack_l(
        ALOGV("minFrameCount: %d, afFrameCount=%d, minBufCount=%d, sampleRate=%d, afSampleRate=%d"
                ", afLatency=%d",
                minFrameCount, afFrameCount, minBufCount, sampleRate, afSampleRate, afLatency);
#define MIN_FRAME_COUNT_FAST 128    // FIXME hard-coded
        if ((flags & AUDIO_OUTPUT_FLAG_FAST) && (minFrameCount > MIN_FRAME_COUNT_FAST)) {
            minFrameCount = MIN_FRAME_COUNT_FAST;
        }

        if (sharedBuffer == 0) {
        if (frameCount == 0) {
            frameCount = minFrameCount;
        }
@@ -807,15 +849,9 @@ status_t AudioTrack::createTrack_l(
                     frameCount, minFrameCount);
            frameCount = minFrameCount;
        }

    } else {
            // Ensure that buffer alignment matches channelCount
            int channelCount = popcount(channelMask);
            if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) {
                ALOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount);
                return BAD_VALUE;
            }
            frameCount = sharedBuffer->size()/channelCount/sizeof(int16_t);
        }
        // For fast tracks, the frame count calculations and checks are done by server
    }

    IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT;
@@ -864,6 +900,9 @@ status_t AudioTrack::createTrack_l(
        } else {
            ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %u", mCblk->frameCount);
        }
        if (sharedBuffer == 0) {
            mNotificationFramesAct = mCblk->frameCount/2;
        }
    }
    if (sharedBuffer == 0) {
        mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
@@ -879,6 +918,7 @@ status_t AudioTrack::createTrack_l(
    mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
    mCblk->waitTimeMs = 0;
    mRemainingFrames = mNotificationFramesAct;
    // FIXME don't believe this lie
    mLatency = afLatency + (1000*mCblk->frameCount) / sampleRate;
    return NO_ERROR;
}
+28 −10
Original line number Diff line number Diff line
@@ -1623,8 +1623,8 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac
    bool isTimed = (flags & IAudioFlinger::TRACK_TIMED) != 0;

    // client expresses a preference for FAST, but we get the final say
    if ((flags & IAudioFlinger::TRACK_FAST) &&
          !(
    if (flags & IAudioFlinger::TRACK_FAST) {
      if (
            // not timed
            (!isTimed) &&
            // either of these use cases:
@@ -1633,11 +1633,11 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac
              (
                (sharedBuffer != 0)
              ) ||
              // use case 2: callback handler and frame count at least as large as HAL
              // use case 2: callback handler and frame count is default or at least as large as HAL
              (
                (tid != -1) &&
                // FIXME supported frame counts should not be hard-coded
                frameCount >= (int) mFrameCount // FIXME int cast is due to wrong parameter type
                ((frameCount == 0) ||
                (frameCount >= (int) mFrameCount)) // FIXME int cast is due to wrong parameter type
              )
            ) &&
            // PCM data
@@ -1655,16 +1655,34 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac
            (mFastTrackAvailMask != 0)
            // FIXME test that MixerThread for this fast track has a capable output HAL
            // FIXME add a permission test also?
          ) ) {
        ALOGW("AUDIO_POLICY_FLAG_FAST denied: isTimed=%d sharedBuffer=%p frameCount=%d "
        ) {
        ALOGI("AUDIO_OUTPUT_FLAG_FAST accepted: frameCount=%d mFrameCount=%d",
                frameCount, mFrameCount);
        // if frameCount not specified, then it defaults to fast mixer (HAL) frame count
        if (frameCount == 0) {
            frameCount = mFrameCount;
        }
      } else {
        ALOGW("AUDIO_OUTPUT_FLAG_FAST denied: isTimed=%d sharedBuffer=%p frameCount=%d "
                "mFrameCount=%d format=%d isLinear=%d channelMask=%d sampleRate=%d mSampleRate=%d "
                "hasFastMixer=%d tid=%d fastTrackAvailMask=%#x",
                isTimed, sharedBuffer.get(), frameCount, mFrameCount, format,
                audio_is_linear_pcm(format),
                channelMask, sampleRate, mSampleRate, hasFastMixer(), tid, mFastTrackAvailMask);
        flags &= ~IAudioFlinger::TRACK_FAST;
        if (0 < frameCount && frameCount < (int) mNormalFrameCount) {
            frameCount = mNormalFrameCount;
        // For compatibility with AudioTrack calculation, buffer depth is forced
        // to be at least 2 x the normal mixer frame count and cover audio hardware latency.
        // This is probably too conservative, but legacy application code may depend on it.
        // If you change this calculation, also review the start threshold which is related.
        uint32_t latencyMs = mOutput->stream->get_latency(mOutput->stream);
        uint32_t minBufCount = latencyMs / ((1000 * mNormalFrameCount) / mSampleRate);
        if (minBufCount < 2) {
            minBufCount = 2;
        }
        int minFrameCount = mNormalFrameCount * minBufCount;
        if (frameCount < minFrameCount) {
            frameCount = minFrameCount;
        }
      }
    }