|
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 |
}
|