[vlc-devel] [PATCH 4/4] audiotrack: use DynamicsProcessing to increase the gain

Thomas Guillem thomas at gllm.fr
Tue Dec 1 17:58:37 CET 2020


This fixes a delay of up to 2 seconds when increasing the volume up to
100%.
---
 modules/audio_output/audiotrack.c | 69 +++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/modules/audio_output/audiotrack.c b/modules/audio_output/audiotrack.c
index e79ba17cb8f..a1b9aee602c 100644
--- a/modules/audio_output/audiotrack.c
+++ b/modules/audio_output/audiotrack.c
@@ -86,6 +86,7 @@ typedef struct
     enum at_dev at_dev;
 
     jobject p_audiotrack; /* AudioTrack ref */
+    jobject p_dp;
     float volume;
     bool mute;
 
@@ -213,6 +214,7 @@ static struct
         jmethodID writeShortV23;
         jmethodID writeBufferV21;
         jmethodID writeFloat;
+        jmethodID getAudioSessionId;
         jmethodID getBufferSizeInFrames;
         jmethodID getLatency;
         jmethodID getPlaybackHeadPosition;
@@ -284,6 +286,12 @@ static struct
         jfieldID framePosition;
         jfieldID nanoTime;
     } AudioTimestamp;
+    struct {
+        jclass clazz;
+        jmethodID ctor;
+        jmethodID setInputGainAllChannelsTo;
+        jmethodID setEnabled;
+    } DynamicsProcessing;
 } jfields;
 
 /* init all jni fields.
@@ -364,6 +372,9 @@ InitJNIFields( audio_output_t *p_aout, JNIEnv* env )
     } else
         GET_ID( GetMethodID, AudioTrack.write, "write", "([BII)I", true );
 
+    GET_ID( GetMethodID, AudioTrack.getAudioSessionId,
+            "getAudioSessionId", "()I", true );
+
     GET_ID( GetMethodID, AudioTrack.getBufferSizeInFrames,
             "getBufferSizeInFrames", "()I", false );
 
@@ -497,6 +508,18 @@ InitJNIFields( audio_output_t *p_aout, JNIEnv* env )
     jfields.AudioManager.has_ERROR_DEAD_OBJECT = field != NULL;
     GET_CONST_INT( AudioManager.STREAM_MUSIC, "STREAM_MUSIC", true );
 
+    GET_CLASS( "android/media/audiofx/DynamicsProcessing", false );
+    if( clazz )
+    {
+        jfields.DynamicsProcessing.clazz = (jclass) (*env)->NewGlobalRef( env, clazz );
+        CHECK_EXCEPTION( "NewGlobalRef", true );
+        GET_ID( GetMethodID, DynamicsProcessing.ctor, "<init>", "(I)V", true );
+        GET_ID( GetMethodID, DynamicsProcessing.setInputGainAllChannelsTo,
+                "setInputGainAllChannelsTo", "(F)V", true );
+        GET_ID( GetMethodID, DynamicsProcessing.setEnabled,
+                "setEnabled", "(Z)I", true );
+    }
+
 #undef CHECK_EXCEPTION
 #undef GET_CLASS
 #undef GET_ID
@@ -1019,6 +1042,21 @@ AudioTrack_New( JNIEnv *env, audio_output_t *p_aout, unsigned int i_rate,
     if( !p_sys->p_audiotrack )
         return -1;
 
+    if (session_id == 0 )
+        session_id = JNI_AT_CALL_INT( getAudioSessionId );
+
+    if( session_id != 0 )
+    {
+        jobject dp = JNI_CALL( NewObject, jfields.DynamicsProcessing.clazz,
+                               jfields.DynamicsProcessing.ctor, session_id );
+
+        if( !CHECK_EXCEPTION( "DynamicsProcessing", "ctor" ) )
+        {
+            p_sys->p_dp = (*env)->NewGlobalRef( env, dp );
+            (*env)->DeleteLocalRef( env, dp );
+        }
+    }
+
     return 0;
 }
 
@@ -1572,6 +1610,12 @@ Stop( audio_output_t *p_aout )
         p_sys->p_audiotrack = NULL;
     }
 
+    if( p_sys->p_dp )
+    {
+        (*env)->DeleteGlobalRef( env, p_sys->p_dp );
+        p_sys->p_dp = NULL;
+    }
+
     /* Release the timestamp object */
     if( p_sys->timestamp.p_obj )
     {
@@ -2162,6 +2206,31 @@ VolumeSet( audio_output_t *p_aout, float volume )
     if( !p_sys->b_error && p_sys->p_audiotrack != NULL && ( env = GET_ENV() ) )
     {
         AudioTrack_SetVolume( env, p_aout, volume );
+
+        /* Apply gain > 1.0f via DynamicsProcessing if possible */
+        if( p_sys->p_dp != NULL )
+        {
+            if( gain <= 1.0f )
+            {
+                /* DynamicsProcessing is not needed anymore (using AudioTrack
+                 * volume) */
+                JNI_CALL_INT( p_sys->p_dp, jfields.DynamicsProcessing.setEnabled, false );
+                CHECK_EXCEPTION( "DynamicsProcessing", "setEnabled" );
+            }
+            else
+            {
+                /* convert linear gain to dB */
+                float dB = 20.0f * log10f(gain);
+
+                JNI_CALL_VOID( p_sys->p_dp, jfields.DynamicsProcessing.setInputGainAllChannelsTo, dB );
+                int ret = JNI_CALL_INT( p_sys->p_dp, jfields.DynamicsProcessing.setEnabled, true );
+
+                if( !CHECK_EXCEPTION( "DynamicsProcessing", "setEnabled" ) && ret == 0 )
+                    gain = 1.0; /* reset sw gain */
+                else
+                    msg_Warn( p_aout, "failed to set gain via DynamicsProcessing, fallback to sw gain");
+            }
+        }
     }
 
     aout_VolumeReport(p_aout, volume);
-- 
2.28.0



More information about the vlc-devel mailing list