[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