From 5bd1bee84eaad5e8a10754636ac014e113d664c4 Mon Sep 17 00:00:00 2001 From: Karl Heyes Date: Tue, 29 Jan 2008 03:24:47 +0000 Subject: [PATCH] doc updates, and some minor changes for the sample conf files. svn path=/icecast/trunk/icecast/; revision=14437 --- conf/icecast_shoutcast_compat.xml.in | 14 +- conf/icecast_urlauth.xml.in | 4 +- doc/Makefile.am | 3 +- doc/icecast2_config_file.html | 262 +++++++++++++++++---------- doc/icecast2_listenerauth.html | 4 +- doc/masterslave.png | Bin 0 -> 9346 bytes doc/relay.png | Bin 0 -> 9921 bytes 7 files changed, 170 insertions(+), 117 deletions(-) create mode 100644 doc/masterslave.png create mode 100644 doc/relay.png diff --git a/conf/icecast_shoutcast_compat.xml.in b/conf/icecast_shoutcast_compat.xml.in index 20da6b96..9e274501 100644 --- a/conf/icecast_shoutcast_compat.xml.in +++ b/conf/icecast_shoutcast_compat.xml.in @@ -19,13 +19,6 @@ 15 http://dir.xiph.org/cgi-bin/yp-cgi - - /stream - @@ -36,12 +29,7 @@ the shoutcast DSP actually will connect the encoder to this port + 1 --> 8000 - - - - 8001 - 1 + /stream 1 diff --git a/conf/icecast_urlauth.xml.in b/conf/icecast_urlauth.xml.in index bd2fbaeb..9a1044d1 100644 --- a/conf/icecast_urlauth.xml.in +++ b/conf/icecast_urlauth.xml.in @@ -3,12 +3,10 @@ 100 2 - 5 524288 30 15 10 - 1 65535 @@ -41,7 +39,7 @@ access.log error.log - 4 + 3 0 diff --git a/doc/Makefile.am b/doc/Makefile.am index c6ef1bae..7d2d8c45 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -7,7 +7,8 @@ doc_DATA = index.html icecast2_admin.html icecast2_basicsetup.html \ icecast2_config_file.html icecast2_faq.html icecast2_glossary.html \ icecast2_introduction.html icecast2_relay.html icecast2_stats.html \ icecast2_win32.html icecast2_yp.html icecast2_listenerauth.html icecast2_changes.html \ - listener_auth1.jpg listener_auth2.jpg listener_auth3.jpg + listener_auth1.jpg listener_auth2.jpg listener_auth3.jpg \ + masterslave.png relay.png EXTRA_DIST = Index.hhk icecast2.hhc icecast2.hhp index_win32.html \ stats1.jpg style.css win32_section1.html win32_section2.html \ diff --git a/doc/icecast2_config_file.html b/doc/icecast2_config_file.html index a5ed06e8..ee1d1db4 100644 --- a/doc/icecast2_config_file.html +++ b/doc/icecast2_config_file.html @@ -16,7 +16,7 @@ This section will describe each section of the config file and is grouped into t
  • Limits
  • Authentication
  • -
  • YP Directory Settings
  • +
  • Stream Directory Settings
  • Misc Server settings
  • Relay settings
  • Mount Specific settings
  • @@ -35,7 +35,6 @@ This section will describe each section of the config file and is grouped into t <limits> <clients>100</clients> <sources>2</sources> - <threadpool>5</threadpool> <queue-size>102400</queue-size> <client-timeout>30</client-timeout> <header-timeout>15</header-timeout> @@ -48,19 +47,21 @@ This section will describe each section of the config file and is grouped into t

    clients

    -Total number of concurrent clients supported by the server. Listeners are considered clients, but so is accesses to any static content (i.e. fileserved content) and also any requests to gather stats. These are max *concurrent* connections for the entire server (not per mountpoint). +Total number of concurrent clients supported by the server. Listeners are considered clients, but so are accesses to any static content (i.e. fileserved content) and also any requests to gather stats. These are max *concurrent* connections for the entire server (not per mountpoint).

    sources

    -Maximum number of connected sources supported by the server. -
    -

    threadpool

    -
    -This is the number of threads that are started to handle client connections. You may need to increase this value if you are running a high traffic stream. This recommended value is for a small to medium traffic server. +Maximum number of connected sources supported by the server. This includes active relays and source clients

    queue-size

    -This is the maximum size (in bytes) of a client (listener) queue. A listener may temporarily lag behind due to network congestion and in this case an internal queue is maintained for each listener. If the queue grows larger than this config value, then the listener will be removed from the stream. + This is the maximum size (in bytes) of the stream queue. A listener may temporarily lag behind + due to network congestion and in this case an internal queue is maintained for the listeners. + If the queue grows larger than this config value, then it is truncated and any listeners found + will be removed from the stream.
    + This will be the default setting for the streams which is 512k unless overridden here. You can + override this in the individual mount settings which can be useful if you have a mixture of high + bandwidth video and low bitrate audio streams.

    client-timeout

    @@ -76,14 +77,15 @@ If a connected source does not send any data within this timeout period (in seco

    burst-on-connect

    -With this enabled, a connecting client will be sent a burst of audio data from the stream. This will have the effect of reducing the startup time for the stream from the perspective of the listener. This is due to the fact that most media players have local buffers that must be filled before the stream begins to play. This may introduce a small latency in the stream (difference in time between when the source plays a clip and the listener hears a clip). If this latency is important to you, then you can disable this feature. The latency is bitrate-dependent, but as an example, for a 128kbps stream, the latency between the source and the player is ~ 1.5 secs WITHOUT burst on connect, and WITH burst on connect the latency is 3 secs. + This setting is really just an alias for burst-size. When enabled the burst-size is 64 kbytes + and disabled the burst-size is 0 kbytes. This option is deprecated, use burst-size instead.

    burst-size

    The burst size is the amount of data (in bytes) to burst to a client at connection time. Like burst-on-connect, this is to quickly fill the pre-buffer used by media players. The default -is 64kbytes which is a typical size used by most clients so changing it is not usually required. -This setting applies to all mountpoints. +is 64 kbytes which is a typical size used by most clients so changing it is not usually required. +This setting applies to all mountpoints unless overridden in the mount settings.


    @@ -101,11 +103,13 @@ This setting applies to all mountpoints. <admin-password>hackme</admin-password> </authentication> -

    This section contains all the users and passwords used for administration purposes or to connect sources and relays. +

    This section contains all the usernames and passwords used for administration purposes or to connect sources and relays.

    source-password

    -The unencrypted password used by sources to connect to icecast2. Currently, the username for all source connections must be 'source'. This is likely to change in the future. + The unencrypted password used by sources to connect to icecast2. The default username + for all source connections is 'source' but this option allows to specify a default + password. This and the username can be changed in the individual mount sections.

    relay-user

    @@ -128,7 +132,7 @@ The username/password used for all administration functions. This includes retr

    -

    YP Directory Settings

    +

    Stream Directory Settings

         <directory>
             <yp-url-timeout>15</yp-url-timeout>
    @@ -152,32 +156,79 @@ The URL which icecast2 uses to communicate with the Directory server.  The value
     

    Misc Server Settings

    +

    Server wide settings.

         <hostname>localhost<hostname>
    +    <fileserve>1</fileserve>
    +    <server-id>icecast 2.3</server-id>
    +
    - <-- You can use these two if you only want a single listening socket --> - <-- <port>8000</port> --> - <-- <bind-address>127.0.0.1</bind-address> --> +

    hostname

    +
    + This is the DNS name or IP address that will be used for the stream directory lookups or + possibily the playlist generation if a Host header is not provided. While localhost is shown + as an example, in fact you will want something that your listeners can use. +
    +

    fileserve

    +
    + This flag turns on the icecast2 fileserver from which static files can be served. All files + are served relative to the path specified in the <paths><webroot> configuration + setting. By default the setting is enabled so that requests for the images on the status + page are retrievable. +
    +

    server-id

    +
    + This optional setting allows for the administrator of the server to override the default + server identification. The default is icecast followed by a version number and most will + not care to change it however this setting will change that. +
    + +

    The following shows how you can specify the listening settings for the server.

    The +first shows an example of a common and simple way to define a listening socket +

    +    <listen-socket>
    +        <port>8000</port>
    +    </listen-socket>
    +
    +

    Using this as a basis we can extend this with an <bind-address> setting to limit which +address icecast will listen on. Most will not need to use bind-address and often get confused +by using it when there is no need. Another possibility is to use an <ssl> boolean setting +which informs icecast that a secured connection is to be used. A common use for using a secure +connection would be for admin page access.

    +

    The following shows how we can extend a single listen-socket to work with shoutcast style +source clients. There are two issues shoutcast source clients have over icecast source clients, +one is the lack of mountpoint and the second is the requirement of two ports. Both of these +issues are handled by a simple addition in the listen-socket.

    +
    +    <listen-socket>
    +        <port>8000</port>
    +        <shoutcast-mount>/live.mp3</shoutcast-mount>
    +    </listen-socket>
    +
    +

    As before the port specified is allocated but this time the shoutcast-mount implicity defines +a second listening socket whose port number is always one higher than the port defined, this also +informs icecast of which mountpoint the shoutcast source client on this socket will be using. +Using this approach you can allow multiple shoutcast source clients to connect at the same time. +

    The following is just to show the longer approach to defining shoutcast compatability.

    +
    +    <shoutcast-mount>/live.nsv</shoutcast-mount>
     
         <-- You may have multiple <listen-socket> elements -->
         <listen-socket>
             <port>8000</port>
    -        <bind-address>127.0.0.1</bind-address>
    -    </listen-socket>
    -    <listen-socket>
    -        <port>8001</port>
    -        <bind-address>127.0.0.1</bind-address>
    -        <shoutcast-compat>1</shoutcast-compat>
         </listen-socket>
     
    -    <fileserve>1</fileserve>
    -    <shoutcast-mount>/live.nsv</shoutcast-mount>
    +    <listen-socket>
    +        <port>8001</port>
    +        <shoutcast-compat>1</shoutcast-compat>
    +    </listen-socket>
     
    -

    This section contains miscellaneous server settings. Note that multiple listen-socket -sections may be configured in order to have icecast2 listen on multiple network interfaces. + +

    Note that multiple listen-socket sections may be configured in order to have icecast2 listen +on multiple network interfaces or multiple ports. If a bind-address is not specified for a particular listen-socket, then the socket will be -bound to all interfaces. Generally, you won't need to set bind-address. There is an internal -limit of 20 listening sockets currently, which may be extended in later releases. +bound to all interfaces (including IPv6 if available). For most people, the bind-address option +will not be required and often confuses people.

    port

    @@ -187,27 +238,38 @@ The TCP port that will be used to accept client connections.
    An optional IP address that can be used to bind to a specific network card. If not supplied, then it will bind to all interfaces.
    +

    shoutcast-mount

    +
    + An optional mountpoint setting to be used when shoutcast DSP compatible clients connect. The + default global setting is /stream but can be overridden here to use an alternative name which + may include an extension that some clients require for certain formats.

    + Defining this within a listen-socket group tells icecast that this port and the subsequent + port are to be used for shoutcast compatible source clients. This is an alternative to the + shoutcast-compat approach as this implicitly defines the second listening socket and allows + for specifying multiple sockets using different mountpoints for shoutcast source + clients. The shoutcast-mount outside of a listen-socket group is the global setting of the + mountpoint to use. +

    shoutcast-compat

    This optional flag will indicate that this port will operate in 'shoutcast-compatibility' mode. Due to major differences in the source client connection protocol, if you wish to use any of the shoutcast DJ tools, you will need to configure at least one socket as shoutcast-compatible. Note that when in this mode, only source clients (and specifically shoutcast source clients) will be able to attach to this port. All listeners may connect to any of the ports defined without this flag. Also, for proper Shoutcast DSP compatibility, you must define a listen socket with a port one less than the one defined as 'shoutcast-compat'. This means if you define 8001 as shoutcast-compat, then you will need to define a listen port of 8000 and it must not also be defined as shoutcast-compat. See the example config file in the distribution for more info.
    -

    fileserve

    -
    -This flag turns on the icecast2 fileserver from which static files can be served. All files are served relative to the path specified in the <paths><webroot> configuration setting. -
    -

    shoutcast-mount

    -
    -An optional mountpoint to use when shoutcast DSP compatible clients connect. The default is /stream but can -be overridden here to use an alternative name which may include an extension that some clients require for -certain formats. -




    -

    Relay Settings

    +

    Relaying Streams

    + +

    This section contains the servers relay settings. The relays are implemented using a pull system where +the receiving server connects as if its a listener to the sending server. There are two types of relay +setups: a "Master server relay" or a "Specific Mountpoint relay." +

    +

    Master Relay

    +

    +A Master server relay is only supported between icecast2 servers and is used to relay a number of +mountpoints from a remote icecast2 server.

         <master-server>127.0.0.1</master-server>
         <master-server-port>8001</master-server-port>
    @@ -215,38 +277,14 @@ certain formats.
         <master-username>relay</master-username>
         <master-password>hackme</master-password>
         <relays-on-demand>0</relays-on-demand>
    -
    -    <relay>
    -        <server>127.0.0.1</server>
    -        <port>8001</port>
    -        <mount>/example.ogg</mount>
    -        <local-mount>/different.ogg</local-mount>
    -        <username>joe</username>
    -        <password>soap</password>
    -        <relay-shoutcast-metadata>0</relay-shoutcast-metadata>
    -        <on-demand>0</on-demand>
    -    </relay>
    -
    -

    This section contains the server's relay settings. There are two types of relays: a "Master server relay" or a "Specific Mountpoint relay." A Master server relay is only supported between icecast2 servers and is used to relays all mountpoints on a remote icecast2 server. -

    -

    Master Relay

    -

    -The following diagram shows the basics of doing a Master relay. Note that Server 1 is configured with the <master-server>, <master-server-port>, etc settings and Server 2 is the server from which Server 1 will pull all attached mountpoints and relay them. Using a Master Server relay, ALL mountpoints on Server 2 will be relayed. If only specific mountpoints need to be relayed, then you must configure Server 1 as a "Specific Mountpoint Relay". Both Master server relays and Specific Mountpoint relays begin their "relaying" when the Server is started. -

    -
    -      |-----|                       |-----|
    -      |     |  all mountpoints      |     | /mount1
    -      |     | <-------------------  |     | /mount2.ogg
    -      |-----|                       |-----| /mount3
    -      Icecast 2                     Icecast 2
    -      Server 1                      Server 2
    -      (RELAY SERVER)                (MASTER SERVER)
    -
    -     configured with
    -     <master-server>
    -     settings
    -
     
    +
    +

    The following diagram shows the basics of using a Master relay. Please note that the slave is +configured with the <master-server>, <master-server-port>, etc settings and the +master is the icecast server from which the slave will pull mountpoints and relay them. Using a +Master server relay, all non-hidden mountpoints on the master can be relayed using this mechanism.

    +
    +

    A server is configured as a Master Server relay by specifying the <master-server>, <master-server-port>,<master-update-interval>,<master-password> values in the config file. The server that is being relayed does not need any special configuration.

    @@ -276,33 +314,29 @@ server for a list of mountpoints to relay.

    relays-on-demand

    -

    Changes the default on-demand setting for relays, so a stream is only relayed if - listeners are connected. 1=enabled, 0=disabled (default). -

    +Global on-demand setting for relays. Because you do not have individual relay options when using a +master server relay, you still may want those relays to only pull the stream when there is at least +one listener on the slave. The typical case here is to avoid surplus bandwidth costs when no one is +listening.

    Specific Mountpoint Relay

    -The following diagram shows the basics of doing a Specific Mountpoint relay. Note that Server 1 is configured with the <relay> settings and Server 2 is the server from which Server 1 will pull the specified mountpoint(s) and relay them. Using a Specific Mountpoint Relay, only those mountpoints specified on Server 1 will be relayed from Server 2. - -
    -      |-----|                       |-----|
    -      |     |      /mount3          |     | /mount1
    -      |     | <-------------------  |     | /mount2.ogg
    -      |-----|                       |-----| /mount3
    -      Icecast 2                     Icecast 2/Shoutcast/Icecast
    -      Server 1                      Server 2
    -      (RELAY SERVER)                (REMOTE SERVER)
    -
    -     configured with
    -     <relay>
    -     settings
    -
    -
    +

    +If only specific mountpoints need to be relayed, then you can configure Icecast with a "Specific +Mountpoint Relay". +

    +The following diagram shows the basics of using a Specific Mountpoint relay. Note that the relaying +Icecast is configured with the <relay> settings and will pull the specified mountpoint(s) and +relay them to the listeners. Using a Specific Mountpoint Relay, only those mountpoints specified +will be relayed. +

    + +

    Specific Mountpoint Relays can be configured to relay from an Icecast 2 server, as well as Icecast 1.x and Shoutcast. A server is configured as a Specific Mountpoint Server relay by specifying a <relay> XML chunk in the config file for each mountpoint to be relayed. The server that is being relayed does not need any special configuration. - +

         <relay>
             <server>127.0.0.1</server>
    @@ -327,11 +361,13 @@ This is the TCP Port for the server which contains the mountpoint to be relayed.
     

    mount

    -The mountpoint located on the remote server. If you are relaying a shoutcast stream, this must be '/'. + The mountpoint located on the remote server. If you are relaying a shoutcast stream, this + should be a '/' or '/;name'.

    local-mount

    -The name to use for the local mountpoint. This is what the mount will be named on the RELAY SERVER. + The name to use for the local mountpoint. This is what the mount will be named on the relaying + server. By default the remote mountpoint name is used.

    username

    @@ -343,13 +379,15 @@ The source of the relay may require authentication itself, if so state the passw

    relay-shoutcast-metadata

    -If you are relaying a Shoutcast stream, you need to specify this indicator to also relay the metadata (song titles) that is part of the Shoutcast stream (1=enabled, 0=disabled). + If you are relaying a Shoutcast stream, you may want to specify this indicator to also relay + the metadata (song titles) that are part of the Shoutcast data stream (1=enabled, 0=disabled). + By default this is enabled but it is up to the remote server on whether it sends any.

    on-demand

    -

    An on-demand relay will only retrieve the stream if there are listeners connected - 1=enabled, 0=disabled (default is <relays-on-demand>). -

    +

    An on-demand relay will only retrieve the stream if there are listeners requesting the + stream. 1=enabled, 0=disabled (default is <relays-on-demand>). This is useful in cases + where you want to limit bandwidth costs when no one is listening.

    @@ -371,6 +409,7 @@ If you are relaying a Shoutcast stream, you need to specify this indicator to al <fallback-mount>/example2.ogg</fallback-mount> <fallback-override>1</fallback-override> <fallback-when-full>1</fallback-when-full> + <charset>ISO8859-1</charset> <public>1</public> <stream-name>My audio stream</stream-name> <stream-description>My audio description</stream-description> @@ -475,6 +514,19 @@ listening clients back from the fallback mount. to connect to a local relay instead. Deprecated option, replaced by <public>

    +

    charset

    +
    +

    For non-Ogg streams like MP3, the metadata that is inserted into the stream often has no + defined character set. We have traditionally assumed UTF8 as it allows for multiple language + sets on the web pages and stream directory, however many source clients for MP3 type streams + have assumed Latin1 (ISO 8859-1) or leave it to whatever character set is in use on the + source client system.

    +

    This character mismatch has been known to cause a problem as the stats engine and stream + directory servers want UTF8 so now we assume Latin1 for non-Ogg streams (to handle the common + case) but you can specify an alternative character set with this option. +

    The source clients can also specify a charset= parameter to the metadata update URL if + they so wish.

    +

    public

    The default setting for this is -1 indicating that it is up to the source client or @@ -581,6 +633,8 @@ This specifies that the named mount point will require listener authentication. <pidfile>./icecast.pid</pidfile> <webroot>./web</webroot> <adminroot>./admin</adminroot> + <allow-ip>/path/to/ip_allowlist</allow-ip> + <deny-ip>/path_to_ip_denylist</deny-ip> <alias source="/foo" dest="/bar"/> </paths> @@ -606,6 +660,18 @@ This path specifies the base directory used for all static file requests. This

    This path specifies the base directory used for all admin requests. More specifically, this is used to hold the XSLT scripts used for the web-based admin interface. The admin directory contained within the icecast distribution contains these files.
    +

    allow-ip

    +
    + If specified, this specifies the location of a file that contains a list of IP addresses that + will be allowed to connect to icecast. This could be useful in cases where a master only + feeds known slaves. The format of the file is simple, one IP per line. +
    +

    deny-ip

    +
    + If specified, this specifies the location of a file that contains a list of IP addressess that + will be dropped immediately. This is mainly for problem clients when you have no access to any + firewall configuration. The format of the file is simple, one IP per line. +

    alias source="/foo" dest="/bar"

    Aliases are used to provide a way to create multiple mountpoints that refer to the same mountpoint. diff --git a/doc/icecast2_listenerauth.html b/doc/icecast2_listenerauth.html index c36f5792..9cb39d88 100644 --- a/doc/icecast2_listenerauth.html +++ b/doc/icecast2_listenerauth.html @@ -51,8 +51,8 @@ do apply to intro files or fallback streams.

    Configuring Users and Passwords

    Once the appropriate entries are made to the config file, connect your source client (using the mountpoint you named in the config file). To configure users and passwords for this stream you must use the web-based admin interface. Navigate to http://server:ip/admin/stats.xsl to begin. If you have configured everything properly, you should see a screen like the following :

    Screenshot of http://server:ip/admin/stats.xsl -

    You will see a red key in front of all mountpoint configured for listener authentication. Also note that this page will only show CONNECTED mountpoints.

    -

    To manage users and passwords for this mountpoint, click on the red key or follow the "Manage Authentication" link. The following screen will be shown :

    +

    You will see a lock in front of all mountpoint configured for listener authentication. Also note that this page will only show CONNECTED mountpoints.

    +

    To manage users and passwords for this mountpoint, click on the lock or follow the "Manage Authentication" link. The following screen will be shown :

    Screenshot of Manage Authentication

    This screen will show all the users configured for this mountpoint. Adding users is as simple as entering a username and password in the fields and clicking "Add New User". Note that usernames MUST be unique and there are NO restrictions on passwords. You can delete users by clicking the appropriate delete link next to each user.


    diff --git a/doc/masterslave.png b/doc/masterslave.png new file mode 100644 index 0000000000000000000000000000000000000000..3ad994dfd340f258b1b84c3ee12776a604aea4f1 GIT binary patch literal 9346 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 literal 0 HcmV?d00001 diff --git a/doc/relay.png b/doc/relay.png new file mode 100644 index 0000000000000000000000000000000000000000..bee2651f22e9ed588843768af7fa7523c55811a5 GIT binary patch literal 9921 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 literal 0 HcmV?d00001