[vlc-devel] [PATCH] Android: add native AudioTrack aout module

Rémi Denis-Courmont remi at remlab.net
Thu Oct 4 22:06:20 CEST 2012


Le jeudi 4 octobre 2012 22:18:29, Rafaël Carré a écrit :
> +static void *InitLibrary(struct aout_sys_t *p_sys)
> +{
> +    /* DL Open libmedia */
> +    void *p_library;
> +    p_library = dlopen("libmedia.so", RTLD_NOW);

Seems to be missing RTLD_LOCAL.

> +    if (!p_library)
> +        return NULL;
> +
> +    /* Register symbols */
> +    p_sys->as_getOutputFrameCount =
> (AudioSystem_getOutputFrameCount)(dlsym(p_library,
> "_ZN7android11AudioSystem19getOutputFrameCountEPii")); +   
> p_sys->as_getOutputLatency =
> (AudioSystem_getOutputLatency)(dlsym(p_library,
> "_ZN7android11AudioSystem16getOutputLatencyEPji")); +   
> if(p_sys->as_getOutputLatency == NULL) {
> +        /* 4.1 Jellybean prototype */
> +        p_sys->as_getOutputLatency =
> (AudioSystem_getOutputLatency)(dlsym(p_library,
> "_ZN7android11AudioSystem16getOutputLatencyEPj19audio_stream_type_t")); + 
>   }
> +    p_sys->as_getOutputSamplingRate =
> (AudioSystem_getOutputSamplingRate)(dlsym(p_library,
> "_ZN7android11AudioSystem21getOutputSamplingRateEPii")); +   
> p_sys->at_getMinFrameCount =
> (AudioTrack_getMinFrameCount)(dlsym(p_library,
> "_ZN7android10AudioTrack16getMinFrameCountEPiij")); +   
> if(p_sys->at_getMinFrameCount == NULL) {
> +        /* 4.1 Jellybean prototype */
> +        p_sys->at_getMinFrameCount =
> (AudioTrack_getMinFrameCount)(dlsym(p_library,
> "_ZN7android10AudioTrack16getMinFrameCountEPi19audio_stream_type_tj")); + 
>   }
> +    p_sys->at_ctor = (AudioTrack_ctor)(dlsym(p_library,
> "_ZN7android10AudioTrackC1EijiiijPFviPvS1_ES1_ii")); +   
> p_sys->at_ctor_legacy = (AudioTrack_ctor_legacy)(dlsym(p_library,
> "_ZN7android10AudioTrackC1EijiiijPFviPvS1_ES1_i")); +    p_sys->at_dtor =
> (AudioTrack_dtor)(dlsym(p_library, "_ZN7android10AudioTrackD1Ev")); +   
> p_sys->at_initCheck = (AudioTrack_initCheck)(dlsym(p_library,
> "_ZNK7android10AudioTrack9initCheckEv")); +    p_sys->at_start =
> (AudioTrack_start)(dlsym(p_library, "_ZN7android10AudioTrack5startEv")); +
>    p_sys->at_stop = (AudioTrack_stop)(dlsym(p_library,
> "_ZN7android10AudioTrack4stopEv")); +    p_sys->at_write =
> (AudioTrack_write)(dlsym(p_library,
> "_ZN7android10AudioTrack5writeEPKvj")); +    p_sys->at_flush =
> (AudioTrack_flush)(dlsym(p_library, "_ZN7android10AudioTrack5flushEv")); +
>    p_sys->at_pause = (AudioTrack_pause)(dlsym(p_library,
> "_ZN7android10AudioTrack5pauseEv")); +
> +    /* We need the first 3 or the last 1 */
> +    if (!((p_sys->as_getOutputFrameCount && p_sys->as_getOutputLatency &&
> p_sys->as_getOutputSamplingRate)
> +        || p_sys->at_getMinFrameCount))

Output latency is not really optional for VLC to work.

> {
> +        dlclose(p_library);
> +        return NULL;
> +    }
> +
> +    // We need all the other Symbols
> +    if (!((p_sys->at_ctor || p_sys->at_ctor_legacy) && p_sys->at_dtor &&
> p_sys->at_initCheck && +           p_sys->at_start && p_sys->at_stop &&
> p_sys->at_write && p_sys->at_flush)) { +        dlclose(p_library);
> +        return NULL;
> +    }
> +    return p_library;
> +}
> +
> +static int Open(vlc_object_t *p_this)
> +{
> +    struct aout_sys_t *p_sys;
> +    audio_output_t *p_aout = (audio_output_t*)(p_this);
> +
> +    int status, size;
> +    int afSampleRate, afFrameCount, afLatency, minBufCount, minFrameCount;
> +    int stream_type, channel, rate, format;
> +
> +    p_sys = (struct aout_sys_t*) malloc(sizeof(aout_sys_t));
> +    if (!p_sys)
> +        return VLC_ENOMEM;
> +
> +    p_sys->libmedia = InitLibrary(p_sys);
> +    if (!p_sys->libmedia) {
> +        msg_Err(p_aout, "Could not initialize libmedia.so!");
> +        free(p_sys);
> +        return VLC_EGENERIC;
> +    }
> +
> +    /* 4000 <= frequency <= 48000 */
> +    if (p_aout->format.i_rate < 4000)
> +        p_aout->format.i_rate = 4000;
> +    if (p_aout->format.i_rate > 48000)
> +        p_aout->format.i_rate = 48000;
> +    rate = p_aout->format.i_rate;

If you modify the format, you MUST return VLC_SUCCESS.

> +
> +    stream_type = MUSIC;
> +
> +    /* We can only accept U8 and S16L */
> +    if (p_aout->format.i_format != VLC_CODEC_U8 && p_aout->format.i_format
> != VLC_CODEC_S16L) +        p_aout->format.i_format = VLC_CODEC_S16L;
> +    format = (p_aout->format.i_format == VLC_CODEC_S16L) ? PCM_16_BIT :
> PCM_8_BIT; +
> +    /* TODO: android supports more channels */
> +    switch(aout_FormatNbChannels(&p_aout->format))
> +    {
> +    case 1:
> +        channel = CHANNEL_OUT_MONO;
> +        break;
> +    case 2:
> +        channel = CHANNEL_OUT_STEREO;

i_physical_channels should probably be forced to CENTER and STEREO 
respectively.

> +        break;
> +    default:
> +        channel = CHANNEL_OUT_STEREO;
> +        p_aout->format.i_physical_channels = AOUT_CHAN_LEFT |
> AOUT_CHAN_RIGHT;

AOUT_CHANS_STEREO

> +        break;
> +    }

i_original_channels, however confusing it is, should be set.

> +
> +    /* Get the minimum buffer value */
> +    if (!p_sys->at_getMinFrameCount) {
> +        status = p_sys->as_getOutputSamplingRate(&afSampleRate,
> stream_type); +        status ^=
> p_sys->as_getOutputFrameCount(&afFrameCount, stream_type); +        status
> ^= p_sys->as_getOutputLatency((uint32_t*)(&afLatency), stream_type); +    
>    if (status != 0) {
> +            msg_Err(p_aout, "Could not query the AudioStream parameters");
> +            dlclose(p_sys->libmedia);
> +            free(p_sys);
> +            return VLC_EGENERIC;
> +        }
> +        minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate);
> +        if (minBufCount < 2)
> +            minBufCount = 2;
> +        minFrameCount = (afFrameCount * rate * minBufCount) /
> afSampleRate; +    }
> +    else {
> +        status = p_sys->at_getMinFrameCount(&minFrameCount, stream_type,
> rate); +        if (status != 0) {
> +            msg_Err(p_aout, "Could not query the AudioTrack parameters");
> +            dlclose(p_sys->libmedia);
> +            free(p_sys);
> +            return VLC_EGENERIC;
> +        }
> +    }
> +
> +    size = minFrameCount * (channel == CHANNEL_OUT_STEREO ? 2 : 1) * 4;
> +
> +    /* Sizeof(AudioTrack) == 0x58 (not sure) on 2.2.1, this should be
> enough */ +    p_sys->AudioTrack = malloc(SIZE_OF_AUDIOTRACK);
> +    if (!p_sys->AudioTrack) {
> +        dlclose(p_sys->libmedia);
> +        free(p_sys);
> +        return VLC_ENOMEM;
> +    }
> +
> +    *((uint32_t *) ((uint32_t)p_sys->AudioTrack + SIZE_OF_AUDIOTRACK - 4))
> = 0xbaadbaad; +    // Higher than android 2.2
> +    if (p_sys->at_ctor)
> +        p_sys->at_ctor(p_sys->AudioTrack, stream_type, rate, format,
> channel, size, 0, NULL, NULL, 0, 0); +    // Higher than android 1.6
> +    else if (p_sys->at_ctor_legacy)
> +        p_sys->at_ctor_legacy(p_sys->AudioTrack, stream_type, rate,
> format, channel, size, 0, NULL, NULL, 0); +
> +    assert( (*((uint32_t *) ((uint32_t)p_sys->AudioTrack +
> SIZE_OF_AUDIOTRACK - 4)) == 0xbaadbaad) ); +
> +    /* And Init */
> +    status = p_sys->at_initCheck(p_sys->AudioTrack);
> +
> +    /* android 1.6 uses channel count instead of stream_type */
> +    if (status != 0) {
> +        channel = (channel == CHANNEL_OUT_STEREO) ? 2 : 1;
> +        p_sys->at_ctor_legacy(p_sys->AudioTrack, stream_type, rate,
> format, channel, size, 0, NULL, NULL, 0); +        status =
> p_sys->at_initCheck(p_sys->AudioTrack);
> +    }
> +    if (status != 0) {
> +        msg_Err(p_aout, "Cannot create AudioTrack!");
> +        free(p_sys->AudioTrack);
> +        free(p_sys);
> +        return VLC_EGENERIC;

Missing dlclose() ?

> +    }
> +
> +    p_aout->sys = p_sys;
> +    p_aout->pf_play = Play;
> +    p_aout->pf_pause = Pause;
> +
> +    p_sys->at_start(p_sys->AudioTrack);
> +
> +    return VLC_SUCCESS;
> +}
> +
> +static void Close(vlc_object_t *p_this)
> +{
> +    audio_output_t *p_aout = (audio_output_t*)p_this;
> +    aout_sys_t *p_sys = p_aout->sys;
> +
> +    p_sys->at_stop(p_sys->AudioTrack);
> +    p_sys->at_flush(p_sys->AudioTrack);
> +    p_sys->at_dtor(p_sys->AudioTrack);
> +    free(p_sys->AudioTrack);
> +    dlclose(p_sys->libmedia);
> +    free(p_sys);
> +}
> +
> +static void Play(audio_output_t *p_aout, block_t *p_buffer)
> +{
> +    aout_sys_t *p_sys = p_aout->sys;
> +
> +    size_t length = 0;
> +    while (length < p_buffer->i_buffer) {
> +        length += p_sys->at_write(p_sys->AudioTrack,
> (char*)(p_buffer->p_buffer) + length, p_buffer->i_buffer - length); +    }
> +
> +    block_Release( p_buffer );
> +}

No synchronization code whatsoever... Lip sync will not be acceptable (been 
there, done that).

> +
> +static void Pause(audio_output_t *p_aout, bool pause, mtime_t date)
> +{
> +    aout_sys_t *p_sys = p_aout->sys;
> +
> +    if (pause) {
> +        p_sys->at_pause(p_sys->AudioTrack);
> +    } else {
> +        p_sys->at_start(p_sys->AudioTrack);
> +    }
> +}

-- 
Rémi Denis-Courmont
http://www.remlab.net/



More information about the vlc-devel mailing list