[svn-commits] rmudgett: branch 10 r355375 - in /branches/10: ./ formats/ include/asterisk/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Feb 14 13:22:33 CST 2012


Author: rmudgett
Date: Tue Feb 14 13:22:28 2012
New Revision: 355375

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=355375
Log:
Fix voicemail problems when using ogg/vorbis.

Ogg/vorbis was fairly useless as a voicemail file format because it did
not implement the seek and tell format callbacks among other problems.

Since we were already using the libvorbis and libvorbisenc libraries we
can use libvorbisfile as it is also part of the vorbis library package.

* Made use the libvorbisfile to handle the ogg/vorbis file stream.  The
format_ogg_vorbis.c is now mostly a wrapper around libvorbisfile.

(closes issue ASTERISK-16926)
Reported by: sque
Patches:
      ogg_vorbis_use_libvorbisfile.patch (license #6108) patch uploaded by sque
........

Merged revisions 355365 from http://svn.asterisk.org/svn/asterisk/branches/1.8

Modified:
    branches/10/   (props changed)
    branches/10/configure
    branches/10/configure.ac
    branches/10/formats/format_ogg_vorbis.c
    branches/10/include/asterisk/autoconfig.h.in

Propchange: branches/10/
------------------------------------------------------------------------------
Binary property 'branch-1.8-merged' - no diff available.

Modified: branches/10/configure.ac
URL: http://svnview.digium.com/svn/asterisk/branches/10/configure.ac?view=diff&rev=355375&r1=355374&r2=355375
==============================================================================
--- branches/10/configure.ac (original)
+++ branches/10/configure.ac Tue Feb 14 13:22:28 2012
@@ -2108,9 +2108,9 @@
 
 if test "${OSARCH}" = "OpenBSD";
 then
-	AST_EXT_LIB_CHECK([VORBIS], [vorbis], [vorbis_info_init], [vorbis/codec.h], [-lm -lvorbisenc -logg])
+	AST_EXT_LIB_CHECK([VORBIS], [vorbis], [vorbis_info_init], [vorbis/codec.h], [-lm -lvorbisenc -lvorbisfile -logg])
 else
-	AST_EXT_LIB_CHECK([VORBIS], [vorbis], [vorbis_info_init], [vorbis/codec.h], [-lm -lvorbisenc])
+	AST_EXT_LIB_CHECK([VORBIS], [vorbis], [vorbis_info_init], [vorbis/codec.h], [-lm -lvorbisenc -lvorbisfile])
 fi
 
 AC_LANG_PUSH(C++)

Modified: branches/10/formats/format_ogg_vorbis.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/formats/format_ogg_vorbis.c?view=diff&rev=355375&r1=355374&r2=355375
==============================================================================
--- branches/10/formats/format_ogg_vorbis.c (original)
+++ branches/10/formats/format_ogg_vorbis.c Tue Feb 14 13:22:28 2012
@@ -37,6 +37,7 @@
 
 #include <vorbis/codec.h>
 #include <vorbis/vorbisenc.h>
+#include <vorbis/vorbisfile.h>
 
 #ifdef _WIN32
 #include <io.h>
@@ -49,14 +50,16 @@
  * this is the number of samples we deal with. Samples are converted
  * to SLINEAR so each one uses 2 bytes in the buffer.
  */
-#define SAMPLES_MAX 160
+#define SAMPLES_MAX 512
 #define	BUF_SIZE	(2*SAMPLES_MAX)
 
 #define BLOCK_SIZE 4096		/* used internally in the vorbis routines */
 
-struct vorbis_desc {	/* format specific parameters */
+struct ogg_vorbis_desc {	/* format specific parameters */
+	/* OggVorbis_File structure for libvorbisfile interface */
+	OggVorbis_File ov_f;
+
 	/* structures for handling the Ogg container */
-	ogg_sync_state oy;
 	ogg_stream_state os;
 	ogg_page og;
 	ogg_packet op;
@@ -69,7 +72,10 @@
 	
 	/*! \brief Indicates whether this filestream is set up for reading or writing. */
 	int writing;
-	
+
+	/*! \brief Stores the current pcm position to support tell() on writing mode. */
+	off_t writing_pcm_pos;
+
 	/*! \brief Indicates whether an End of Stream condition has been detected. */
 	int eos;
 };
@@ -81,105 +87,32 @@
  */
 static int ogg_vorbis_open(struct ast_filestream *s)
 {
-	int i;
-	int bytes;
 	int result;
-	char **ptr;
-	char *buffer;
-	struct vorbis_desc *tmp = (struct vorbis_desc *)s->_private;
-
-	tmp->writing = 0;
-
-	ogg_sync_init(&tmp->oy);
-
-	buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE);
-	bytes = fread(buffer, 1, BLOCK_SIZE, s->f);
-	ogg_sync_wrote(&tmp->oy, bytes);
-
-	result = ogg_sync_pageout(&tmp->oy, &tmp->og);
-	if (result != 1) {
-		if(bytes < BLOCK_SIZE) {
-			ast_log(LOG_ERROR, "Run out of data...\n");
-		} else {
-			ast_log(LOG_ERROR, "Input does not appear to be an Ogg bitstream.\n");
-		}
-		ogg_sync_clear(&tmp->oy);
-		return -1;
-	}
-	
-	ogg_stream_init(&tmp->os, ogg_page_serialno(&tmp->og));
-	vorbis_info_init(&tmp->vi);
-	vorbis_comment_init(&tmp->vc);
-
-	if (ogg_stream_pagein(&tmp->os, &tmp->og) < 0) { 
-		ast_log(LOG_ERROR, "Error reading first page of Ogg bitstream data.\n");
-error:
-		ogg_stream_clear(&tmp->os);
-		vorbis_comment_clear(&tmp->vc);
-		vorbis_info_clear(&tmp->vi);
-		ogg_sync_clear(&tmp->oy);
-		return -1;
-	}
-	
-	if (ogg_stream_packetout(&tmp->os, &tmp->op) != 1) { 
-		ast_log(LOG_ERROR, "Error reading initial header packet.\n");
-		goto error;
-	}
-	
-	if (vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op) < 0) { 
-		ast_log(LOG_ERROR, "This Ogg bitstream does not contain Vorbis audio data.\n");
-		goto error;
-	}
-	
-	for (i = 0; i < 2 ; ) {
-		while (i < 2) {
-			result = ogg_sync_pageout(&tmp->oy, &tmp->og);
-			if (result == 0)
-				break;
-			if (result == 1) {
-				ogg_stream_pagein(&tmp->os, &tmp->og);
-				while(i < 2) {
-					result = ogg_stream_packetout(&tmp->os,&tmp->op);
-					if(result == 0)
-						break;
-					if(result < 0) {
-						ast_log(LOG_ERROR, "Corrupt secondary header.  Exiting.\n");
-						goto error;
-					}
-					vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op);
-					i++;
-				}
-			}
-		}
-
-		buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE);
-		bytes = fread(buffer, 1, BLOCK_SIZE, s->f);
-		if (bytes == 0 && i < 2) {
-			ast_log(LOG_ERROR, "End of file before finding all Vorbis headers!\n");
-			goto error;
-		}
-		ogg_sync_wrote(&tmp->oy, bytes);
-	}
-	
-	for (ptr = tmp->vc.user_comments; *ptr; ptr++)
-		ast_debug(1, "OGG/Vorbis comment: %s\n", *ptr);
-		ast_debug(1, "OGG/Vorbis bitstream is %d channel, %ldHz\n", tmp->vi.channels, tmp->vi.rate);
-		ast_debug(1, "OGG/Vorbis file encoded by: %s\n", tmp->vc.vendor);
-
-	if (tmp->vi.channels != 1) {
+	struct ogg_vorbis_desc *desc = (struct ogg_vorbis_desc *) s->_private;
+
+	/* initialize private description block */
+	memset(desc, 0, sizeof(struct ogg_vorbis_desc));
+	desc->writing = 0;
+
+	/* actually open file */
+	result = ov_open_callbacks(s->f, &desc->ov_f, NULL, 0, OV_CALLBACKS_NOCLOSE);
+	if (result != 0) {
+		ast_log(LOG_ERROR, "Error opening Ogg/Vorbis file stream.\n");
+		return -1;
+	}
+
+	/* check stream(s) type */
+	if (desc->ov_f.vi->channels != 1) {
 		ast_log(LOG_ERROR, "Only monophonic OGG/Vorbis files are currently supported!\n");
-		goto error;
-	}
-	
-	if (tmp->vi.rate != DEFAULT_SAMPLE_RATE) {
+		ov_clear(&desc->ov_f);
+		return -1;
+	}
+
+	if (desc->ov_f.vi->rate != DEFAULT_SAMPLE_RATE) {
 		ast_log(LOG_ERROR, "Only 8000Hz OGG/Vorbis files are currently supported!\n");
-		vorbis_block_clear(&tmp->vb);
-		vorbis_dsp_clear(&tmp->vd);
-		goto error;
-	}
-	
-	vorbis_synthesis_init(&tmp->vd, &tmp->vi);
-	vorbis_block_init(&tmp->vd, &tmp->vb);
+		ov_clear(&desc->ov_f);
+		return -1;
+	}
 
 	return 0;
 }
@@ -196,9 +129,10 @@
 	ogg_packet header;
 	ogg_packet header_comm;
 	ogg_packet header_code;
-	struct vorbis_desc *tmp = (struct vorbis_desc *)s->_private;
+	struct ogg_vorbis_desc *tmp = (struct ogg_vorbis_desc *) s->_private;
 
 	tmp->writing = 1;
+	tmp->writing_pcm_pos = 0;
 
 	vorbis_info_init(&tmp->vi);
 
@@ -244,7 +178,7 @@
  * \param s An OGG/Vorbis filestream.
  * \param f The file to write to.
  */
-static void write_stream(struct vorbis_desc *s, FILE *f)
+static void write_stream(struct ogg_vorbis_desc *s, FILE *f)
 {
 	while (vorbis_analysis_blockout(&s->vd, &s->vb) == 1) {
 		vorbis_analysis(&s->vb, NULL);
@@ -281,7 +215,7 @@
 	int i;
 	float **buffer;
 	short *data;
-	struct vorbis_desc *s = (struct vorbis_desc *)fs->_private;
+	struct ogg_vorbis_desc *s = (struct ogg_vorbis_desc *) fs->_private;
 
 	if (!s->writing) {
 		ast_log(LOG_ERROR, "This stream is not set up for writing!\n");
@@ -311,6 +245,8 @@
 
 	write_stream(s, fs->f);
 
+	s->writing_pcm_pos +=  f->samples;
+
 	return 0;
 }
 
@@ -320,102 +256,16 @@
  */
 static void ogg_vorbis_close(struct ast_filestream *fs)
 {
-	struct vorbis_desc *s = (struct vorbis_desc *)fs->_private;
+	struct ogg_vorbis_desc *s = (struct ogg_vorbis_desc *) fs->_private;
 
 	if (s->writing) {
 		/* Tell the Vorbis encoder that the stream is finished
 		 * and write out the rest of the data */
 		vorbis_analysis_wrote(&s->vd, 0);
 		write_stream(s, fs->f);
-	}
-
-	ogg_stream_clear(&s->os);
-	vorbis_block_clear(&s->vb);
-	vorbis_dsp_clear(&s->vd);
-	vorbis_comment_clear(&s->vc);
-	vorbis_info_clear(&s->vi);
-
-	if (s->writing) {
-		ogg_sync_clear(&s->oy);
-	}
-}
-
-/*!
- * \brief Get audio data.
- * \param fs An OGG/Vorbis filestream.
- * \param pcm Pointer to a buffere to store audio data in.
- */
-
-static int read_samples(struct ast_filestream *fs, float ***pcm)
-{
-	int samples_in;
-	int result;
-	char *buffer;
-	int bytes;
-	struct vorbis_desc *s = (struct vorbis_desc *)fs->_private;
-
-	while (1) {
-		samples_in = vorbis_synthesis_pcmout(&s->vd, pcm);
-		if (samples_in > 0) {
-			return samples_in;
-		}
-
-		/* The Vorbis decoder needs more data... */
-		/* See ifOGG has any packets in the current page for the Vorbis decoder. */
-		result = ogg_stream_packetout(&s->os, &s->op);
-		if (result > 0) {
-			/* Yes OGG had some more packets for the Vorbis decoder. */
-			if (vorbis_synthesis(&s->vb, &s->op) == 0) {
-				vorbis_synthesis_blockin(&s->vd, &s->vb);
-			}
-
-			continue;
-		}
-
-		if (result < 0)
-			ast_log(LOG_WARNING,
-					"Corrupt or missing data at this page position; continuing...\n");
-
-		/* No more packets left in the current page... */
-
-		if (s->eos) {
-			/* No more pages left in the stream */
-			return -1;
-		}
-
-		while (!s->eos) {
-			/* See ifOGG has any pages in it's internal buffers */
-			result = ogg_sync_pageout(&s->oy, &s->og);
-			if (result > 0) {
-				/* Yes, OGG has more pages in it's internal buffers,
-				   add the page to the stream state */
-				result = ogg_stream_pagein(&s->os, &s->og);
-				if (result == 0) {
-					/* Yes, got a new,valid page */
-					if (ogg_page_eos(&s->og)) {
-						s->eos = 1;
-					}
-					break;
-				}
-				ast_log(LOG_WARNING,
-						"Invalid page in the bitstream; continuing...\n");
-			}
-
-			if (result < 0)
-				ast_log(LOG_WARNING,
-						"Corrupt or missing data in bitstream; continuing...\n");
-
-			/* No, we need to read more data from the file descrptor */
-			/* get a buffer from OGG to read the data into */
-			buffer = ogg_sync_buffer(&s->oy, BLOCK_SIZE);
-			/* read more data from the file descriptor */
-			bytes = fread(buffer, 1, BLOCK_SIZE, fs->f);
-			/* Tell OGG how many bytes we actually read into the buffer */
-			ogg_sync_wrote(&s->oy, bytes);
-			if (bytes == 0) {
-				s->eos = 1;
-			}
-		}
+	} else {
+		/* clear OggVorbis_File handle */
+		ov_clear(&s->ov_f);
 	}
 }
 
@@ -428,74 +278,45 @@
 static struct ast_frame *ogg_vorbis_read(struct ast_filestream *fs,
 					 int *whennext)
 {
-	int clipflag = 0;
-	int i;
-	int j;
-	double accumulator[SAMPLES_MAX];
-	int val;
-	int samples_in;
-	int samples_out = 0;
-	struct vorbis_desc *s = (struct vorbis_desc *)fs->_private;
-	short *buf;	/* SLIN data buffer */
-
+	struct ogg_vorbis_desc *desc = (struct ogg_vorbis_desc *) fs->_private;
+	int current_bitstream = -10;
+	char *out_buf;
+	long bytes_read;
+
+	if (desc->writing) {
+		ast_log(LOG_WARNING, "Reading is not suport on OGG/Vorbis on write files.");
+		return NULL;
+	}
+
+	/* initialize frame */
 	fs->fr.frametype = AST_FRAME_VOICE;
 	ast_format_set(&fs->fr.subclass.format, AST_FORMAT_SLINEAR, 0);
 	fs->fr.mallocd = 0;
 	AST_FRAME_SET_BUFFER(&fs->fr, fs->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
-	buf = (short *)(fs->fr.data.ptr);	/* SLIN data buffer */
-
-	while (samples_out != SAMPLES_MAX) {
-		float **pcm;
-		int len = SAMPLES_MAX - samples_out;
-
-		/* See ifVorbis decoder has some audio data for us ... */
-		samples_in = read_samples(fs, &pcm);
-		if (samples_in <= 0)
-			break;
-
-		/* Got some audio data from Vorbis... */
-		/* Convert the float audio data to 16-bit signed linear */
-
-		clipflag = 0;
-		if (samples_in > len)
-			samples_in = len;
-		for (j = 0; j < samples_in; j++)
-			accumulator[j] = 0.0;
-
-		for (i = 0; i < s->vi.channels; i++) {
-			float *mono = pcm[i];
-			for (j = 0; j < samples_in; j++)
-				accumulator[j] += mono[j];
-		}
-
-		for (j = 0; j < samples_in; j++) {
-			val = accumulator[j] * 32767.0 / s->vi.channels;
-			if (val > 32767) {
-				val = 32767;
-				clipflag = 1;
-			} else if (val < -32768) {
-				val = -32768;
-				clipflag = 1;
-			}
-			buf[samples_out + j] = val;
-		}
-
-		if (clipflag)
-			ast_log(LOG_WARNING, "Clipping in frame %ld\n", (long) (s->vd.sequence));
-		/* Tell the Vorbis decoder how many samples we actually used. */
-		vorbis_synthesis_read(&s->vd, samples_in);
-		samples_out += samples_in;
-	}
-
-	if (samples_out > 0) {
-		fs->fr.datalen = samples_out * 2;
-		fs->fr.samples = samples_out;
-		*whennext = samples_out;
-
-		return &fs->fr;
-	} else {
+	out_buf = (char *) (fs->fr.data.ptr);	/* SLIN data buffer */
+
+	/* read samples from OV interface */
+	bytes_read = ov_read(
+		&desc->ov_f,
+		out_buf,						/* Buffer to write data */
+		BUF_SIZE,						/* Size of buffer */
+		(__BYTE_ORDER == __BIG_ENDIAN),	/* Endianes (0 for little) */
+		2,								/* 1 = 8bit, 2 = 16bit */
+		1,								/* 0 = unsigned, 1 = signed */
+		&current_bitstream				/* Returns the current bitstream section */
+	);
+
+	/* check returned data */
+	if (bytes_read <= 0) {
+		/* End of stream */
 		return NULL;
 	}
+
+	/* Return decoded bytes */
+	fs->fr.datalen = bytes_read;
+	fs->fr.samples = bytes_read / 2;
+	*whennext = fs->fr.samples;
+	return &fs->fr;
 }
 
 /*!
@@ -504,29 +325,76 @@
  * \return 0 on success, -1 on failure.
  */
 
-static int ogg_vorbis_trunc(struct ast_filestream *s)
+static int ogg_vorbis_trunc(struct ast_filestream *fs)
 {
 	ast_log(LOG_WARNING, "Truncation is not supported on OGG/Vorbis streams!\n");
 	return -1;
 }
 
 /*!
+ * \brief Tell the current position in OGG/Vorbis filestream measured in pcms.
+ * \param s The filestream to take action on.
+ * \return 0 or greater with the position measured in samples, or -1 for false.
+ */
+static off_t ogg_vorbis_tell(struct ast_filestream *fs)
+{
+	off_t pos;
+	struct ogg_vorbis_desc *desc = (struct ogg_vorbis_desc *) fs->_private;
+
+	if (desc->writing) {
+		return desc->writing_pcm_pos;
+	}
+
+	if ((pos = ov_pcm_tell(&desc->ov_f)) < 0) {
+		return -1;
+	}
+	return pos;
+}
+
+/*!
  * \brief Seek to a specific position in an OGG/Vorbis filestream.
- * \param s The filestream to truncate.
+ * \param s The filestream to take action on.
  * \param sample_offset New position for the filestream, measured in 8KHz samples.
  * \param whence Location to measure 
  * \return 0 on success, -1 on failure.
  */
-static int ogg_vorbis_seek(struct ast_filestream *s, off_t sample_offset, int whence)
-{
-	ast_log(LOG_WARNING, "Seeking is not supported on OGG/Vorbis streams!\n");
-	return -1;
-}
-
-static off_t ogg_vorbis_tell(struct ast_filestream *s)
-{
-	ast_log(LOG_WARNING, "Telling is not supported on OGG/Vorbis streams!\n");
-	return -1;
+static int ogg_vorbis_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
+{
+	int seek_result = -1;
+	off_t relative_pcm_pos;
+	struct ogg_vorbis_desc *desc = (struct ogg_vorbis_desc *) fs->_private;
+
+	if (desc->writing) {
+		ast_log(LOG_WARNING, "Seeking is not supported on OGG/Vorbis streams in writing mode!\n");
+		return -1;
+	}
+
+	/* ov_pcm_seek support seeking only from begining (SEEK_SET), the rest must be emulated */
+	switch (whence) {
+	case SEEK_SET:
+		seek_result = ov_pcm_seek(&desc->ov_f, sample_offset);
+		break;
+	case SEEK_CUR:
+		if ((relative_pcm_pos = ogg_vorbis_tell(fs)) < 0) {
+			seek_result = -1;
+			break;
+		}
+		seek_result = ov_pcm_seek(&desc->ov_f, relative_pcm_pos + sample_offset);
+		break;
+	case SEEK_END:
+		if ((relative_pcm_pos = ov_pcm_total(&desc->ov_f, -1)) < 0) {
+			seek_result = -1;
+			break;
+		}
+		seek_result = ov_pcm_seek(&desc->ov_f, relative_pcm_pos - sample_offset);
+		break;
+	default:
+		ast_log(LOG_WARNING, "Unknown *whence* to seek on OGG/Vorbis streams!\n");
+		break;
+	}
+
+	/* normalize error value to -1,0 */
+	return (seek_result == 0) ? 0 : -1;
 }
 
 static struct ast_format_def vorbis_f = {
@@ -541,7 +409,7 @@
 	.read = ogg_vorbis_read,
 	.close = ogg_vorbis_close,
 	.buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
-	.desc_size = sizeof(struct vorbis_desc),
+	.desc_size = sizeof(struct ogg_vorbis_desc),
 };
 
 static int load_module(void)

Modified: branches/10/include/asterisk/autoconfig.h.in
URL: http://svnview.digium.com/svn/asterisk/branches/10/include/asterisk/autoconfig.h.in?view=diff&rev=355375&r1=355374&r2=355375
==============================================================================
--- branches/10/include/asterisk/autoconfig.h.in (original)
+++ branches/10/include/asterisk/autoconfig.h.in Tue Feb 14 13:22:28 2012
@@ -836,19 +836,19 @@
 /* Define to 1 if you have the `strtoq' function. */
 #undef HAVE_STRTOQ
 
-/* Define to 1 if `ifr_ifru.ifru_hwaddr' is a member of `struct ifreq'. */
+/* Define to 1 if `ifr_ifru.ifru_hwaddr' is member of `struct ifreq'. */
 #undef HAVE_STRUCT_IFREQ_IFR_IFRU_IFRU_HWADDR
 
-/* Define to 1 if `uid' is a member of `struct sockpeercred'. */
+/* Define to 1 if `uid' is member of `struct sockpeercred'. */
 #undef HAVE_STRUCT_SOCKPEERCRED_UID
 
-/* Define to 1 if `st_blksize' is a member of `struct stat'. */
+/* Define to 1 if `st_blksize' is member of `struct stat'. */
 #undef HAVE_STRUCT_STAT_ST_BLKSIZE
 
-/* Define to 1 if `cr_uid' is a member of `struct ucred'. */
+/* Define to 1 if `cr_uid' is member of `struct ucred'. */
 #undef HAVE_STRUCT_UCRED_CR_UID
 
-/* Define to 1 if `uid' is a member of `struct ucred'. */
+/* Define to 1 if `uid' is member of `struct ucred'. */
 #undef HAVE_STRUCT_UCRED_UID
 
 /* Define to 1 if you have the mISDN Supplemental Services library. */
@@ -1125,9 +1125,6 @@
 
 /* Define to the one symbol short name of this package. */
 #undef PACKAGE_TARNAME
-
-/* Define to the home page for this package. */
-#undef PACKAGE_URL
 
 /* Define to the version of this package. */
 #undef PACKAGE_VERSION




More information about the svn-commits mailing list