[vlc-commits] [Git][videolan/vlc][master] 3 commits: audiotrack: remove WRITE_BYTEBUFFER method

Steve Lhomme (@robUx4) gitlab at videolan.org
Fri Sep 29 10:29:18 UTC 2023



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
ccd3eaae by Thomas Guillem at 2023-09-29T10:02:18+00:00
audiotrack: remove WRITE_BYTEBUFFER method

It was only used with Android API 21 and 22 (Android 5.x).
Remove this code that behave differently than all other write methods
and that is not as tested as the others.

- - - - -
17e4aee3 by Thomas Guillem at 2023-09-29T10:02:18+00:00
audiotrack: fix invalid join in case of clone error

- - - - -
a235b9dd by Thomas Guillem at 2023-09-29T10:02:18+00:00
audiotrack: use a fixed size for the jarray

Don't try to copy the whole frame to the jarray buffer but copy it chunk
by chunk (50ms max). Therefore, a same frame can now be used for more
than one java write.

This fixes the following error and abort when allocating a too big
jarray (likely when sending a lot of silence to catch up with a playback
way to early).

E VLC   : [9b14b710/138c] libvlc generic: jarray allocation failed
E VLC   : [9b14b710/138c] libvlc generic: Write failed: ERROR
F DEBUG : Abort message: 'art/runtime/java_vm_ext.cc:470] JNI DETECTED ERROR IN APPLICATION: JNI GetJavaVM called with pending exception java.lang.OutOfMemoryError: Failed to allocate a 99591132 byte allocation with 3792244 free bytes and 90MB until OOM'

- - - - -


1 changed file:

- modules/audio_output/android/audiotrack.c


Changes:

=====================================
modules/audio_output/android/audiotrack.c
=====================================
@@ -47,6 +47,8 @@
 
 #define TIMING_REPORT_DELAY_TICKS VLC_TICK_FROM_MS(1000)
 
+#define JARRAY_SIZE_US VLC_TICK_FROM_MS(50)
+
 typedef struct
 {
     jobject p_audiotrack; /* AudioTrack ref */
@@ -87,7 +89,6 @@ typedef struct
         WRITE_BYTEARRAY,
         WRITE_BYTEARRAYV23,
         WRITE_SHORTARRAYV23,
-        WRITE_BYTEBUFFER,
         WRITE_FLOATARRAY
     } i_write_type;
 
@@ -904,11 +905,18 @@ AudioTrack_Create( JNIEnv *env, aout_stream_t *stream,
 }
 
 static void
-AudioTrack_ConsumeFrame(aout_stream_t *stream, vlc_frame_t *f)
+AudioTrack_ConsumeFrame(aout_stream_t *stream, vlc_frame_t *f, size_t size)
 {
     aout_sys_t *p_sys = stream->sys;
     assert(f != NULL && f == p_sys->frame_chain);
 
+    f->i_buffer -= size;
+    if (f->i_buffer > 0)
+    {
+        f->p_buffer += size;
+        return;
+    }
+
     p_sys->frame_chain = f->p_next;
     if (p_sys->frame_chain == NULL)
         p_sys->frame_last = &p_sys->frame_chain;
@@ -917,28 +925,24 @@ AudioTrack_ConsumeFrame(aout_stream_t *stream, vlc_frame_t *f)
 }
 
 static int
-AudioTrack_AllocJArray(JNIEnv *env, aout_stream_t *stream, size_t size,
+AudioTrack_AllocJArray(JNIEnv *env, aout_stream_t *stream, unsigned sample_size,
                        jarray (*new)(JNIEnv *env, jsize size))
 {
     aout_sys_t *p_sys = stream->sys;
 
-    if (size > p_sys->jbuffer.maxsize)
-    {
-        p_sys->jbuffer.maxsize = 0;
-        if (p_sys->jbuffer.array != NULL)
-            (*env)->DeleteLocalRef(env, p_sys->jbuffer.array);
+    size_t size = US_TO_BYTES(JARRAY_SIZE_US) / sample_size;
 
-        p_sys->jbuffer.array = new(env, size);
-        if (p_sys->jbuffer.array != NULL)
-            p_sys->jbuffer.maxsize = size;
-        else
-            msg_Err(stream, "jarray allocation failed");
-    }
+    jobject array = new(env, size);
+    if (array == NULL)
+        return jfields.AudioTrack.ERROR;
 
+    p_sys->jbuffer.array = (*env)->NewGlobalRef(env, array);
+    (*env)->DeleteLocalRef(env, array);
     if (p_sys->jbuffer.array == NULL)
         return jfields.AudioTrack.ERROR;
 
-    p_sys->jbuffer.size = size;
+    p_sys->jbuffer.maxsize = size;
+    p_sys->jbuffer.size = 0;
     p_sys->jbuffer.offset = 0;
 
     return 0;
@@ -956,21 +960,23 @@ AudioTrack_WriteByteArray( JNIEnv *env, aout_stream_t *stream, bool b_force )
     uint64_t i_samples;
     uint64_t i_audiotrack_pos;
     uint64_t i_samples_pending;
-
     int ret;
-    if (p_sys->jbuffer.offset == p_sys->jbuffer.size)
+
+    if (p_sys->jbuffer.size == 0)
     {
         vlc_frame_t *f = p_sys->frame_chain;
         assert(f != NULL);
-        ret = AudioTrack_AllocJArray(env, stream, f->i_buffer,
-                                     (*env)->NewByteArray);
-        if (ret != 0)
-            return ret;
-
-        (*env)->SetByteArrayRegion(env, p_sys->jbuffer.array,
-                                   0, f->i_buffer, (jbyte *)f->p_buffer);
-        AudioTrack_ConsumeFrame(stream, f);
+
+        size_t size = f->i_buffer > p_sys->jbuffer.maxsize ?
+                      p_sys->jbuffer.maxsize : f->i_buffer;
+        p_sys->jbuffer.size = size;
+        p_sys->jbuffer.offset = 0;
+        (*env)->SetByteArrayRegion(env, p_sys->jbuffer.array, 0,
+                                   size, (jbyte *)f->p_buffer);
+        AudioTrack_ConsumeFrame(stream, f, size);
     }
+    assert(p_sys->jbuffer.size > 0);
+    assert(p_sys->jbuffer.size > p_sys->jbuffer.offset);
 
     i_audiotrack_pos = AudioTrack_getPlaybackHeadPosition( env, stream );
 
@@ -998,7 +1004,11 @@ AudioTrack_WriteByteArray( JNIEnv *env, aout_stream_t *stream, bool b_force )
     ret = JNI_AT_CALL_INT( write, p_sys->jbuffer.array, p_sys->jbuffer.offset,
                            FRAMES_TO_BYTES( i_samples ) );
     if (ret > 0)
+    {
         p_sys->jbuffer.offset += ret;
+        if (p_sys->jbuffer.offset == p_sys->jbuffer.size)
+            p_sys->jbuffer.size = 0;
+    }
 
     return ret;
 }
@@ -1012,73 +1022,33 @@ static int
 AudioTrack_WriteByteArrayV23(JNIEnv *env, aout_stream_t *stream)
 {
     aout_sys_t *p_sys = stream->sys;
-
     int ret;
-    if (p_sys->jbuffer.offset == p_sys->jbuffer.size)
+
+    if (p_sys->jbuffer.size == 0)
     {
         vlc_frame_t *f = p_sys->frame_chain;
         assert(f != NULL);
-        ret = AudioTrack_AllocJArray(env, stream, f->i_buffer,
-                                     (*env)->NewByteArray);
-        if (ret != 0)
-            return ret;
-
-        (*env)->SetByteArrayRegion(env, p_sys->jbuffer.array,
-                                   0, f->i_buffer, (jbyte *)f->p_buffer);
-        AudioTrack_ConsumeFrame(stream, f);
+
+        size_t size = f->i_buffer > p_sys->jbuffer.maxsize ?
+                      p_sys->jbuffer.maxsize : f->i_buffer;
+        p_sys->jbuffer.size = size;
+        p_sys->jbuffer.offset = 0;
+        (*env)->SetByteArrayRegion(env, p_sys->jbuffer.array, 0,
+                                   size, (jbyte *)f->p_buffer);
+        AudioTrack_ConsumeFrame(stream, f, size);
     }
+    assert(p_sys->jbuffer.size > 0);
+    assert(p_sys->jbuffer.size > p_sys->jbuffer.offset);
 
     ret = JNI_AT_CALL_INT( writeV23, p_sys->jbuffer.array,
                            p_sys->jbuffer.offset,
                            p_sys->jbuffer.size - p_sys->jbuffer.offset,
                            jfields.AudioTrack.WRITE_NON_BLOCKING );
-    if (ret > 0)
-        p_sys->jbuffer.offset += ret;
-
-    return ret;
-}
-
-/**
- * Non blocking play function for Lollipop and after, run from
- * AudioTrack_Thread. It calls a new write method with WRITE_NON_BLOCKING
- * flags.
- */
-static int
-AudioTrack_WriteByteBuffer(JNIEnv *env, aout_stream_t *stream)
-{
-    aout_sys_t *p_sys = stream->sys;
-
-    if (p_sys->jbuffer.offset == p_sys->jbuffer.size)
-    {
-        vlc_frame_t *f = p_sys->frame_chain;
-        assert(f != NULL);
-        if (p_sys->jbuffer.array != NULL)
-            (*env)->DeleteLocalRef(env, p_sys->jbuffer.array);
-        p_sys->jbuffer.array = (*env)->NewDirectByteBuffer(env,
-                                                           f->p_buffer,
-                                                           f->i_buffer);
-        if (p_sys->jbuffer.array == NULL)
-        {
-            if ((*env)->ExceptionCheck(env))
-                (*env)->ExceptionClear(env);
-            return jfields.AudioTrack.ERROR;
-        }
-        p_sys->jbuffer.offset = 0;
-        p_sys->jbuffer.size = f->i_buffer;
-        /* Don't take account of the current frame for the delay */
-        f->i_buffer = 0;
-    }
-
-    int ret = JNI_AT_CALL_INT(writeBufferV21, p_sys->jbuffer.array,
-                              p_sys->jbuffer.size - p_sys->jbuffer.offset,
-                              jfields.AudioTrack.WRITE_NON_BLOCKING);
     if (ret > 0)
     {
         p_sys->jbuffer.offset += ret;
-        /* The ByteBuffer reference directly the data from the frame, so it
-         * should stay allocated until all the data is written */
         if (p_sys->jbuffer.offset == p_sys->jbuffer.size)
-            AudioTrack_ConsumeFrame(stream, p_sys->frame_chain);
+            p_sys->jbuffer.size = 0;
     }
 
     return ret;
@@ -1093,21 +1063,24 @@ static int
 AudioTrack_WriteShortArrayV23(JNIEnv *env, aout_stream_t *stream)
 {
     aout_sys_t *p_sys = stream->sys;
-
     int ret;
-    if (p_sys->jbuffer.offset == p_sys->jbuffer.size)
+
+    if (p_sys->jbuffer.size == 0)
     {
         vlc_frame_t *f = p_sys->frame_chain;
         assert(f != NULL);
-        ret = AudioTrack_AllocJArray(env, stream, f->i_buffer / 2,
-                                     (*env)->NewShortArray);
-        if (ret != 0)
-            return ret;
-
-        (*env)->SetShortArrayRegion(env, p_sys->jbuffer.array,
-                                    0, f->i_buffer / 2, (jshort *)f->p_buffer);
-        AudioTrack_ConsumeFrame(stream, f);
+
+        size_t buffer_size_short = f->i_buffer / 2;
+        size_t size = buffer_size_short > p_sys->jbuffer.maxsize ?
+                      p_sys->jbuffer.maxsize : buffer_size_short;
+        p_sys->jbuffer.size = size;
+        p_sys->jbuffer.offset = 0;
+        (*env)->SetShortArrayRegion(env, p_sys->jbuffer.array, 0,
+                                    size, (jshort *)f->p_buffer);
+        AudioTrack_ConsumeFrame(stream, f, size * 2);
     }
+    assert(p_sys->jbuffer.size > 0);
+    assert(p_sys->jbuffer.size > p_sys->jbuffer.offset);
 
     ret = JNI_AT_CALL_INT( writeShortV23, p_sys->jbuffer.array,
                            p_sys->jbuffer.offset,
@@ -1116,6 +1089,8 @@ AudioTrack_WriteShortArrayV23(JNIEnv *env, aout_stream_t *stream)
     if (ret > 0)
     {
         p_sys->jbuffer.offset += ret;
+        if (p_sys->jbuffer.offset == p_sys->jbuffer.size)
+            p_sys->jbuffer.size = 0;
         ret *= 2;
     }
 
@@ -1133,28 +1108,32 @@ AudioTrack_WriteFloatArray(JNIEnv *env, aout_stream_t *stream)
     aout_sys_t *p_sys = stream->sys;
     int ret;
 
-    if (p_sys->jbuffer.offset == p_sys->jbuffer.size)
+    if (p_sys->jbuffer.size == 0)
     {
         vlc_frame_t *f = p_sys->frame_chain;
         assert(f != NULL);
-        ret = AudioTrack_AllocJArray(env, stream, f->i_buffer / 4,
-                                     (*env)->NewFloatArray);
-        if (ret != 0)
-            return ret;
-
-        (*env)->SetFloatArrayRegion(env, p_sys->jbuffer.array,
-                                   0, f->i_buffer / 4, (jfloat *)f->p_buffer);
-        AudioTrack_ConsumeFrame(stream, f);
+
+        size_t buffer_size_float = f->i_buffer / 4;
+        size_t size = buffer_size_float > p_sys->jbuffer.maxsize ?
+                      p_sys->jbuffer.maxsize : buffer_size_float;
+        p_sys->jbuffer.size = size;
+        p_sys->jbuffer.offset = 0;
+        (*env)->SetFloatArrayRegion(env, p_sys->jbuffer.array, 0,
+                                    size, (jfloat *)f->p_buffer);
+        AudioTrack_ConsumeFrame(stream, f, size * 4);
     }
+    assert(p_sys->jbuffer.size > 0);
+    assert(p_sys->jbuffer.size > p_sys->jbuffer.offset);
 
     ret = JNI_AT_CALL_INT(writeFloat, p_sys->jbuffer.array,
                           p_sys->jbuffer.offset,
                           p_sys->jbuffer.size - p_sys->jbuffer.offset,
                           jfields.AudioTrack.WRITE_NON_BLOCKING);
-
     if (ret > 0)
     {
         p_sys->jbuffer.offset += ret;
+        if (p_sys->jbuffer.offset == p_sys->jbuffer.size)
+            p_sys->jbuffer.size = 0;
         ret *= 4;
     }
 
@@ -1172,9 +1151,6 @@ AudioTrack_Write( JNIEnv *env, aout_stream_t *stream, bool b_force )
     case WRITE_BYTEARRAYV23:
         i_ret = AudioTrack_WriteByteArrayV23(env, stream);
         break;
-    case WRITE_BYTEBUFFER:
-        i_ret = AudioTrack_WriteByteBuffer(env, stream);
-        break;
     case WRITE_SHORTARRAYV23:
         i_ret = AudioTrack_WriteShortArrayV23(env, stream);
         break;
@@ -1291,7 +1267,7 @@ AudioTrack_Thread( void *p_data )
 
         /* Wait for more data in the jbuffer buffer */
         while (p_sys->b_thread_running
-            && p_sys->jbuffer.offset == p_sys->jbuffer.size
+            && p_sys->jbuffer.size == 0
             && p_sys->frame_chain == NULL)
             vlc_cond_wait( &p_sys->thread_cond, &p_sys->lock );
 
@@ -1357,12 +1333,6 @@ AudioTrack_Thread( void *p_data )
         vlc_mutex_unlock( &p_sys->lock );
     }
 
-    if (p_sys->jbuffer.array != NULL)
-    {
-        (*env)->DeleteLocalRef(env, p_sys->jbuffer.array);
-        p_sys->jbuffer.array = NULL;
-    }
-
     return NULL;
 }
 
@@ -1815,6 +1785,9 @@ Stop( aout_stream_t *stream )
     else
         vlc_mutex_unlock(  &p_sys->lock );
 
+    if (p_sys->jbuffer.array != NULL)
+        (*env)->DeleteGlobalRef(env, p_sys->jbuffer.array);
+
     /* Release the AudioTrack object */
     if( p_sys->p_audiotrack )
     {
@@ -1869,6 +1842,7 @@ Start( aout_stream_t *stream, audio_sample_format_t *restrict p_fmt,
 
     vlc_mutex_init(&p_sys->lock);
     vlc_cond_init(&p_sys->thread_cond);
+    p_sys->jbuffer.array = NULL;
 
     p_sys->volume = 1.0f;
     p_sys->mute = false;
@@ -1918,9 +1892,6 @@ Start( aout_stream_t *stream, audio_sample_format_t *restrict p_fmt,
             goto error;
     }
 
-    p_sys->jbuffer.array = NULL;
-    p_sys->jbuffer.size = p_sys->jbuffer.offset = 0;
-    p_sys->jbuffer.maxsize = 0;
     p_sys->frame_chain = NULL;
     p_sys->frame_last = &p_sys->frame_chain;
     AudioTrack_Reset( env, stream );
@@ -1929,27 +1900,32 @@ Start( aout_stream_t *stream, audio_sample_format_t *restrict p_fmt,
     {
         msg_Dbg( stream, "using WRITE_FLOATARRAY");
         p_sys->i_write_type = WRITE_FLOATARRAY;
+        i_ret = AudioTrack_AllocJArray(env, stream, 4, (*env)->NewFloatArray);
     }
     else if( p_sys->fmt.i_format == VLC_CODEC_SPDIFL )
     {
         assert( jfields.AudioFormat.has_ENCODING_IEC61937 );
         msg_Dbg( stream, "using WRITE_SHORTARRAYV23");
         p_sys->i_write_type = WRITE_SHORTARRAYV23;
+        i_ret = AudioTrack_AllocJArray(env, stream, 2, (*env)->NewShortArray);
     }
     else if( jfields.AudioTrack.writeV23 )
     {
         msg_Dbg( stream, "using WRITE_BYTEARRAYV23");
         p_sys->i_write_type = WRITE_BYTEARRAYV23;
-    }
-    else if( jfields.AudioTrack.writeBufferV21 )
-    {
-        msg_Dbg( stream, "using WRITE_BYTEBUFFER");
-        p_sys->i_write_type = WRITE_BYTEBUFFER;
+        i_ret = AudioTrack_AllocJArray(env, stream, 1, (*env)->NewByteArray);
     }
     else
     {
         msg_Dbg( stream, "using WRITE_BYTEARRAY");
         p_sys->i_write_type = WRITE_BYTEARRAY;
+        i_ret = AudioTrack_AllocJArray(env, stream, 1, (*env)->NewByteArray);
+    }
+
+    if (i_ret != 0)
+    {
+        msg_Err(stream, "jbuffer allocation failed");
+        goto error;
     }
 
     /* Run AudioTrack_Thread */
@@ -1957,6 +1933,7 @@ Start( aout_stream_t *stream, audio_sample_format_t *restrict p_fmt,
     p_sys->b_thread_paused = false;
     if ( vlc_clone( &p_sys->thread, AudioTrack_Thread, stream ) )
     {
+        p_sys->b_thread_running = false;
         msg_Err(stream, "vlc clone failed");
         goto error;
     }



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/cc8e12bea60715b7c70b1b9865a2815c4a83528c...a235b9dd1b591c89eb555a9de82534227fa0d3a1

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/cc8e12bea60715b7c70b1b9865a2815c4a83528c...a235b9dd1b591c89eb555a9de82534227fa0d3a1
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