Quellcode durchsuchen

add vorbis, tweak SPIRAM/ISRAM stack

philippe44 vor 5 Jahren
Ursprung
Commit
05925261f2

+ 3 - 0
README.md

@@ -8,12 +8,15 @@ Adding squeezelite
 		#pragma GCC optimize ("O0")
 		#pragma GCC pop_options
  - libflac can use espressif's version	
+ - vorbis
+	- set SPIRAM_MALLOC_ALWAYSINTERNAL to 2048 as it consumes a lot of 8K blocks and uses all internal memory - when no memoru, WiFI chip fails
  - set IDF_PATH=/home/esp-idf
  - set ESPPORT=COM9
  - change <esp-idf>\components\partition_table\partitions_singleapp.csv to 2M instead of 1M (or more)
  - change flash's size in serial flash config to 16M
  - change main stack size to 8000 as well (for app_main which is slimproto)
  - use old "make" environment no CMake
+ 
   
 # Wifi SCAN Example
 

+ 15 - 1
components/codecs/component.mk

@@ -2,4 +2,18 @@
 # "main" pseudo-component makefile.
 #
 # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
-COMPONENT_ADD_LDFLAGS=$(COMPONENT_PATH)/lib/libmad.a $(COMPONENT_PATH)/lib/libesp-flac.a $(COMPONENT_PATH)/lib/libfaad.a -l$(COMPONENT_NAME)
+COMPONENT_ADD_LDFLAGS=-l$(COMPONENT_NAME) 	\
+	$(COMPONENT_PATH)/lib/libmad.a 			\
+	$(COMPONENT_PATH)/lib/libesp-flac.a 	\
+	$(COMPONENT_PATH)/lib/libfaad.a 		\
+	$(COMPONENT_PATH)/lib/libvorbisidec.a	\
+	$(COMPONENT_PATH)/lib/libogg.a
+	
+	#$(COMPONENT_PATH)/lib/libvorbisidec.a
+	#$(COMPONENT_PATH)/lib/libogg.a
+	#$(COMPONENT_PATH)/lib/libesp-tremor.a
+	#$(COMPONENT_PATH)/lib/libesp-ogg-container.a
+	
+
+	
+	

+ 25 - 0
components/codecs/inc/ogg/config_types.h

@@ -0,0 +1,25 @@
+#ifndef __CONFIG_TYPES_H__
+#define __CONFIG_TYPES_H__
+
+/* these are filled in by configure */
+#define INCLUDE_INTTYPES_H 1
+#define INCLUDE_STDINT_H 1
+#define INCLUDE_SYS_TYPES_H 1
+
+#if INCLUDE_INTTYPES_H
+#  include <inttypes.h>
+#endif
+#if INCLUDE_STDINT_H
+#  include <stdint.h>
+#endif
+#if INCLUDE_SYS_TYPES_H
+#  include <sys/types.h>
+#endif
+
+typedef int16_t ogg_int16_t;
+typedef uint16_t ogg_uint16_t;
+typedef int32_t ogg_int32_t;
+typedef uint32_t ogg_uint32_t;
+typedef int64_t ogg_int64_t;
+
+#endif

+ 210 - 0
components/codecs/inc/ogg/ogg.h

@@ -0,0 +1,210 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007             *
+ * by the Xiph.Org Foundation http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+ function: toplevel libogg include
+ last mod: $Id$
+
+ ********************************************************************/
+#ifndef _OGG_H
+#define _OGG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h>
+#include <ogg/os_types.h>
+
+typedef struct {
+  void *iov_base;
+  size_t iov_len;
+} ogg_iovec_t;
+
+typedef struct {
+  long endbyte;
+  int  endbit;
+
+  unsigned char *buffer;
+  unsigned char *ptr;
+  long storage;
+} oggpack_buffer;
+
+/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/
+
+typedef struct {
+  unsigned char *header;
+  long header_len;
+  unsigned char *body;
+  long body_len;
+} ogg_page;
+
+/* ogg_stream_state contains the current encode/decode state of a logical
+   Ogg bitstream **********************************************************/
+
+typedef struct {
+  unsigned char   *body_data;    /* bytes from packet bodies */
+  long    body_storage;          /* storage elements allocated */
+  long    body_fill;             /* elements stored; fill mark */
+  long    body_returned;         /* elements of fill returned */
+
+
+  int     *lacing_vals;      /* The values that will go to the segment table */
+  ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact
+                                this way, but it is simple coupled to the
+                                lacing fifo */
+  long    lacing_storage;
+  long    lacing_fill;
+  long    lacing_packet;
+  long    lacing_returned;
+
+  unsigned char    header[282];      /* working space for header encode */
+  int              header_fill;
+
+  int     e_o_s;          /* set when we have buffered the last packet in the
+                             logical bitstream */
+  int     b_o_s;          /* set after we've written the initial page
+                             of a logical bitstream */
+  long    serialno;
+  long    pageno;
+  ogg_int64_t  packetno;  /* sequence number for decode; the framing
+                             knows where there's a hole in the data,
+                             but we need coupling so that the codec
+                             (which is in a separate abstraction
+                             layer) also knows about the gap */
+  ogg_int64_t   granulepos;
+
+} ogg_stream_state;
+
+/* ogg_packet is used to encapsulate the data and metadata belonging
+   to a single raw Ogg/Vorbis packet *************************************/
+
+typedef struct {
+  unsigned char *packet;
+  long  bytes;
+  long  b_o_s;
+  long  e_o_s;
+
+  ogg_int64_t  granulepos;
+
+  ogg_int64_t  packetno;     /* sequence number for decode; the framing
+                                knows where there's a hole in the data,
+                                but we need coupling so that the codec
+                                (which is in a separate abstraction
+                                layer) also knows about the gap */
+} ogg_packet;
+
+typedef struct {
+  unsigned char *data;
+  int storage;
+  int fill;
+  int returned;
+
+  int unsynced;
+  int headerbytes;
+  int bodybytes;
+} ogg_sync_state;
+
+/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/
+
+extern void  oggpack_writeinit(oggpack_buffer *b);
+extern int   oggpack_writecheck(oggpack_buffer *b);
+extern void  oggpack_writetrunc(oggpack_buffer *b,long bits);
+extern void  oggpack_writealign(oggpack_buffer *b);
+extern void  oggpack_writecopy(oggpack_buffer *b,void *source,long bits);
+extern void  oggpack_reset(oggpack_buffer *b);
+extern void  oggpack_writeclear(oggpack_buffer *b);
+extern void  oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
+extern void  oggpack_write(oggpack_buffer *b,unsigned long value,int bits);
+extern long  oggpack_look(oggpack_buffer *b,int bits);
+extern long  oggpack_look1(oggpack_buffer *b);
+extern void  oggpack_adv(oggpack_buffer *b,int bits);
+extern void  oggpack_adv1(oggpack_buffer *b);
+extern long  oggpack_read(oggpack_buffer *b,int bits);
+extern long  oggpack_read1(oggpack_buffer *b);
+extern long  oggpack_bytes(oggpack_buffer *b);
+extern long  oggpack_bits(oggpack_buffer *b);
+extern unsigned char *oggpack_get_buffer(oggpack_buffer *b);
+
+extern void  oggpackB_writeinit(oggpack_buffer *b);
+extern int   oggpackB_writecheck(oggpack_buffer *b);
+extern void  oggpackB_writetrunc(oggpack_buffer *b,long bits);
+extern void  oggpackB_writealign(oggpack_buffer *b);
+extern void  oggpackB_writecopy(oggpack_buffer *b,void *source,long bits);
+extern void  oggpackB_reset(oggpack_buffer *b);
+extern void  oggpackB_writeclear(oggpack_buffer *b);
+extern void  oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
+extern void  oggpackB_write(oggpack_buffer *b,unsigned long value,int bits);
+extern long  oggpackB_look(oggpack_buffer *b,int bits);
+extern long  oggpackB_look1(oggpack_buffer *b);
+extern void  oggpackB_adv(oggpack_buffer *b,int bits);
+extern void  oggpackB_adv1(oggpack_buffer *b);
+extern long  oggpackB_read(oggpack_buffer *b,int bits);
+extern long  oggpackB_read1(oggpack_buffer *b);
+extern long  oggpackB_bytes(oggpack_buffer *b);
+extern long  oggpackB_bits(oggpack_buffer *b);
+extern unsigned char *oggpackB_get_buffer(oggpack_buffer *b);
+
+/* Ogg BITSTREAM PRIMITIVES: encoding **************************/
+
+extern int      ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op);
+extern int      ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov,
+                                   int count, long e_o_s, ogg_int64_t granulepos);
+extern int      ogg_stream_pageout(ogg_stream_state *os, ogg_page *og);
+extern int      ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill);
+extern int      ogg_stream_flush(ogg_stream_state *os, ogg_page *og);
+extern int      ogg_stream_flush_fill(ogg_stream_state *os, ogg_page *og, int nfill);
+
+/* Ogg BITSTREAM PRIMITIVES: decoding **************************/
+
+extern int      ogg_sync_init(ogg_sync_state *oy);
+extern int      ogg_sync_clear(ogg_sync_state *oy);
+extern int      ogg_sync_reset(ogg_sync_state *oy);
+extern int      ogg_sync_destroy(ogg_sync_state *oy);
+extern int      ogg_sync_check(ogg_sync_state *oy);
+
+extern char    *ogg_sync_buffer(ogg_sync_state *oy, long size);
+extern int      ogg_sync_wrote(ogg_sync_state *oy, long bytes);
+extern long     ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og);
+extern int      ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og);
+extern int      ogg_stream_pagein(ogg_stream_state *os, ogg_page *og);
+extern int      ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op);
+extern int      ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op);
+
+/* Ogg BITSTREAM PRIMITIVES: general ***************************/
+
+extern int      ogg_stream_init(ogg_stream_state *os,int serialno);
+extern int      ogg_stream_clear(ogg_stream_state *os);
+extern int      ogg_stream_reset(ogg_stream_state *os);
+extern int      ogg_stream_reset_serialno(ogg_stream_state *os,int serialno);
+extern int      ogg_stream_destroy(ogg_stream_state *os);
+extern int      ogg_stream_check(ogg_stream_state *os);
+extern int      ogg_stream_eos(ogg_stream_state *os);
+
+extern void     ogg_page_checksum_set(ogg_page *og);
+
+extern int      ogg_page_version(const ogg_page *og);
+extern int      ogg_page_continued(const ogg_page *og);
+extern int      ogg_page_bos(const ogg_page *og);
+extern int      ogg_page_eos(const ogg_page *og);
+extern ogg_int64_t  ogg_page_granulepos(const ogg_page *og);
+extern int      ogg_page_serialno(const ogg_page *og);
+extern long     ogg_page_pageno(const ogg_page *og);
+extern int      ogg_page_packets(const ogg_page *og);
+
+extern void     ogg_packet_clear(ogg_packet *op);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* _OGG_H */

+ 148 - 0
components/codecs/inc/ogg/os_types.h

@@ -0,0 +1,148 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002             *
+ * by the Xiph.Org Foundation http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+ function: #ifdef jail to whip a few platforms into the UNIX ideal.
+ last mod: $Id$
+
+ ********************************************************************/
+#ifndef _OS_TYPES_H
+#define _OS_TYPES_H
+
+/* make it easy on the folks that want to compile the libs with a
+   different malloc than stdlib */
+#define _ogg_malloc  malloc
+#define _ogg_calloc  calloc
+#define _ogg_realloc realloc
+#define _ogg_free    free
+
+#if defined(_WIN32)
+
+#  if defined(__CYGWIN__)
+#    include <stdint.h>
+     typedef int16_t ogg_int16_t;
+     typedef uint16_t ogg_uint16_t;
+     typedef int32_t ogg_int32_t;
+     typedef uint32_t ogg_uint32_t;
+     typedef int64_t ogg_int64_t;
+     typedef uint64_t ogg_uint64_t;
+#  elif defined(__MINGW32__)
+#    include <sys/types.h>
+     typedef short ogg_int16_t;
+     typedef unsigned short ogg_uint16_t;
+     typedef int ogg_int32_t;
+     typedef unsigned int ogg_uint32_t;
+     typedef long long ogg_int64_t;
+     typedef unsigned long long ogg_uint64_t;
+#  elif defined(__MWERKS__)
+     typedef long long ogg_int64_t;
+     typedef int ogg_int32_t;
+     typedef unsigned int ogg_uint32_t;
+     typedef short ogg_int16_t;
+     typedef unsigned short ogg_uint16_t;
+#  else
+#    if defined(_MSC_VER) && (_MSC_VER >= 1800) /* MSVC 2013 and newer */
+#      include <stdint.h>
+       typedef int16_t ogg_int16_t;
+       typedef uint16_t ogg_uint16_t;
+       typedef int32_t ogg_int32_t;
+       typedef uint32_t ogg_uint32_t;
+       typedef int64_t ogg_int64_t;
+       typedef uint64_t ogg_uint64_t;
+#    else
+       /* MSVC/Borland */
+       typedef __int64 ogg_int64_t;
+       typedef __int32 ogg_int32_t;
+       typedef unsigned __int32 ogg_uint32_t;
+       typedef __int16 ogg_int16_t;
+       typedef unsigned __int16 ogg_uint16_t;
+#    endif
+#  endif
+
+#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */
+
+#  include <inttypes.h>
+   typedef int16_t ogg_int16_t;
+   typedef uint16_t ogg_uint16_t;
+   typedef int32_t ogg_int32_t;
+   typedef uint32_t ogg_uint32_t;
+   typedef int64_t ogg_int64_t;
+
+#elif defined(__HAIKU__)
+
+  /* Haiku */
+#  include <sys/types.h>
+   typedef short ogg_int16_t;
+   typedef unsigned short ogg_uint16_t;
+   typedef int ogg_int32_t;
+   typedef unsigned int ogg_uint32_t;
+   typedef long long ogg_int64_t;
+
+#elif defined(__BEOS__)
+
+   /* Be */
+#  include <inttypes.h>
+   typedef int16_t ogg_int16_t;
+   typedef uint16_t ogg_uint16_t;
+   typedef int32_t ogg_int32_t;
+   typedef uint32_t ogg_uint32_t;
+   typedef int64_t ogg_int64_t;
+
+#elif defined (__EMX__)
+
+   /* OS/2 GCC */
+   typedef short ogg_int16_t;
+   typedef unsigned short ogg_uint16_t;
+   typedef int ogg_int32_t;
+   typedef unsigned int ogg_uint32_t;
+   typedef long long ogg_int64_t;
+
+#elif defined (DJGPP)
+
+   /* DJGPP */
+   typedef short ogg_int16_t;
+   typedef int ogg_int32_t;
+   typedef unsigned int ogg_uint32_t;
+   typedef long long ogg_int64_t;
+
+#elif defined(R5900)
+
+   /* PS2 EE */
+   typedef long ogg_int64_t;
+   typedef int ogg_int32_t;
+   typedef unsigned ogg_uint32_t;
+   typedef short ogg_int16_t;
+
+#elif defined(__SYMBIAN32__)
+
+   /* Symbian GCC */
+   typedef signed short ogg_int16_t;
+   typedef unsigned short ogg_uint16_t;
+   typedef signed int ogg_int32_t;
+   typedef unsigned int ogg_uint32_t;
+   typedef long long int ogg_int64_t;
+
+#elif defined(__TMS320C6X__)
+
+   /* TI C64x compiler */
+   typedef signed short ogg_int16_t;
+   typedef unsigned short ogg_uint16_t;
+   typedef signed int ogg_int32_t;
+   typedef unsigned int ogg_uint32_t;
+   typedef long long int ogg_int64_t;
+
+#else
+
+#  include <ogg/config_types.h>
+
+#endif
+
+#endif  /* _OS_TYPES_H */

+ 203 - 0
components/codecs/inc/vorbis/ivorbiscodec.h

@@ -0,0 +1,203 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
+ *                                                                  *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002    *
+ * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+ function: libvorbis codec headers
+
+ ********************************************************************/
+
+#ifndef _vorbis_codec_h_
+#define _vorbis_codec_h_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#include <ogg/ogg.h>
+
+typedef struct vorbis_info{
+  int version;
+  int channels;
+  long rate;
+
+  /* The below bitrate declarations are *hints*.
+     Combinations of the three values carry the following implications:
+     
+     all three set to the same value: 
+       implies a fixed rate bitstream
+     only nominal set: 
+       implies a VBR stream that averages the nominal bitrate.  No hard 
+       upper/lower limit
+     upper and or lower set: 
+       implies a VBR bitstream that obeys the bitrate limits. nominal 
+       may also be set to give a nominal rate.
+     none set:
+       the coder does not care to speculate.
+  */
+
+  long bitrate_upper;
+  long bitrate_nominal;
+  long bitrate_lower;
+  long bitrate_window;
+
+  void *codec_setup;
+} vorbis_info;
+
+/* vorbis_dsp_state buffers the current vorbis audio
+   analysis/synthesis state.  The DSP state belongs to a specific
+   logical bitstream ****************************************************/
+typedef struct vorbis_dsp_state{
+  int analysisp;
+  vorbis_info *vi;
+
+  ogg_int32_t **pcm;
+  ogg_int32_t **pcmret;
+  int      pcm_storage;
+  int      pcm_current;
+  int      pcm_returned;
+
+  int  preextrapolate;
+  int  eofflag;
+
+  long lW;
+  long W;
+  long nW;
+  long centerW;
+
+  ogg_int64_t granulepos;
+  ogg_int64_t sequence;
+
+  void       *backend_state;
+} vorbis_dsp_state;
+
+typedef struct vorbis_block{
+  /* necessary stream state for linking to the framing abstraction */
+  ogg_int32_t  **pcm;       /* this is a pointer into local storage */ 
+  oggpack_buffer opb;
+  
+  long  lW;
+  long  W;
+  long  nW;
+  int   pcmend;
+  int   mode;
+
+  int         eofflag;
+  ogg_int64_t granulepos;
+  ogg_int64_t sequence;
+  vorbis_dsp_state *vd; /* For read-only access of configuration */
+
+  /* local storage to avoid remallocing; it's up to the mapping to
+     structure it */
+  void               *localstore;
+  long                localtop;
+  long                localalloc;
+  long                totaluse;
+  struct alloc_chain *reap;
+
+} vorbis_block;
+
+/* vorbis_block is a single block of data to be processed as part of
+the analysis/synthesis stream; it belongs to a specific logical
+bitstream, but is independant from other vorbis_blocks belonging to
+that logical bitstream. *************************************************/
+
+struct alloc_chain{
+  void *ptr;
+  struct alloc_chain *next;
+};
+
+/* vorbis_info contains all the setup information specific to the
+   specific compression/decompression mode in progress (eg,
+   psychoacoustic settings, channel setup, options, codebook
+   etc). vorbis_info and substructures are in backends.h.
+*********************************************************************/
+
+/* the comments are not part of vorbis_info so that vorbis_info can be
+   static storage */
+typedef struct vorbis_comment{
+  /* unlimited user comment fields.  libvorbis writes 'libvorbis'
+     whatever vendor is set to in encode */
+  char **user_comments;
+  int   *comment_lengths;
+  int    comments;
+  char  *vendor;
+
+} vorbis_comment;
+
+
+/* libvorbis encodes in two abstraction layers; first we perform DSP
+   and produce a packet (see docs/analysis.txt).  The packet is then
+   coded into a framed OggSquish bitstream by the second layer (see
+   docs/framing.txt).  Decode is the reverse process; we sync/frame
+   the bitstream and extract individual packets, then decode the
+   packet back into PCM audio.
+
+   The extra framing/packetizing is used in streaming formats, such as
+   files.  Over the net (such as with UDP), the framing and
+   packetization aren't necessary as they're provided by the transport
+   and the streaming layer is not used */
+
+/* Vorbis PRIMITIVES: general ***************************************/
+
+extern void     vorbis_info_init(vorbis_info *vi);
+extern void     vorbis_info_clear(vorbis_info *vi);
+extern int      vorbis_info_blocksize(vorbis_info *vi,int zo);
+extern void     vorbis_comment_init(vorbis_comment *vc);
+extern void     vorbis_comment_add(vorbis_comment *vc, char *comment); 
+extern void     vorbis_comment_add_tag(vorbis_comment *vc, 
+				       char *tag, char *contents);
+extern char    *vorbis_comment_query(vorbis_comment *vc, char *tag, int count);
+extern int      vorbis_comment_query_count(vorbis_comment *vc, char *tag);
+extern void     vorbis_comment_clear(vorbis_comment *vc);
+
+extern int      vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb);
+extern int      vorbis_block_clear(vorbis_block *vb);
+extern void     vorbis_dsp_clear(vorbis_dsp_state *v);
+
+/* Vorbis PRIMITIVES: synthesis layer *******************************/
+extern int      vorbis_synthesis_idheader(ogg_packet *op);
+extern int      vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,
+					  ogg_packet *op);
+
+extern int      vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi);
+extern int      vorbis_synthesis_restart(vorbis_dsp_state *v);
+extern int      vorbis_synthesis(vorbis_block *vb,ogg_packet *op);
+extern int      vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op);
+extern int      vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb);
+extern int      vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm);
+extern int      vorbis_synthesis_read(vorbis_dsp_state *v,int samples);
+extern long     vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op);
+
+/* Vorbis ERRORS and return codes ***********************************/
+
+#define OV_FALSE      -1  
+#define OV_EOF        -2
+#define OV_HOLE       -3
+
+#define OV_EREAD      -128
+#define OV_EFAULT     -129
+#define OV_EIMPL      -130
+#define OV_EINVAL     -131
+#define OV_ENOTVORBIS -132
+#define OV_EBADHEADER -133
+#define OV_EVERSION   -134
+#define OV_ENOTAUDIO  -135
+#define OV_EBADPACKET -136
+#define OV_EBADLINK   -137
+#define OV_ENOSEEK    -138
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif

+ 130 - 0
components/codecs/inc/vorbis/vorbisfile.h

@@ -0,0 +1,130 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
+ *                                                                  *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002    *
+ * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+ function: stdio-based convenience library for opening/seeking/decoding
+
+ ********************************************************************/
+
+#ifndef _OV_FILE_H_
+#define _OV_FILE_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#include <stdio.h>
+#include "ivorbiscodec.h"
+
+#define CHUNKSIZE 65535
+#define READSIZE  1024
+/* The function prototypes for the callbacks are basically the same as for
+ * the stdio functions fread, fseek, fclose, ftell. 
+ * The one difference is that the FILE * arguments have been replaced with
+ * a void * - this is to be used as a pointer to whatever internal data these
+ * functions might need. In the stdio case, it's just a FILE * cast to a void *
+ * 
+ * If you use other functions, check the docs for these functions and return
+ * the right values. For seek_func(), you *MUST* return -1 if the stream is
+ * unseekable
+ */
+typedef struct {
+  size_t (*read_func)  (void *ptr, size_t size, size_t nmemb, void *datasource);
+  int    (*seek_func)  (void *datasource, ogg_int64_t offset, int whence);
+  int    (*close_func) (void *datasource);
+  long   (*tell_func)  (void *datasource);
+} ov_callbacks;
+
+#define  NOTOPEN   0
+#define  PARTOPEN  1
+#define  OPENED    2
+#define  STREAMSET 3
+#define  INITSET   4
+
+typedef struct OggVorbis_File {
+  void            *datasource; /* Pointer to a FILE *, etc. */
+  int              seekable;
+  ogg_int64_t      offset;
+  ogg_int64_t      end;
+  ogg_sync_state   oy;
+
+  /* If the FILE handle isn't seekable (eg, a pipe), only the current
+     stream appears */
+  int              links;
+  ogg_int64_t     *offsets;
+  ogg_int64_t     *dataoffsets;
+  ogg_uint32_t    *serialnos;
+  ogg_int64_t     *pcmlengths;
+  vorbis_info     *vi;
+  vorbis_comment  *vc;
+
+  /* Decoding working state local storage */
+  ogg_int64_t      pcm_offset;
+  int              ready_state;
+  ogg_uint32_t     current_serialno;
+  int              current_link;
+
+  ogg_int64_t      bittrack;
+  ogg_int64_t      samptrack;
+
+  ogg_stream_state os; /* take physical pages, weld into a logical
+                          stream of packets */
+  vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
+  vorbis_block     vb; /* local working space for packet->PCM decode */
+
+  ov_callbacks callbacks;
+
+} OggVorbis_File;
+
+extern int ov_clear(OggVorbis_File *vf);
+extern int ov_open(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes);
+extern int ov_open_callbacks(void *datasource, OggVorbis_File *vf,
+		const char *initial, long ibytes, ov_callbacks callbacks);
+
+extern int ov_test(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes);
+extern int ov_test_callbacks(void *datasource, OggVorbis_File *vf,
+		const char *initial, long ibytes, ov_callbacks callbacks);
+extern int ov_test_open(OggVorbis_File *vf);
+
+extern long ov_bitrate(OggVorbis_File *vf,int i);
+extern long ov_bitrate_instant(OggVorbis_File *vf);
+extern long ov_streams(OggVorbis_File *vf);
+extern long ov_seekable(OggVorbis_File *vf);
+extern long ov_serialnumber(OggVorbis_File *vf,int i);
+
+extern ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i);
+extern ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i);
+extern ogg_int64_t ov_time_total(OggVorbis_File *vf,int i);
+
+extern int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos);
+extern int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos);
+extern int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos);
+extern int ov_time_seek(OggVorbis_File *vf,ogg_int64_t pos);
+extern int ov_time_seek_page(OggVorbis_File *vf,ogg_int64_t pos);
+
+extern ogg_int64_t ov_raw_tell(OggVorbis_File *vf);
+extern ogg_int64_t ov_pcm_tell(OggVorbis_File *vf);
+extern ogg_int64_t ov_time_tell(OggVorbis_File *vf);
+
+extern vorbis_info *ov_info(OggVorbis_File *vf,int link);
+extern vorbis_comment *ov_comment(OggVorbis_File *vf,int link);
+
+extern long ov_read(OggVorbis_File *vf,char *buffer,int length,
+		    int *bitstream);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
+

BIN
components/codecs/lib/libesp-ogg-container.a


BIN
components/codecs/lib/libesp-tremor.a


BIN
components/codecs/lib/libesp_processing.a


BIN
components/codecs/lib/libmad.a


BIN
components/codecs/lib/libogg.a


BIN
components/codecs/lib/libvorbisidec.a


+ 1 - 2
main/decode.c

@@ -54,6 +54,7 @@ static bool running = true;
 #endif
 
 static void *decode_thread() {
+	
 
 	while (running) {
 		size_t bytes, space, min_space;
@@ -171,10 +172,8 @@ void decode_init(log_level level, const char *include_codecs, const char *exclud
 	if (!strstr(exclude_codecs, "aac")	&& (!include_codecs || (order_codecs = strstr(include_codecs, "aac"))))
 		sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_faad());
 #endif
-/*
 	if (!strstr(exclude_codecs, "ogg")	&& (!include_codecs || (order_codecs = strstr(include_codecs, "ogg"))))
 		sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_vorbis());
-*/	
 
 	if (!strstr(exclude_codecs, "flac") && (!include_codecs || (order_codecs = strstr(include_codecs, "flac"))))
 		sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_flac());

+ 5 - 1
main/squeezelite.h

@@ -280,8 +280,12 @@
 #include <sys/types.h>
 #endif /* SUN */
 
+#ifndef PTHREAD_STACK_MIN
+#define PTHREAD_STACK_MIN	256
+#endif
+
 #define STREAM_THREAD_STACK_SIZE  8 * 1024
-#define DECODE_THREAD_STACK_SIZE 32 * 1024
+#define DECODE_THREAD_STACK_SIZE 20 * 1024
 #define OUTPUT_THREAD_STACK_SIZE  8 * 1024
 #define IR_THREAD_STACK_SIZE      8 * 1024
 #if !OSX

+ 339 - 0
main/vorbis.c

@@ -0,0 +1,339 @@
+/* 
+ *  Squeezelite - lightweight headless squeezebox emulator
+ *
+ *  (c) Adrian Smith 2012-2015, triode1@btinternet.com
+ *      Ralph Irving 2015-2017, ralph_irving@hotmail.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "squeezelite.h"
+
+// automatically select between floating point (preferred) and fixed point libraries:
+// NOTE: works with Tremor version here: http://svn.xiph.org/trunk/Tremor, not vorbisidec.1.0.2 currently in ubuntu
+
+// we take common definations from <vorbis/vorbisfile.h> even though we can use tremor at run time
+// tremor's OggVorbis_File struct is normally smaller so this is ok, but padding added to malloc in case it is bigger
+#define OV_EXCLUDE_STATIC_CALLBACKS
+
+#include <vorbis/vorbisfile.h>
+
+struct vorbis {
+	OggVorbis_File *vf;
+	bool opened;
+#if !LINKALL
+	// vorbis symbols to be dynamically loaded - from either vorbisfile or vorbisidec (tremor) version of library
+	vorbis_info *(* ov_info)(OggVorbis_File *vf, int link);
+	int (* ov_clear)(OggVorbis_File *vf);
+	long (* ov_read)(OggVorbis_File *vf, char *buffer, int length, int bigendianp, int word, int sgned, int *bitstream);
+	long (* ov_read_tremor)(OggVorbis_File *vf, char *buffer, int length, int *bitstream);
+	int (* ov_open_callbacks)(void *datasource, OggVorbis_File *vf, const char *initial, long ibytes, ov_callbacks callbacks);
+#endif
+};
+
+static struct vorbis *v;
+
+extern log_level loglevel;
+
+extern struct buffer *streambuf;
+extern struct buffer *outputbuf;
+extern struct streamstate stream;
+extern struct outputstate output;
+extern struct decodestate decode;
+extern struct processstate process;
+
+#define LOCK_S   mutex_lock(streambuf->mutex)
+#define UNLOCK_S mutex_unlock(streambuf->mutex)
+#define LOCK_O   mutex_lock(outputbuf->mutex)
+#define UNLOCK_O mutex_unlock(outputbuf->mutex)
+#if PROCESS
+#define LOCK_O_direct   if (decode.direct) mutex_lock(outputbuf->mutex)
+#define UNLOCK_O_direct if (decode.direct) mutex_unlock(outputbuf->mutex)
+#define LOCK_O_not_direct   if (!decode.direct) mutex_lock(outputbuf->mutex)
+#define UNLOCK_O_not_direct if (!decode.direct) mutex_unlock(outputbuf->mutex)
+#define IF_DIRECT(x)    if (decode.direct) { x }
+#define IF_PROCESS(x)   if (!decode.direct) { x }
+#else
+#define LOCK_O_direct   mutex_lock(outputbuf->mutex)
+#define UNLOCK_O_direct mutex_unlock(outputbuf->mutex)
+#define LOCK_O_not_direct
+#define UNLOCK_O_not_direct
+#define IF_DIRECT(x)    { x }
+#define IF_PROCESS(x)
+#endif
+
+#if LINKALL
+#define OV(h, fn, ...) (ov_ ## fn)(__VA_ARGS__)
+#define TREMOR(h)      0
+#if !WIN
+extern int ov_read_tremor(); // needed to enable compilation, not linked
+#endif
+#else
+#define OV(h, fn, ...) (h)->ov_##fn(__VA_ARGS__)
+#define TREMOR(h)      (h)->ov_read_tremor
+#endif
+
+// called with mutex locked within vorbis_decode to avoid locking O before S
+static size_t _read_cb(void *ptr, size_t size, size_t nmemb, void *datasource) {
+	size_t bytes;
+
+	bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf));
+	bytes = min(bytes, size * nmemb);
+
+	memcpy(ptr, streambuf->readp, bytes);
+	_buf_inc_readp(streambuf, bytes);
+
+	return bytes / size;
+}
+
+// these are needed for older versions of tremor, later versions and libvorbis allow NULL to be used
+static int _seek_cb(void *datasource, ogg_int64_t offset, int whence) {  return -1; }
+static int _close_cb(void *datasource) { return 0; }
+static long _tell_cb(void *datasource) { return 0; }
+
+static decode_state vorbis_decode(void) {
+	static int channels;
+	bool end;
+	frames_t frames;
+	int bytes, s, n;
+	u8_t *write_buf;
+
+	LOCK_S;
+	LOCK_O_direct;
+	end = (stream.state <= DISCONNECT);
+
+	IF_DIRECT(
+		frames = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME;
+	);
+	IF_PROCESS(
+		frames = process.max_in_frames;
+	);
+
+	if (!frames && end) {
+		UNLOCK_O_direct;
+		UNLOCK_S;
+		return DECODE_COMPLETE;
+	}
+
+	if (decode.new_stream) {
+		ov_callbacks cbs;
+		int err;
+		struct vorbis_info *info;
+
+		cbs.read_func = _read_cb;
+		
+		if (TREMOR(v)) {
+			cbs.seek_func = _seek_cb; cbs.close_func = _close_cb; cbs.tell_func = _tell_cb;
+		} else {
+			cbs.seek_func = NULL; cbs.close_func = NULL; cbs.tell_func = NULL;
+		}
+
+		if ((err = OV(v, open_callbacks, streambuf, v->vf, NULL, 0, cbs)) < 0) {
+			LOG_WARN("open_callbacks error: %d", err);
+			UNLOCK_O_direct;
+			UNLOCK_S;
+			return DECODE_COMPLETE;
+		}
+		v->opened = true;
+
+		info = OV(v, info, v->vf, -1);
+				
+		LOG_INFO("setting track_start");
+		LOCK_O_not_direct;
+		output.next_sample_rate = decode_newstream(info->rate, output.supported_rates); 
+		IF_DSD(	output.next_fmt = PCM; )
+		output.track_start = outputbuf->writep;
+		if (output.fade_mode) _checkfade(true);
+		decode.new_stream = false;
+		UNLOCK_O_not_direct;
+
+		IF_PROCESS(
+			frames = process.max_in_frames;
+		);
+
+		channels = info->channels;
+
+		if (channels > 2) {
+			LOG_WARN("too many channels: %d", channels);
+			UNLOCK_O_direct;
+			UNLOCK_S;
+			return DECODE_ERROR;
+		}
+	}
+
+	bytes = frames * 2 * channels; // samples returned are 16 bits
+
+	IF_DIRECT(
+		write_buf = outputbuf->writep;
+	);
+	IF_PROCESS(
+		write_buf = process.inbuf;
+	);
+
+	// write the decoded frames into outputbuf even though they are 16 bits per sample, then unpack them
+#if 0	
+	if (!TREMOR(v)) {
+#if SL_LITTLE_ENDIAN
+		n = OV(v, read, v->vf, (char *)write_buf, bytes, 0, 2, 1, &s);
+#else
+		n = OV(v, read, v->vf, (char *)write_buf, bytes, 1, 2, 1, &s);
+#endif
+#if !WIN
+	} else {
+		n = OV(v, read_tremor, v->vf, (char *)write_buf, bytes, &s);
+#endif
+	}
+#endif	
+	n = OV(v, read, v->vf, (char *)write_buf, bytes, &s);
+	
+	if (n > 0) {
+
+		frames_t count;
+		s16_t *iptr;
+		s32_t *optr;
+
+		frames = n / 2 / channels;
+		count = frames * channels;
+
+		// work backward to unpack samples to 4 bytes per sample
+		iptr = (s16_t *)write_buf + count;
+		optr = (s32_t *)write_buf + frames * 2;
+
+		if (channels == 2) {
+			while (count--) {
+				*--optr = *--iptr << 16;
+			}
+		} else if (channels == 1) {
+			while (count--) {
+				*--optr = *--iptr << 16;
+				*--optr = *iptr   << 16;
+			}
+		}
+
+		IF_DIRECT(
+			_buf_inc_writep(outputbuf, frames * BYTES_PER_FRAME);
+		);
+		IF_PROCESS(
+			process.in_frames = frames;
+		);
+
+		LOG_SDEBUG("wrote %u frames", frames);
+
+	} else if (n == 0) {
+
+		LOG_INFO("end of stream");
+		UNLOCK_O_direct;
+		UNLOCK_S;
+		return DECODE_COMPLETE;
+
+	} else if (n == OV_HOLE) {
+
+		// recoverable hole in stream, seen when skipping
+		LOG_DEBUG("hole in stream");
+	
+	} else {
+
+		LOG_INFO("ov_read error: %d", n);
+		UNLOCK_O_direct;
+		UNLOCK_S;
+		return DECODE_COMPLETE;
+	}
+
+	UNLOCK_O_direct;
+	UNLOCK_S;
+
+	return DECODE_RUNNING;
+}
+
+static void vorbis_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) {
+	if (!v->vf) {
+		v->vf = malloc(sizeof(OggVorbis_File) + 128); // add some padding as struct size may be larger
+		memset(v->vf, 0, sizeof(OggVorbis_File) + 128);
+	} else {
+		if (v->opened) {
+			OV(v, clear, v->vf);
+			v->opened = false;
+		}
+	}
+}
+
+static void vorbis_close(void) {
+	if (v->opened) {
+		OV(v, clear, v->vf);
+		v->opened = false;
+	}
+	free(v->vf);
+	v->vf = NULL;
+}
+
+static bool load_vorbis() {
+#if !LINKALL
+	void *handle = dlopen(LIBVORBIS, RTLD_NOW);
+	char *err;
+	bool tremor = false;
+
+	if (!handle) {
+		handle = dlopen(LIBTREMOR, RTLD_NOW);
+		if (handle) {
+			tremor = true;
+		} else {
+			LOG_INFO("dlerror: %s", dlerror());
+			return false;
+		}
+	}
+
+	v->ov_read = tremor ? NULL : dlsym(handle, "ov_read");
+	v->ov_read_tremor = tremor ? dlsym(handle, "ov_read") : NULL;
+	v->ov_info = dlsym(handle, "ov_info");
+	v->ov_clear = dlsym(handle, "ov_clear");
+	v->ov_open_callbacks = dlsym(handle, "ov_open_callbacks");
+	
+	if ((err = dlerror()) != NULL) {
+		LOG_INFO("dlerror: %s", err);		
+		return false;
+	}
+	
+	LOG_INFO("loaded %s", tremor ? LIBTREMOR : LIBVORBIS);
+#endif
+
+	return true;
+}
+
+struct codec *register_vorbis(void) {
+	static struct codec ret = {
+		'o',          // id
+		"ogg",        // types
+		4096,         // min read
+		40960,        // min space
+		vorbis_open,  // open
+		vorbis_close, // close
+		vorbis_decode,// decode
+	};
+
+	v = malloc(sizeof(struct vorbis));
+	if (!v) {
+		return NULL;
+	}
+
+	v->vf = NULL;
+	v->opened = false;
+
+	if (!load_vorbis()) {
+		return NULL;
+	}
+
+	LOG_INFO("using vorbis to decode ogg");
+	return &ret;
+}