=^.^=

Stream Webcams and Sound in Flash via RTMP with JW Player

karma

WARNING A lot of folks have reported they can't get the audio working. I dropped this method for http://code.google.com/p/flash-videoio/ and wouldn't recomment wasting your time with jwplayer. flash-videoio has JavaScript hooks that let you configure most player/recorder settings on-the-fly which has huge potential when mixed with AJAX.

JW Player is a popular extensible flash (now also available in HTML5) video player. Until versions 4.5 and up it supported grabbing video and audio sources locally attached to the client machine and publishing them to a streaming server (like Flash Media Server, Red5 or C++ RTMP Server) via RTMP. This feature was abandoned due to inherent limitations of the built-in encoding capabilities of Flash Player vs. stand-alone encoding software like Flash Live Media Encoder. This situation doesn't suit everyone however; in a video conferencing scenario users must be able to connect with as little hassle as possible and forcing them to download specialized software presents a significant enough accessibility barrier to warrant swallowing the quality losses associated with Flash Player encoding.

Using version 4.4.198 available at http://developer.longtailvideo.com/trac/browser/tags/mediaplayer-4.4?rev=885, an RTMP server and the latest version of JW Player (available here) we will make a simple broadcast and view page. Extract the contents of these archives to jwpublisher/ and jwplayer/ respectively.

Let rtmp://xxx.xxx.xxx.xxx/live be the URI to your working FMS/Red5/C++ RTMP Server application and livestream be the name of our stream. Create an index.html in jwpublisher/ to reflect:

<html lang="en">
  <head>
    <script src="swfobject.js"></script>
    <script type="text/javascript">
      var flashvars =
      {
        'streamer':                     'rtmp://xxx.xxx.xxx.xxx/live',
        'file':                         'livestream',
        'type':                         'camera',
        'controlbar':                   'bottom',
        'stretching':                   'none',
        'frontcolor':                   '86C29D',  // text & icons                  (green)
        'backcolor':                    '849BC1',  // playlist background           (blue)
        'lightcolor':                   'C286BA',  // selected text/track highlight (pink)
        'screencolor':                  'FFFFFF',  // screen background             (black)
        'id':                           'playerID',
        'autostart':                    'true'
      };

      var params =
      {
        'allowfullscreen':              'true',
        'allowscriptaccess':            'always',
        'bgcolor':                      '#FFFFFF'
      };

      var attributes =
      {
        'id':                           'playerID',
        'name':                         'playerID'
      };
      swfobject.embedSWF('player.swf', 'player', '320', '260', '9.0.124', false, flashvars, params, attributes);
    </script>
  </head>
  <body>
    <div id="playercontainer" class="playercontainer"><a id="player" class="player" href="http://get.adobe.com/flashplayer/">Get the Adobe Flash Player to see this video.</a></div>
  </body>
</html> 

Now create an index.html in jwplayer/:

<html>
<head>
<script type='text/javascript' src='jwplayer.js'></script>
</head>
<body>
<div id='mediaspace'>This text will be replaced</div>
<script type='text/javascript'>
  jwplayer('mediaspace').setup({
    'flashplayer': 'player.swf',
    'type': 'rtmp',
    'streamer': 'rtmp://xxx.xxx.xxx.xxx/live',
    'autostart': 'true',
    'bufferlength': '3,
    'file': 'livestream',
    'controlbar': 'none',
    'width': '320',
    'height': '260'
  });
</script>
</body>
</html>

Load jwpublisher/ in your browser. Flash will ask for access to your webcam if it can find one. Once the video appears load jwplayer/ and allow a few seconds for buffering. If your streaming server works you should now be watching a slightly delayed version of the video being captured from your webcam.

Installing C++ RTMP Server (rtmpd, crtmpdserver) From Source on Gentoo

karma

C++ RTMP Server is a lightweight streaming server that supports multiple streaming protocols and - most importantly - trans-coding between them. I stumbled upon it when I was looking for a solution that would trans-code an RTSP stream from an Axis webcam to a flash-playable RTMP stream. It can also be used as a drop-in replacement for some of Flash Media Server or Red5's basic stream publishing functions but does not provide support for Flex applications or tomcat servlets, for example.

Download the latest source release at the bottom of http://www.rtmpd.com/downloads/ and extract it in your /usr/src directory, or download a snapshot from SVN with a blank password:

$ svn co --username anonymous https://svn.rtmpd.com/crtmpserver/branches/1.0 crtmpserver

Now compile the source and install the binaries:

# cd builders/cmake
# cmake -DCRTMPSERVER_INSTALL_PREFIX=/usr/local .
# make install

Copy /usr/local/etc/crtmpserver.lua.sample to /usr/local/etc/crtmpserver.lua then edit it to reflect:

        -- this node holds all the RTMP applications
        applications=
        {
                -- this is the root directory of all applications
                -- usually this is relative to the binary execuable
                rootDirectory="/usr/local/lib/crtmpserver/applications",

Copy the SSL key and certificate:

# cp /usr/src/crtmpserver-690/builders/cmake/applications/appselector/server.* /usr/local/lib/crtmpserver/applications/appselector/

Create a media directory and link it in the flvplayback application's folder then copy users.lua:

# mkdir /var/crtmpserver
# mkdir /var/crtmpserver/media
# ln -s /var/crtmpserver/media/ /usr/local/lib/crtmpserver/applications/flvplayback/mediaFolder
# cp /usr/src/crtmpserver-690/builders/cmake/applications/flvplayback/users.lua /usr/local/lib/crtmpserver/applications/flvplayback/

You should now be able to run the binary:

# crtmpserver /usr/local/etc/crtmpserver.lua
/usr/src/crtmpserver-690/sources/crtmpserver/src/crtmpserver.cpp:203 Initialize I/O handlers manager: epoll
/usr/src/crtmpserver-690/sources/crtmpserver/src/crtmpserver.cpp:206 Configure modules
/usr/src/crtmpserver-690/sources/thelib/src/configuration/module.cpp:84 Module /usr/local/lib/crtmpserver/applications/appselector/libappselector.so loaded
/usr/src/crtmpserver-690/sources/thelib/src/configuration/module.cpp:84 Module /usr/local/lib/crtmpserver/applications/flvplayback/libflvplayback.so loaded
/usr/src/crtmpserver-690/sources/thelib/src/configuration/module.cpp:84 Module /usr/local/lib/crtmpserver/applications/samplefactory/libsamplefactory.so loaded
/usr/src/crtmpserver-690/sources/thelib/src/configuration/module.cpp:84 Module /usr/local/lib/crtmpserver/applications/vptests/libvptests.so loaded
/usr/src/crtmpserver-690/sources/thelib/src/configuration/module.cpp:84 Module /usr/local/lib/crtmpserver/applications/admin/libadmin.so loaded
/usr/src/crtmpserver-690/sources/thelib/src/configuration/module.cpp:84 Module /usr/local/lib/crtmpserver/applications/proxypublish/libproxypublish.so loaded
/usr/src/crtmpserver-690/sources/thelib/src/configuration/module.cpp:84 Module /usr/local/lib/crtmpserver/applications/stresstest/libstresstest.so loaded
/usr/src/crtmpserver-690/sources/thelib/src/configuration/module.cpp:84 Module /usr/local/lib/crtmpserver/applications/applestreamingclient/libapplestreamingclient.so loaded
/usr/src/crtmpserver-690/sources/crtmpserver/src/crtmpserver.cpp:212 Plug in the default protocol factory
/usr/src/crtmpserver-690/sources/crtmpserver/src/crtmpserver.cpp:219 Configure factories
/usr/src/crtmpserver-690/sources/thelib/src/configuration/module.cpp:97 Loaded factory from application samplefactory
/usr/src/crtmpserver-690/sources/crtmpserver/src/crtmpserver.cpp:225 Configure acceptors
/usr/src/crtmpserver-690/sources/thelib/src/netio/epoll/iohandlermanager.cpp:100 Handlers count changed: 0->1 IOHT_ACCEPTOR
/usr/src/crtmpserver-690/sources/thelib/src/netio/epoll/iohandlermanager.cpp:100 Handlers count changed: 1->2 IOHT_ACCEPTOR
/usr/src/crtmpserver-690/sources/thelib/src/netio/epoll/iohandlermanager.cpp:100 Handlers count changed: 2->3 IOHT_ACCEPTOR
/usr/src/crtmpserver-690/sources/thelib/src/netio/epoll/iohandlermanager.cpp:100 Handlers count changed: 3->4 IOHT_ACCEPTOR
/usr/src/crtmpserver-690/sources/thelib/src/netio/epoll/iohandlermanager.cpp:100 Handlers count changed: 4->5 IOHT_ACCEPTOR
/usr/src/crtmpserver-690/sources/thelib/src/netio/epoll/iohandlermanager.cpp:100 Handlers count changed: 5->6 IOHT_ACCEPTOR
/usr/src/crtmpserver-690/sources/thelib/src/netio/epoll/iohandlermanager.cpp:100 Handlers count changed: 6->7 IOHT_ACCEPTOR
/usr/src/crtmpserver-690/sources/thelib/src/netio/epoll/iohandlermanager.cpp:100 Handlers count changed: 7->8 IOHT_ACCEPTOR
/usr/src/crtmpserver-690/sources/thelib/src/netio/epoll/iohandlermanager.cpp:100 Handlers count changed: 8->9 IOHT_ACCEPTOR
/usr/src/crtmpserver-690/sources/thelib/src/netio/epoll/iohandlermanager.cpp:100 Handlers count changed: 9->10 IOHT_ACCEPTOR
/usr/src/crtmpserver-690/sources/crtmpserver/src/crtmpserver.cpp:231 Configure instances
/usr/src/crtmpserver-690/sources/crtmpserver/src/crtmpserver.cpp:237 Start I/O handlers manager: epoll
/usr/src/crtmpserver-690/sources/crtmpserver/src/crtmpserver.cpp:240 Configure applications
/usr/src/crtmpserver-690/sources/thelib/src/configuration/module.cpp:177 Application admin instantiated
/usr/src/crtmpserver-690/sources/thelib/src/configuration/module.cpp:177 Application applestreamingclient instantiated
/usr/src/crtmpserver-690/sources/thelib/src/configuration/module.cpp:177 Application appselector instantiated
/usr/src/crtmpserver-690/sources/thelib/src/configuration/module.cpp:177 Application flvplayback instantiated
/usr/src/crtmpserver-690/sources/thelib/src/configuration/module.cpp:177 Application proxypublish instantiated
/usr/src/crtmpserver-690/sources/thelib/src/netio/epoll/iohandlermanager.cpp:100 Handlers count changed: 10->11 IOHT_TIMER
/usr/src/crtmpserver-690/sources/thelib/src/configuration/module.cpp:177 Application samplefactory instantiated
/usr/src/crtmpserver-690/sources/thelib/src/configuration/module.cpp:177 Application stresstest instantiated
/usr/src/crtmpserver-690/sources/thelib/src/configuration/module.cpp:177 Application vptests instantiated
/usr/src/crtmpserver-690/sources/crtmpserver/src/crtmpserver.cpp:246 Install the quit signal
/usr/src/crtmpserver-690/sources/crtmpserver/src/crtmpserver.cpp:257
+-----------------------------------------------------------------------------+
|                                                                     Services|
+---+---------------+-----+-------------------------+-------------------------+
| c |      ip       | port|   protocol stack name   |     application name    |
+---+---------------+-----+-------------------------+-------------------------+
|tcp|        0.0.0.0| 1112|           inboundJsonCli|                    admin|
+---+---------------+-----+-------------------------+-------------------------+
|tcp|        0.0.0.0| 1935|              inboundRtmp|              appselector|
+---+---------------+-----+-------------------------+-------------------------+
|tcp|        0.0.0.0| 8081|             inboundRtmps|              appselector|
+---+---------------+-----+-------------------------+-------------------------+
|tcp|        0.0.0.0| 8080|             inboundRtmpt|              appselector|
+---+---------------+-----+-------------------------+-------------------------+
|tcp|        0.0.0.0| 6666|           inboundLiveFlv|              flvplayback|
+---+---------------+-----+-------------------------+-------------------------+
|tcp|        0.0.0.0| 9999|             inboundTcpTs|              flvplayback|
+---+---------------+-----+-------------------------+-------------------------+
|tcp|        0.0.0.0| 6665|           inboundLiveFlv|             proxypublish|
+---+---------------+-----+-------------------------+-------------------------+
|tcp|        0.0.0.0| 8989|         httpEchoProtocol|            samplefactory|
+---+---------------+-----+-------------------------+-------------------------+
|tcp|        0.0.0.0| 8988|             echoProtocol|            samplefactory|
+---+---------------+-----+-------------------------+-------------------------+
|tcp|        0.0.0.0| 1111|    inboundHttpXmlVariant|                  vptests|
+---+---------------+-----+-------------------------+-------------------------+
/usr/src/crtmpserver-690/sources/crtmpserver/src/crtmpserver.cpp:258 GO! GO! GO! (4108)

If it simply returns to the command line ensure you have not configured crtmpserver.lua to daemonize then run it with the following flags:

# crtmpserver --use-implicit-console-appender /usr/local/etc/crtmpserver.lua

Hit Control+C to terminate the process. Now we will create an unprivileged user account for the daemon to run under:

# useradd -d /usr/local -s /sbin/nologin -r rtmpd

Change the permissions of /var/crtmpserver:

# chown rtmpd: /var/crtmpserver -R

Edit /usr/local/etc/crtmpserver.lua to reflect:

configuration=
{
        -- if true, the server will run as a daemon.
        -- NOTE: all console appenders will be ignored if this is a daemon
        daemon=true,

Create a directory for the logs:

# mkdir /var/log/rtmpd
# chown rtmpd: /var/log/rtmpd

Edit /usr/local/etc/crtmpserver.lua to reflect:

                {
                        name="file appender",
                        type="file",
                        level=6,
                        -- the file where the log messages are going to land
                        fileName="/var/log/rtmpd/rtmpd.log",
                        --newLineCharacters="\r\n",
                        fileHistorySize=10,
                        fileLength=1024*256,
                        singleLine=true
                }

Now create the init script /etc/init.d/rtmpd:

#!/sbin/runscript
# Copyright (c) 2011 http://foxpa.ws
# All rights released

description="Runs C++ RTMP Server on Gentoo"

depend()
{
        need net
}

start()
{
        ebegin "Starting C++ RTMP Server"
        /usr/local/sbin/crtmpserver --daemon --gid=`id -g rtmpd` --uid=`id -u rtmpd` /usr/local/etc/crtmpserver.lua
        eend ${?}
}

stop()
{
        ebegin "Stopping C++ RTMP Server"
        killall crtmpserver
        eend ${?}
}

Make the script executable and add it to the default runlevel:

# chmod +x /etc/init.d/rtmpd
# rc-update add rtmpd default

You can now start the daemon by running:

# /etc/init.d/rtmpd start

Dumpster Diving Part Two: Self Indulgence and KSU Resets due to Power Loss

karma

I wasn't going to write about the Meridian I adopted way back again because I planned on cleaning it up and selling the system. It turns out I have had better things to do. One night recently I decided to reward myself for being productive by dicking around with it for a bit and managed to get it working on a VoIP line by way of an ATA. I was so impressed with the quality of the audio I decided to keep the system for personal use. There is a subtle irony to having a three metre analogue bridge between two perfectly digital systems and all this fire-retardant 1990s-beige/grey plastic is getting to my head.

The POTS interface is generally terminated with a 25-pair BIX (Building Industry Cross-connect) block. These require a punch-down tool. My only punch-down tool at the moment has automatic snippers on one end which is useless as the position of the terminal teeth alternates from top to bottom.

I jammed the pairs in with the attached blade tool which is strongly discouraged as you invariably weaken the teeth and risk cracking the (especially ancient) plastic.

The KSU had been unplugged some time and defaulted. Interestingly, the dialing mode defaults to pulse which, intuitively enough, doesn't work with my ATA. It turns out you have to go in and set each line to tone dialing individually.

It took me forever to find out how to do this so pay close attention, I'm only going to remember this once:

  • Punch FEATURE **CONFIG
    • **CONFIG is **266344
  • The password should be CONFIG,  if lost will have to be reset.
  • Press the top-rightmost indicated meta key, the display will read:
    • 1. Trk/Line Data
  • Press the top-rightmost indicated meta key again. The display will read:
    • Show line: _
  • This prompt expects three digits. To configure line one, press 001. The display will read:
    • Trunk data
  • Press the top-rightmost indicated meta key once then the bottom-rightmost twice. The display will read:
    • Dial Mode: Pulse
  • The rightmost display key will read
    • CHANGE
  • Press the CHANGE display key and it will toggle between Pulse and Tone.
  • Press Rls to exit the menu

Above you can see the data and software cartridges for the M8x24; one fits into the other which fits into the cabinet. If your KSU loses all of its settings when the power goes out you need to replace the backup capacitors mounted on the data board. They are 1 farad and 5.5 volts each.

These appear to be a very common capacitor configuration for data backup and shouldn't be hard to find at a reasonable price.

Something neat I learned in my travels is that when these 24V phones are subjected to the ring voltage on a POTS line (90V in NA?) they tend to blow. What they may lack in ruggedness they more than make up for in ease of installation however, as their all-digital signalling makes their ports polarity agnostic.

Red5 Streaming Media Server Init Script for Gentoo

karma

NOTE Please see Rotate Red5 Logs Without logrotate for a better way to configure logging.

This script assumes you have installed Red5 to /opt/red5, added a non-privileged user named Red5 and applied the appropriate ownership/permissions to the red5/log, red5/webapps and red5/work directories. It is compatible with OpenRC.

#!/sbin/runscript
# Copyright (c) 2011 http://foxpa.ws
# All rights released

description="Runs Red5 streaming media server on Gentoo"

depend()
{
        need net
}

start()
{
        ebegin "Starting Red5"
        start-stop-daemon --start --quiet --user=red5 --background --chdir=/opt/red5/ --stdout /var/log/red5/red5.log --stderr /var/log/red5/red5_errors.log --exec "/opt/red5/red5.sh"
        eend ${?}
}

stop()
{
        ebegin "Stopping Red5"
        cd /opt/red5/
        start-stop-daemon --stop --quiet --exec "/opt/red5/red5.sh"
        ./red5-shutdown.sh &> /dev/null
        eend ${?}
}

ClearOS: Can Not Ping Internal or External Gateway IPs from Open DMZ Host

karma

You may find yourself unable to ping the local and remote IPs of the ClearOS router from a host configured with a public IP address participating on a DMZ subnet. I haven't had time to find out why but it is possible to address this by explicitly accepting pings on the DMZ interface; modify /etc/rc.d/rc.firewall.custom:

iptables -I INPUT -i eth1 -p icmp -m icmp --icmp-type 8 -j ACCEPT # Accept pings on DMZ