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

Commit 681be039 authored by Eric Laurent's avatar Eric Laurent
Browse files

ToneGenerator: fix truncated tones

The first DTMF tone after a silent period is truncated.
This is because the phone app starts and stops the tone
when the user presses and releases the key.
This combined to the fact that the tones use the low latency path
and that when the output stream exists standby there is a period
of several milliseconds during which no audio is mixed until the
stream is "warmed up".
The result is that much less audio is generated than the actual
key press duration.

The fix consists in storing the tone start time and making sure that
the number of samples generated corresponds at least to the time difference
between the tone start and stop commands.

Bug 6607077

Change-Id: I070d20dd8600c25a9e5d5a60c1d3313b7917b00d
parent 2d595c0e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -271,6 +271,7 @@ private:
    float mVolume;  // Volume applied to audio track
    audio_stream_type_t mStreamType; // Audio stream used for output
    unsigned int mProcessSize;  // Size of audio blocks generated at a time by audioCallback() (in PCM frames).
    struct timespec mStartTime; // tone start time: needed to guaranty actual tone duration

    bool initAudioTrack();
    static void audioCallback(int event, void* user, void *info);
+31 −1
Original line number Diff line number Diff line
@@ -922,6 +922,9 @@ bool ToneGenerator::startTone(tone_type toneType, int durationMs) {
            ALOGV("Immediate start, time %d", (unsigned int)(systemTime()/1000000));
            lResult = true;
            mState = TONE_STARTING;
            if (clock_gettime(CLOCK_MONOTONIC, &mStartTime) != 0) {
                mStartTime.tv_sec = 0;
            }
            mLock.unlock();
            mpAudioTrack->start();
            mLock.lock();
@@ -940,6 +943,7 @@ bool ToneGenerator::startTone(tone_type toneType, int durationMs) {
    } else {
        ALOGV("Delayed start");
        mState = TONE_RESTARTING;
        mStartTime.tv_sec = 0;
        lStatus = mWaitCbkCond.waitRelative(mLock, seconds(3));
        if (lStatus == NO_ERROR) {
            if (mState != TONE_IDLE) {
@@ -978,8 +982,31 @@ void ToneGenerator::stopTone() {
    mLock.lock();
    if (mState != TONE_IDLE && mState != TONE_INIT) {
        if (mState == TONE_PLAYING || mState == TONE_STARTING || mState == TONE_RESTARTING) {
            struct timespec stopTime;
            // If the start time is valid, make sure that the number of audio samples produced
            // corresponds at least to the time between the start and stop commands.
            // This is needed in case of cold start of the output stream.
            if ((mStartTime. tv_sec != 0) && (clock_gettime(CLOCK_MONOTONIC, &stopTime) == 0)) {
                time_t sec = stopTime.tv_sec - mStartTime.tv_sec;
                long nsec = stopTime.tv_nsec - mStartTime.tv_nsec;
                long durationMs;
                if (nsec < 0) {
                    --sec;
                    nsec += 1000000000;
                }

                if ((sec + 1) > ((long)(INT_MAX / mSamplingRate))) {
                    mMaxSmp = sec * mSamplingRate;
                } else {
                    // mSamplingRate is always > 1000
                    sec = sec * 1000 + nsec / 1000000; // duration in milliseconds
                    mMaxSmp = (sec * mSamplingRate) / 1000;
                }
                ALOGV("stopTone() forcing mMaxSmp to %d, total for far %d", mMaxSmp,  mTotalSmp);
            } else {
                mState = TONE_STOPPING;
            }
        }
        ALOGV("waiting cond");
        status_t lStatus = mWaitCbkCond.waitRelative(mLock, seconds(3));
        if (lStatus == NO_ERROR) {
@@ -1263,6 +1290,9 @@ audioCallback_EndLoop:
            ALOGV("Cbk restarting track");
            if (lpToneGen->prepareWave()) {
                lpToneGen->mState = TONE_STARTING;
                if (clock_gettime(CLOCK_MONOTONIC, &lpToneGen->mStartTime) != 0) {
                    lpToneGen->mStartTime.tv_sec = 0;
                }
                // must reload lpToneDesc as prepareWave() may change mpToneDesc
                lpToneDesc = lpToneGen->mpToneDesc;
            } else {