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

Commit 7fd0422f authored by Glenn Kasten's avatar Glenn Kasten
Browse files

Sample rate 0 means a route-dependent rate

Remove check for primary _output_ [sic] sampling rate for fast capture.
Clean up AudioRecord handling of frame count and sample rate.
Clean up AudioTrack handling of notification period updates.
Make AudioRecord and AudioTrack more similar in order of operation, comments, and whitespace.

Bug: 25641253
Bug: 21019153
Change-Id: I24a6677945987fc39a9bf93f70357e4bc7410f98
parent 2c073da0
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -145,7 +145,7 @@ public:
     * Parameters:
     *
     * inputSource:        Select the audio input to record from (e.g. AUDIO_SOURCE_DEFAULT).
     * sampleRate:         Data sink sampling rate in Hz.
     * sampleRate:         Data sink sampling rate in Hz.  Zero means to use the source sample rate.
     * format:             Audio format (e.g AUDIO_FORMAT_PCM_16_BIT for signed
     *                     16 bits per sample).
     * channelMask:        Channel mask, such that audio_is_input_channel(channelMask) is true.
@@ -258,6 +258,7 @@ public:
            bool        stopped() const;

    /* Return the sink sample rate for this record track in Hz.
     * If specified as zero in constructor or set(), this will be the source sample rate.
     * Unlike AudioTrack, the sample rate is const after initialization, so doesn't need a lock.
     */
            uint32_t    getSampleRate() const   { return mSampleRate; }
+9 −3
Original line number Diff line number Diff line
@@ -167,7 +167,10 @@ public:
     *
     * streamType:         Select the type of audio stream this track is attached to
     *                     (e.g. AUDIO_STREAM_MUSIC).
     * sampleRate:         Data source sampling rate in Hz.
     * sampleRate:         Data source sampling rate in Hz.  Zero means to use the sink sample rate.
     *                     A non-zero value must be specified if AUDIO_OUTPUT_FLAG_DIRECT is set.
     *                     0 will not work with current policy implementation for direct output
     *                     selection where an exact match is needed for sampling rate.
     * format:             Audio format. For mixed tracks, any PCM format supported by server is OK.
     *                     For direct and offloaded tracks, the possible format(s) depends on the
     *                     output sink.
@@ -395,11 +398,14 @@ public:
            status_t    setAuxEffectSendLevel(float level);
            void        getAuxEffectSendLevel(float* level) const;

    /* Set source sample rate for this track in Hz, mostly used for games' sound effects
    /* Set source sample rate for this track in Hz, mostly used for games' sound effects.
     * Zero is not permitted.
     */
            status_t    setSampleRate(uint32_t sampleRate);

    /* Return current source sample rate in Hz */
    /* Return current source sample rate in Hz.
     * If specified as zero in constructor or set(), this will be the sink sample rate.
     */
            uint32_t    getSampleRate() const;

    /* Return the original source sample rate in Hz. This corresponds to the sample rate
+62 −45
Original line number Diff line number Diff line
@@ -191,10 +191,6 @@ status_t AudioRecord::set(
              mAttributes.source, mAttributes.flags, mAttributes.tags);
    }

    if (sampleRate == 0) {
        ALOGE("Invalid sample rate %u", sampleRate);
        return BAD_VALUE;
    }
    mSampleRate = sampleRate;

    // these below should probably come from the audioFlinger too...
@@ -517,27 +513,71 @@ status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16
        return NO_INIT;
    }

    // Fast tracks must be at the primary _output_ [sic] sampling rate,
    // because there is currently no concept of a primary input sampling rate
    uint32_t afSampleRate = AudioSystem::getPrimaryOutputSamplingRate();
    if (afSampleRate == 0) {
        ALOGW("getPrimaryOutputSamplingRate failed");
    if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
    }
    audio_io_handle_t input;

    status_t status;
    status = AudioSystem::getInputForAttr(&mAttributes, &input,
                                        (audio_session_t)mSessionId,
                                        // FIXME compare to AudioTrack
                                        IPCThreadState::self()->getCallingUid(),
                                        mSampleRate, mFormat, mChannelMask,
                                        mFlags, mSelectedDeviceId);

    if (status != NO_ERROR || input == AUDIO_IO_HANDLE_NONE) {
        ALOGE("Could not get audio input for session %d, record source %d, sample rate %u, "
              "format %#x, channel mask %#x, flags %#x",
              mSessionId, mAttributes.source, mSampleRate, mFormat, mChannelMask, mFlags);
        return BAD_VALUE;
    }
    {
    // Now that we have a reference to an I/O handle and have not yet handed it off to AudioFlinger,
    // we must release it ourselves if anything goes wrong.

#if 0
    size_t afFrameCount;
    status = AudioSystem::getFrameCount(input, &afFrameCount);
    if (status != NO_ERROR) {
        ALOGE("getFrameCount(input=%d) status %d", input, status);
        goto release;
    }
#endif

    uint32_t afSampleRate;
    status = AudioSystem::getSamplingRate(input, &afSampleRate);
    if (status != NO_ERROR) {
        ALOGE("getSamplingRate(input=%d) status %d", input, status);
        goto release;
    }
    if (mSampleRate == 0) {
        mSampleRate = afSampleRate;
    }

    // Client can only express a preference for FAST.  Server will perform additional tests.
    if ((mFlags & AUDIO_INPUT_FLAG_FAST) && !((
    if (mFlags & AUDIO_INPUT_FLAG_FAST) {
        bool useCaseAllowed =
            // either of these use cases:
            // use case 1: callback transfer mode
            (mTransfer == TRANSFER_CALLBACK) ||
            // use case 2: obtain/release mode
            (mTransfer == TRANSFER_OBTAIN)) &&
            // matching sample rate
            (mSampleRate == afSampleRate))) {
        ALOGW("AUDIO_INPUT_FLAG_FAST denied by client; transfer %d, track %u Hz, primary %u Hz",
            (mTransfer == TRANSFER_OBTAIN);
        // sample rates must also match
        bool fastAllowed = useCaseAllowed && (mSampleRate == afSampleRate);
        if (!fastAllowed) {
            ALOGW("AUDIO_INPUT_FLAG_FAST denied by client; transfer %d, "
                "track %u Hz, input %u Hz",
                mTransfer, mSampleRate, afSampleRate);
            // once denied, do not request again if IAudioRecord is re-created
            mFlags = (audio_input_flags_t) (mFlags & ~AUDIO_INPUT_FLAG_FAST);
        }
    }

    // The notification frame count is the period between callbacks, as suggested by the client
    // but moderated by the server.  For record, the calculations are done entirely on server side.
    size_t notificationFrames = mNotificationFramesReq;
    size_t frameCount = mReqFrameCount;

    IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT;

@@ -549,35 +589,10 @@ status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16
        }
    }

    if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
    }

    audio_io_handle_t input;
    status_t status = AudioSystem::getInputForAttr(&mAttributes, &input,
                                        (audio_session_t)mSessionId,
                                        IPCThreadState::self()->getCallingUid(),
                                        mSampleRate, mFormat, mChannelMask,
                                        mFlags, mSelectedDeviceId);

    if (status != NO_ERROR) {
        ALOGE("Could not get audio input for record source %d, sample rate %u, format %#x, "
              "channel mask %#x, session %d, flags %#x",
              mAttributes.source, mSampleRate, mFormat, mChannelMask, mSessionId, mFlags);
        return BAD_VALUE;
    }
    {
    // Now that we have a reference to an I/O handle and have not yet handed it off to AudioFlinger,
    // we must release it ourselves if anything goes wrong.

    size_t frameCount = mReqFrameCount;
    size_t temp = frameCount;   // temp may be replaced by a revised value of frameCount,
                                // but we will still need the original value also
    int originalSessionId = mSessionId;

    // The notification frame count is the period between callbacks, as suggested by the server.
    size_t notificationFrames = mNotificationFramesReq;

    sp<IMemory> iMem;           // for cblk
    sp<IMemory> bufferMem;
    sp<IAudioRecord> record = audioFlinger->openRecord(input,
@@ -660,11 +675,13 @@ status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16
        }
    }

    // Make sure that application is notified with sufficient margin before overrun
    if (notificationFrames == 0 || notificationFrames > frameCount) {
        ALOGW("Received notificationFrames %zu for frameCount %zu", notificationFrames, frameCount);
    // Make sure that application is notified with sufficient margin before overrun.
    // The computation is done on server side.
    if (mNotificationFramesReq > 0 && notificationFrames != mNotificationFramesReq) {
        ALOGW("Server adjusted notificationFrames from %u to %zu for frameCount %zu",
                mNotificationFramesReq, notificationFrames, frameCount);
    }
    mNotificationFramesAct = notificationFrames;
    mNotificationFramesAct = (uint32_t) notificationFrames;

    // We retain a copy of the I/O handle, but don't own the reference
    mInput = input;
+21 −15
Original line number Diff line number Diff line
@@ -1192,6 +1192,7 @@ status_t AudioTrack::createTrack_l()
        mSampleRate = mAfSampleRate;
        mOriginalSampleRate = mAfSampleRate;
    }

    // Client can only express a preference for FAST.  Server will perform additional tests.
    if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
        bool useCaseAllowed =
@@ -1215,13 +1216,6 @@ status_t AudioTrack::createTrack_l()
        }
    }

    // The client's AudioTrack buffer is divided into n parts for purpose of wakeup by server, where
    //  n = 1   fast track with single buffering; nBuffering is ignored
    //  n = 2   fast track with double buffering
    //  n = 2   normal track, (including those with sample rate conversion)
    //  n >= 3  very high latency or very small notification interval (unused).
    const uint32_t nBuffering = 2;

    mNotificationFramesAct = mNotificationFramesReq;

    size_t frameCount = mReqFrameCount;
@@ -1320,6 +1314,7 @@ status_t AudioTrack::createTrack_l()
    // AudioFlinger now owns the reference to the I/O handle,
    // so we are no longer responsible for releasing it.

    // FIXME compare to AudioRecord
    sp<IMemory> iMem = track->getCblk();
    if (iMem == 0) {
        ALOGE("Could not get control block");
@@ -1383,14 +1378,25 @@ status_t AudioTrack::createTrack_l()
            //return NO_INIT;
        }
    }
    // Make sure that application is notified with sufficient margin before underrun

    // Make sure that application is notified with sufficient margin before underrun.
    // The client's AudioTrack buffer is divided into n parts for purpose of wakeup by server, where
    //  n = 1   fast track with single buffering; nBuffering is ignored
    //  n = 2   fast track with double buffering
    //  n = 2   normal track, (including those with sample rate conversion)
    //  n >= 3  very high latency or very small notification interval (unused).
    // FIXME Move the computation from client side to server side,
    //       and allow nBuffering to be larger than 1 for OpenSL ES, like it can be for Java.
    if (mSharedBuffer == 0 && audio_is_linear_pcm(mFormat)) {
        // Theoretically double-buffering is not required for fast tracks,
        // due to tighter scheduling.  But in practice, to accommodate kernels with
        // scheduling jitter, and apps with computation jitter, we use double-buffering
        // for fast tracks just like normal streaming tracks.
        if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount / nBuffering) {
            mNotificationFramesAct = frameCount / nBuffering;
        size_t maxNotificationFrames = frameCount;
        if (!(trackFlags & IAudioFlinger::TRACK_FAST)) {
            const uint32_t nBuffering = 2;
            maxNotificationFrames /= nBuffering;
        }
        if (mNotificationFramesAct == 0 || mNotificationFramesAct > maxNotificationFrames) {
            ALOGW("Client adjusted notificationFrames from %u to %zu for frameCount %zu",
                    mNotificationFramesAct, maxNotificationFrames, frameCount);
            mNotificationFramesAct = (uint32_t) maxNotificationFrames;
        }
    }

+1 −0
Original line number Diff line number Diff line
@@ -564,6 +564,7 @@ private:
                                     PlaybackThread *srcThread,
                                     PlaybackThread *dstThread,
                                     bool reRegister);

              // return thread associated with primary hardware device, or NULL
              PlaybackThread *primaryPlaybackThread_l() const;
              audio_devices_t primaryOutputDevice_l() const;
Loading