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

Commit 77d4f307 authored by Eric Laurent's avatar Eric Laurent
Browse files

A2DP audio HAL: fix write error behavior

Do not return -1 status in case of write error but
emulate normal timing and return the number of bytes written
as if no error had occured.

This is because audio flinger does not take any recovery
action in case of write error anyway but does not increment the
number of frames written to the HAL.
In case of persisting error, active audio tracks will not finish playback
and a wakelock will be held indefinitely.

Bug: 25488825
Change-Id: I4f00ba8d7a5c55f70520d448d894240c54685027
parent 476ebb63
Loading
Loading
Loading
Loading
+18 −18
Original line number Diff line number Diff line
@@ -189,7 +189,7 @@ static int calc_audiotime(struct a2dp_config cfg, int bytes)
    ASSERTC(cfg.format == AUDIO_FORMAT_PCM_16_BIT,
            "unsupported sample sz", cfg.format);

    return bytes*(1000000/(chan_count*2))/cfg.rate;
    return (int)(((int64_t)bytes * (1000000 / (chan_count * 2))) / cfg.rate);
}

/*****************************************************************************
@@ -550,6 +550,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
{
    struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
    int sent;
    int us_delay;

    DEBUG("write %zu bytes (fd %d)", bytes, out->common.audio_fd);

@@ -559,7 +560,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
    {
        DEBUG("stream suspended");
        pthread_mutex_unlock(&out->common.lock);
        return -1;
        goto error;
    }

    /* only allow autostarting if we are in stopped or standby */
@@ -568,23 +569,15 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
    {
        if (start_audio_datapath(&out->common) < 0)
        {
            /* emulate time this write represents to avoid very fast write
               failures during transition periods or remote suspend */

            int us_delay = calc_audiotime(out->common.cfg, bytes);

            DEBUG("emulate a2dp write delay (%d us)", us_delay);

            usleep(us_delay);
            pthread_mutex_unlock(&out->common.lock);
            return -1;
            goto error;
        }
    }
    else if (out->common.state != AUDIO_A2DP_STATE_STARTED)
    {
        ERROR("stream not in stopped or standby");
        pthread_mutex_unlock(&out->common.lock);
        return -1;
        goto error;
    }

    pthread_mutex_unlock(&out->common.lock);
@@ -597,14 +590,21 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
            out->common.state = AUDIO_A2DP_STATE_STOPPED;
        else
            ERROR("write failed : stream suspended, avoid resetting state");
    } else {
        goto error;
    }

    const size_t frames = bytes / audio_stream_out_frame_size(stream);
    out->frames_rendered += frames;
    out->frames_presented += frames;
    }
    return bytes;

    DEBUG("wrote %d bytes out of %zu bytes", sent, bytes);
    return sent;
error:
    us_delay = calc_audiotime(out->common.cfg, bytes);

    DEBUG("emulate a2dp write delay (%d us)", us_delay);

    usleep(us_delay);
    return bytes;
}