Commit e272e734 authored by Philipp Schafft's avatar Philipp Schafft 🦁

Merge branch 'ph3-feature-opus' into devel

parents f1f6793c d24e05e9
......@@ -183,6 +183,14 @@
comments. If a line has a single '-' then standard input is read, which
provides a way of getting some external Ogg Vorbis stream into ices.
</div>
<h4>format</h4>
<div class=indentedbox>
This sets the used codec for input files.
Use "ogg" for generic Ogg handling. In this mode codec specific features
will not available but codec is detected on the fly.
Currently "vorbis" and "ogg" are supported.
By default "vorbis" is used.
</div>
<h4>random</h4>
<div class=indentedbox>
When set to 1, the playlist will be randomised when the playlist is
......@@ -257,7 +265,7 @@
<div class=indentedbox>
The codec to read the audio data in from the sound server.
Currently the values "default", "pcm_s", "pcm_s_le", "pcm_s_be",
"ogg_vorbis" and "ogg_general" are supported.
"ogg_vorbis", "ogg_opus", "ogg_speex", "ogg_flac" and "ogg_general" are supported.
"default" is an alias for "pcm_s" which itself is an alias to "pcm_s_le" or "pcm_s_be" depending
on the native byte order of the system. "ogg_general" should not be used.
</div>
......
......@@ -231,7 +231,7 @@ input_module_t *playlist_open_module(module_param_t *params)
module_param_t *current;
int (*init)(module_param_t *, playlist_state_t *)=NULL;
mod->type = ICES_INPUT_VORBIS;
mod->type = ICES_INPUT_VORBIS; /* Default as it was the historical value */
mod->getdata = playlist_read;
mod->handle_event = event_handler;
mod->metadata_update = NULL; /* Not used for playlists */
......@@ -262,6 +262,22 @@ input_module_t *playlist_open_module(module_param_t *params)
goto fail;
}
}
else if (!strcmp(current->name, "format"))
{
if (!strcmp(current->value, "vorbis"))
{
mod->type = ICES_INPUT_VORBIS;
}
else if (!strcmp(current->value, "ogg"))
{
mod->type = ICES_INPUT_OGG;
}
else
{
LOG_ERROR1("Unknown playlist format \"%s\"", current->value);
goto fail;
}
}
current = current->next;
}
......
......@@ -293,6 +293,14 @@ input_module_t *roar_open_module(module_param_t *params)
break;
case ROAR_CODEC_OGG_GENERAL:
LOG_WARN0("Codec may not work, specify ogg_vorbis for Vorbis streaming");
/* fall through */
case ROAR_CODEC_OGG_OPUS:
/* fall through */
case ROAR_CODEC_OGG_SPEEX:
/* fall through */
case ROAR_CODEC_OGG_FLAC:
mod->type = ICES_INPUT_OGG;
break;
case ROAR_CODEC_OGG_VORBIS:
mod->type = ICES_INPUT_VORBIS;
// we do not set mod->subtype here, strange design ices2 has...
......
......@@ -131,12 +131,38 @@ int input_calculate_pcm_sleep(unsigned bytes, unsigned bytes_per_sec)
return 0;
}
static uint32_t __read_int32_le(const unsigned char in[4])
{
uint32_t ret = 0;
ret |= in[3];
ret <<= 8;
ret |= in[2];
ret <<= 8;
ret |= in[1];
ret <<= 8;
ret |= in[0];
return ret;
}
static uint32_t __read_int20_be(const unsigned char in[3])
{
uint32_t ret = 0;
ret |= in[0];
ret <<= 8;
ret |= in[1];
ret <<= 8;
ret |= in[2];
ret >>= 4;
return ret;
}
int input_calculate_ogg_sleep(ogg_page *page)
{
static ogg_stream_state os;
ogg_packet op;
static vorbis_info vi;
static vorbis_comment vc;
static input_type codec = ICES_INPUT_UNKNOWN;
static int need_start_pos, need_headers, state_in_use = 0;
static int serialno = 0;
static uint64_t offset;
......@@ -160,6 +186,7 @@ int input_calculate_ogg_sleep(ogg_page *page)
vorbis_comment_init (&vc);
need_start_pos = 1;
need_headers = 3;
codec = ICES_INPUT_UNKNOWN;
offset = (uint64_t)0;
}
if (need_start_pos)
......@@ -171,16 +198,69 @@ int input_calculate_ogg_sleep(ogg_page *page)
{
if (need_headers)
{
if (vorbis_synthesis_headerin (&vi, &vc, &op) < 0)
/* check for Vorbis. For Vorbis the Magic is {0x01|0x03|0x05}"vorbis" */
if (op.bytes > 7 && memcmp(op.packet+1, "vorbis", 6) == 0)
{
if (vorbis_synthesis_headerin (&vi, &vc, &op) < 0)
{
LOG_ERROR0("Timing control: can't determine sample rate for input, not vorbis.");
control.samplerate = 0;
vorbis_info_clear (&vi);
ogg_stream_clear (&os);
return -1;
}
control.samplerate = vi.rate;
codec = ICES_INPUT_VORBIS;
}
/* check for Opus. For Opus the magic is "OpusHead" */
else if (op.bytes == 19 && memcmp(op.packet, "OpusHead", 8) == 0)
{
LOG_ERROR0("Timing control: can't determine sample rate for input, not vorbis.");
if (op.packet[8] != 1)
{
LOG_ERROR0("Timing control: can't determine sample rate for input, unsupported Opus version.");
control.samplerate = 0;
vorbis_info_clear (&vi);
ogg_stream_clear (&os);
return -1;
}
/* Sample rate is fixed for Opus: 48kHz */
control.samplerate = 48000;
codec = ICES_INPUT_OGG;
/* No more headers after this one needed */
need_headers = 1;
}
else if (op.bytes >= 80 && memcmp(op.packet, "Speex ", 8) == 0)
{
if (__read_int32_le(op.packet+28) != 1 || __read_int32_le(op.packet+32) != op.bytes)
{
LOG_ERROR0("Timing control: can't determine sample rate for input, bad or unsupported Speex header.");
control.samplerate = 0;
vorbis_info_clear (&vi);
ogg_stream_clear (&os);
return -1;
}
control.samplerate = __read_int32_le(op.packet+36);
codec = ICES_INPUT_OGG;
/* No more headers after this one needed */
need_headers = 1;
}
else if (op.bytes >= 51 && memcmp(op.packet, "\177FLAC\1\0", 7) == 0 && memcmp(op.packet+9, "fLaC\0", 5) == 0)
{
control.samplerate = __read_int20_be(op.packet+27);
codec = ICES_INPUT_OGG;
/* No more headers after this one needed */
need_headers = 1;
}
else if (codec == ICES_INPUT_UNKNOWN)
{
LOG_ERROR0("Timing control: can't determine sample rate for input, unsupported input format.");
control.samplerate = 0;
vorbis_info_clear (&vi);
ogg_stream_clear (&os);
return -1;
}
need_headers--;
control.samplerate = vi.rate;
if (need_headers == 0)
{
......@@ -196,7 +276,10 @@ int input_calculate_ogg_sleep(ogg_page *page)
first_granulepos = op.granulepos;
found_first_granulepos = 1;
}
offset += vorbis_packet_blocksize (&vi, &op) / 4;
if (codec == ICES_INPUT_VORBIS)
{
offset += vorbis_packet_blocksize (&vi, &op) / 4;
}
}
if (!found_first_granulepos)
return 0;
......
......@@ -20,8 +20,10 @@
#include <vorbis/codec.h>
typedef enum _input_type {
ICES_INPUT_UNKNOWN, /* not yet known */
ICES_INPUT_PCM,
ICES_INPUT_VORBIS,
ICES_INPUT_OGG, /* generic Ogg */
/* Can add others here in the future, if we want */
} input_type;
......
......@@ -55,8 +55,8 @@ void *ices_instance_stream(void *arg)
stream_description *sdsc = arg;
instance_t *stream = sdsc->stream;
input_module_t *inmod = sdsc->input;
int reencoding = (inmod->type == ICES_INPUT_VORBIS) && stream->encode;
int encoding = (inmod->type == ICES_INPUT_PCM) && stream->encode;
int reencoding = 0;
int encoding = 0;
char *stream_name = NULL, *stream_genre = NULL, *stream_description = NULL;
char *stream_url = NULL, *user = NULL;
char audio_info[11];
......@@ -65,10 +65,28 @@ void *ices_instance_stream(void *arg)
sdsc->shout = shout_new();
/* we only support the ice protocol and vorbis streams currently */
shout_set_format(sdsc->shout, SHOUT_FORMAT_VORBIS);
/* we only support the ice protocol */
shout_set_protocol(sdsc->shout, SHOUT_PROTOCOL_HTTP);
switch (inmod->type) {
case ICES_INPUT_UNKNOWN:
LOG_ERROR0("Unknown stream type.\n");
stream->died = 1;
return NULL;
break;
case ICES_INPUT_VORBIS:
shout_set_format(sdsc->shout, SHOUT_FORMAT_VORBIS);
reencoding = stream->encode;
break;
case ICES_INPUT_OGG:
shout_set_format(sdsc->shout, SHOUT_FORMAT_OGG);
break;
case ICES_INPUT_PCM:
shout_set_format(sdsc->shout, SHOUT_FORMAT_VORBIS);
encoding = stream->encode;
break;
}
#ifndef _WIN32
signal(SIGPIPE, signal_hup_handler);
#endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment