[vlc-commits] [Git][videolan/vlc][master] 9 commits: aaudio: use LogAAudioError

Jean-Baptiste Kempf (@jbk) gitlab at videolan.org
Sun Mar 12 09:54:16 UTC 2023



Jean-Baptiste Kempf pushed to branch master at VideoLAN / VLC


Commits:
65c3634e by Thomas Guillem at 2023-03-12T09:26:44+00:00
aaudio: use LogAAudioError

To convert the result to a string.

- - - - -
a149122d by Thomas Guillem at 2023-03-12T09:26:44+00:00
aaudio: report latency only in the STARTED state

And not in the STARTING state.

- - - - -
b41e2276 by Thomas Guillem at 2023-03-12T09:26:44+00:00
aaudio: move function up

To avoid forward declaration in a next commit.

No functional changes.

- - - - -
bb8f2163 by Thomas Guillem at 2023-03-12T09:26:44+00:00
aaudio: create CloseAAudioStream() function

- - - - -
9f6da290 by Thomas Guillem at 2023-03-12T09:26:44+00:00
aaudio: close even in case of failure

- - - - -
3aee1739 by Thomas Guillem at 2023-03-12T09:26:44+00:00
aaudio: split OpenAAudioStream()

In order to be able to call it again, when flushing (cf. next commits).

- - - - -
3fa5113b by Thomas Guillem at 2023-03-12T09:26:44+00:00
aaudio: handle device_id

In order to use the same decide_id when we restart the AAudio stream.

- - - - -
c9563144 by Thomas Guillem at 2023-03-12T09:26:44+00:00
aaudio: assert that "as" is valid after checking the state

sys->as will be set to NULL in case of flush error in the next commit.

- - - - -
4c353853 by Thomas Guillem at 2023-03-12T09:26:44+00:00
aaudio: restart stream when flushing

Since flush is not working.

There are 2 main issues:

 - AAudioStream_getTimestamp() could fail from Flush(), resulting in the
   impossibility to report a correct timing. As the doc says:
   "TODO review Frame counters are not reset by a flush", and we need a point
   of comparison after a flush.

 - Some devices (seen on The Galaxy S22 Ultra API Level 31) can't report
   a timestamp once the stream is flushed, resulting in the
   impossibility to report a correct timing.

Now, the whole Flush() function take between 10ms and 25ms (depending on the
device).

Fixes #27917

- - - - -


1 changed file:

- modules/audio_output/android/aaudio.c


Changes:

=====================================
modules/audio_output/android/aaudio.c
=====================================
@@ -39,6 +39,14 @@
 
 struct sys
 {
+    struct
+    {
+        aaudio_format_t format;
+        int32_t session_id;
+        int32_t device_id;
+        bool low_latency;
+    } cfg;
+
     AAudioStream *as;
 
     jobject dp;
@@ -46,7 +54,6 @@ struct sys
     bool muted;
 
     audio_sample_format_t fmt;
-    int64_t frames_flush_pos;
     bool error;
 
     /* Spinlock that protect all the following variables */
@@ -78,6 +85,7 @@ static struct {
     void *handle;
     aaudio_result_t       (*AAudio_createStreamBuilder)(AAudioStreamBuilder **);
     const char           *(*AAudio_convertResultToText)(aaudio_result_t);
+    void                  (*AAudioStreamBuilder_setDeviceId)(AAudioStreamBuilder *, int32_t);
     void                  (*AAudioStreamBuilder_setFormat)(AAudioStreamBuilder *, aaudio_format_t);
     void                  (*AAudioStreamBuilder_setChannelCount)(AAudioStreamBuilder *, int32_t);
     void                  (*AAudioStreamBuilder_setDataCallback)(AAudioStreamBuilder *, AAudioStream_dataCallback, void *);
@@ -91,6 +99,7 @@ static struct {
     aaudio_result_t       (*AAudioStream_requestStop)(AAudioStream *);
     aaudio_result_t       (*AAudioStream_requestPause)(AAudioStream *);
     aaudio_result_t       (*AAudioStream_requestFlush)(AAudioStream *);
+    int32_t               (*AAudioStream_getDeviceId)(AAudioStream *);
     int32_t               (*AAudioStream_getSampleRate)(AAudioStream *);
     aaudio_result_t       (*AAudioStream_getTimestamp)(AAudioStream *, clockid_t,
                                                        int64_t *framePosition, int64_t *timeNanoseconds);
@@ -144,6 +153,7 @@ LoadSymbols(aout_stream_t *stream)
     AAUDIO_DLSYM(AAudio_createStreamBuilder);
     AAUDIO_DLSYM(AAudio_convertResultToText);
     AAUDIO_DLSYM(AAudioStreamBuilder_setChannelCount);
+    AAUDIO_DLSYM(AAudioStreamBuilder_setDeviceId);
     AAUDIO_DLSYM(AAudioStreamBuilder_setFormat);
     AAUDIO_DLSYM(AAudioStreamBuilder_setDataCallback);
     AAUDIO_DLSYM(AAudioStreamBuilder_setErrorCallback);
@@ -156,6 +166,7 @@ LoadSymbols(aout_stream_t *stream)
     AAUDIO_DLSYM(AAudioStream_requestStop);
     AAUDIO_DLSYM(AAudioStream_requestPause);
     AAUDIO_DLSYM(AAudioStream_requestFlush);
+    AAUDIO_DLSYM(AAudioStream_getDeviceId);
     AAUDIO_DLSYM(AAudioStream_getSampleRate);
     AAUDIO_DLSYM(AAudioStream_getTimestamp);
     AAUDIO_DLSYM(AAudioStream_write);
@@ -221,6 +232,8 @@ WaitState(aout_stream_t *stream, aaudio_result_t wait_state)
     if (sys->error)
         return VLC_EGENERIC;
 
+    assert(sys->as);
+
     aaudio_stream_state_t next_state = vt.AAudioStream_getState(sys->as);
     aaudio_stream_state_t current_state = next_state;
 
@@ -244,8 +257,12 @@ GetState(aout_stream_t *stream)
 {
     struct sys *sys = stream->sys;
 
-    return sys->error ? AAUDIO_STREAM_STATE_UNINITIALIZED
-                      : vt.AAudioStream_getState(sys->as);
+    if (sys->error)
+        return AAUDIO_STREAM_STATE_UNINITIALIZED;
+
+    assert(sys->as);
+
+    return vt.AAudioStream_getState(sys->as);
 }
 
 #define Request(x) do { \
@@ -331,7 +348,7 @@ GetFrameTimestampLocked(aout_stream_t *stream, int64_t *pos_frames,
                                          pos_frames, &time_ns);
     if (result != AAUDIO_OK)
     {
-        msg_Err(stream, "AAudioStream_getTimestamp failed: %d", result);
+        LogAAudioError(stream, "AAudioStream_getTimestamp failed", result);
         return VLC_EGENERIC;
     }
     if (*pos_frames <= 0)
@@ -352,6 +369,7 @@ DataCallback(AAudioStream *as, void *user, void *data_, int32_t num_frames)
     uint8_t *data = data_;
 
     vlc_mutex_lock(&sys->lock);
+    aaudio_stream_state_t state = GetState(stream);
 
     if (!sys->started)
     {
@@ -419,7 +437,8 @@ DataCallback(AAudioStream *as, void *user, void *data_, int32_t num_frames)
 
         int64_t pos_frames;
         vlc_tick_t system_ts;
-        if (sys->timing_report_last_written_bytes >= sys->timing_report_delay_bytes
+        if (state == AAUDIO_STREAM_STATE_STARTED
+         && sys->timing_report_last_written_bytes >= sys->timing_report_delay_bytes
          && GetFrameTimestampLocked(stream, &pos_frames, &system_ts) == VLC_SUCCESS)
         {
             sys->timing_report_last_written_bytes = 0;
@@ -428,9 +447,6 @@ DataCallback(AAudioStream *as, void *user, void *data_, int32_t num_frames)
             sys->timing_report_delay_bytes =
                 TicksToBytes(sys, TIMING_REPORT_DELAY_TICKS);
 
-            pos_frames -= sys->frames_flush_pos;
-            if (unlikely(pos_frames < 0))
-                pos_frames = 0;
             vlc_tick_t pos_ticks = FramesToTicks(sys, pos_frames);
 
             /* Add the start silence to the system time and don't subtract
@@ -471,15 +487,117 @@ ErrorCallback(AAudioStream *as, void *user, aaudio_result_t error)
     aout_stream_RestartRequest(stream, AOUT_RESTART_OUTPUT);
 }
 
+static void
+CloseAAudioStream(aout_stream_t *stream)
+{
+    struct sys *sys = stream->sys;
+
+    RequestStop(stream);
+
+    if (WaitState(stream, AAUDIO_STREAM_STATE_STOPPED) != VLC_SUCCESS)
+        msg_Warn(stream, "Error waiting for stopped state");
+
+    vt.AAudioStream_close(sys->as);
+
+    sys->as = NULL;
+}
+
+static int
+OpenAAudioStream(aout_stream_t *stream)
+{
+    struct sys *sys = stream->sys;
+    aaudio_result_t result;
+
+    AAudioStreamBuilder *builder;
+    result = vt.AAudio_createStreamBuilder(&builder);
+    if (result != AAUDIO_OK)
+    {
+        LogAAudioError(stream, "Failed to create AAudio stream builder", result);
+        return VLC_EGENERIC;
+    }
+
+    vt.AAudioStreamBuilder_setFormat(builder, sys->cfg.format);
+    vt.AAudioStreamBuilder_setChannelCount(builder, sys->fmt.i_channels);
+
+    /* Setup the session-id */
+    vt.AAudioStreamBuilder_setSessionId(builder, sys->cfg.session_id);
+
+    /* Setup the role */
+    char *vlc_role = var_InheritString(stream, "role");
+    if (vlc_role != NULL)
+    {
+        aaudio_usage_t usage = GetUsageFromVLCRole(vlc_role);
+        vt.AAudioStreamBuilder_setUsage(builder, usage);
+        free(vlc_role);
+    } /* else if not set, default is MEDIA usage */
+
+    vt.AAudioStreamBuilder_setDataCallback(builder, DataCallback, stream);
+    vt.AAudioStreamBuilder_setErrorCallback(builder, ErrorCallback, stream);
+
+    if (sys->cfg.low_latency)
+        vt.AAudioStreamBuilder_setPerformanceMode(builder,
+            AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+
+    if (sys->cfg.device_id != AAUDIO_UNSPECIFIED)
+        vt.AAudioStreamBuilder_setDeviceId(builder, sys->cfg.device_id);
+
+    AAudioStream *as;
+    result = vt.AAudioStreamBuilder_openStream(builder, &as);
+    if (result != AAUDIO_OK)
+    {
+        LogAAudioError(stream, "Failed to open AAudio stream", result);
+        vt.AAudioStreamBuilder_delete(builder);
+        return VLC_EGENERIC;
+    }
+    vt.AAudioStreamBuilder_delete(builder);
+
+    sys->as = as;
+
+    return VLC_SUCCESS;
+}
+
+static void
+PrepareAudioFormat(aout_stream_t *stream, audio_sample_format_t *fmt)
+{
+    struct sys *sys = stream->sys;
+
+    sys->cfg.device_id = AAUDIO_UNSPECIFIED;
+
+    sys->cfg.session_id = var_InheritInteger(stream, "audiotrack-session-id");
+    if (sys->cfg.session_id == 0)
+        sys->cfg.session_id = AAUDIO_SESSION_ID_ALLOCATE;
+
+    if (fmt->i_format == VLC_CODEC_S16N)
+        sys->cfg.format = AAUDIO_FORMAT_PCM_I16;
+    else
+    {
+        if (fmt->i_format != VLC_CODEC_FL32)
+        {
+            /* override to request conversion */
+            fmt->i_format = VLC_CODEC_FL32;
+            fmt->i_bytes_per_frame = 4 * fmt->i_channels;
+        }
+        sys->cfg.format = AAUDIO_FORMAT_PCM_FLOAT;
+    }
+
+    if (fmt->channel_type == AUDIO_CHANNEL_TYPE_AMBISONICS)
+    {
+        fmt->channel_type = AUDIO_CHANNEL_TYPE_BITMAP;
+        sys->cfg.low_latency = true;
+    }
+    else
+        sys->cfg.low_latency = false;
+
+    sys->fmt = *fmt;
+}
+
 static void
 Play(aout_stream_t *stream, vlc_frame_t *frame, vlc_tick_t date)
 {
     struct sys *sys = stream->sys;
-    assert(sys->as);
 
     aaudio_stream_state_t state = GetState(stream);
-    if (state == AAUDIO_STREAM_STATE_OPEN
-     || state == AAUDIO_STREAM_STATE_FLUSHED)
+    if (state == AAUDIO_STREAM_STATE_OPEN)
     {
         if (RequestStart(stream) != VLC_SUCCESS)
             goto bailout;
@@ -492,6 +610,8 @@ Play(aout_stream_t *stream, vlc_frame_t *frame, vlc_tick_t date)
             || state == AAUDIO_STREAM_STATE_STARTED);
     }
 
+    assert(sys->as);
+
     vlc_mutex_lock(&sys->lock);
 
     if (!sys->started)
@@ -561,7 +681,6 @@ Flush(aout_stream_t *stream)
     aaudio_stream_state_t state = GetState(stream);
 
     if (state == AAUDIO_STREAM_STATE_UNINITIALIZED
-     || state == AAUDIO_STREAM_STATE_FLUSHED
      || state == AAUDIO_STREAM_STATE_OPEN)
         return;
 
@@ -577,12 +696,13 @@ Flush(aout_stream_t *stream)
      && WaitState(stream, AAUDIO_STREAM_STATE_PAUSED) != VLC_SUCCESS)
         return;
 
-    /* The doc states that "Pausing a stream will freeze the data flow but not
-     * flush any buffers" but this does not seem to be the case for all
-     * arch/devices/versions. So, flush everything with the lock held in the
-     * unlikely case that the data callback is called between PAUSED and
-     * FLUSHING */
-    vlc_mutex_lock(&sys->lock);
+    if (RequestFlush(stream) != VLC_SUCCESS)
+        return;
+
+    if (WaitState(stream, AAUDIO_STREAM_STATE_FLUSHED) != VLC_SUCCESS)
+        return;
+
+    CloseAAudioStream(stream);
 
     vlc_frame_ChainRelease(sys->frame_chain);
     sys->frame_chain = NULL;
@@ -597,20 +717,21 @@ Flush(aout_stream_t *stream)
     sys->timing_report_delay_bytes = 0;
     sys->underrun_bytes = 0;
 
-    vlc_tick_t unused;
-    if (GetFrameTimestampLocked(stream, &sys->frames_flush_pos, &unused) != VLC_SUCCESS)
+    int ret = OpenAAudioStream(stream);
+    if (ret != VLC_SUCCESS)
     {
-        sys->frames_flush_pos = 0;
-        msg_Warn(stream, "Flush: can't get paused position");
-    }
-
-    vlc_mutex_unlock(&sys->lock);
-
-    if (RequestFlush(stream) != VLC_SUCCESS)
+        sys->error = true;
         return;
+    }
 
-    if (WaitState(stream, AAUDIO_STREAM_STATE_FLUSHED) != VLC_SUCCESS)
-        return;
+    int32_t new_rate = vt.AAudioStream_getSampleRate(sys->as);
+    assert(new_rate > 0);
+    if ((unsigned) new_rate != sys->fmt.i_rate)
+    {
+        msg_Err(stream, "rate changed after flush, from %u to %d",
+                sys->fmt.i_rate, new_rate);
+        aout_stream_RestartRequest(stream, AOUT_RESTART_OUTPUT);
+    }
 }
 
 static void
@@ -669,96 +790,13 @@ MuteSet(aout_stream_t *stream, bool mute)
         msg_Warn(stream, "failed to mute via DynamicsProcessing");
 }
 
-static int OpenAAudioStream(aout_stream_t *stream, audio_sample_format_t *fmt)
-{
-    struct sys *sys = stream->sys;
-    aaudio_result_t result;
-
-    AAudioStreamBuilder *builder;
-    result = vt.AAudio_createStreamBuilder(&builder);
-    if (result != AAUDIO_OK)
-    {
-        LogAAudioError(stream, "Failed to create AAudio stream builder", result);
-        return VLC_EGENERIC;
-    }
-
-    aaudio_format_t format;
-    if (fmt->i_format == VLC_CODEC_S16N)
-        format = AAUDIO_FORMAT_PCM_I16;
-    else
-    {
-        if (fmt->i_format != VLC_CODEC_FL32)
-        {
-            /* override to request conversion */
-            fmt->i_format = VLC_CODEC_FL32;
-            fmt->i_bytes_per_frame = 4 * fmt->i_channels;
-        }
-        format = AAUDIO_FORMAT_PCM_FLOAT;
-    }
-
-    vt.AAudioStreamBuilder_setFormat(builder, format);
-    vt.AAudioStreamBuilder_setChannelCount(builder, fmt->i_channels);
-
-    /* Setup the session-id */
-    int32_t session_id = var_InheritInteger(stream, "audiotrack-session-id");
-    if (session_id == 0)
-        session_id = AAUDIO_SESSION_ID_ALLOCATE;
-    vt.AAudioStreamBuilder_setSessionId(builder, session_id);
-
-    /* Setup the role */
-    char *vlc_role = var_InheritString(stream, "role");
-    if (vlc_role != NULL)
-    {
-        aaudio_usage_t usage = GetUsageFromVLCRole(vlc_role);
-        vt.AAudioStreamBuilder_setUsage(builder, usage);
-        free(vlc_role);
-    } /* else if not set, default is MEDIA usage */
-
-    bool low_latency = false;
-    if (fmt->channel_type == AUDIO_CHANNEL_TYPE_AMBISONICS)
-    {
-        fmt->channel_type = AUDIO_CHANNEL_TYPE_BITMAP;
-        low_latency = true;
-    }
-
-    vt.AAudioStreamBuilder_setDataCallback(builder, DataCallback, stream);
-    vt.AAudioStreamBuilder_setErrorCallback(builder, ErrorCallback, stream);
-
-    if (low_latency)
-        vt.AAudioStreamBuilder_setPerformanceMode(builder,
-            AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
-
-    AAudioStream *as;
-    result = vt.AAudioStreamBuilder_openStream(builder, &as);
-    if (result != AAUDIO_OK)
-    {
-        LogAAudioError(stream, "Failed to open AAudio stream", result);
-        vt.AAudioStreamBuilder_delete(builder);
-        return VLC_EGENERIC;
-    }
-    vt.AAudioStreamBuilder_delete(builder);
-
-    /* Use the native sample rate of the device */
-    fmt->i_rate = vt.AAudioStream_getSampleRate(as);
-    assert(fmt->i_rate > 0);
-
-    sys->as = as;
-    sys->fmt = *fmt;
-
-    return VLC_SUCCESS;
-}
-
 static void
 Stop(aout_stream_t *stream)
 {
     struct sys *sys = stream->sys;
 
-    RequestStop(stream);
-
-    if (WaitState(stream, AAUDIO_STREAM_STATE_STOPPED) == VLC_SUCCESS)
-        vt.AAudioStream_close(sys->as);
-    else
-        msg_Warn(stream, "Error waiting for stopped state");
+    if (sys->as != NULL)
+        CloseAAudioStream(stream);
 
     if (sys->dp != NULL)
         DynamicsProcessing_Delete(stream, sys->dp);
@@ -786,7 +824,6 @@ Start(aout_stream_t *stream, audio_sample_format_t *fmt,
 
     sys->volume = 1.0f;
     sys->muted = false;
-    sys->frames_flush_pos = 0;
     sys->error = false;
 
     vlc_mutex_init(&sys->lock);
@@ -801,23 +838,31 @@ Start(aout_stream_t *stream, audio_sample_format_t *fmt,
     sys->timing_report_last_written_bytes = 0;
     sys->timing_report_delay_bytes = 0;
 
-    int ret = OpenAAudioStream(stream, fmt);
+    PrepareAudioFormat(stream, fmt);
+
+    int ret = OpenAAudioStream(stream);
     if (ret != VLC_SUCCESS)
     {
         free(sys);
         return ret;
     }
 
-    int32_t session_id = vt.AAudioStream_getSessionId(sys->as);
+    /* Use the native sample rate of the device */
+    sys->fmt.i_rate = fmt->i_rate = vt.AAudioStream_getSampleRate(sys->as);
+    assert(fmt->i_rate > 0);
 
-    if (session_id != AAUDIO_SESSION_ID_NONE)
-        sys->dp = DynamicsProcessing_New(stream, session_id);
+    sys->cfg.session_id = vt.AAudioStream_getSessionId(sys->as);
+
+    if (sys->cfg.session_id != AAUDIO_SESSION_ID_NONE)
+        sys->dp = DynamicsProcessing_New(stream, sys->cfg.session_id);
     else
         sys->dp = NULL;
 
     if (sys->dp == NULL)
         msg_Warn(stream, "failed to attach DynamicsProcessing to the stream)");
 
+    sys->cfg.device_id = vt.AAudioStream_getDeviceId(sys->as);
+
     stream->stop = Stop;
     stream->play = Play;
     stream->pause = Pause;



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/371e18c1703c4e201ef9b586d8c1df31bd9b92bb...4c3538533e33379f216fbecb5accbd99893ef8b8

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/371e18c1703c4e201ef9b586d8c1df31bd9b92bb...4c3538533e33379f216fbecb5accbd99893ef8b8
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list