]> git.tuebingen.mpg.de Git - paraslash.git/blobdiff - spx_common.c
Add support for the speex codec.
[paraslash.git] / spx_common.c
diff --git a/spx_common.c b/spx_common.c
new file mode 100644 (file)
index 0000000..ce01e23
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2002-2006 Jean-Marc Valin
+ * Copyright (C) 2010 Andre Noll <maan@systemlinux.org>
+ *
+ * Licensed under the GPL v2. For licencing details see COPYING.
+ */
+
+/**
+ * \file spx_common.c Functions used by the speex decoder and the speex audio
+ * format handler.
+ */
+
+/* This file is based on speexdec.c, by Jean-Marc Valin, see below. */
+
+/* Copyright (C) 2002-2006 Jean-Marc Valin
+   File: speexdec.c
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <regex.h>
+#include <speex/speex_header.h>
+#include <speex/speex_stereo.h>
+#include <speex/speex_callbacks.h>
+
+#include "para.h"
+#include "error.h"
+#include "spx.h"
+
+/**
+ * Wrapper for speex_decoder_ctl().
+ *
+ * \param state Decoder state.
+ * \param request ioctl-type request.
+ * \param ptr Value-result pointer.
+ *
+ * \return Standard.
+ */
+int spx_ctl(void *state, int request, void *ptr)
+{
+       int ret = speex_decoder_ctl(state, request, ptr);
+
+       if (ret == 0) /* success */
+               return 1;
+       if (ret == -1)
+               return -E_SPX_CTL_BAD_RQ;
+       return -E_SPX_CTL_INVAL;
+}
+
+/**
+ * Obtain information about a speex file from an ogg packet.
+ *
+ * \param packet Start of the ogg packet.
+ * \param bytes Length of the ogg packet.
+ * \param shi Result pointer.
+ *
+ * \return Standard.
+ */
+int spx_process_header(unsigned char *packet, long bytes,
+               struct spx_header_info *shi)
+{
+       int ret;
+       spx_int32_t enh_enabled = 1;
+       SpeexHeader *h = speex_packet_to_header((char *)packet, bytes);
+
+       if (!h)
+               return -E_SPX_HEADER;
+       ret = -E_SPX_HEADER_MODE;
+       if (h->mode >= SPEEX_NB_MODES || h->mode < 0)
+               goto out;
+       shi->mode = speex_lib_get_mode(h->mode);
+
+       ret = -E_SPX_VERSION;
+       if (h->speex_version_id > 1)
+               goto out;
+       if (shi->mode->bitstream_version < h->mode_bitstream_version)
+               goto out;
+       if (shi->mode->bitstream_version > h->mode_bitstream_version)
+               goto out;
+
+       ret = -E_SPX_DECODER_INIT;
+       shi->state = speex_decoder_init(shi->mode);
+       if (!shi->state)
+               goto out;
+
+       ret = spx_ctl(shi->state, SPEEX_SET_ENH, &enh_enabled);
+       if (ret < 0)
+               goto out;
+       ret = spx_ctl(shi->state, SPEEX_GET_FRAME_SIZE, &shi->frame_size);
+       if (ret < 0)
+               goto out;
+       shi->sample_rate = h->rate;
+       ret = spx_ctl(shi->state, SPEEX_SET_SAMPLING_RATE, &shi->sample_rate);
+       if (ret < 0)
+               goto out;
+       shi->nframes = h->frames_per_packet;
+       shi->channels = h->nb_channels;
+       if (shi->channels != 1) {
+               shi->stereo = (SpeexStereoState)SPEEX_STEREO_STATE_INIT;
+               SpeexCallback callback = {
+                       .callback_id = SPEEX_INBAND_STEREO,
+                       .func = speex_std_stereo_request_handler,
+                       .data = &shi->stereo,
+               };
+               ret = spx_ctl(shi->state, SPEEX_SET_HANDLER, &callback);
+               if (ret < 0)
+                       goto out;
+               shi->channels = 2;
+       }
+       ret = spx_ctl(shi->state, SPEEX_GET_BITRATE, &shi->bitrate);
+       if (ret < 0)
+               goto out;
+       PARA_NOTICE_LOG("%d Hz, %s, %s, %s, %d bits/s\n",
+               shi->sample_rate, shi->mode->modeName,
+               shi->channels == 1? "mono" : "stereo",
+               h->vbr? "vbr" : "cbr",
+               shi->bitrate
+       );
+       shi->extra_headers = h->extra_headers;
+       ret = 1;
+out:
+       free(h);
+       return ret;
+}