--- /dev/null
+/*
+ * 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;
+}