Browse Source

feat: Docs and first streaming client

Matthias Ladkau 4 years ago
commit
a2e5d6bc40

+ 80 - 0
doc/configs.txt

@@ -0,0 +1,80 @@
+Install
+=======
+
+1. Put raspbian on a SD card and boot the image
+
+2. Login with pi / raspberry
+
+3. Change root and pi passwords
+
+# sudo su
+# passwd
+# passwd pi
+
+4. Enable WLan network
+
+add to /etc/wpa_supplicant/wpa_supplicant.conf
+
+network={
+    ssid="Kleines Arschloch"
+    psk="<the wlan password>"
+}
+
+Enable ssh via raspi-config
+
+Interfacing Options -> SSH
+
+Change hostname in /etc/hostname and /etc/hosts to
+
+hackerradio
+
+5. Add prompt and ll command
+
+Add to .profile for root and pi
+
+PS1="\u@\h:\w>"
+
+ll () {
+    ls -alh --color=always "$@"
+}
+
+6. Add essential commands
+
+apt-get install screen
+apt-get install lsof
+
+7. Add mplayer
+
+apt-get install mplayer
+
+8. Make logging write to tmpfs
+
+add to /etc/fstab
+tmpfs   /var/log   tmpfs   size=1M,noatime  0   0
+
+9. Disable bluetooth
+
+Add to /boot/config.txt
+
+dtoverlay=pi3-disable-bt
+
+Disable services
+sudo systemctl disable hciuart.service
+sudo systemctl disable bluealsa.service
+sudo systemctl disable bluetooth.service
+
+10. Mount in Osel
+
+Create /mnt/media
+
+Add to /etc/fstab
+
+//10.0.0.4/media        /mnt/media                   cifs    vers=1.0,password=  0 0
+
+11. Configure audio
+
+Force audio via jack via raspi-config
+
+Advanced Options -> Audio
+
+Increase audio level to max via alsamixer

+ 57 - 0
streaming-client/v1/client.py

@@ -0,0 +1,57 @@
+#!/usr/bin/python3
+
+import tornado.ioloop, tornado.web, os
+import mplayer_ctl
+
+
+class Index(tornado.web.RequestHandler):
+    def get(self):
+        self.redirect("/web/index.html", permanent=True)
+ 
+class PlayerControl(tornado.web.RequestHandler):
+    
+    def get(self):
+        cmd = None
+        c   = self.get_argument('cmd')
+        
+        if c == "new_artist_stream":
+            cmd = mplayer_ctl.Cmd(mplayer_ctl.CMD_NEW_ARTIST_STREAM, {
+                "name" : self.get_argument('name')
+            })
+        
+        elif c == "stop_stream":
+            cmd = mplayer_ctl.Cmd(mplayer_ctl.CMD_STOP_STREAM)
+
+        if cmd is not None:
+            print("Adding command:", cmd)
+            mplayer_ctl.cmd_queue.insert(0, cmd)
+
+        self.redirect("/")
+
+urls = [
+    (r"/", Index),
+    (r"/player_control", PlayerControl),
+]
+
+settings = {
+    "static_path"       : os.path.join(os.path.dirname(__file__),  "web"),
+    "static_url_prefix" : "/web/",
+    "debug"             : True,
+}
+
+app = tornado.web.Application(urls, **settings)
+
+if __name__ == "__main__":
+    print("Yams PI client")
+
+    # Kick off mplayer control thread
+
+    mplayer_ctl.start({
+        "streaming_url" : "http://yozh.devt.de:9092",
+        "default_url"   : "http://web:gemasuxx@devt.de:5051/pleasuredome",
+    })
+
+    # Kick off tornado
+
+    app.listen(80)
+    tornado.ioloop.IOLoop.instance().start()

+ 5 - 0
streaming-client/v1/install.txt

@@ -0,0 +1,5 @@
+Installation on a PI:
+====================
+
+apt-get install mplayer python-setuptools
+easy_install tornado

+ 127 - 0
streaming-client/v1/mplayer_ctl.py

@@ -0,0 +1,127 @@
+#!/usr/bin/python3
+
+from subprocess import Popen, PIPE, call
+from threading import Thread
+import time
+
+# Declarations
+# ============
+
+# Default configuration for mplayer control thread
+default_config = {
+    "streaming_url"    : "http://localhost:9092",
+    "per_artist_path"  : "/artist",
+    "default_url"      : "",
+}
+
+# Queue for player commands
+cmd_queue        = []
+
+# Command object
+class Cmd(object):
+    def __init__(self, name, param={}):
+        self.name  =  name
+        self.param =  param
+
+# Command names for the queue
+
+# Stream per artist
+# Expected parameter: name - Name of the artist
+CMD_NEW_ARTIST_STREAM  = "New Artist Stream" 
+
+# Stop current stream
+CMD_STOP_STREAM        = "Stop Stream"
+
+# Internal
+# ========
+
+# Internal reference to mplayer process
+_player_instance = None
+
+# Internal mplayer control table
+_mplayer_control = {
+    "step-backward" : "\x1B[B",
+    "backward"      : "\x1B[D", 
+    "forward"       : "\x1B[C", 
+    "step-forward"  : "\x1B[A",
+    "volume-down"   : "9", 
+    "volume-off"    : "m", 
+    "volume-up"     : "0",
+    "stop"          : "q", 
+    "pause"         : " ", 
+    "play"          : " ",
+}
+
+# Internal config
+_config = None
+
+def run():
+    global _player_instance, _config, _mplayer_control
+
+    while True:
+        try:
+
+            # Read the next command
+
+            cmd = cmd_queue.pop()
+
+        except IndexError:
+
+            # If nothing is in the queue wait for a second and try again
+
+            time.sleep(1)
+
+        else:
+            if cmd.name == CMD_STOP_STREAM:
+
+                # Stop the current stream
+
+                _stopPlayer()
+
+            if cmd.name == CMD_NEW_ARTIST_STREAM:
+
+                # Stop any current stream
+
+                _stopPlayer()
+
+                #  Start a new player with the given artist playlist
+
+                _player_instance = Popen(["mplayer", "-slave", _config["streaming_url"] + 
+                    _config["per_artist_path"] + "/" + cmd.param["name"]], stdin=PIPE)
+
+def _stopPlayer():
+    '''
+    Stop A running player instance.
+    '''
+    global _player_instance, _mplayer_control
+
+    if _player_instance is not None:
+        _player_instance.stdin.write(bytes(_mplayer_control["stop"], "UTF-8"))
+        _player_instance.stdin.flush()
+        _player_instance.terminate()
+        _player_instance = None
+
+# Main API
+# ========
+
+def start(config=None):
+    '''
+    Start the new mplayer control thread.
+    '''
+    global _config, _player_instance
+
+    c = default_config.copy()
+    if config is not None:
+        c.update(config)
+
+    _config = c
+
+    playerThread = Thread(target=run, args=())
+    playerThread.daemon = True
+    playerThread.start()
+
+    # Start default playlist if defined
+
+    d = config["default_url"]
+    if d != "":
+        _player_instance = Popen(["mplayer", "-slave", d], stdin=PIPE)

+ 48 - 0
streaming-client/v1/web/index.html

@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Yams Login</title>
+
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+
+    <link rel="stylesheet" href="/web/spectre/spectre.min.css">
+    <link rel="stylesheet" href="/web/spectre/spectre-exp.min.css">
+    <link rel="stylesheet" href="/web/spectre/spectre-icons.min.css">
+
+    <style>
+        body {
+            padding : 5%;
+        }
+        
+        h1 {
+            padding: 0.5em;
+            margin-bottom: 1em;
+            border-radius: 1em;
+        }
+    </style>
+
+</head>
+<body>
+
+
+
+
+<div class="section">
+    <div class="container grid-lg text-center">
+        <h1 class="bg-gray">Hackerradio <a class="btn btn-primary" href="/player_control?cmd=stop_stream">Stop Playing</a></h1>        
+    </div>
+    <div class="container grid-lg text-center">
+        <h2>Playlist by Artist</h2>        
+        <p>
+            <a class="btn btn-primary" href="/player_control?cmd=new_artist_stream&name=Test">Test</a>
+        </p>
+        <form action="/player_control" method="GET">
+            <input name="cmd" value="new_artist_stream" type="hidden">
+            <input name="name" value="Test">
+            <input type="submit" value="Play">
+        </form>
+    </div>
+</div>    
+    
+</body>
+</html>

+ 21 - 0
streaming-client/v1/web/spectre/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 朱龑
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

File diff suppressed because it is too large
+ 1 - 0
streaming-client/v1/web/spectre/spectre-exp.min.css


File diff suppressed because it is too large
+ 1 - 0
streaming-client/v1/web/spectre/spectre-icons.min.css


File diff suppressed because it is too large
+ 1 - 0
streaming-client/v1/web/spectre/spectre.min.css


BIN
streaming-client/v1/web/thumbnail/radio.xcf


BIN
streaming-client/v1/web/thumbnail/radio_128.png


BIN
streaming-client/v1/web/thumbnail/radio_16.gif


BIN
streaming-client/v1/web/thumbnail/radio_192.png