[vlc-devel] [patch] fix for sndio bits

Rémi Denis-Courmont remi at remlab.net
Sat Mar 23 12:56:03 CET 2013


	Hello,

Le vendredi 22 mars 2013 16:30:41, Alexandre Ratchov a écrit :
> diff --git a/modules/audio_output/sndio.c b/modules/audio_output/sndio.c
> index 7f121dc..f484dc3 100644
> --- a/modules/audio_output/sndio.c
> +++ b/modules/audio_output/sndio.c
> @@ -54,87 +55,106 @@ static void PositionChanged (void *, int);
>  struct aout_sys_t
>  {
>      struct sio_hdl *hdl;
> -    unsigned long long read_offset;
> -    unsigned long long write_offset;
> +    int started;
> +    int delay;
>      unsigned rate;
> +    unsigned bpf;
>      unsigned volume;
>      bool mute;
>  };
> 
> +struct fmt_to_par {
> +    unsigned int format, sig, bits, le;
> +} fmt_to_par[] = {
> +    {VLC_CODEC_S8,   1,  8, 0},
> +    {VLC_CODEC_U8,   0,  8, 0},
> +    {VLC_CODEC_S16L, 1, 16, 1},
> +    {VLC_CODEC_S16B, 1, 16, 0},
> +    {VLC_CODEC_U16L, 0, 16, 1},
> +    {VLC_CODEC_U16B, 0, 16, 0},
> +    {VLC_CODEC_S24L, 1, 24, 1},
> +    {VLC_CODEC_S24B, 1, 24, 0},
> +    {VLC_CODEC_U24L, 0, 24, 1},
> +    {VLC_CODEC_U24B, 0, 24, 0},
> +    {VLC_CODEC_S32L, 1, 32, 1},
> +    {VLC_CODEC_S32B, 1, 32, 0},
> +    {VLC_CODEC_U32L, 0, 32, 1},
> +    {VLC_CODEC_U32B, 0, 32, 0},
> +    {0, 0, 0, 0}
> +};

This is probably overkill. In VLC 2.1.x, only U8, S16N, S32N, FL32 and FL64 
can occur in the VLC audio output, except for pass-through.

> +
>  /** Initializes an sndio playback stream */
>  static int Start (audio_output_t *aout, audio_sample_format_t *restrict
> fmt) {
>      aout_sys_t *sys = aout->sys;
> +    struct fmt_to_par *fp;
> 
>      sys->hdl = sio_open (NULL, SIO_PLAY, 0 /* blocking */);
>      if (sys->hdl == NULL)
>      {
> -        msg_Err (obj, "cannot create audio playback stream");
> -        free (sys);
> +        msg_Err (aout, "cannot create audio playback stream");
>          return VLC_EGENERIC;
>      }
> -    aout->sys = sys;
> 
>      struct sio_par par;
>      sio_initpar (&par);
> -    par.bits = 16;
> -    par.bps = par.bits >> 3;
> -    par.sig = 1;
> -    par.le = SIO_LE_NATIVE;
> +    for (fp = fmt_to_par; ; fp++) {
> +        if (fp->format == 0) {
> +            par.bits = 16;
> +            par.sig = 1;
> +            break;
> +        }
> +        if (fp->format == fmt->i_format) {
> +            par.sig = fp->sig;
> +            par.bits = fp->bits;
> +            par.le = fp->le;
> +            break;
> +        }
> +    }
>      par.pchan = aout_FormatNbChannels (fmt);
>      par.rate = fmt->i_rate;
> -    par.xrun = SIO_SYNC;
> +    par.round = par.rate / 50;
> +    par.appbufsz = par.rate / 4;
> 
>      if (!sio_setpar (sys->hdl, &par) || !sio_getpar (sys->hdl, &par))
>      {
> -        msg_Err (obj, "cannot negotiate audio playback parameters");
> +        msg_Err (aout, "cannot negotiate audio playback parameters");
>          goto error;
>      }
> 
> -    if (par.bps != par.bits >> 3)
> +    if (par.bps != par.bits >> 3 && !par.msb)
>      {
> -        msg_Err (obj, "unsupported audio sample format (%u bits in %u
> bytes)",
> +        msg_Err (aout, "unsupported audio sample format (%u bits
> in %u bytes)", par.bits, par.bps);
>          goto error;
>      }
> -    if (par.sig != (par.bits != 8))
> -    {
> -        msg_Err (obj, "unsupported audio sample format (%ssigned)",
> -                 par.sig ? "" : "un");
> -        goto error;
> -    }
> -#ifdef WORDS_BIGENDIAN
> -    if (par.le)
> -    {
> -        msg_Err (obj, "unsupported audio sample format (little endian)");
> -        goto error;
> -    }
> -#else
> -    if (!par.le)
> -    {
> -        msg_Err (obj, "unsupported audio sample format (big endian)");
> -        goto error;
> -    }
> -#endif
> -    switch (par.bits)
> +
> +    switch (par.bps)
>      {
> -        case 8:
> -            fmt->i_format = VLC_CODEC_U8;
> +        case 1:
> +            fmt->i_format = par.sig ? VLC_CODEC_S8 : VLC_CODEC_U8;
>              break;
> -        case 16:
> -            fmt->i_format = VLC_CODEC_S16N;
> +        case 2:
> +            fmt->i_format = par.sig ? (par.le ? VLC_CODEC_S16L :
> VLC_CODEC_S16B) +                                 : (par.le ?
> VLC_CODEC_U16L : VLC_CODEC_U16B); break;
> -        case 32:
> -            fmt->i_format = VLC_CODEC_S32N;
> +        case 3:
> +            fmt->i_format = par.sig ? (par.le ? VLC_CODEC_S24L :
> VLC_CODEC_S24B)
> +                                 : (par.le ?
> VLC_CODEC_U24L : VLC_CODEC_U24B);
> +            break;
> +        case 4:
> +            fmt->i_format = par.sig ? (par.le ? VLC_CODEC_S32L :
> VLC_CODEC_S32B)
> +                                 : (par.le ?
> VLC_CODEC_U32L : VLC_CODEC_U32B); break;
>          default:
> -            msg_Err (obj, "unsupported audio sample format (%u bits)",
> +            msg_Err (aout, "unsupported audio sample format (%u bits)",
>                       par.bits);
>              goto error;
>      }
> 
>      fmt->i_rate = par.rate;
>      sys->rate = par.rate;
> +    sys->bpf = par.bps * par.pchan;
> 
>      /* Channel map */
>      unsigned chans;
> @@ -163,10 +183,9 @@ static int Start (audio_output_t *aout,
> audio_sample_format_t *restrict fmt) fmt->i_original_channels =
> fmt->i_physical_channels = chans;
>      aout_FormatPrepare (fmt);
> 
> -    aout->sys = sys;
>      aout->time_get = TimeGet;
>      aout->play = Play;
> -    aout->pause = NULL;
> +    aout->pause = Pause;
>      aout->flush = Flush;
>      if (sio_onvol(sys->hdl, VolumeChanged, aout))
>      {
> @@ -179,8 +198,8 @@ static int Start (audio_output_t *aout,
> audio_sample_format_t *restrict fmt) aout->mute_set = NULL;
>      }
> 
> -    sys->read_offset = 0;
> -    sys->write_offset = 0;
> +    sys->started = 0;
> +    sys->delay = 0;
>      sio_onmove (sys->hdl, PositionChanged, aout);
>      sio_start (sys->hdl);
>      return VLC_SUCCESS;
> @@ -190,9 +209,8 @@ error:
>      return VLC_EGENERIC;
>  }
> 
> -static void Close (vlc_object_t *obj)
> +static void Stop (audio_output_t *aout)
>  {
> -    audio_output_t *aout = (audio_output_t *)obj;
>      aout_sys_t *sys = aout->sys;
> 
>      sio_close (sys->hdl);
> @@ -203,18 +221,19 @@ static void PositionChanged (void *arg, int delta)
>      audio_output_t *aout = arg;
>      aout_sys_t *sys = aout->sys;
> 
> -    sys->read_offset += delta;
> +    sys->delay -= delta;
> +    sys->started = 1;
>  }
> 
>  static int TimeGet (audio_output_t *aout, mtime_t *restrict delay)
>  {
>      aout_sys_t *sys = aout->sys;
> -    long long frames = sys->write_offset - sys->read_offset;
> -
> -    if (frames == 0)
> -        return -1;
> 
> -    *delay = frames * CLOCK_FREQ / sys->rate;
> +    if (!sys->started)
> +	*delay = 0;
> +    else
> +	*delay = (mtime_t)sys->delay * CLOCK_FREQ / sys->rate;
>      return 0;
>  }
> 
> @@ -222,35 +241,43 @@ static void Play (audio_output_t *aout, block_t
> *block) {
>      aout_sys_t *sys = aout->sys;
> 
> -    sys->write_offset += block->i_nb_samples;
> -
> -    while (block->i_buffer > 0 && !sio_eof (sys->hdl))
> -    {
> -        size_t bytes = sio_write (sys->hdl, block->p_buffer,
> block->i_buffer); -
> -        block->p_buffer += bytes;
> -        block->i_buffer -= bytes;
> -        /* Note that i_nb_samples and i_pts are not updated here. */
> -    }
> +    sio_write (sys->hdl, block->p_buffer, block->i_nb_samples * sys->bpf);
> +    sys->delay += block->i_nb_samples;
>      block_Release (block);
>  }
> 
>  static void Flush (audio_output_t *aout, bool wait)
>  {
> -    if (wait)
> -    {
> -        long long frames = sys->write_offset - sys->read_offset;
> +    aout_sys_t *sys = aout->sys;
> 
> -        if (frames > 0)
> -            msleep (frames * CLOCK_FREQ / sys->rate);

Does this not break draining?

> -    }
> -    else
> -    {
> +    sio_stop (sys->hdl);
> +    sio_start (sys->hdl);
> +    sys->started = 0;
> +    sys->delay = 0;
> +    (void)wait;
> +}
> +
> +static void Pause (audio_output_t *aout, bool pause, mtime_t date)
> +{
> +    aout_sys_t *sys = aout->sys;
> +    char zero[1024];
> +    int n, todo;
> +
> +    if (pause) {
>          sio_stop (sys->hdl);
> -        sys->read_offset = 0;
> -        sys->write_offset = 0;
>          sio_start (sys->hdl);
> +    } else {
> +	memset (zero, 0, sizeof (zero));
> +	todo = sys->delay * sys->bpf;
> +	while (todo > 0) {
> +	    n = sizeof (zero);
> +	    if (n > todo)
> +		n = todo;
> +	    sio_write(sys->hdl, zero, n);
> +	    todo -= n;
> +	}

Does this really work when resuming from a long pause? This looks a bit 
simplistic.

>      }
> +    (void) date;
>  }
> 
>  static void VolumeChanged (void *arg, unsigned volume)

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



More information about the vlc-devel mailing list