0
0
mirror of https://gitlab.xiph.org/xiph/ezstream.git synced 2025-06-30 22:18:27 -04:00

Merge branch 'release/0.6.0'

This commit is contained in:
Moritz Grimm 2015-01-18 01:22:10 +01:00
commit ee0700992e
32 changed files with 363 additions and 2210 deletions

16
.gitignore vendored Normal file
View File

@ -0,0 +1,16 @@
Makefile.in
aclocal.m4
compile
config.guess
config.h.in
config.sub
configure
depcomp
install-sh
libtool.m4
ltmain.sh
ltoptions.m4
ltsugar.m4
ltversion.m4
lt~obsolete.m4
missing

View File

@ -1,6 +1,6 @@
ezstream - source client for Icecast with external en-/decoder support ezstream - source client for Icecast with external en-/decoder support
Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org> Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org>
Copyright (C) 2007, 2009 Moritz Grimm <mdgrimm@gmx.net> Copyright (C) 2007, 2009, 2015 Moritz Grimm <mgrimm@mrsserver.net>
The ezstream program, in its entirety, is licensed under the terms and The ezstream program, in its entirety, is licensed under the terms and

2025
ChangeLog

File diff suppressed because it is too large Load Diff

60
NEWS
View File

@ -1,3 +1,48 @@
Changes in 0.6.0, released on 2015-01-18:
* This release contains a SECURITY FIX for a command injection vulnerability
that was found and reported by Alexandre Rebert:
The previous handling of metadata placeholders allowed for arbitrary shell
commands to be trivially injected and executed as the ezstream user, via
malicious media files.
This vulnerability depends on both a configuration using metadata
placeholders and the user streaming media files from untrusted sources
without noticing `commands` or $(commands) in artist or title fields.
While the group of actually affected users may be limited, all users are
advised to upgrade.
* This release requires users to ADJUST their CONFIGURATION:
To protect against the injection vulnerability above, metadata is now
properly quoted and escaped from the shell. This means that any extra
quoting must be removed from configuration files.
Remove all quoting from metadata placeholders in <encode/> and <decode/>
commands, e.g. replace "@M@" with @M@, and "@T@" with @T@, etc. Without
these changes, stream metadata will look both wrong and the injection
vulnerability may be re-introduced.
Configuration examples have been adjusted accordingly.
* src/ezstream.c:
- [FIX] Prevent certain characters from being interpreted by the shell.
- [FIX] Prevent ezstream from entering an infinite loop when stopping to
send data to standard input. From gquintard.
(Ticket #2045)
* various:
- [NEW] Add new <metadata_refreshinterval/> feature from Matthew Adams
(with minor changes plus documentation.) This allows for recurring
and custom metadata updates in between song changes via
<metadata_progname/>.
- [NEW] Add new command line option `-m' to disable any active metadata
updates. Idea from Richard Thomas.
(Ticket #1620)
Changes in 0.5.6, released on 2009-08-31: Changes in 0.5.6, released on 2009-08-31:
* ezstream-file.sh: * ezstream-file.sh:
@ -23,6 +68,7 @@ Changes in 0.5.6, released on 2009-08-31:
- [NEW] Add a real-world example playlist script with logging feature. - [NEW] Add a real-world example playlist script with logging feature.
Changes in 0.5.5, released on 2009-08-01: Changes in 0.5.5, released on 2009-08-01:
* win32/config.h: * win32/config.h:
@ -177,7 +223,7 @@ Changes in 0.4.0, released on 2007-03-11:
program. program.
* src/compat.c: * src/compat.c:
- [ADD] Implement a basename() function for Windows that behaves like the - [NEW] Implement a basename() function for Windows that behaves like the
ones used on Unix systems. ones used on Unix systems.
* win32/: * win32/:
@ -185,19 +231,19 @@ Changes in 0.4.0, released on 2007-03-11:
distribution, and provide a much better PDF version instead. distribution, and provide a much better PDF version instead.
* various: * various:
- [ADD] Allow ezstream to use TagLib for reading metadata from media - [NEW] Allow ezstream to use TagLib for reading metadata from media
files. TagLib (libtag_c) is now an optional dependency. files. TagLib (libtag_c) is now an optional dependency.
- [ADD] When built with TagLib support, include the song length in the - [NEW] When built with TagLib support, include the song length in the
"real-time" information line, if available. "real-time" information line, if available.
- [ADD] New <metadata_progname> configuration option, which causes - [NEW] New <metadata_progname> configuration option, which causes
metadata to be read from the output of an external program or metadata to be read from the output of an external program or
script. script.
- [ADD] New runtime control via the SIGUSR2 signal, which triggers reading - [NEW] New runtime control via the SIGUSR2 signal, which triggers reading
of fresh metadata information from <metadata_progname> (metadata of fresh metadata information from <metadata_progname> (metadata
is always read at song changes.) is always read at song changes.)
- [ADD] New <metadata_format> configuration option, to customize metadata - [NEW] New <metadata_format> configuration option, to customize metadata
strings when used with the new <metadata_progname> feature. strings when used with the new <metadata_progname> feature.
- [ADD] New '@a@' and '@t@' placeholders for separate artist and title - [NEW] New '@a@' and '@t@' placeholders for separate artist and title
metadata in de-/encoder commands. metadata in de-/encoder commands.

4
README
View File

@ -40,7 +40,7 @@ Ezstream optionally uses:
- For reading metadata from Ogg Vorbis files: - For reading metadata from Ogg Vorbis files:
* TagLib 1.x (1.4 or newer recommended, will be used via the libtag_c * TagLib 1.x (1.4 or newer recommended, will be used via the libtag_c
wrapper) wrapper)
(http://developer.kde.org/~wheeler/taglib.html) (https://taglib.github.io/)
OR: OR:
* libvorbis 1.x * libvorbis 1.x
(http://www.vorbis.com) (http://www.vorbis.com)
@ -48,7 +48,7 @@ Ezstream optionally uses:
many additional media file types. many additional media file types.
- For basic non-ASCII charset support in metadata and filenames: - For basic non-ASCII charset support in metadata and filenames:
* Libiconv, if iconv() is not available in the system libc. * Libiconv, if iconv() is not available in the system libc.
(http://www.gnu.org/software/libiconv/) (https://www.gnu.org/software/libiconv/)

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: tree.3,v 1.20 2009/01/28 12:22:48 stsp Exp $ .\" $OpenBSD: tree.3,v 1.26 2014/09/08 01:27:55 schwarze Exp $
.\"/* .\"/*
.\" * Copyright 2002 Niels Provos <provos@citi.umich.edu> .\" * Copyright 2002 Niels Provos <provos@citi.umich.edu>
.\" * All rights reserved. .\" * All rights reserved.
@ -23,7 +23,7 @@
.\" * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" */ .\" */
.Dd $Mdocdate: January 28 2009 $ .Dd $Mdocdate: September 8 2014 $
.Dt TREE 3 .Dt TREE 3
.Os .Os
.Sh NAME .Sh NAME
@ -63,13 +63,15 @@
.Nm RB_RIGHT , .Nm RB_RIGHT ,
.Nm RB_PARENT , .Nm RB_PARENT ,
.Nm RB_FOREACH , .Nm RB_FOREACH ,
.Nm RB_FOREACH_SAFE ,
.Nm RB_FOREACH_REVERSE , .Nm RB_FOREACH_REVERSE ,
.Nm RB_FOREACH_REVERSE_SAFE ,
.Nm RB_INIT , .Nm RB_INIT ,
.Nm RB_INSERT , .Nm RB_INSERT ,
.Nm RB_REMOVE .Nm RB_REMOVE
.Nd "implementations of splay and red-black trees" .Nd implementations of splay and red-black trees
.Sh SYNOPSIS .Sh SYNOPSIS
.Fd #include <sys/tree.h> .In sys/tree.h
.Pp .Pp
.Fn SPLAY_PROTOTYPE "NAME" "TYPE" "FIELD" "CMP" .Fn SPLAY_PROTOTYPE "NAME" "TYPE" "FIELD" "CMP"
.Fn SPLAY_GENERATE "NAME" "TYPE" "FIELD" "CMP" .Fn SPLAY_GENERATE "NAME" "TYPE" "FIELD" "CMP"
@ -130,7 +132,9 @@
.Ft "struct TYPE *" .Ft "struct TYPE *"
.Fn RB_PARENT "struct TYPE *elm" "RB_ENTRY NAME" .Fn RB_PARENT "struct TYPE *elm" "RB_ENTRY NAME"
.Fn RB_FOREACH "VARNAME" "NAME" "RB_HEAD *head" .Fn RB_FOREACH "VARNAME" "NAME" "RB_HEAD *head"
.Fn RB_FOREACH_SAFE "VARNAME" "NAME" "RB_HEAD *head" "TEMP_VARNAME"
.Fn RB_FOREACH_REVERSE "VARNAME" "NAME" "RB_HEAD *head" .Fn RB_FOREACH_REVERSE "VARNAME" "NAME" "RB_HEAD *head"
.Fn RB_FOREACH_REVERSE_SAFE "VARNAME" "NAME" "RB_HEAD *head" "TEMP_VARNAME"
.Ft void .Ft void
.Fn RB_INIT "RB_HEAD *head" .Fn RB_INIT "RB_HEAD *head"
.Ft "struct TYPE *" .Ft "struct TYPE *"
@ -258,6 +262,11 @@ The
macro inserts the new element macro inserts the new element
.Fa elm .Fa elm
into the tree. into the tree.
Upon success,
.Va NULL
is returned.
If a matching element already exists in the tree, the insertion is
aborted, and a pointer to the existing element is returned.
.Pp .Pp
The The
.Fn SPLAY_REMOVE .Fn SPLAY_REMOVE
@ -265,6 +274,11 @@ macro removes the element
.Fa elm .Fa elm
from the tree pointed by from the tree pointed by
.Fa head . .Fa head .
Upon success, a pointer to the removed element is returned.
.Va NULL
is returned if
.Fa elm
is not present in the tree.
.Pp .Pp
The The
.Fn SPLAY_FIND .Fn SPLAY_FIND
@ -405,6 +419,9 @@ macro removes the element
.Fa elm .Fa elm
from the tree pointed by from the tree pointed by
.Fa head . .Fa head .
.Fn RB_REMOVE
returns
.Fa elm .
.Pp .Pp
The The
.Fn RB_FIND .Fn RB_FIND
@ -443,6 +460,18 @@ macros:
RB_FOREACH(np, NAME, &head) RB_FOREACH(np, NAME, &head)
.Ed .Ed
.Pp .Pp
The macros
.Fn RB_FOREACH_SAFE
and
.Fn RB_FOREACH_REVERSE_SAFE
traverse the tree referenced by head
in a forward or reverse direction respectively,
assigning each element in turn to np.
However, unlike their unsafe counterparts,
they permit both the removal of np
as well as freeing it from within the loop safely
without interfering with the traversal.
.Pp
The The
.Fn RB_EMPTY .Fn RB_EMPTY
macro should be used to check whether a red-black tree is empty. macro should be used to check whether a red-black tree is empty.
@ -543,22 +572,6 @@ for (var = SPLAY_MIN(NAME, &head); var != NULL; var = nxt) {
free(var); free(var);
} }
.Ed .Ed
.Pp
Both
.Fn RB_INSERT
and
.Fn SPLAY_INSERT
return
.Va NULL
if the element was inserted in the tree successfully, otherwise they
return a pointer to the element with the colliding key.
.Pp
Accordingly,
.Fn RB_REMOVE
and
.Fn SPLAY_REMOVE
return the pointer to the removed element, otherwise they return
.Va NULL
to indicate an error.
.Sh AUTHORS .Sh AUTHORS
The author of the tree macros is Niels Provos. The author of the tree macros is
.An Niels Provos .

View File

@ -1,4 +1,4 @@
/* $OpenBSD: tree.h,v 1.11 2008/05/11 22:19:09 millert Exp $ */ /* $OpenBSD: tree.h,v 1.13 2011/07/09 00:19:45 pirofti Exp $ */
/* /*
* Copyright 2002 Niels Provos <provos@citi.umich.edu> * Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved. * All rights reserved.
@ -329,7 +329,7 @@ struct { \
} while (0) } while (0)
#ifndef RB_AUGMENT #ifndef RB_AUGMENT
#define RB_AUGMENT(x) #define RB_AUGMENT(x) do {} while (0)
#endif #endif
#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ #define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
@ -730,9 +730,19 @@ name##_RB_MINMAX(struct name *head, int val) \
(x) != NULL; \ (x) != NULL; \
(x) = name##_RB_NEXT(x)) (x) = name##_RB_NEXT(x))
#define RB_FOREACH_SAFE(x, name, head, y) \
for ((x) = RB_MIN(name, head); \
((x) != NULL) && ((y) = name##_RB_NEXT(x), 1); \
(x) = (y))
#define RB_FOREACH_REVERSE(x, name, head) \ #define RB_FOREACH_REVERSE(x, name, head) \
for ((x) = RB_MAX(name, head); \ for ((x) = RB_MAX(name, head); \
(x) != NULL; \ (x) != NULL; \
(x) = name##_RB_PREV(x)) (x) = name##_RB_PREV(x))
#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \
for ((x) = RB_MAX(name, head); \
((x) != NULL) && ((y) = name##_RB_PREV(x), 1); \
(x) = (y))
#endif /* _SYS_TREE_H_ */ #endif /* _SYS_TREE_H_ */

View File

@ -2,7 +2,7 @@ dnl ###########
dnl ## SETUP ########################################################### dnl ## SETUP ###########################################################
dnl ########### dnl ###########
AC_INIT([ezstream], [0.5.6], AC_INIT([ezstream], [0.6.0],
[https://trac.xiph.org/newticket?component=ezstream]) [https://trac.xiph.org/newticket?component=ezstream])
AC_REVISION([$Id$]) AC_REVISION([$Id$])
AC_PREREQ([2.61]) AC_PREREQ([2.61])

View File

@ -1,6 +1,6 @@
.\" $Id$ .\" $Id$
.\" .\"
.\" Copyright (c) 2009 Moritz Grimm <mdgrimm@gmx.net> .\" Copyright (c) 2009, 2015 Moritz Grimm <mgrimm@mrsserver.net>
.\" .\"
.\" Permission to use, copy, modify, and distribute this software for any .\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above .\" purpose with or without fee is hereby granted, provided that the above
@ -23,7 +23,7 @@
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm .Nm
.Bk -words .Bk -words
.Op Fl hnqVv .Op Fl hmnqVv
.Op Fl T Ar cfg_template .Op Fl T Ar cfg_template
.Op Ar .Op Ar
.Ek .Ek
@ -62,6 +62,12 @@ binary.
.It Fl h .It Fl h
Print a summary of available command line parameters with short descriptions Print a summary of available command line parameters with short descriptions
and exit. and exit.
.It Fl m
.Po
Passed to
.Nm ezstream .
.Pc
Disable all metadata updates and keep existing metadata in streams untouched.
.It Fl n .It Fl n
.Po .Po
Passed to Passed to
@ -108,4 +114,4 @@ as well as example playlist and metadata scripts.
The The
.Nm .Nm
script and this manual were written by script and this manual were written by
.An Moritz Grimm Aq mdgrimm@gmx.net . .An Moritz Grimm .

View File

@ -1,6 +1,6 @@
.\" $Id$ .\" $Id$
.\" .\"
.\" Copyright (c) 2007, 2009 Moritz Grimm <mdgrimm@gmx.net> .\" Copyright (c) 2007, 2009, 2015 Moritz Grimm <mgrimm@mrsserver.net>
.\" .\"
.\" This program is free software; you can redistribute it and/or modify .\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License version 2 as .\" it under the terms of the GNU General Public License version 2 as
@ -24,7 +24,7 @@
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm .Nm
.Bk -words .Bk -words
.Op Fl hnqVv .Op Fl hmnqVv
.Fl c Ar configfile .Fl c Ar configfile
.Ek .Ek
.Nm .Nm
@ -52,6 +52,8 @@ Use the XML configuration in
.It Fl h .It Fl h
Print a summary of available command line parameters with short descriptions Print a summary of available command line parameters with short descriptions
and exit. and exit.
.It Fl m
Disable all metadata updates and keep existing metadata in streams untouched.
.It Fl n .It Fl n
Normalize metadata strings by removing excess whitespaces. Normalize metadata strings by removing excess whitespaces.
.It Fl q .It Fl q
@ -275,6 +277,17 @@ See the
.Sy METADATA .Sy METADATA
section for details on how metadata is handled by section for details on how metadata is handled by
.Nm . .Nm .
.It Sy \&<metadata_refreshinterval\ /\&>
.Pq Optional.
Configures the time
.Pq in seconds
inbetween additional metadata updates via
.Li \&<metadata_progname/\&> .
A value of 0
.Pq zero
triggers updates as fast as possible, while a value of \&-1
.Pq minus one
or the absence of this configuration element disables this feature.
.It Sy \&<stream_once\ /\&> .It Sy \&<stream_once\ /\&>
Set to Set to
.Sy 1 .Sy 1
@ -428,7 +441,7 @@ For example, to decode Ogg Vorbis files using the
.Cm oggdec .Cm oggdec
utility: utility:
.Pp .Pp
.Dl \&<decode\&>oggdec -R -o - \&"@T@\&"\&</decode\&> .Dl \&<decode\&>oggdec -R -o - @T@\&</decode\&>
.It Sy \&<encode\ /\&> .It Sy \&<encode\ /\&>
Set the command to encode raw data, received from standard input, to the Set the command to encode raw data, received from standard input, to the
specified stream format. specified stream format.
@ -447,7 +460,7 @@ the
.Cm oggenc .Cm oggenc
utility: utility:
.Pp .Pp
.Dl \&<encode\&>oggenc -r -q 1.5 -t \&"@M@\&" -\&</encode\&> .Dl \&<encode\&>oggenc -r -q 1.5 -t @M@ -\&</encode\&>
.El .El
.Sh SCRIPTING .Sh SCRIPTING
The The
@ -506,9 +519,17 @@ The main tool for handling metadata with
.Nm .Nm
is placeholders in decoder and encoder commands that are replaced with real is placeholders in decoder and encoder commands that are replaced with real
content during runtime. content during runtime.
The tricky part is that one of the placeholders has to be handled differently, .Pp
depending on where the metadata comes from. .Em Note:
This section will explain each possible scenario. To prevent malicious shell script in metadata
.Pq such as artist and title tags
from being executed, all metadata content is automatically enclosed in single
quotes, with escaped single quote and backslash characters inbetween.
To prevent this from causing unwanted side-effects
.Pq or introducting security risk ,
placeholders
.Em must not
be quoted any further.
.Ss Metadata Placeholders .Ss Metadata Placeholders
.Bl -tag -width -Ds .Bl -tag -width -Ds
.It Sy @T@ .It Sy @T@
@ -633,6 +654,8 @@ as well as example playlist and metadata scripts.
was written by: was written by:
.Pp .Pp
.An Ed Zaleski Aq oddsock@oddsock.org .An Ed Zaleski Aq oddsock@oddsock.org
.An Moritz Grimm Aq mdgrimm@gmx.net .An Moritz Grimm Aq mgrimm@mrsserver.net
.Pp .Pp
This manual was written by Moritz Grimm. .An -nosplit
This manual was written by
.An Moritz Grimm .

View File

@ -18,6 +18,11 @@
configuration must be as follows: configuration must be as follows:
--> -->
<filename>%FILENAME%</filename> <filename>%FILENAME%</filename>
<!--
If the generated playlist should not loop forever, set <stream_once />
to 1.
-->
<stream_once>0</stream_once>
<!-- <!--
The usual, remaining configuration statements follow. See the other The usual, remaining configuration statements follow. See the other
examples and the documentation for details. examples and the documentation for details.
@ -35,19 +40,19 @@
<encdec> <encdec>
<format>FLAC</format> <format>FLAC</format>
<match>.flac</match> <match>.flac</match>
<decode>flac -s -d --force-raw-format --sign=signed --endian=little -o - "@T@"</decode> <decode>flac -s -d --force-raw-format --sign=signed --endian=little -o - @T@</decode>
</encdec> </encdec>
<encdec> <encdec>
<format>MP3</format> <format>MP3</format>
<match>.mp3</match> <match>.mp3</match>
<decode>madplay -b 16 -R 44100 -S -o raw:- "@T@"</decode> <decode>madplay -b 16 -R 44100 -S -o raw:- @T@</decode>
<encode>lame --preset cbr 128 -r -s 44.1 --bitwidth 16 - -</encode> <encode>lame --preset cbr 128 -r -s 44.1 --bitwidth 16 - -</encode>
</encdec> </encdec>
<encdec> <encdec>
<format>VORBIS</format> <format>VORBIS</format>
<match>.ogg</match> <match>.ogg</match>
<decode>oggdec -R -b 16 -e 0 -s 1 -o - "@T@"</decode> <decode>oggdec -R -b 16 -e 0 -s 1 -o - @T@</decode>
<encode>oggenc -r -B 16 -C 2 -R 44100 --raw-endianness 0 -q 1.5 -t "@M@" -</encode> <encode>oggenc -r -B 16 -C 2 -R 44100 --raw-endianness 0 -q 1.5 -t @M@ -</encode>
</encdec> </encdec>
</reencode> </reencode>
</ezstream> </ezstream>

View File

@ -20,6 +20,8 @@
<metadata_progname>meta.sh</metadata_progname> <metadata_progname>meta.sh</metadata_progname>
<!-- Set the metadata string according to this format: --> <!-- Set the metadata string according to this format: -->
<metadata_format>@s@: @a@ - @t@</metadata_format> <metadata_format>@s@: @a@ - @t@</metadata_format>
<!-- Update metadata from meta.sh at least once every 10 seconds: -->
<metadata_refreshinterval>10</metadata_refreshinterval>
<!-- <!--
The following settings are used to describe your stream to the server. The following settings are used to describe your stream to the server.
It's up to you to make sure that the bitrate/quality/samplerate/channels It's up to you to make sure that the bitrate/quality/samplerate/channels

View File

@ -61,7 +61,7 @@
<!-- Support for FLAC decoding: --> <!-- Support for FLAC decoding: -->
<format>FLAC</format> <format>FLAC</format>
<match>.flac</match> <match>.flac</match>
<decode>flac -s -d --force-raw-format --sign=signed --endian=little -o - "@T@"</decode> <decode>flac -s -d --force-raw-format --sign=signed --endian=little -o - @T@</decode>
<!-- <encode>Not supported Yet</encode> --> <!-- <encode>Not supported Yet</encode> -->
</encdec> </encdec>
<encdec> <encdec>
@ -71,7 +71,7 @@
<format>MP3</format> <format>MP3</format>
<match>.mp3</match> <match>.mp3</match>
<!-- Note: madplay uses host byte order for raw samples. --> <!-- Note: madplay uses host byte order for raw samples. -->
<decode>madplay -b 16 -R 44100 -S -o raw:- "@T@"</decode> <decode>madplay -b 16 -R 44100 -S -o raw:- @T@</decode>
<encode>lame --preset cbr 128 -r -s 44.1 --bitwidth 16 - -</encode> <encode>lame --preset cbr 128 -r -s 44.1 --bitwidth 16 - -</encode>
</encdec> </encdec>
<encdec> <encdec>
@ -80,8 +80,8 @@
--> -->
<format>VORBIS</format> <format>VORBIS</format>
<match>.ogg</match> <match>.ogg</match>
<decode>oggdec -R -b 16 -e 0 -s 1 -o - "@T@"</decode> <decode>oggdec -R -b 16 -e 0 -s 1 -o - @T@</decode>
<encode>oggenc -r -B 16 -C 2 -R 44100 --raw-endianness 0 -q 1.5 -t "@M@" -</encode> <encode>oggenc -r -B 16 -C 2 -R 44100 --raw-endianness 0 -q 1.5 -t @M@ -</encode>
</encdec> </encdec>
</reencode> </reencode>
</ezstream> </ezstream>

View File

@ -67,12 +67,12 @@
--> -->
<format>THEORA</format> <format>THEORA</format>
<match>.avi</match> <match>.avi</match>
<decode>ffmpeg2theora -x 192 -y 128 -a 0 -v 4 --title "@M@" -o - "@T@"</decode> <decode>ffmpeg2theora -x 192 -y 128 -a 0 -v 4 --title @M@ -o - @T@</decode>
</encdec> </encdec>
<encdec> <encdec>
<format>THEORA</format> <format>THEORA</format>
<match>.mpg</match> <match>.mpg</match>
<decode>ffmpeg2theora -x 192 -y 128 -a 0 -v 4 --title "@M@" -o - "@T@"</decode> <decode>ffmpeg2theora -x 192 -y 128 -a 0 -v 4 --title @M@ -o - @T@</decode>
</encdec> </encdec>
</reencode> </reencode>
</ezstream> </ezstream>

View File

@ -62,7 +62,7 @@
<!-- Support for FLAC decoding: --> <!-- Support for FLAC decoding: -->
<format>FLAC</format> <format>FLAC</format>
<match>.flac</match> <match>.flac</match>
<decode>flac -s -d --force-raw-format --sign=signed --endian=little -o - "@T@"</decode> <decode>flac -s -d --force-raw-format --sign=signed --endian=little -o - @T@</decode>
<!-- <encode>Not supported Yet</encode> --> <!-- <encode>Not supported Yet</encode> -->
</encdec> </encdec>
<encdec> <encdec>
@ -72,7 +72,7 @@
<format>MP3</format> <format>MP3</format>
<match>.mp3</match> <match>.mp3</match>
<!-- Note: madplay uses host byte order for raw samples. --> <!-- Note: madplay uses host byte order for raw samples. -->
<decode>madplay -b 16 -R 44100 -S -o raw:- "@T@"</decode> <decode>madplay -b 16 -R 44100 -S -o raw:- @T@</decode>
<encode>lame --preset cbr 128 -r -s 44.1 --bitwidth 16 - -</encode> <encode>lame --preset cbr 128 -r -s 44.1 --bitwidth 16 - -</encode>
</encdec> </encdec>
<encdec> <encdec>
@ -81,8 +81,8 @@
--> -->
<format>VORBIS</format> <format>VORBIS</format>
<match>.ogg</match> <match>.ogg</match>
<decode>oggdec -R -b 16 -e 0 -s 1 -o - "@T@"</decode> <decode>oggdec -R -b 16 -e 0 -s 1 -o - @T@</decode>
<encode>oggenc -r -B 16 -C 2 -R 44100 --raw-endianness 0 -q 1.5 -t "@M@" -</encode> <encode>oggenc -r -B 16 -C 2 -R 44100 --raw-endianness 0 -q 1.5 -t @M@ -</encode>
</encdec> </encdec>
</reencode> </reencode>
</ezstream> </ezstream>

View File

@ -1,3 +0,0 @@
#!/bin/sh
svn2cl --stdout -i --reparagraph --break-before-msg -o ChangeLog

View File

@ -14,9 +14,8 @@ ezstream_SOURCES = \
xalloc.c xalloc.c
ezstream_LDADD = @LIBOBJS@ @EZ_LIBS@ ezstream_LDADD = @LIBOBJS@ @EZ_LIBS@
INCLUDES = @COMPAT_INCLUDES@
AM_CFLAGS = @EZ_CFLAGS@ AM_CFLAGS = @EZ_CFLAGS@
AM_CPPFLAGS = @EZ_CPPFLAGS@ AM_CPPFLAGS = @EZ_CPPFLAGS@ @COMPAT_INCLUDES@
AM_LDFLAGS = @EZ_LDFLAGS@ AM_LDFLAGS = @EZ_LDFLAGS@
EXTRA_DIST = \ EXTRA_DIST = \

View File

@ -2,7 +2,7 @@
/* /*
* ezstream - source client for Icecast with external en-/decoder support * ezstream - source client for Icecast with external en-/decoder support
* Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org> * Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org>
* Copyright (C) 2007, 2009 Moritz Grimm <mdgrimm@gmx.net> * Copyright (C) 2007, 2009, 2015 Moritz Grimm <mgrimm@mrsserver.net>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@ -89,7 +89,8 @@ parseConfig(const char *fileName)
xmlNodePtr cur; xmlNodePtr cur;
char *ls_xmlContentPtr; char *ls_xmlContentPtr;
int program_set, reconnect_set, shuffle_set, int program_set, reconnect_set, shuffle_set,
streamOnce_set, svrinfopublic_set; streamOnce_set, svrinfopublic_set,
refresh_set;
unsigned int config_error; unsigned int config_error;
xmlLineNumbersDefault(1); xmlLineNumbersDefault(1);
@ -106,14 +107,17 @@ parseConfig(const char *fileName)
return (0); return (0);
} }
memset(&ezConfig, '\000', sizeof(ezConfig)); memset(&ezConfig, 0, sizeof(ezConfig));
ezConfig.metadataRefreshInterval = -1;
config_error = 0; config_error = 0;
program_set = 0; program_set = 0;
reconnect_set = 0; reconnect_set = 0;
refresh_set = 0;
shuffle_set = 0; shuffle_set = 0;
streamOnce_set = 0; streamOnce_set = 0;
svrinfopublic_set = 0; svrinfopublic_set = 0;
for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
if (!xmlStrcmp(cur->name, (const xmlChar *)"url")) { if (!xmlStrcmp(cur->name, (const xmlChar *)"url")) {
if (ezConfig.URL != NULL) { if (ezConfig.URL != NULL) {
@ -230,6 +234,27 @@ parseConfig(const char *fileName)
} }
} }
} }
if (!xmlStrcmp(cur->name, (const xmlChar *)"metadata_refreshinterval")) {
if (refresh_set) {
printf("%s[%ld]: Error: Cannot have multiple <metadata_refreshinterval> elements\n",
fileName, xmlGetLineNo(cur));
config_error++;
continue;
}
if (cur->xmlChildrenNode != NULL) {
const char *errstr;
ls_xmlContentPtr = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
ezConfig.metadataRefreshInterval = (unsigned int)strtonum(ls_xmlContentPtr, -1LL, (long long)INT_MAX, &errstr);
if (errstr) {
printf("%s[%ld]: Error: In <metadata_refreshinterval>: '%s' is %s\n",
fileName, xmlGetLineNo(cur), ls_xmlContentPtr, errstr);
config_error++;
continue;
}
xmlFree(ls_xmlContentPtr);
refresh_set = 1;
}
}
if (!xmlStrcmp(cur->name, (const xmlChar *)"playlist_program")) { if (!xmlStrcmp(cur->name, (const xmlChar *)"playlist_program")) {
if (program_set) { if (program_set) {
printf("%s[%ld]: Error: Cannot have multiple <playlist_program> elements\n", printf("%s[%ld]: Error: Cannot have multiple <playlist_program> elements\n",

View File

@ -2,7 +2,7 @@
/* /*
* ezstream - source client for Icecast with external en-/decoder support * ezstream - source client for Icecast with external en-/decoder support
* Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org> * Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org>
* Copyright (C) 2007 Moritz Grimm <mdgrimm@gmx.net> * Copyright (C) 2007, 2015 Moritz Grimm <mgrimm@mrsserver.net>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@ -66,6 +66,7 @@ typedef struct tag_EZCONFIG {
int fileNameIsProgram; int fileNameIsProgram;
int streamOnce; int streamOnce;
unsigned int reconnectAttempts; unsigned int reconnectAttempts;
int metadataRefreshInterval;
} EZCONFIG; } EZCONFIG;
EZCONFIG * getEZConfig(void); EZCONFIG * getEZConfig(void);

View File

@ -4,7 +4,7 @@
# Convenience/wrapper script that uses ezstream to stream one or more files # Convenience/wrapper script that uses ezstream to stream one or more files
# given on the command line. # given on the command line.
# Copyright (c) 2009 Moritz Grimm <mdgrimm@gmx.net> # Copyright (c) 2009, 2015 Moritz Grimm <mgrimm@mrsserver.net>
# #
# Permission to use, copy, modify, and distribute this software for any # Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above # purpose with or without fee is hereby granted, provided that the above
@ -21,10 +21,10 @@
_myname="$(basename $0)" _myname="$(basename $0)"
_filename_placeholder="%FILENAME%" _filename_placeholder="%FILENAME%"
_opt_string="hnqT:Vv" _opt_string="hmnqT:Vv"
print_usage() print_usage()
{ {
echo "usage: ${_myname} [-hnqVv] [-T cfg_template] [file ...]" >&2 echo "usage: ${_myname} [-hmnqVv] [-T cfg_template] [file ...]" >&2
} }
print_usage_help() print_usage_help()
@ -32,6 +32,7 @@ print_usage_help()
cat << __EOT >&2 cat << __EOT >&2
-h print this help and exit -h print this help and exit
-m [ezstream] disable metadata updates
-n [ezstream] normalize metadata strings -n [ezstream] normalize metadata strings
-q [ezstream] suppress STDERR output from external en-/decoders -q [ezstream] suppress STDERR output from external en-/decoders
-T template run ezstream using template for configuration -T template run ezstream using template for configuration
@ -45,6 +46,7 @@ See the ezstream-file.sh(1) manual for detailed information.
__EOT __EOT
} }
_metadisable=""
_normalize="" _normalize=""
_quiet="" _quiet=""
_verbose="" _verbose=""
@ -64,6 +66,8 @@ do
print_usage_help print_usage_help
exit 0 exit 0
;; ;;
-m)
_metadisable="-m"; shift ;;
-n) -n)
_normalize="-n"; shift ;; _normalize="-n"; shift ;;
-q) -q)
@ -140,6 +144,6 @@ else
done done
fi fi
${EZSTREAM} ${_normalize} ${_quiet} ${_verbose} -c "${_cfg}" ${EZSTREAM} ${_metadisable} ${_normalize} ${_quiet} ${_verbose} -c "${_cfg}"
exit $? exit $?

View File

@ -2,7 +2,7 @@
/* /*
* ezstream - source client for Icecast with external en-/decoder support * ezstream - source client for Icecast with external en-/decoder support
* Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org> * Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org>
* Copyright (C) 2007, 2009 Moritz Grimm <mdgrimm@gmx.net> * Copyright (C) 2007, 2009, 2015 Moritz Grimm <mgrimm@mrsserver.net>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@ -50,6 +50,7 @@ char *__progname;
#endif /* HAVE___PROGNAME */ #endif /* HAVE___PROGNAME */
int nFlag; int nFlag;
int mFlag;
int qFlag; int qFlag;
int sFlag; int sFlag;
int vFlag; int vFlag;
@ -89,8 +90,8 @@ typedef struct tag_ID3Tag {
} ID3Tag; } ID3Tag;
int urlParse(const char *, char **, unsigned short *, char **); int urlParse(const char *, char **, unsigned short *, char **);
void replaceString(const char *, char *, size_t, const char *, char * shellQuote(const char *);
const char *); char * replaceString(const char *, const char *, const char *);
char * buildCommandString(const char *, const char *, metadata_t *); char * buildCommandString(const char *, const char *, metadata_t *);
char * getMetadataString(const char *, metadata_t *); char * getMetadataString(const char *, metadata_t *);
metadata_t * getMetadata(const char *); metadata_t * getMetadata(const char *);
@ -196,25 +197,67 @@ urlParse(const char *url, char **hostname, unsigned short *port,
return (1); return (1);
} }
void #define SHELLQUOTE_INLEN_MAX 8191UL
replaceString(const char *source, char *dest, size_t size,
const char *from, const char *to)
{
const char *p1 = source;
const char *p2;
char *
shellQuote(const char *in)
{
char *out, *out_p;
size_t out_len;
const char *in_p;
out_len = (strlen(in) > SHELLQUOTE_INLEN_MAX)
? SHELLQUOTE_INLEN_MAX
: strlen(in);
out_len = out_len * 2 + 2;
out = xcalloc(out_len + 1, sizeof(char));
out_p = out;
in_p = in;
*out_p++ = '\'';
out_len--;
while (*in_p && out_len > 2) {
switch (*in_p) {
case '\'':
case '\\':
*out_p++ = '\\';
out_len--;
break;
default:
break;
}
*out_p++ = *in_p++;
out_len--;
}
*out_p++ = '\'';
return (out);
}
char *
replaceString(const char *source, const char *from, const char *to)
{
char *to_quoted, *dest;
size_t dest_size;
const char *p1, *p2;
to_quoted = shellQuote(to);
dest_size = strlen(source) + strlen(to_quoted) + 1;
dest = xcalloc(dest_size, sizeof(char));
p1 = source;
p2 = strstr(p1, from); p2 = strstr(p1, from);
if (p2 != NULL) { if (p2 != NULL) {
if ((unsigned int)(p2 - p1) >= size) {
printf("%s: replaceString(): Internal error: p2 - p1 >= size\n",
__progname);
abort();
}
strncat(dest, p1, (size_t)(p2 - p1)); strncat(dest, p1, (size_t)(p2 - p1));
strlcat(dest, to, size); strlcat(dest, to_quoted, dest_size);
p1 = p2 + strlen(from); p1 = p2 + strlen(from);
} }
strlcat(dest, p1, size); strlcat(dest, p1, dest_size);
xfree(to_quoted);
return (dest);
} }
char * char *
@ -226,9 +269,7 @@ buildCommandString(const char *extension, const char *fileName,
char *encoder = NULL; char *encoder = NULL;
char *decoder = NULL; char *decoder = NULL;
char *newDecoder = NULL; char *newDecoder = NULL;
size_t newDecoderLen = 0;
char *newEncoder = NULL; char *newEncoder = NULL;
size_t newEncoderLen = 0;
char *localTitle = UTF8toCHAR(metadata_get_title(mdata), char *localTitle = UTF8toCHAR(metadata_get_title(mdata),
ICONV_REPLACE); ICONV_REPLACE);
char *localArtist = UTF8toCHAR(metadata_get_artist(mdata), char *localArtist = UTF8toCHAR(metadata_get_artist(mdata),
@ -246,23 +287,16 @@ buildCommandString(const char *extension, const char *fileName,
xfree(decoder); xfree(decoder);
return (NULL); return (NULL);
} }
newDecoderLen = strlen(decoder) + strlen(fileName) + 1; newDecoder = replaceString(decoder, TRACK_PLACEHOLDER, fileName);
newDecoder = xcalloc(newDecoderLen, sizeof(char));
replaceString(decoder, newDecoder, newDecoderLen, TRACK_PLACEHOLDER,
fileName);
if (strstr(decoder, ARTIST_PLACEHOLDER) != NULL) { if (strstr(decoder, ARTIST_PLACEHOLDER) != NULL) {
size_t tmpLen = strlen(newDecoder) + strlen(localArtist) + 1; char *tmpStr = replaceString(newDecoder, ARTIST_PLACEHOLDER,
char *tmpStr = xcalloc(tmpLen, sizeof(char)); localArtist);
replaceString(newDecoder, tmpStr, tmpLen, ARTIST_PLACEHOLDER,
localArtist);
xfree(newDecoder); xfree(newDecoder);
newDecoder = tmpStr; newDecoder = tmpStr;
} }
if (strstr(decoder, TITLE_PLACEHOLDER) != NULL) { if (strstr(decoder, TITLE_PLACEHOLDER) != NULL) {
size_t tmpLen = strlen(newDecoder) + strlen(localTitle) + 1; char *tmpStr = replaceString(newDecoder, TITLE_PLACEHOLDER,
char *tmpStr = xcalloc(tmpLen, sizeof(char)); localTitle);
replaceString(newDecoder, tmpStr, tmpLen, TITLE_PLACEHOLDER,
localTitle);
xfree(newDecoder); xfree(newDecoder);
newDecoder = tmpStr; newDecoder = tmpStr;
} }
@ -279,27 +313,20 @@ buildCommandString(const char *extension, const char *fileName,
if (strstr(decoder, METADATA_PLACEHOLDER) != NULL) { if (strstr(decoder, METADATA_PLACEHOLDER) != NULL) {
if (metadataFromProgram && pezConfig->metadataFormat != NULL) { if (metadataFromProgram && pezConfig->metadataFormat != NULL) {
char *mdataString = getMetadataString(pezConfig->metadataFormat, mdata); char *mdataString = getMetadataString(pezConfig->metadataFormat, mdata);
size_t tmpLen = strlen(newDecoder) + strlen(mdataString) + 1; char *tmpStr = replaceString(newDecoder,
char *tmpStr = xcalloc(tmpLen, sizeof(char)); METADATA_PLACEHOLDER, mdataString);
replaceString(newDecoder, tmpStr, tmpLen,
METADATA_PLACEHOLDER, mdataString);
xfree(newDecoder); xfree(newDecoder);
xfree(mdataString); xfree(mdataString);
newDecoder = tmpStr; newDecoder = tmpStr;
} else { } else {
if (!metadataFromProgram && strstr(decoder, TITLE_PLACEHOLDER) != NULL) { if (!metadataFromProgram && strstr(decoder, TITLE_PLACEHOLDER) != NULL) {
size_t tmpLen = strlen(newDecoder) + 1; char *tmpStr = replaceString(newDecoder,
char *tmpStr = xcalloc(tmpLen, sizeof(char)); METADATA_PLACEHOLDER, "");
replaceString(newDecoder, tmpStr, tmpLen,
METADATA_PLACEHOLDER, "");
xfree(newDecoder); xfree(newDecoder);
newDecoder = tmpStr; newDecoder = tmpStr;
} else { } else {
size_t tmpLen = strlen(newDecoder) + strlen(localMetaString) + 1; char *tmpStr = replaceString(newDecoder,
char *tmpStr = xcalloc(tmpLen, sizeof(char)); METADATA_PLACEHOLDER, localMetaString);
replaceString(newDecoder, tmpStr, tmpLen,
METADATA_PLACEHOLDER,
localMetaString);
xfree(newDecoder); xfree(newDecoder);
newDecoder = tmpStr; newDecoder = tmpStr;
} }
@ -325,42 +352,30 @@ buildCommandString(const char *extension, const char *fileName,
return (commandString); return (commandString);
} }
newEncoderLen = strlen(encoder) + strlen(localArtist) + 1; newEncoder = replaceString(encoder, ARTIST_PLACEHOLDER, localArtist);
newEncoder = xcalloc(newEncoderLen, sizeof(char));
replaceString(encoder, newEncoder, newEncoderLen, ARTIST_PLACEHOLDER,
localArtist);
if (strstr(encoder, TITLE_PLACEHOLDER) != NULL) { if (strstr(encoder, TITLE_PLACEHOLDER) != NULL) {
size_t tmpLen = strlen(newEncoder) + strlen(localTitle) + 1; char *tmpStr = replaceString(newEncoder, TITLE_PLACEHOLDER,
char *tmpStr = xcalloc(tmpLen, sizeof(char)); localTitle);
replaceString(newEncoder, tmpStr, tmpLen, TITLE_PLACEHOLDER,
localTitle);
xfree(newEncoder); xfree(newEncoder);
newEncoder = tmpStr; newEncoder = tmpStr;
} }
if (strstr(encoder, METADATA_PLACEHOLDER) != NULL) { if (strstr(encoder, METADATA_PLACEHOLDER) != NULL) {
if (metadataFromProgram && pezConfig->metadataFormat != NULL) { if (metadataFromProgram && pezConfig->metadataFormat != NULL) {
char *mdataString = getMetadataString(pezConfig->metadataFormat, mdata); char *mdataString = getMetadataString(pezConfig->metadataFormat, mdata);
size_t tmpLen = strlen(newEncoder) + strlen(mdataString) + 1; char *tmpStr = replaceString(newEncoder,
char *tmpStr = xcalloc(tmpLen, sizeof(char)); METADATA_PLACEHOLDER, mdataString);
replaceString(newEncoder, tmpStr, tmpLen,
METADATA_PLACEHOLDER, mdataString);
xfree(newEncoder); xfree(newEncoder);
xfree(mdataString); xfree(mdataString);
newEncoder = tmpStr; newEncoder = tmpStr;
} else { } else {
if (!metadataFromProgram && strstr(encoder, TITLE_PLACEHOLDER) != NULL) { if (!metadataFromProgram && strstr(encoder, TITLE_PLACEHOLDER) != NULL) {
size_t tmpLen = strlen(newEncoder) + 1; char *tmpStr = replaceString(newEncoder,
char *tmpStr = xcalloc(tmpLen, sizeof(char)); METADATA_PLACEHOLDER, "");
replaceString(newEncoder, tmpStr, tmpLen,
METADATA_PLACEHOLDER, "");
xfree(newEncoder); xfree(newEncoder);
newEncoder = tmpStr; newEncoder = tmpStr;
} else { } else {
size_t tmpLen = strlen(newEncoder) + strlen(localMetaString) + 1; char *tmpStr = replaceString(newEncoder,
char *tmpStr = xcalloc(tmpLen, sizeof(char)); METADATA_PLACEHOLDER, localMetaString);
replaceString(newEncoder, tmpStr, tmpLen,
METADATA_PLACEHOLDER,
localMetaString);
xfree(newEncoder); xfree(newEncoder);
newEncoder = tmpStr; newEncoder = tmpStr;
} }
@ -388,7 +403,6 @@ char *
getMetadataString(const char *format, metadata_t *mdata) getMetadataString(const char *format, metadata_t *mdata)
{ {
char *tmp, *str; char *tmp, *str;
size_t len;
if (mdata == NULL) { if (mdata == NULL) {
printf("%s: getMetadataString(): Internal error: NULL metadata_t\n", printf("%s: getMetadataString(): Internal error: NULL metadata_t\n",
@ -402,34 +416,26 @@ getMetadataString(const char *format, metadata_t *mdata)
str = xstrdup(format); str = xstrdup(format);
if (strstr(format, ARTIST_PLACEHOLDER) != NULL) { if (strstr(format, ARTIST_PLACEHOLDER) != NULL) {
len = strlen(str) + strlen(metadata_get_artist(mdata)) + 1; tmp = replaceString(str, ARTIST_PLACEHOLDER,
tmp = xcalloc(len, sizeof(char)); metadata_get_artist(mdata));
replaceString(str, tmp, len, ARTIST_PLACEHOLDER,
metadata_get_artist(mdata));
xfree(str); xfree(str);
str = tmp; str = tmp;
} }
if (strstr(format, TITLE_PLACEHOLDER) != NULL) { if (strstr(format, TITLE_PLACEHOLDER) != NULL) {
len = strlen(str) + strlen(metadata_get_title(mdata)) + 1; tmp = replaceString(str, TITLE_PLACEHOLDER,
tmp = xcalloc(len, sizeof(char)); metadata_get_title(mdata));
replaceString(str, tmp, len, TITLE_PLACEHOLDER,
metadata_get_title(mdata));
xfree(str); xfree(str);
str = tmp; str = tmp;
} }
if (strstr(format, STRING_PLACEHOLDER) != NULL) { if (strstr(format, STRING_PLACEHOLDER) != NULL) {
len = strlen(str) + strlen(metadata_get_string(mdata)) + 1; tmp = replaceString(str, STRING_PLACEHOLDER,
tmp = xcalloc(len, sizeof(char)); metadata_get_string(mdata));
replaceString(str, tmp, len, STRING_PLACEHOLDER,
metadata_get_string(mdata));
xfree(str); xfree(str);
str = tmp; str = tmp;
} }
if (strstr(format, TRACK_PLACEHOLDER) != NULL) { if (strstr(format, TRACK_PLACEHOLDER) != NULL) {
len = strlen(str) + strlen(metadata_get_filename(mdata)) + 1; tmp = replaceString(str, TRACK_PLACEHOLDER,
tmp = xcalloc(len, sizeof(char)); metadata_get_filename(mdata));
replaceString(str, tmp, len, TRACK_PLACEHOLDER,
metadata_get_filename(mdata));
xfree(str); xfree(str);
str = tmp; str = tmp;
} }
@ -477,6 +483,9 @@ setMetadata(shout_t *shout, metadata_t *mdata, char **mdata_copy)
abort(); abort();
} }
if (mFlag)
return (SHOUTERR_SUCCESS);
if (mdata == NULL) if (mdata == NULL)
return 1; return 1;
@ -750,6 +759,7 @@ sendStream(shout_t *shout, FILE *filepstream, const char *fileName,
int ret; int ret;
double kbps = -1.0; double kbps = -1.0;
struct timeval timeStamp, *startTime = tv; struct timeval timeStamp, *startTime = tv;
struct timeval callTime, currentTime;
if (startTime == NULL) { if (startTime == NULL) {
printf("%s: sendStream(): Internal error: startTime is NULL\n", printf("%s: sendStream(): Internal error: startTime is NULL\n",
@ -757,6 +767,8 @@ sendStream(shout_t *shout, FILE *filepstream, const char *fileName,
abort(); abort();
} }
ez_gettimeofday((void *)&callTime);
timeStamp.tv_sec = startTime->tv_sec; timeStamp.tv_sec = startTime->tv_sec;
timeStamp.tv_usec = startTime->tv_usec; timeStamp.tv_usec = startTime->tv_usec;
@ -795,7 +807,15 @@ sendStream(shout_t *shout, FILE *filepstream, const char *fileName,
ret = STREAM_SKIP; ret = STREAM_SKIP;
break; break;
} }
if (queryMetadata) {
ez_gettimeofday((void *)&currentTime);
if (queryMetadata ||
(pezConfig->metadataRefreshInterval != -1
&& (currentTime.tv_sec - callTime.tv_sec
>= pezConfig->metadataRefreshInterval)
)
) {
queryMetadata = 0; queryMetadata = 0;
if (metadataFromProgram) { if (metadataFromProgram) {
ret = STREAM_UPDMDATA; ret = STREAM_UPDMDATA;
@ -805,8 +825,7 @@ sendStream(shout_t *shout, FILE *filepstream, const char *fileName,
total += bytes_read; total += bytes_read;
if (qFlag && vFlag) { if (qFlag && vFlag) {
struct timeval tval; double oldTime, newTime;
double oldTime, newTime;
if (!isStdin && playlistMode) { if (!isStdin && playlistMode) {
if (pezConfig->fileNameIsProgram) { if (pezConfig->fileNameIsProgram) {
@ -822,20 +841,22 @@ sendStream(shout_t *shout, FILE *filepstream, const char *fileName,
oldTime = (double)timeStamp.tv_sec oldTime = (double)timeStamp.tv_sec
+ (double)timeStamp.tv_usec / 1000000.0; + (double)timeStamp.tv_usec / 1000000.0;
ez_gettimeofday((void *)&tval); newTime = (double)currentTime.tv_sec
newTime = (double)tval.tv_sec + (double)currentTime.tv_usec / 1000000.0;
+ (double)tval.tv_usec / 1000000.0;
if (songLenStr == NULL) if (songLenStr == NULL)
printf(" [ %s]", printf(" [ %s]",
getTimeString(tval.tv_sec - startTime->tv_sec)); getTimeString(currentTime.tv_sec -
startTime->tv_sec));
else else
printf(" [ %s/%s]", printf(" [ %s/%s]",
getTimeString(tval.tv_sec - startTime->tv_sec), getTimeString(currentTime.tv_sec -
startTime->tv_sec),
songLenStr); songLenStr);
if (newTime - oldTime >= 1.0) { if (newTime - oldTime >= 1.0) {
kbps = (((double)(total - oldTotal) / (newTime - oldTime)) * 8.0) / 1000.0; kbps = (((double)(total - oldTotal)
timeStamp.tv_sec = tval.tv_sec; / (newTime - oldTime)) * 8.0) / 1000.0;
timeStamp.tv_usec = tval.tv_usec; timeStamp.tv_sec = currentTime.tv_sec;
timeStamp.tv_usec = currentTime.tv_usec;
oldTotal = total; oldTotal = total;
} }
if (kbps < 0) if (kbps < 0)
@ -936,6 +957,8 @@ streamFile(shout_t *shout, const char *fileName)
} }
if (ret == STREAM_UPDMDATA || queryMetadata) { if (ret == STREAM_UPDMDATA || queryMetadata) {
queryMetadata = 0; queryMetadata = 0;
if (mFlag)
continue;
if (metadataFromProgram) { if (metadataFromProgram) {
char *mdataStr = NULL; char *mdataStr = NULL;
metadata_t *prog_mdata; metadata_t *prog_mdata;
@ -954,8 +977,9 @@ streamFile(shout_t *shout, const char *fileName)
continue; continue;
} }
metadata_free(&prog_mdata); metadata_free(&prog_mdata);
printf("%s: New metadata: ``%s''\n", if (vFlag > 1)
__progname, mdataStr); printf("%s: New metadata: ``%s''\n",
__progname, mdataStr);
xfree(mdataStr); xfree(mdataStr);
} }
} }
@ -969,7 +993,7 @@ streamFile(shout_t *shout, const char *fileName)
if (popenFlag) if (popenFlag)
pclose(filepstream); pclose(filepstream);
else else if (!isStdin)
fclose(filepstream); fclose(filepstream);
if (songLenStr != NULL) if (songLenStr != NULL)
@ -1073,7 +1097,7 @@ ez_shutdown(int exitval)
void void
usage(void) usage(void)
{ {
printf("usage: %s [-hnqVv] -c configfile\n", __progname); printf("usage: %s [-hmnqVv] -c configfile\n", __progname);
printf(" %s -s [playlist]\n", __progname); printf(" %s -s [playlist]\n", __progname);
} }
@ -1083,6 +1107,7 @@ usageHelp(void)
printf("\n"); printf("\n");
printf(" -c configfile use XML configuration in configfile (mandatory)\n"); printf(" -c configfile use XML configuration in configfile (mandatory)\n");
printf(" -h display this additional help and exit\n"); printf(" -h display this additional help and exit\n");
printf(" -m disable metadata updates\n");
printf(" -n normalize metadata strings\n"); printf(" -n normalize metadata strings\n");
printf(" -q suppress STDERR output from external en-/decoders\n"); printf(" -q suppress STDERR output from external en-/decoders\n");
printf(" -s [playlist] read lines from playlist (or STDIN), shuffle and print them to\n"); printf(" -s [playlist] read lines from playlist (or STDIN), shuffle and print them to\n");
@ -1120,11 +1145,12 @@ main(int argc, char *argv[])
__progname = getProgname(argv[0]); __progname = getProgname(argv[0]);
pezConfig = getEZConfig(); pezConfig = getEZConfig();
mFlag = 0;
nFlag = 0; nFlag = 0;
qFlag = 0; qFlag = 0;
vFlag = 0; vFlag = 0;
while ((c = local_getopt(argc, argv, "c:hnqsVv")) != -1) { while ((c = local_getopt(argc, argv, "c:hmnqsVv")) != -1) {
switch (c) { switch (c) {
case 'c': case 'c':
if (configFile != NULL) { if (configFile != NULL) {
@ -1138,6 +1164,9 @@ main(int argc, char *argv[])
usage(); usage();
usageHelp(); usageHelp();
return (ez_shutdown(0)); return (ez_shutdown(0));
case 'm':
mFlag = 1;
break;
case 'n': case 'n':
nFlag = 1; nFlag = 1;
break; break;
@ -1316,7 +1345,6 @@ main(int argc, char *argv[])
printf("%s: Using program '%s' to get filenames for streaming\n", printf("%s: Using program '%s' to get filenames for streaming\n",
__progname, pezConfig->fileName); __progname, pezConfig->fileName);
ret = 1;
do { do {
if (playlistMode) { if (playlistMode) {
ret = streamPlaylist(shout, ret = streamPlaylist(shout,

View File

@ -1,6 +1,6 @@
/* $Id$ */ /* $Id$ */
/* /*
* Copyright (c) 2007, 2009 Moritz Grimm <mdgrimm@gmx.net> * Copyright (c) 2007, 2009 Moritz Grimm <mgrimm@mrsserver.net>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -27,9 +27,8 @@
#endif /* HAVE_SYS_TYPES_H */ #endif /* HAVE_SYS_TYPES_H */
#ifdef HAVE_SYS_TIME_H #ifdef HAVE_SYS_TIME_H
# include <sys/time.h> # include <sys/time.h>
#else /* HAVE_SYS_TIME_H */
# include <time.h>
#endif /* HAVE_SYS_TIME_H */ #endif /* HAVE_SYS_TIME_H */
#include <time.h>
#ifdef HAVE_SYS_STAT_H #ifdef HAVE_SYS_STAT_H
# include <sys/stat.h> # include <sys/stat.h>
#endif /* HAVE_SYS_STAT_H */ #endif /* HAVE_SYS_STAT_H */

View File

@ -1,6 +1,6 @@
/* $Id$ */ /* $Id$ */
/* /*
* Copyright (c) 2007, 2009 Moritz Grimm <mdgrimm@gmx.net> * Copyright (c) 2007, 2009 Moritz Grimm <mgrimm@mrsserver.net>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above

View File

@ -1,6 +1,6 @@
/* $Id$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Moritz Grimm <mdgrimm@gmx.net> * Copyright (c) 2007 Moritz Grimm <mgrimm@mrsserver.net>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above

View File

@ -1,6 +1,6 @@
/* $Id$ */ /* $Id$ */
/* /*
* Copyright (c) 2007, 2009 Moritz Grimm <mdgrimm@gmx.net> * Copyright (c) 2007, 2009 Moritz Grimm <mgrimm@mrsserver.net>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above

View File

@ -1,6 +1,6 @@
/* $Id$ */ /* $Id$ */
/* /*
* Copyright (c) 2007 Moritz Grimm <mdgrimm@gmx.net> * Copyright (c) 2007 Moritz Grimm <mgrimm@mrsserver.net>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above

View File

@ -2,7 +2,7 @@
/* /*
* ezstream - source client for Icecast with external en-/decoder support * ezstream - source client for Icecast with external en-/decoder support
* Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org> * Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org>
* Copyright (C) 2007, 2009 Moritz Grimm <mdgrimm@gmx.net> * Copyright (C) 2007, 2009 Moritz Grimm <mgrimm@mrsserver.net>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as

View File

@ -2,7 +2,7 @@
/* /*
* ezstream - source client for Icecast with external en-/decoder support * ezstream - source client for Icecast with external en-/decoder support
* Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org> * Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org>
* Copyright (C) 2007 Moritz Grimm <mdgrimm@gmx.net> * Copyright (C) 2007 Moritz Grimm <mgrimm@mrsserver.net>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as

View File

@ -1,6 +1,6 @@
/* $Id$ */ /* $Id$ */
/* /*
* Copyright (C) 2007 Moritz Grimm <mdgrimm@gmx.net> * Copyright (C) 2007 Moritz Grimm <mgrimm@mrsserver.net>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above

View File

@ -7,7 +7,7 @@
* and ensures that out-of-memory issues always cause the * and ensures that out-of-memory issues always cause the
* application to exit. * application to exit.
* *
* Copyright (C) 2007 Moritz Grimm <mdgrimm@gmx.net> * Copyright (C) 2007 Moritz Grimm <mgrimm@mrsserver.net>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above

View File

@ -67,13 +67,13 @@ A few useful features are missing in the Windows version of ezstream:
Ezstream uses: Ezstream uses:
* zlib (http://www.zlib.net/, BSD-like license) * zlib (http://www.zlib.net/, BSD-like license)
* libiconv (http://www.gnu.org/software/libiconv/, LGPL) * libiconv (https://www.gnu.org/software/libiconv/, LGPL)
* libxml2 (http://xmlsoft.org/, BSD-like license) * libxml2 (http://xmlsoft.org/, BSD-like license)
* libogg, libvorbis, libvorbisfile (http://www.vorbis.com/, BSD-like license) * libogg, libvorbis, libvorbisfile (http://www.vorbis.com/, BSD-like license)
* libFLAC (http://flac.sourceforge.net/, BSD-like license) * libFLAC (https://xiph.org/flac/, BSD-like license)
* libtheora (http://www.theora.org/, BSD-like license) * libtheora (http://www.theora.org/, BSD-like license)
* libshout (http://www.icecast.org, LGPL) * libshout (http://www.icecast.org, LGPL)
* TagLib (http://ktown.kde.org/~wheeler/taglib.html, LGPL) * TagLib (https://taglib.github.io/, LGPL)
These libraries are statically linked into the ezstream.exe file. These libraries are statically linked into the ezstream.exe file.

View File

@ -1,7 +1,7 @@
#ifndef __WIN32_CONFIG_H__ #ifndef __WIN32_CONFIG_H__
#define __WIN32_CONFIG_H__ #define __WIN32_CONFIG_H__
#define PACKAGE_STRING "ezstream 0.5.6" #define PACKAGE_STRING "ezstream 0.6.0"
#define HAVE_SYS_TYPES_H 1 #define HAVE_SYS_TYPES_H 1
#define HAVE_SYS_STAT_H 1 #define HAVE_SYS_STAT_H 1