Blame src/ogg.c

Packit Service 102f81
/* -*- c-basic-offset: 8; -*- */
Packit Service 102f81
/* ogg.c: Generic ogg data handler
Packit Service 102f81
 * $Id: ogg.c 10686 2006-01-03 18:47:54Z brendan $
Packit Service 102f81
 *
Packit Service 102f81
 *  Copyright (C) 2002-2004 the Icecast team <team@icecast.org>
Packit Service 102f81
 *
Packit Service 102f81
 *  This library is free software; you can redistribute it and/or
Packit Service 102f81
 *  modify it under the terms of the GNU Library General Public
Packit Service 102f81
 *  License as published by the Free Software Foundation; either
Packit Service 102f81
 *  version 2 of the License, or (at your option) any later version.
Packit Service 102f81
 *
Packit Service 102f81
 *  This library is distributed in the hope that it will be useful,
Packit Service 102f81
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 102f81
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 102f81
 *  Library General Public License for more details.
Packit Service 102f81
 *
Packit Service 102f81
 *  You should have received a copy of the GNU Library General Public
Packit Service 102f81
 *  License along with this library; if not, write to the Free
Packit Service 102f81
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Packit Service 102f81
 */
Packit Service 102f81
Packit Service 102f81
#ifdef HAVE_CONFIG_H
Packit Service 102f81
 #include <config.h>
Packit Service 102f81
#endif
Packit Service 102f81
Packit Service 102f81
#include <stdlib.h>
Packit Service 102f81
#include <string.h>
Packit Service 102f81
Packit Service 102f81
#ifdef HAVE_INTTYPES_H
Packit Service 102f81
#include <inttypes.h>
Packit Service 102f81
#endif
Packit Service 102f81
Packit Service 102f81
#include <ogg/ogg.h>
Packit Service 102f81
Packit Service 102f81
#include <shout/shout.h>
Packit Service 102f81
#include "shout_private.h"
Packit Service 102f81
#include "shout_ogg.h"
Packit Service 102f81
Packit Service 102f81
/* -- local datatypes -- */
Packit Service 102f81
typedef struct {
Packit Service 102f81
	ogg_sync_state oy;
Packit Service 102f81
	ogg_codec_t *codecs;
Packit Service 102f81
	char bos;
Packit Service 102f81
} ogg_data_t;
Packit Service 102f81
Packit Service 102f81
/* -- static prototypes -- */
Packit Service 102f81
static int send_ogg(shout_t *self, const unsigned char *data, size_t len);
Packit Service 102f81
static void close_ogg(shout_t *self);
Packit Service 102f81
static int open_codec(ogg_codec_t *codec, ogg_page *page);
Packit Service 102f81
static void free_codec(ogg_codec_t *codec);
Packit Service 102f81
static void free_codecs(ogg_data_t *ogg_data);
Packit Service 102f81
static int send_page(shout_t *self, ogg_page *page);
Packit Service 102f81
Packit Service 102f81
typedef int (*codec_open_t)(ogg_codec_t *codec, ogg_page *page);
Packit Service 102f81
static codec_open_t codecs[] = {
Packit Service 102f81
	_shout_open_vorbis,
Packit Service 102f81
#ifdef HAVE_THEORA
Packit Service 102f81
	_shout_open_theora,
Packit Service 102f81
#endif
Packit Service 102f81
#ifdef HAVE_SPEEX
Packit Service 102f81
	_shout_open_speex,
Packit Service 102f81
#endif
Packit Service 102f81
	NULL
Packit Service 102f81
};
Packit Service 102f81
Packit Service 102f81
int shout_open_ogg(shout_t *self)
Packit Service 102f81
{
Packit Service 102f81
	ogg_data_t *ogg_data;
Packit Service 102f81
Packit Service 102f81
	if (!(ogg_data = (ogg_data_t *)calloc(1, sizeof(ogg_data_t))))
Packit Service 102f81
		return self->error = SHOUTERR_MALLOC;
Packit Service 102f81
	self->format_data = ogg_data;
Packit Service 102f81
Packit Service 102f81
	ogg_sync_init(&ogg_data->oy);
Packit Service 102f81
	ogg_data->bos = 1;
Packit Service 102f81
Packit Service 102f81
	self->send = send_ogg;
Packit Service 102f81
	self->close = close_ogg;
Packit Service 102f81
Packit Service 102f81
	return SHOUTERR_SUCCESS;
Packit Service 102f81
}
Packit Service 102f81
Packit Service 102f81
static int send_ogg(shout_t *self, const unsigned char *data, size_t len)
Packit Service 102f81
{
Packit Service 102f81
	ogg_data_t *ogg_data = (ogg_data_t *)self->format_data;
Packit Service 102f81
	ogg_codec_t *codec;
Packit Service 102f81
	char *buffer;
Packit Service 102f81
	ogg_page page;
Packit Service 102f81
Packit Service 102f81
	buffer = ogg_sync_buffer(&ogg_data->oy, len);
Packit Service 102f81
	memcpy(buffer, data, len);
Packit Service 102f81
	ogg_sync_wrote(&ogg_data->oy, len);
Packit Service 102f81
Packit Service 102f81
	while (ogg_sync_pageout(&ogg_data->oy, &page) == 1) {
Packit Service 102f81
		if (ogg_page_bos (&page)) {
Packit Service 102f81
			if (! ogg_data->bos) {
Packit Service 102f81
				free_codecs(ogg_data);
Packit Service 102f81
				ogg_data->bos = 1;
Packit Service 102f81
			}
Packit Service 102f81
Packit Service 102f81
			codec = calloc(1, sizeof(ogg_codec_t));
Packit Service 102f81
			if (! codec)
Packit Service 102f81
				return self->error = SHOUTERR_MALLOC;
Packit Service 102f81
			
Packit Service 102f81
			if ((self->error = open_codec(codec, &page)) != SHOUTERR_SUCCESS)
Packit Service 102f81
				return self->error;
Packit Service 102f81
Packit Service 102f81
			codec->headers = 1;
Packit Service 102f81
			codec->senttime = self->senttime;
Packit Service 102f81
			codec->next = ogg_data->codecs;
Packit Service 102f81
			ogg_data->codecs = codec;
Packit Service 102f81
		} else {
Packit Service 102f81
			ogg_data->bos = 0;
Packit Service 102f81
Packit Service 102f81
			codec = ogg_data->codecs;
Packit Service 102f81
			while (codec) {
Packit Service 102f81
				if (ogg_page_serialno(&page) == codec->os.serialno) {
Packit Service 102f81
					if (codec->read_page) {
Packit Service 102f81
						ogg_stream_pagein(&codec->os, &page);
Packit Service 102f81
						codec->read_page(codec, &page);
Packit Service 102f81
Packit Service 102f81
						if (self->senttime < codec->senttime)
Packit Service 102f81
							self->senttime = codec->senttime;
Packit Service 102f81
					}
Packit Service 102f81
					
Packit Service 102f81
					break;
Packit Service 102f81
				}
Packit Service 102f81
Packit Service 102f81
				codec = codec->next;
Packit Service 102f81
			}
Packit Service 102f81
		}
Packit Service 102f81
Packit Service 102f81
		if ((self->error = send_page(self, &page)) != SHOUTERR_SUCCESS)
Packit Service 102f81
			return self->error;
Packit Service 102f81
	}
Packit Service 102f81
Packit Service 102f81
	return self->error = SHOUTERR_SUCCESS;
Packit Service 102f81
}
Packit Service 102f81
Packit Service 102f81
static void close_ogg(shout_t *self)
Packit Service 102f81
{
Packit Service 102f81
	ogg_data_t *ogg_data = (ogg_data_t *)self->format_data;
Packit Service 102f81
	free_codecs(ogg_data);
Packit Service 102f81
	ogg_sync_clear(&ogg_data->oy);
Packit Service 102f81
	free(ogg_data);
Packit Service 102f81
}
Packit Service 102f81
Packit Service 102f81
static int open_codec(ogg_codec_t *codec, ogg_page *page)
Packit Service 102f81
{
Packit Service 102f81
	codec_open_t this_codec;
Packit Service 102f81
	int i = 0;
Packit Service 102f81
Packit Service 102f81
	while ((this_codec = codecs[i])) {
Packit Service 102f81
		ogg_stream_init(&codec->os, ogg_page_serialno(page));
Packit Service 102f81
		ogg_stream_pagein(&codec->os, page);
Packit Service 102f81
Packit Service 102f81
		if (this_codec(codec, page) == SHOUTERR_SUCCESS)
Packit Service 102f81
			return SHOUTERR_SUCCESS;
Packit Service 102f81
Packit Service 102f81
		ogg_stream_clear(&codec->os);
Packit Service 102f81
		i++;
Packit Service 102f81
	}
Packit Service 102f81
	
Packit Service 102f81
	/* if no handler is found, we currently just fall back to untimed send_raw */
Packit Service 102f81
	return SHOUTERR_SUCCESS;
Packit Service 102f81
}
Packit Service 102f81
Packit Service 102f81
static void free_codecs(ogg_data_t *ogg_data)
Packit Service 102f81
{
Packit Service 102f81
	ogg_codec_t *codec, *next;
Packit Service 102f81
Packit Service 102f81
	if (ogg_data == NULL)
Packit Service 102f81
		return;
Packit Service 102f81
Packit Service 102f81
	codec = ogg_data->codecs;
Packit Service 102f81
	while (codec) {
Packit Service 102f81
		next = codec->next;
Packit Service 102f81
		free_codec(codec);
Packit Service 102f81
		codec = next;
Packit Service 102f81
	}
Packit Service 102f81
	ogg_data->codecs = NULL;
Packit Service 102f81
}
Packit Service 102f81
Packit Service 102f81
static void free_codec(ogg_codec_t *codec)
Packit Service 102f81
{
Packit Service 102f81
	if (codec->free_data)
Packit Service 102f81
		codec->free_data(codec->codec_data);
Packit Service 102f81
	ogg_stream_clear(&codec->os);
Packit Service 102f81
	free(codec);
Packit Service 102f81
}
Packit Service 102f81
Packit Service 102f81
static int send_page(shout_t *self, ogg_page *page)
Packit Service 102f81
{
Packit Service 102f81
	int ret;
Packit Service 102f81
Packit Service 102f81
	ret = shout_send_raw(self, page->header, page->header_len);
Packit Service 102f81
	if (ret != page->header_len)
Packit Service 102f81
		return self->error = SHOUTERR_SOCKET;
Packit Service 102f81
	ret = shout_send_raw(self, page->body, page->body_len);
Packit Service 102f81
	if (ret != page->body_len)
Packit Service 102f81
		return self->error = SHOUTERR_SOCKET;
Packit Service 102f81
Packit Service 102f81
	return SHOUTERR_SUCCESS;
Packit Service 102f81
}