269 lines
10 KiB
Plaintext
269 lines
10 KiB
Plaintext
|
|
OP25 HTTP live streaming December 2020
|
|
=====================================================================
|
|
|
|
These hacks ("OP25-hls hacks") add a new option for audio reception
|
|
and playback in OP25; namely, via an HTTP live stream to any remote
|
|
client using a standard Web browser*. The web server software used
|
|
(nginx) is industrial-strength and immediately scalable to dozens or
|
|
hundreds of simultaneous remote users with zero added effort. More
|
|
than one upstream source (in parallel) can be served simultaneously.
|
|
|
|
OP25's liquidsoap script is hacked to pipe output PCM audio data
|
|
to ffmpeg, which also reads the www/images/status.png image file
|
|
that makes up the video portion of the encoded live stream. The
|
|
image png file is kept updated by rx.py.
|
|
|
|
The selection of ffmpeg codecs ("libx264" for video and "aac" for
|
|
audio) allows us directly to send the encoded data stream from
|
|
ffmpeg to the web server (nginx) utilizing RTMP. Individual
|
|
MPEG-TS segments are stored as files in nginx web server URL-space,
|
|
and served to web clients via standard HTTP GET requests. The
|
|
hls.js package is used at the client.
|
|
|
|
The entire effort mostly involved assembling existing off-the-shelf
|
|
building blocks. The ffmpeg package was built manually from source
|
|
to enable the "libx264" codec, and a modified nginx config was
|
|
used.
|
|
|
|
*the web browser must support the "MediaSource Extensions" API.
|
|
All recent broswer versions should qualify.
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
1. nginx installation
|
|
|
|
The libnginx-mod-rtmp package must be installed (in addition to
|
|
nginx itself). You can copy the sample nginx configuration at the
|
|
end of this README file to /etc/nginx/nginx.conf, followed by
|
|
restarting the web server
|
|
sudo systemctl stop nginx
|
|
sudo systemctl start nginx
|
|
With this configuration the web server should listen on HTTP port
|
|
8081 and RTMP port 1935.
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
2. ffmpeg installation
|
|
git clone https://code.videolan.org/videolan/x264.git
|
|
git clone https://git.ffmpeg.org/ffmpeg.git
|
|
cd x264
|
|
./configure
|
|
make
|
|
sudo make install
|
|
cd ../ffmpeg
|
|
./configure --enable-shared --enable-libx264 --enable-gpl
|
|
make
|
|
sudo make install
|
|
|
|
To confirm the installation run the "ffmpeg" command and
|
|
verify the presence of "--enable-shared" and "--enable-libx264"
|
|
in the "configuration:" section of the output.
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
3. liquidsoap installation
|
|
Both packages "liquidsoap" and "liquidsoap-plugin-all" were
|
|
installed, but not tested whether the plugins are required for
|
|
this application.
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
4. nginx setup
|
|
with the custom config installed as per step 1, copy the files
|
|
from op25/gr_op25_repeater/www to /var/www/html as follows:
|
|
|
|
live.html
|
|
live.m3u8
|
|
hls.js
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
5. liquidsoap setup
|
|
in the op25/gr_op25_repeater/apps directory, note the ffmpeg.liq
|
|
script. Overall the filtering and buffering options should be
|
|
similar to those in op25.liq. The default version of ffmpeg.liq
|
|
should be OK for most uses.
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
6. operation
|
|
With OP25 rx.py started using the options -V -w (and -2 if using
|
|
TDMA) and with ffmpeg.liq started (both from the apps directory),
|
|
you should be able to connect to http://hostip:8081/live.html
|
|
and click the Play button to begin. NOTE: See note E for more
|
|
details about how to specify the value for 'hostip' in the above
|
|
link.
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
7. troubleshooting
|
|
A. with the ffmpeg.liq script running ffmpeg should start sending
|
|
rtmp data over port 1935 to nginx. You should see files
|
|
start being populated in /var/www/html/hls/ .
|
|
B. If /var/www/html/hls is empty, check ffmpeg message output
|
|
for possible errors, and also check the nginx access and
|
|
error logs. Note that the /var/www/html/hls directory should
|
|
start receiving files a few seconds after ffmpeg.liq is started
|
|
(regardless of whether OP25 is actively receiving a station,
|
|
or is not receiving).
|
|
C. js debug can be enabled for hls.js by editing that file as
|
|
follows; locate the lines of code and change the "debug"
|
|
setting to "true"
|
|
|
|
var hlsDefaultConfig = _objectSpread(_objectSpread({
|
|
autoStartLoad: true,
|
|
// used by stream-controller
|
|
startPosition: -1,
|
|
// used by stream-controller
|
|
defaultAudioCodec: void 0,
|
|
// used by stream-controller
|
|
debug: true, ///// <<<=== change this line from
|
|
///// "false" to "true"
|
|
|
|
D. after reloading the page and with the web browser js console
|
|
opened (and with all message types enabled), debug messages
|
|
should now start appearing in the console. As before another
|
|
place to look for messages is in the nginx access and error
|
|
logs.
|
|
E. if you are doing heavy client-side debugging it may be helpful
|
|
to obtain a copy of the hls.js distribution and to populate
|
|
the hls.js.map file (with updated hls.js) in /var/www/html.
|
|
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
8. notes
|
|
A. due to the propagation delay inherent in the streaming
|
|
process, there is a latency of several seconds from when
|
|
the transmissions are receieved before they are played in
|
|
the remote web browser. OP25 attempts to keep the video
|
|
and audio synchronized but the usual user controls (hold,
|
|
lockout, etc). are not available (in this release) because
|
|
the several-second delay could cause the commands to operate
|
|
on stale talkgroup data (without additional work).
|
|
B. in keeping with the current OP25 liquidsoap setup, the audio
|
|
stream is converted to mono prior to streaming. It might be
|
|
possible to retain the stereo data (in cases where the L and
|
|
R channels contain separate information), but this has not
|
|
been tested. The ffmpeg.liq script would need to be changed to
|
|
use "output" instead of "mean(output)" and the ffmpeg script
|
|
would need to change "-ac 1" to "-ac 2". In addition the
|
|
options stereo=true and channels=2 would need to be set in the
|
|
%wav specification parameters.
|
|
C. multiple independent streams can be served simultaneously by
|
|
invoking a separate ffmpeg.sh script for each stream and by
|
|
changing the last component of the rtmp URL to a unique
|
|
value; for example:
|
|
rtmp://localhost/live/stream2
|
|
A unified (parameterized) version of ffmpeg.sh could also be
|
|
used.
|
|
Also, new versions of live.html and live.m3u8 in /var/www/html
|
|
(reflecting the above modification) would need to be added.
|
|
D. note that pausing and seeking etc. in the media feed isn't
|
|
possible when doing live streaming.
|
|
E. when connecting from the remote client to the nginx server as
|
|
detailed in step 6 (above) you should specify the value for
|
|
'hostip' as follows (omitting the quotes):
|
|
|
|
'localhost' (default) - use this when the client is on the same
|
|
machine as the server
|
|
'host.ip.address' - specify the IP address of the server when
|
|
the client and server machines are different, and the server
|
|
does not have a DNS hostname.
|
|
'hostname' - if the server has a DNS hostname, this name should
|
|
be used in place of 'hostip'.
|
|
|
|
Note that in the second and third cases above you must also
|
|
change the hostname from 'localhost' to the IP address or DNS
|
|
hostname, respectively, in the following files
|
|
live.html
|
|
live.m3u8
|
|
in /var/www/html (total three occurrences).
|
|
|
|
Similarly, if an IP port other than 8081 is to be used, the same
|
|
updates as above must be made, and also the nginx conf file must
|
|
be updated to reflect the changed port number.
|
|
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
########################################################################
|
|
####### tested on ubuntu 18.04 #######
|
|
####### sample nginx conf file - copy everything below this line #######
|
|
|
|
user www-data;
|
|
worker_processes auto;
|
|
pid /run/nginx.pid;
|
|
include /etc/nginx/modules-enabled/*.conf;
|
|
|
|
events {
|
|
worker_connections 768;
|
|
# multi_accept on;
|
|
}
|
|
|
|
# RTMP configuration
|
|
rtmp {
|
|
server {
|
|
listen 1935; # Listen on standard RTMP port
|
|
chunk_size 4000;
|
|
|
|
application live {
|
|
live on;
|
|
# Turn on HLS
|
|
hls on;
|
|
hls_path /var/www/html/hls/;
|
|
hls_fragment 3;
|
|
hls_playlist_length 60;
|
|
# disable consuming the stream from nginx as rtmp
|
|
deny play all;
|
|
}
|
|
}
|
|
}
|
|
|
|
http {
|
|
sendfile off;
|
|
tcp_nopush on;
|
|
#aio on;
|
|
directio 512;
|
|
default_type application/octet-stream;
|
|
|
|
server {
|
|
listen 8081;
|
|
|
|
location / {
|
|
# Disable cache
|
|
add_header 'Cache-Control' 'no-cache';
|
|
|
|
# CORS setup
|
|
add_header 'Access-Control-Allow-Origin' '*' always;
|
|
add_header 'Access-Control-Expose-Headers' 'Content-Length';
|
|
|
|
# allow CORS preflight requests
|
|
if ($request_method = 'OPTIONS') {
|
|
add_header 'Access-Control-Allow-Origin' '*';
|
|
add_header 'Access-Control-Max-Age' 1728000;
|
|
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
|
add_header 'Content-Length' 0;
|
|
return 204;
|
|
}
|
|
|
|
# include /etc/nginx/mime.types;
|
|
types {
|
|
text/html html;
|
|
text/css css;
|
|
application/javascript js;
|
|
application/dash+xml mpd;
|
|
application/vnd.apple.mpegurl m3u8;
|
|
video/mp2t ts;
|
|
}
|
|
|
|
access_log /var/log/nginx/access.log;
|
|
error_log /var/log/nginx/error.log;
|
|
|
|
root /var/www/html;
|
|
|
|
}
|
|
}
|
|
}
|
|
|