On Tue, Oct 15, 2013 at 09:28:23AM -0500, Jeremy White wrote: > Signed-off-by: Jeremy White <jwhite@xxxxxxxxxxxxxxx> > --- > common/Makefile.am | 4 + > common/snd_codec.c | 261 ++++++++++++++++++++++++++++++++++++++++++++++++++++ > common/snd_codec.h | 79 ++++++++++++++++ > configure.ac | 16 ++++ > 4 files changed, 360 insertions(+) > create mode 100644 common/snd_codec.c > create mode 100644 common/snd_codec.h > > diff --git a/common/Makefile.am b/common/Makefile.am > index 45568c6..bef6a14 100644 > --- a/common/Makefile.am > +++ b/common/Makefile.am > @@ -52,6 +52,8 @@ libspice_common_la_SOURCES = \ > ring.h \ > rop3.c \ > rop3.h \ > + snd_codec.c \ > + snd_codec.h \ > spice_common.h \ > ssl_verify.c \ > ssl_verify.h \ > @@ -81,6 +83,7 @@ endif > AM_CPPFLAGS = \ > $(GL_CFLAGS) \ > $(PIXMAN_CFLAGS) \ > + $(CELT051_CFLAGS) \ > $(PROTOCOL_CFLAGS) \ > $(SMARTCARD_CFLAGS) \ > $(VISIBILITY_HIDDEN_CFLAGS) \ > @@ -142,6 +145,7 @@ EXTRA_DIST = \ > quic_family_tmpl.c \ > quic_rgb_tmpl.c \ > quic_tmpl.c \ > + snd_codec.h \ > sw_canvas.c \ > sw_canvas.h \ > $(NULL) > diff --git a/common/snd_codec.c b/common/snd_codec.c > new file mode 100644 > index 0000000..5d8ded1 > --- /dev/null > +++ b/common/snd_codec.c > @@ -0,0 +1,261 @@ > +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ > +/* > + Copyright (C) 2013 Jeremy White > + > + This library is free software; you can redistribute it and/or > + modify it under the terms of the GNU Lesser General Public > + License as published by the Free Software Foundation; either > + version 2.1 of the License, or (at your option) any later version. > + > + This library is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public > + License along with this library; if not, see <http://www.gnu.org/licenses/>. > +*/ > + > +/* snd_codec.c > + General purpose sound codec routines for use by Spice. > + These routines abstract the work of picking a codec and > + encoding and decoding the buffers. > + Note: these routines have some peculiarities that come from > + wanting to provide full backwards compatibility with the original > + Spice celt 0.51 implementation. It has some hard requirements > + (fixed sample size, fixed compressed buffer size). > + > + See below for documentation of the public routines. > +*/ > + > +#include <stdio.h> > +#include <string.h> > +#include "config.h" > +#include <spice/macros.h> > +#include <spice/enums.h> > + > + > +#include "snd_codec.h" > +#include "log.h" > + > + > + > +/* celt 0.51 specific support routines */ > +#if HAVE_CELT051 > +static void snd_codec_destroy_celt051(SndCodec *codec) > +{ > + if (codec->celt_decoder) > + { > + celt051_decoder_destroy(codec->celt_decoder); > + codec->celt_decoder = NULL; > + } > + > + if (codec->celt_encoder) > + { > + celt051_encoder_destroy(codec->celt_encoder); > + codec->celt_encoder = NULL; > + } > + > + if (codec->celt_mode) > + { > + celt051_mode_destroy(codec->celt_mode); > + codec->celt_mode = NULL; > + } > +} > + > +static int snd_codec_create_celt051(SndCodec *codec, int encode, int decode) > +{ > + int celt_error; > + > + codec->celt_mode = celt051_mode_create(codec->frequency, > + SND_CODEC_CELT_PLAYBACK_CHAN, > + SND_CODEC_CELT_FRAME_SIZE, &celt_error); > + if (! codec->celt_mode) > + { > + spice_printerr("create celt mode failed %d", celt_error); > + return SND_CODEC_UNAVAILABLE; > + } > + > + if (encode) > + { > + codec->celt_encoder = celt051_encoder_create(codec->celt_mode); > + if (! codec->celt_encoder) > + { > + spice_printerr("create celt encoder failed"); > + goto error; > + } > + } > + > + if (decode) > + { > + codec->celt_decoder = celt051_decoder_create(codec->celt_mode); > + if (! codec->celt_decoder) > + { > + spice_printerr("create celt decoder failed"); > + goto error; > + } > + } > + > + codec->mode = SPICE_AUDIO_DATA_MODE_CELT_0_5_1; > + return SND_CODEC_OK; > + > +error: > + snd_codec_destroy_celt051(codec); > + return SND_CODEC_UNAVAILABLE; > +} > + > +static int snd_codec_encode_celt051(SndCodec *codec, uint8_t *in_ptr, int in_size, uint8_t *out_ptr, int *out_size) > +{ > + int n; > + if (in_size != SND_CODEC_CELT_FRAME_SIZE * SND_CODEC_CELT_PLAYBACK_CHAN * 2) > + return SND_CODEC_INVALID_ENCODE_SIZE; > + n = celt051_encode(codec->celt_encoder, (celt_int16_t *) in_ptr, NULL, out_ptr, *out_size); > + if (n < 0) { > + spice_printerr("celt051_encode failed %d\n", n); > + return SND_CODEC_ENCODE_FAILED; > + } > + *out_size = n; > + return SND_CODEC_OK; > +} > + > +static int snd_codec_decode_celt051(SndCodec *codec, uint8_t *in_ptr, int in_size, uint8_t *out_ptr, int *out_size) > +{ > + int n; > + n = celt051_decode(codec->celt_decoder, in_ptr, in_size, (celt_int16_t *) out_ptr); > + if (n < 0) { > + spice_printerr("celt051_decode failed %d\n", n); > + return SND_CODEC_DECODE_FAILED; > + } > + *out_size = SND_CODEC_CELT_FRAME_SIZE * SND_CODEC_CELT_PLAYBACK_CHAN * 2 /* 16 fmt */; > + return SND_CODEC_OK; > +} > +#endif > + > + > + > +/*---------------------------------------------------------------------------- > +** PUBLIC INTERFACE > +**--------------------------------------------------------------------------*/ > + > +/* > + snd_codec_is_capable > + Returns TRUE if the current spice implementation can > + use the given codec, FALSE otherwise. > + mode must be a SPICE_AUDIO_DATA_MODE_XXX enum from spice/enum.h > + */ > +int snd_codec_is_capable(int mode) > +{ > +#if HAVE_CELT051 > + if (mode == SPICE_AUDIO_DATA_MODE_CELT_0_5_1) > + return TRUE; > +#else > + return FALSE; > +#endif > +} > + > +/* > + snd_codec_create > + Create a codec control. Required for most functions in this library. > + Parameters: > + 1. codec Pointer to preallocated codec control > + 2. mode SPICE_AUDIO_DATA_MODE_XXX enum from spice/enum.h > + 3. encode TRUE if encoding is desired > + 4. decode TRUE if decoding is desired > + Returns: > + SND_CODEC_OK if all went well; a different code if not. > + > + snd_codec_destroy is the obvious partner of snd_codec_create. > + */ > +int snd_codec_create(SndCodec *codec, int mode, int frequency, int encode, int decode) > +{ > + int rc = SND_CODEC_UNAVAILABLE; > + memset(codec, 0, sizeof(*codec)); > + codec->frequency = frequency; > + > +#if HAVE_CELT051 > + if (mode == SPICE_AUDIO_DATA_MODE_CELT_0_5_1) > + rc = snd_codec_create_celt051(codec, encode, decode); > +#endif > + > + return rc; > +} > + > +/* > + snd_codec_destroy > + The obvious companion to snd_codec_create > +*/ > +void snd_codec_destroy(SndCodec *codec) > +{ > +#if HAVE_CELT051 > + snd_codec_destroy_celt051(codec); > +#endif > +} > + > +/* > + snd_codec_frame_size > + Returns the size, in frames, of the raw PCM frame buffer > + required by this codec. To get bytes, you'll need > + to multiply by channels and sample width. > + */ > +int snd_codec_frame_size(SndCodec *codec) > +{ > +#if HAVE_CELT051 > + if (codec->mode == SPICE_AUDIO_DATA_MODE_CELT_0_5_1) > + return SND_CODEC_CELT_FRAME_SIZE; > +#endif > + return SND_CODEC_MAX_FRAME_SIZE; > +} > + > +/* > + snd_codec_encode > + Encode a block of data to a compressed buffer. > + > + Parameters: > + 1. codec Pointer to codec control previously allocated + created > + 2. in_data Pointer to uncompressed PCM data > + 3. in_size Input size (for celt, this must be a > + particular size, governed by the frame size) > + 4. out_ptr Pointer to area to write encoded data > + 5. out_size On input, the maximum size of the output buffer; on > + successful return, it will hold the number of bytes > + returned. For celt, this must be set to a particular > + size to ensure compatibility. > + > + Returns: > + SND_CODEC_OK if all went well > +*/ > +int snd_codec_encode(SndCodec *codec, uint8_t *in_ptr, int in_size, uint8_t *out_ptr, int *out_size) > +{ > +#if HAVE_CELT051 > + if (codec->mode == SPICE_AUDIO_DATA_MODE_CELT_0_5_1) > + return snd_codec_encode_celt051(codec, in_ptr, in_size, out_ptr, out_size); > +#endif > + > + return SND_CODEC_ENCODER_UNAVAILABLE; > +} > + > +/* > + snd_codec_decode > + Decode a block of data from a compressed buffer. > + > + Parameters: > + 1. codec Pointer to codec control previously allocated + created > + 2. in_data Pointer to compressed data > + 3. in_size Input size > + 4. out_ptr Pointer to area to write decoded data > + 5. out_size On input, the maximum size of the output buffer; on > + successful return, it will hold the number of bytes > + returned. > + > + Returns: > + SND_CODEC_OK if all went well > +*/ > +int snd_codec_decode(SndCodec *codec, uint8_t *in_ptr, int in_size, uint8_t *out_ptr, int *out_size) > +{ > +#if HAVE_CELT051 > + if (codec->mode == SPICE_AUDIO_DATA_MODE_CELT_0_5_1) > + return snd_codec_decode_celt051(codec, in_ptr, in_size, out_ptr, out_size); > +#endif > + > + return SND_CODEC_DECODER_UNAVAILABLE; > +} > diff --git a/common/snd_codec.h b/common/snd_codec.h > new file mode 100644 > index 0000000..632588e > --- /dev/null > +++ b/common/snd_codec.h > @@ -0,0 +1,79 @@ > +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ > +/* > + Copyright (C) 2013 Jeremy White <jwhite@xxxxxxxxxxxxxxx> > + > + This library is free software; you can redistribute it and/or > + modify it under the terms of the GNU Lesser General Public > + License as published by the Free Software Foundation; either > + version 2.1 of the License, or (at your option) any later version. > + > + This library is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public > + License along with this library; if not, see <http://www.gnu.org/licenses/>. > +*/ > + > +#ifndef _H_SND_CODEC > +#define _H_SND_CODEC > + > + > +#if HAVE_CELT051 > +#include <celt051/celt.h> > +#endif > + > +/* Spice uses a very fixed protocol when transmitting CELT audio; > + audio must be transmitted in frames of 256, and we must compress > + data down to a fairly specific size (47, computation below). > + While the protocol doesn't inherently specify this, the expectation > + of older clients and server mandates it. > +*/ > +#define SND_CODEC_CELT_FRAME_SIZE 256 > +#define SND_CODEC_CELT_BIT_RATE (64 * 1024) > +#define SND_CODEC_CELT_PLAYBACK_FREQ 44100 > +#define SND_CODEC_CELT_PLAYBACK_CHAN 2 > +#define SND_CODEC_CELT_COMPRESSED_FRAME_BYTES (SND_CODEC_CELT_FRAME_SIZE * SND_CODEC_CELT_BIT_RATE / \ > + SND_CODEC_CELT_PLAYBACK_FREQ / 8) > + > + > +#define SND_CODEC_MAX_FRAME_SIZE SND_CODEC_CELT_FRAME_SIZE > +#define SND_CODEC_MAX_FRAME_BYTES (SND_CODEC_MAX_FRAME_SIZE * SND_CODEC_CELT_PLAYBACK_CHAN * 2 /* FMT_S16 */) > +#define SND_CODEC_MAX_COMPRESSED_BYTES SND_CODEC_CELT_COMPRESSED_FRAME_BYTES > + > +#define SND_CODEC_OK 0 > +#define SND_CODEC_UNAVAILABLE 1 > +#define SND_CODEC_ENCODER_UNAVAILABLE 2 > +#define SND_CODEC_DECODER_UNAVAILABLE 3 > +#define SND_CODEC_ENCODE_FAILED 4 > +#define SND_CODEC_DECODE_FAILED 4 Are you intentionally using the same value for ENCODE/DECODE_FAILED? I'm asking because ENCODER/DECODER_UNAVAILABLE got different values. Looks good otherwise, ACK. Christophe
Attachment:
pgpeAZcgxUD9a.pgp
Description: PGP signature
_______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel