dect
/
asterisk
Archived
13
0
Fork 0

Add Icecast streaming support

git-svn-id: http://svn.digium.com/svn/asterisk/trunk@2185 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
markster 2004-02-17 07:03:14 +00:00
parent 9d7fa3f3f0
commit d07601c72a
5 changed files with 305 additions and 1 deletions

View File

@ -1,3 +1,5 @@
-- Add ices/icecast support
-- Numerous bug fixes
Asterisk 0.7.2
-- Countless small bug fixes from bug tracker
-- DSP Fixes

View File

@ -25,7 +25,7 @@ APPS=app_dial.so app_playback.so app_voicemail.so app_directory.so app_mp3.so\
app_waitforring.so app_privacy.so app_db.so app_chanisavail.so \
app_enumlookup.so app_transfer.so app_setcidnum.so app_cdr.so \
app_hasnewvoicemail.so app_sayunixtime.so app_cut.so app_read.so \
app_setcdruserfield.so app_random.so
app_setcdruserfield.so app_random.so app_ices.so
ifneq (${OSARCH},Darwin)
APPS+=app_intercom.so

197
apps/app_ices.c Executable file
View File

@ -0,0 +1,197 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Stream to an icecast server via ICES (see contrib/asterisk-ices.xml)
*
* Copyright (C) 1999, Mark Spencer
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/frame.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/time.h>
#include <errno.h>
#include "../astconf.h"
#define ICES "/usr/bin/ices"
#define LOCAL_ICES "/usr/local/bin/ices"
static char *tdesc = "Encode and Stream via icecast and ices";
static char *app = "ICES";
static char *synopsis = "Encode and stream using 'ices'";
static char *descrip =
" ICES(config.xml) Streams to an icecast server using ices\n"
"(available separately). A configuration file must be supplied\n"
"for ices (see examples/asterisk-ices.conf). Returns -1 on\n"
"hangup or 0 otherwise.\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int icesencode(char *filename, int fd)
{
int res;
int x;
res = fork();
if (res < 0)
ast_log(LOG_WARNING, "Fork failed\n");
if (res)
return res;
dup2(fd, STDIN_FILENO);
for (x=STDERR_FILENO + 1;x<256;x++) {
if ((x != STDIN_FILENO) && (x != STDOUT_FILENO))
close(x);
}
/* Most commonly installed in /usr/local/bin */
execl(ICES, "ices", filename, (char *)NULL);
/* But many places has it in /usr/bin */
execl(LOCAL_ICES, "ices", filename, (char *)NULL);
/* As a last-ditch effort, try to use PATH */
execlp("ices", "ices", filename, (char *)NULL);
ast_log(LOG_WARNING, "Execute of ices failed\n");
return -1;
}
static int ices_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct localuser *u;
int fds[2];
int ms = -1;
int pid = -1;
int flags;
int oreadformat;
struct timeval last;
struct ast_frame *f;
char filename[256]="";
char *c;
last.tv_usec = 0;
last.tv_sec = 0;
if (!data || !strlen(data)) {
ast_log(LOG_WARNING, "ICES requires an argument (configfile.xml)\n");
return -1;
}
if (pipe(fds)) {
ast_log(LOG_WARNING, "Unable to create pipe\n");
return -1;
}
flags = fcntl(fds[1], F_GETFL);
fcntl(fds[1], F_SETFL, flags | O_NONBLOCK);
LOCAL_USER_ADD(u);
ast_stopstream(chan);
if (chan->_state != AST_STATE_UP)
res = ast_answer(chan);
if (res) {
close(fds[0]);
close(fds[1]);
ast_log(LOG_WARNING, "Answer failed!\n");
return -1;
}
oreadformat = chan->readformat;
res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
if (res < 0) {
close(fds[0]);
close(fds[1]);
ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
return -1;
}
if (((char *)data)[0] == '/')
strncpy(filename, (char *)data, sizeof(filename) - 1);
else
snprintf(filename, sizeof(filename), "%s/%s", (char *)ast_config_AST_CONFIG_DIR, (char *)data);
/* Placeholder for options */
c = strchr(filename, '|');
if (c)
*c = '\0';
res = icesencode(filename, fds[0]);
close(fds[0]);
if (res >= 0) {
pid = res;
for (;;) {
/* Wait for audio, and stream */
ms = ast_waitfor(chan, -1);
if (ms < 0) {
ast_log(LOG_DEBUG, "Hangup detected\n");
res = -1;
break;
}
f = ast_read(chan);
if (!f) {
ast_log(LOG_DEBUG, "Null frame == hangup() detected\n");
res = -1;
break;
}
if (f->frametype == AST_FRAME_VOICE) {
res = write(fds[1], f->data, f->datalen);
if (res < 0) {
if (errno != EAGAIN) {
ast_log(LOG_WARNING, "Write failed to pipe: %s\n", strerror(errno));
res = -1;
break;
}
}
}
ast_frfree(f);
}
}
close(fds[1]);
LOCAL_USER_REMOVE(u);
if (pid > -1)
kill(pid, SIGKILL);
if (!res && oreadformat)
ast_set_read_format(chan, oreadformat);
return res;
}
int unload_module(void)
{
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
int load_module(void)
{
return ast_register_application(app, ices_exec, synopsis, descrip);
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

93
contrib/asterisk-ices.xml Executable file
View File

@ -0,0 +1,93 @@
<?xml version="1.0"?>
<ices>
<!-- run in background -->
<background>0</background>
<!-- where logs go. -->
<logpath>/var/log/ices</logpath>
<logfile>ices.log</logfile>
<!-- 1=error, 2=warn, 3=infoa ,4=debug -->
<loglevel>4</loglevel>
<!-- logfile is ignored if this is set to 1 -->
<consolelog>0</consolelog>
<!-- optional filename to write process id to -->
<!-- <pidfile>/home/ices/ices.pid</pidfile> -->
<stream>
<!-- metadata used for stream listing -->
<metadata>
<name>Example stream name</name>
<genre>Example genre</genre>
<description>A short description of your stream</description>
<url>http://mysite.org</url>
</metadata>
<!-- Input module.
This example uses the 'oss' module. It takes input from the
OSS audio device (e.g. line-in), and processes it for live
encoding. -->
<input>
<module>stdinpcm</module>
<param name="rate">8000</param>
<param name="channels">1</param>
<!-- Read metadata (from stdin by default, or -->
<!-- filename defined below (if the latter, only on SIGUSR1) -->
<param name="metadata">1</param>
<param name="metadatafilename">test</param>
</input>
<!-- Stream instance.
You may have one or more instances here. This allows you to
send the same input data to one or more servers (or to different
mountpoints on the same server). Each of them can have different
parameters. This is primarily useful for a) relaying to multiple
independent servers, and b) encoding/reencoding to multiple
bitrates.
If one instance fails (for example, the associated server goes
down, etc), the others will continue to function correctly.
This example defines a single instance doing live encoding at
low bitrate. -->
<instance>
<!-- Server details.
You define hostname and port for the server here, along
with the source password and mountpoint. -->
<hostname>localhost</hostname>
<port>8000</port>
<password>temppass</password>
<mount>/example.ogg</mount>
<yp>1</yp> <!-- allow stream to be advertised on YP, default 0 -->
<!-- Live encoding/reencoding:
channels and samplerate currently MUST match the channels
and samplerate given in the parameters to the oss input
module above or the remsaple/downmix section below. -->
<encode>
<quality>0</quality>
<samplerate>8000</samplerate>
<channels>1</channels>
</encode>
<!-- stereo->mono downmixing, enabled by setting this to 1 -->
<downmix>0</downmix>
<!-- resampling.
Set to the frequency (in Hz) you wish to resample to, -->
<!-- <resample>
<in-rate>44100</in-rate>
<out-rate>22050</out-rate>
</resample> -->
</instance>
</stream>
</ices>

12
doc/README.ices Executable file
View File

@ -0,0 +1,12 @@
Icecast + Asterisk
==================
The advent of icecast into Asterisk allows you to do neat things like have
a caller stream right into an ice-cast stream as well as using chan_local
to place things like conferences, music on hold, etc. into the stream.
You'll need to specify a config file for the ices encoder. An example is
included in contrib/asterisk-ices.xml
Anyway hope you like it.
Mark