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

Commit bda7469d authored by Eric Laurent's avatar Eric Laurent
Browse files

Fix issue 2203561: Sholes: audio playing out of earpiece.

Create a new IAudioTrack interface to AudioFlinger when start() fails due to a broken pipe error.
Do the same if start fails due to the same error after time out in obtainBuffer().
Do not indicate that the AudioTrack is started to AudioPolicyManager if IAudioTrack start fails.
This avoids that an AudioTrack keeps a dead IAudioTrack after a media server crash.

Same modifications for AudioRecord.

Add a flag to ToneGenerator indicating that the callback thread can call Java. Without it, when the media server crashes and restarts, the AudioSystem error callback will crash in JNI if the IAudiotrack is created from AudioTrack callback thread.
parent e1e0dc8e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -79,7 +79,7 @@ static void android_media_ToneGenerator_release(JNIEnv *env, jobject thiz) {

static void android_media_ToneGenerator_native_setup(JNIEnv *env, jobject thiz,
        jint streamType, jint volume) {
    ToneGenerator *lpToneGen = new ToneGenerator(streamType, AudioSystem::linearToLog(volume));
    ToneGenerator *lpToneGen = new ToneGenerator(streamType, AudioSystem::linearToLog(volume), true);

    env->SetIntField(thiz, fields.context, 0);

+6 −0
Original line number Diff line number Diff line
@@ -314,6 +314,11 @@ private:
    };

            bool processAudioBuffer(const sp<ClientRecordThread>& thread);
            status_t openRecord(uint32_t sampleRate,
                                int format,
                                int channelCount,
                                int frameCount,
                                uint32_t flags);

    sp<IAudioRecord>        mAudioRecord;
    sp<IMemory>             mCblkMemory;
@@ -341,6 +346,7 @@ private:
    uint32_t                mNewPosition;
    uint32_t                mUpdatePeriod;
    audio_io_handle_t       mInput;
    uint32_t                mFlags;
};

}; // namespace android
+8 −0
Original line number Diff line number Diff line
@@ -391,6 +391,14 @@ private:
    };

            bool processAudioBuffer(const sp<AudioTrackThread>& thread);
            status_t createTrack(int streamType,
                                 uint32_t sampleRate,
                                 int format,
                                 int channelCount,
                                 int frameCount,
                                 uint32_t flags,
                                 const sp<IMemory>& sharedBuffer,
                                 audio_io_handle_t output);

    sp<IAudioTrack>         mAudioTrack;
    sp<IMemory>             mCblkMemory;
+2 −1
Original line number Diff line number Diff line
@@ -151,7 +151,7 @@ public:
        NUM_SUP_TONES = LAST_SUP_TONE-FIRST_SUP_TONE+1
    };

    ToneGenerator(int streamType, float volume);
    ToneGenerator(int streamType, float volume, bool threadCanCallJava = false);
    ~ToneGenerator();

    bool startTone(int toneType, int durationMs = -1);
@@ -242,6 +242,7 @@ private:

    static const ToneDescriptor sToneDescriptors[];

    bool mThreadCanCallJava;
    unsigned int mTotalSmp;  // Total number of audio samples played (gives current time)
    unsigned int mNextSegSmp;  // Position of next segment transition expressed in samples
    // NOTE: because mTotalSmp, mNextSegSmp are stored on 32 bit, current design will operate properly
+85 −42
Original line number Diff line number Diff line
@@ -101,11 +101,6 @@ status_t AudioRecord::set(
        return INVALID_OPERATION;
    }

    const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
    if (audioFlinger == 0) {
        return NO_INIT;
    }

    if (inputSource == AUDIO_SOURCE_DEFAULT) {
        inputSource = AUDIO_SOURCE_MIC;
    }
@@ -171,22 +166,14 @@ status_t AudioRecord::set(
        notificationFrames = frameCount/2;
    }

    // open record channel
    status_t status;
    sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), mInput,
                                                       sampleRate, format,
                                                       channelCount,
                                                       frameCount,
                                                       ((uint16_t)flags) << 16,
                                                       &status);
    if (record == 0) {
        LOGE("AudioFlinger could not create record track, status: %d", status);
    // create the IAudioRecord
    status_t status = openRecord(sampleRate, format, channelCount,
                                 frameCount, flags);

    if (status != NO_ERROR) {
        return status;
    }
    sp<IMemory> cblk = record->getCblk();
    if (cblk == 0) {
        return NO_INIT;
    }

    if (cbf != 0) {
        mClientRecordThread = new ClientRecordThread(*this, threadCanCallJava);
        if (mClientRecordThread == 0) {
@@ -196,11 +183,6 @@ status_t AudioRecord::set(

    mStatus = NO_ERROR;

    mAudioRecord = record;
    mCblkMemory = cblk;
    mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
    mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
    mCblk->out = 0;
    mFormat = format;
    // Update buffer size in case it has been limited by AudioFlinger during track creation
    mFrameCount = mCblk->frameCount;
@@ -217,6 +199,7 @@ status_t AudioRecord::set(
    mNewPosition = 0;
    mUpdatePeriod = 0;
    mInputSource = (uint8_t)inputSource;
    mFlags = flags;

    return NO_ERROR;
}
@@ -283,6 +266,13 @@ status_t AudioRecord::start()

    if (android_atomic_or(1, &mActive) == 0) {
        ret = AudioSystem::startInput(mInput);
        if (ret == NO_ERROR) {
            ret = mAudioRecord->start();
            if (ret == DEAD_OBJECT) {
                LOGV("start() dead IAudioRecord: creating a new one");
                ret = openRecord(mCblk->sampleRate, mFormat, mChannelCount,
                        mFrameCount, mFlags);
            }
            if (ret == NO_ERROR) {
                mNewPosition = mCblk->user + mUpdatePeriod;
                mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
@@ -292,7 +282,11 @@ status_t AudioRecord::start()
                } else {
                    setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
                }
            ret = mAudioRecord->start();
            } else {
                LOGV("start() failed");
                AudioSystem::stopInput(mInput);
                android_atomic_and(~1, &mActive);
            }
        }
    }

@@ -396,10 +390,48 @@ status_t AudioRecord::getPosition(uint32_t *position)

// -------------------------------------------------------------------------

status_t AudioRecord::openRecord(
        uint32_t sampleRate,
        int format,
        int channelCount,
        int frameCount,
        uint32_t flags)
{
    status_t status;
    const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
    if (audioFlinger == 0) {
        return NO_INIT;
    }

    sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), mInput,
                                                       sampleRate, format,
                                                       channelCount,
                                                       frameCount,
                                                       ((uint16_t)flags) << 16,
                                                       &status);
    if (record == 0) {
        LOGE("AudioFlinger could not create record track, status: %d", status);
        return status;
    }
    sp<IMemory> cblk = record->getCblk();
    if (cblk == 0) {
        LOGE("Could not get control block");
        return NO_INIT;
    }
    mAudioRecord.clear();
    mAudioRecord = record;
    mCblkMemory.clear();
    mCblkMemory = cblk;
    mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
    mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
    mCblk->out = 0;

    return NO_ERROR;
}

status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
{
    int active;
    int timeout = 0;
    status_t result;
    audio_track_cblk_t* cblk = mCblk;
    uint32_t framesReq = audioBuffer->frameCount;
@@ -411,25 +443,40 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
    uint32_t framesReady = cblk->framesReady();

    if (framesReady == 0) {
        Mutex::Autolock _l(cblk->lock);
        cblk->lock.lock();
        goto start_loop_here;
        while (framesReady == 0) {
            active = mActive;
            if (UNLIKELY(!active))
            if (UNLIKELY(!active)) {
                cblk->lock.unlock();
                return NO_MORE_BUFFERS;
            if (UNLIKELY(!waitCount))
            }
            if (UNLIKELY(!waitCount)) {
                cblk->lock.unlock();
                return WOULD_BLOCK;
            timeout = 0;
            }
            result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
            if (__builtin_expect(result!=NO_ERROR, false)) {
                cblk->waitTimeMs += waitTimeMs;
                if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
                    LOGW(   "obtainBuffer timed out (is the CPU pegged?) "
                            "user=%08x, server=%08x", cblk->user, cblk->server);
                    timeout = 1;
                    cblk->lock.unlock();
                    result = mAudioRecord->start();
                    if (result == DEAD_OBJECT) {
                        LOGW("obtainBuffer() dead IAudioRecord: creating a new one");
                        result = openRecord(cblk->sampleRate, mFormat, mChannelCount,
                                            mFrameCount, mFlags);
                        if (result == NO_ERROR) {
                            cblk = mCblk;
                            cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
                        }
                    }
                    cblk->lock.lock();
                    cblk->waitTimeMs = 0;
                }
                if (--waitCount == 0) {
                    cblk->lock.unlock();
                    return TIMED_OUT;
                }
            }
@@ -437,13 +484,9 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
        start_loop_here:
            framesReady = cblk->framesReady();
        }
        cblk->lock.unlock();
    }

    LOGW_IF(timeout,
        "*** SERIOUS WARNING *** obtainBuffer() timed out "
        "but didn't need to be locked. We recovered, but "
        "this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server);

    cblk->waitTimeMs = 0;

    if (framesReq > framesReady) {
Loading