[vlc-commits] audiotrack: test if encodings are supported

Thomas Guillem git at videolan.org
Wed Mar 8 15:03:17 CET 2017


vlc | branch: master | Thomas Guillem <thomas at gllm.fr> | Tue Mar  7 13:08:18 2017 +0100| [43c0350263eebcc3713533e2424e164def2ac20c] | committer: Thomas Guillem

audiotrack: test if encodings are supported

There is no way to know if a device supports a specific codec using the
ENCODING_IEC61937 audio format.

There is an API for that, starting Android 21. But unfortunately, you need a
Context and to implement an interface. This is not possible via JNI (except if
we depend on a proxy Java class).

Therefore, we let the Android LibVLC listening to audio devices events and
report new supported encodings via libvlc_audio_output_device_set().

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=43c0350263eebcc3713533e2424e164def2ac20c
---

 modules/audio_output/audiotrack.c | 103 +++++++++++++++++++++++++++++---------
 1 file changed, 80 insertions(+), 23 deletions(-)

diff --git a/modules/audio_output/audiotrack.c b/modules/audio_output/audiotrack.c
index f823adc..b7ba093 100644
--- a/modules/audio_output/audiotrack.c
+++ b/modules/audio_output/audiotrack.c
@@ -68,6 +68,13 @@ static const struct {
 } at_devs[] = {
     { "stereo", "Up to 2 channels (compat mode).", AT_DEV_STEREO },
     { "pcm", "Up to 8 channels.", AT_DEV_PCM },
+
+    /* With "encoded", the module will try to play every audio codecs via
+     * passthrough.
+     *
+     * With "encoded:ENCODING_FLAGS_MASK", the module will try to play only
+     * codecs specified by ENCODING_FLAGS_MASK. This extra value is a long long
+     * that contains binary-shifted AudioFormat.ENCODING_* values. */
     { "encoded", "Up to 8 channels, passthrough if available.", AT_DEV_ENCODED },
     {  NULL, NULL, AT_DEV_DEFAULT },
 };
@@ -116,6 +123,7 @@ struct aout_sys_t {
     } smoothpos;
 
     uint32_t i_max_audiotrack_samples;
+    long long i_encoding_flags;
     bool b_passthrough;
     uint8_t i_chans_to_reorder; /* do we need channel reordering */
     uint8_t p_chan_table[AOUT_CHAN_MAX];
@@ -218,11 +226,13 @@ static struct
         jint ENCODING_PCM_FLOAT;
         bool has_ENCODING_PCM_FLOAT;
         jint ENCODING_AC3;
-        jint ENCODING_E_AC3;
         bool has_ENCODING_AC3;
+        jint ENCODING_E_AC3;
+        bool has_ENCODING_E_AC3;
         jint ENCODING_DTS;
-        jint ENCODING_DTS_HD;
         bool has_ENCODING_DTS;
+        jint ENCODING_DTS_HD;
+        bool has_ENCODING_DTS_HD;
         jint ENCODING_IEC61937;
         bool has_ENCODING_IEC61937;
         jint CHANNEL_OUT_MONO;
@@ -394,24 +404,16 @@ InitJNIFields( audio_output_t *p_aout, JNIEnv* env )
     }
     else
         jfields.AudioFormat.has_ENCODING_IEC61937 = false;
-    if( !jfields.AudioFormat.has_ENCODING_IEC61937 )
-    {
-        GET_CONST_INT( AudioFormat.ENCODING_AC3, "ENCODING_AC3", false );
-        if( field != NULL )
-        {
-            GET_CONST_INT( AudioFormat.ENCODING_E_AC3, "ENCODING_E_AC3", false );
-            jfields.AudioFormat.has_ENCODING_AC3 = field != NULL;
-        } else
-            jfields.AudioFormat.has_ENCODING_AC3 = false;
-        GET_CONST_INT( AudioFormat.ENCODING_DTS, "ENCODING_DTS", false );
-        if ( field != NULL )
-        {
-            GET_CONST_INT( AudioFormat.ENCODING_DTS_HD, "ENCODING_DTS_HD", false );
-            jfields.AudioFormat.has_ENCODING_DTS = field != NULL;
-        }
-        else
-            jfields.AudioFormat.has_ENCODING_DTS = false;
-    }
+
+    GET_CONST_INT( AudioFormat.ENCODING_AC3, "ENCODING_AC3", false );
+    jfields.AudioFormat.has_ENCODING_AC3 = field != NULL;
+    GET_CONST_INT( AudioFormat.ENCODING_E_AC3, "ENCODING_E_AC3", false );
+    jfields.AudioFormat.has_ENCODING_E_AC3 = field != NULL;
+
+    GET_CONST_INT( AudioFormat.ENCODING_DTS, "ENCODING_DTS", false );
+    jfields.AudioFormat.has_ENCODING_DTS = field != NULL;
+    GET_CONST_INT( AudioFormat.ENCODING_DTS_HD, "ENCODING_DTS_HD", false );
+    jfields.AudioFormat.has_ENCODING_DTS_HD = field != NULL;
 
     GET_CONST_INT( AudioFormat.CHANNEL_OUT_MONO, "CHANNEL_OUT_MONO", true );
     GET_CONST_INT( AudioFormat.CHANNEL_OUT_STEREO, "CHANNEL_OUT_STEREO", true );
@@ -907,6 +909,34 @@ AudioTrack_Create( JNIEnv *env, audio_output_t *p_aout,
     return 0;
 }
 
+static bool
+AudioTrack_HasEncoding( audio_output_t *p_aout, vlc_fourcc_t i_format,
+                        bool *p_dtshd )
+{
+    aout_sys_t *p_sys = p_aout->sys;
+
+#define MATCH_ENCODING_FLAG(x) jfields.AudioFormat.has_##x && \
+    ( p_sys->i_encoding_flags == 0 || p_sys->i_encoding_flags & (1 << jfields.AudioFormat.x) )
+
+    *p_dtshd = false;
+    switch( i_format )
+    {
+        case VLC_CODEC_DTS:
+            if( MATCH_ENCODING_FLAG( ENCODING_DTS_HD ) )
+            {
+                *p_dtshd = true;
+                return true;
+            }
+            return MATCH_ENCODING_FLAG( ENCODING_DTS );
+        case VLC_CODEC_A52:
+            return MATCH_ENCODING_FLAG( ENCODING_AC3 );
+        case VLC_CODEC_EAC3:
+            return MATCH_ENCODING_FLAG( ENCODING_E_AC3 );
+        default:
+            return false;
+    }
+}
+
 static int
 StartPassthrough( JNIEnv *env, audio_output_t *p_aout )
 {
@@ -915,6 +945,9 @@ StartPassthrough( JNIEnv *env, audio_output_t *p_aout )
 
     if( jfields.AudioFormat.has_ENCODING_IEC61937 )
     {
+        bool b_dtshd;
+        if( !AudioTrack_HasEncoding( p_aout, p_sys->fmt.i_format, &b_dtshd ) )
+            return VLC_EGENERIC;
         i_at_format = jfields.AudioFormat.ENCODING_IEC61937;
         switch( p_sys->fmt.i_format )
         {
@@ -1831,7 +1864,7 @@ static int DeviceSelect(audio_output_t *p_aout, const char *p_id)
     {
         for( unsigned int i = 0; at_devs[i].id; ++i )
         {
-            if( !strcmp( p_id, at_devs[i].id ) )
+            if( strncmp( p_id, at_devs[i].id, strlen( at_devs[i].id ) ) == 0 )
             {
                 at_dev = at_devs[i].at_dev;
                 break;
@@ -1839,11 +1872,35 @@ static int DeviceSelect(audio_output_t *p_aout, const char *p_id)
         }
     }
 
-    if( at_dev != p_sys->at_dev )
+    long long i_encoding_flags = 0;
+    if( at_dev == AT_DEV_ENCODED )
+    {
+        const size_t i_prefix_size = strlen( "encoded:" );
+        if( strncmp( p_id, "encoded:", i_prefix_size ) == 0 )
+            i_encoding_flags = atoll( p_id + i_prefix_size );
+    }
+
+    if( at_dev != p_sys->at_dev || i_encoding_flags != p_sys->i_encoding_flags )
     {
         p_sys->at_dev = at_dev;
+        p_sys->i_encoding_flags = i_encoding_flags;
         aout_RestartRequest( p_aout, AOUT_RESTART_OUTPUT );
-        msg_Dbg(p_aout, "selected audiotrack device: %s", p_id);
+        msg_Dbg( p_aout, "selected device: %s", p_id );
+
+        if( at_dev == AT_DEV_ENCODED )
+        {
+            static const vlc_fourcc_t enc_fourccs[] = {
+                VLC_CODEC_DTS, VLC_CODEC_A52, VLC_CODEC_EAC3
+            };
+            for( size_t i = 0;
+                 i < sizeof( enc_fourccs ) / sizeof( enc_fourccs[0] ); ++i )
+            {
+                bool b_dtshd;
+                if( AudioTrack_HasEncoding( p_aout, enc_fourccs[i], &b_dtshd ) )
+                    msg_Dbg( p_aout, "device has %4.4s passthrough support",
+                             b_dtshd ? "dtsh" : (const char *)&enc_fourccs[i] );
+            }
+        }
     }
     aout_DeviceReport( p_aout, p_id );
     return VLC_SUCCESS;



More information about the vlc-commits mailing list