Když jsem se před časem rozhodl začít používat IPTV, představovalo to pro mě zajímavou možnost, jak to pojmout po svém. Řešení kombinující HTPC a na něm provozovaný některý z na Linuxu dostupných multimediálních přehrávačů se přímo nabízelo a nakonec se ho podařilo dotáhnout do úspěšného konce. V následujícím článku bych se rád zaměřil na možnosti vzdáleného ovládání v nadpisu zmíněných přehrávačů, na které jsem v průběhu tvorby daného řešení narazil a se kterými jsem experimentoval.

Nástin řešení

Zadání bylo relativně prosté, výsledek si musel umět poradit jak s playlistem generovaným pro DVB-T příjem, tak s playlisty přímo od IPTV poskytovatelů, které mám k dispozici. Ve všech případech šlo o m3u playlisty, takže vcelku nic nestandardního. Ovládání umožňující základní funkcionalitu (volbu stanic, hlasitosti apod.) pak muselo probíhat vzdáleně optimálně pomocí chytrého telefonu. Opět nic zvláštního. Mezi možnostmi se nabízelo použití webového rozhraní, popř. ovládání pomocí nativní aplikace pro chytrý telefon (v mém případě na Androidu).

Roky používám VLC jako svůj primární video přehrávač. Ten byl proto první logickou volbou. Řešení postavené na jeho bázi bylo z hlediska rychlosti zprovoznění nejjednodušší a nakonec jsem ho používal několik měsíců. V průběhu času se ale nároky mírně změnily, i když kořen prvotní nespokojenosti v podobě neschopnosti VLC korektně pracovat s jedním z poskytovaných playlistů byl jiný. To vyústilo v následnou volbu MPV a řešení ne tak jednoduchém v základu, ale zato se širšími možnostmi pro další rozvoj.

Možnosti ve VLC

Zmíněnou jednoduchou variantou ovládání je Lua HTTP modul, pomocí kterého lze pracovat s webovým rozhraním vystaveným přímo VLC a zároveň ovládat přehrávač přes HTTP requesty. V mém případě jsem nakonec zvolil ovládání přes Python a pro něj dostupný modul requests. Tato možnost je zajímavá i tím, že jí využívá značné množství (různě kvalitních) aplikací třetích stran pro Android. (Není to ale jediné rozhraní, které zprostředkovává Lua interpreter, je poskytováno i rozhraní Lua CLI a LUa telnet.)

Jak tedy zprovoznit ovládání přes HTTP? Po instalaci pomocí obligátního...

sudo dnf in vlc

(Pozor je nutné mít povolený repozitář rpmfusion-free.)

...v nastavení VLC při zobrazení všech konfiguračních direktiv zaškrtneme v menu Rozhraní > Hlavní rozhraní možnost "web". Je možné volitelně změnit nastavení Modulu vzhledu z "Výchozího" na "Rozhraní dálkového ovládání", ale pozor, poté se VLC spustí opravdu pouze v minimalistickém režimu, tj. bez okna přehrávače. Po nastavení hesla v menu Rozhraní > Hlavní rozhraní > Lua (nezbytné), uložení daného nastavení a restartu VLC po každé změně je ovládací rozhraní přístupné na localhostu na portu 8080 (při výzvě k zadání uživatelského jména a hesla pak zadejte pouze heslo, nikoliv uživatele).

Poznámka nikoliv pod čarou na téma http vs. https: VLC ve výchozím stavu používá http 🙂

VLC Web UI

Webové rozhraní přehrávače VLC

Jak IP adresu, tak i port, lze samozřejmě změnit pomocí argumentů při spuštění VLC:

 --http-host IP
 --http-port PORT

A kdybychom se nechtěli zatěžovat klikáním v uživatelském rozhraní VLC vůbec, lze zmíněné nastavení provést následujícím zápisem:

vlc --intf http --http-host 127.0.0.1 --http-port 8080 --http-password 1234 [adresář s multimédii | m3u playlist]

Pro zpřístupnění ovládání pro další počítače v místní síti ještě musíme upravit konfigurační soubor /usr/share/vlc/lua/http/.hosts. Pokud neexistuje, vytvořte jej; obsahem souboru může být jediná povolená IP adresa, nebo rozsah. Zpřístupnění pro zařízení v domácí síti tak může vypadat např. takto: 192.168.0.0). Poté je ještě nutné přizpůsobit nastavení firewallu, na Fedoře pomocí firewall-cmd, kterým povolíme přístup na port 8080:

sudo firewall-cmd --add-port=8080/tcp
sudo firewall-cmd --runtime-to-permanent

Nyní máme zprovozněné webové rozhraní, je prosté, ale funkční, můžeme tedy začít používat přímo to, nebo některou z aplikací třetích stran. Nebo... realizovat vlastní řešení 🙂 V následujícím demonstračním příkladu použijeme Python a kombinaci modulů requests (pro komunikaci s VLC skrze http requesty) a bottle, který poslouží pro vytvoření jednoduchého webového rozhraní, tentokrát už dle našeho gusta.

Nainstalujme tedy zmíněné moduly, např. pomocí pipu:

pip install requests bottle --user

(Zvažte, prosím, použití pipenv nebo virtualenv; můžete nainstalovat i přímo RPM balíky z Fedory, konkrétně jsou to: python3-requests a python3-bottle.)

Příklad implementující zcela elementární funkcionalitu (spuštění a zastavení videa) může vypadat třeba takto:

#!/usr/bin/env python3

import requests
from bottle import route, run

def run_command(command):
    req = requests.get(
        f'http://127.0.0.1:8080/requests/status.xml?command={command}', 
        auth=('', '1234'))
    return req.status_code

@route('/')
@route('/<command>')
def index(command=""):
    run_command(command)
    return "<a href='/pl_play'>PŘEHRÁT</a> | \
            <a href='/pl_pause'>PAUZA</a> | \
            <a href='/pl_stop'>STOP</a>"

run(host='localhost', port=8888)

(Příklad předpokládá, že VLC i náš skript jsou spuštěny na stejném počítači,.)

Primitivní rozhraní našeho skriptu

Primitivní webové rozhraní našeho skriptu

Dané řešení je funkční, nicméně lze vůči němu mít mnoho výhrad. Ta největší vychází z poznání, že používáme jeden webový server (přes bottle) pouze k tomu, abychom odesílali requesty na jiný, vystavený přímo VLC. Nebylo by možné s VLC komunikovat i efektivnějším způsobem? Otázka je to pouze řečnická, neboť VLC nabízí možnost komunikace i dalšími způsoby, např. přes unixové nebo TCP sockety.

Pojďme se nyní podívat na to, jakým způsobem je možné vzdáleně ovládat další přehrávač a to MPV.

MPV a jak na něj

MPV je známý fork mplayeru, ke kterému jsem se uchýlil po VLC. A u něj je snad přímo esenciální možností vzdálené ovládání pomocí socketů (tentokrát unixových pro meziprocesovou komunikaci). VLC je, co do poskytovaných prostředků mocné, ale MPV je dle mého názoru ještě o krok dál. Pojďme se podívat na to, jak zprovoznit MPV právě v tomto režimu. Než se ale vrhneme na krátkou ukázku použití, musím doporučit (když ne k prostudování, tak alespoň k nahlédnutí) manuál, kterým MPV disponuje. Není nad kvalitní dokumentaci a tahle je jedním slovem impozantní.

I u MPV začneme instalací přehrávače samotného a souběžně utlity socat, jehož účel vystihují manuálové stránky, když ho popisují jako "SOcket CAT":

sudo dnf in mpv socat

(I zde je je nutný repozitář rpmfusion-free.)

Více netřeba, pojďme k příkladu samotnému. MPV spustíme přes:

mpv --input-ipc-server=/tmp/mpv.sock [adresář s multimédii]

Kdybychom chtěli jako vstup použít playlist, je nutné doplnit argument --playlist, ale o užitečných argumentech více až za chvíli. Takto spuštěné MPV začně přehrávat specifikované multimediální soubory a zároveň vytvoří v adresáři /tmp unixový socket, jak se můžeme snadno oveřit (všimněte si "s" na začátku výpisu oprávnění):

ls -l /tmp/mpv.sock
srw------- 1 lkotek lkotek 0 2. pro 15.45 /tmp/mpv.sock

Nyní přichází chvíle pro utilitu socat. Jejím prostřednictvím zašleme běžícímu MPV pokyn na pozastavení aktuálně přehrávaného souboru:

echo "cycle pause" | socat - /tmp/mpv.sock

Příkaz cycle je obzvlášť praktický, protože (přesně v duchu jeho názvu) můžeme opakovaným voláním cycle spolu s dalším parametrem (vlastností) postupně přepínat mezi dvěma nebo i více stavy (vlastnostmi). V naší ukázce mezi přehráváním a pauzou. Trochu komplexnější příklad (za použití cycle-values) pak může vypadat takto:

echo "cycle-values video-aspect 16:9 4:3 2.35:1 -1" | socat - /tmp/mpv.sock

Jde v něm o nastavení poměru stran u přehrávaného videa (-1 odpovídá výchozí hodnotě), při každém volání příkazu výše se tak iteruje mezi výčtem hodnot vlastnosti video-aspect.

Jak vzdáleně ovládat MPV tedy víme. Jak to skloubit dohromady s jednoduchým webovým rozhraním, které jsme použili prve u příkladu s VLC? MPV nám k tomu dává vícero cest. Předně existuje hned několik modulů pro Python, které jsou určeny přímo pro ovládání MPV (za všechny lze jmenovat python-mpv) a stejně tak Python disponuje již v základu modulem socket, který dělá čest svému názvu a zpřístupňuje nám práci se sockety.

Minimalistický program implementuje podobnou funkcionalitu jako předchozí ukázka s VLC a je ve výsledku jen nepatrně delší:

#!/usr/bin/env python3

import socket
from bottle import route, run

try:
    mpv_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    mpv_sock.connect('/tmp/mpv.sock')
except Exception as e:
    print(e)
    exit(1)

def run_command(command):
    mpv_commands = {
        "play": b"cycle pause\n",
        "prev": b"playlist-prev\n",
        "next": b"playlist-next\n"
    }
    mpv_sock.sendall(mpv_commands[command])

@route('/')
@route('/<command>')
def index(command="play"):
    run_command(command)
    return "<a href='/play'>PŘEHRÁT/PAUZA</a> | \
            <a href='/prev'>PŘEDCHOZÍ</a> | \
            <a href='/next'>DALŠÍ</a>"

run(host='localhost', port=8888)

K tomu malý dovětek. Stál jsem před volbou, zda použít výše zmíněný modul python-mpv, nebo přímo rozhraní poskytované MPV. Ve výsledku mi druhý jmenovaný přístup (i díky své ve výsledku až polopatické jednoduchosti a přímočarosti) vyhovoval lépe. Ostatně kdybychom šli ještě dále, lze si představit i řešení, ve kterém bychom nemuseli spoléhat na modul socket a volali utilitu socat např. skrz funkci Popen modulu subprocess.

Tipy na závěr

Na závěr mám několik tipů na řešení problémů, na které jsem v průběhu času narazil. Předně výchozí pythonní webserver, který používá bottle, je fajn na prototypování (což je přesně to, na co se hodí a k čemu je určen), ale v reálném nasazení člověk brzy narazí na jeho limity. Tvůrci bottle si jsou toho vědomi a doporučují použití alternativních webserverů, konkrétně těch poskytovaných paste nebo cherrypy. Následná úprava kódu je jednoduchá a uchráníte tak uživatele před nepříjemným lagováním (a že i desetiny sekundy dokáží pěkně zabolet).

Jak na to? Zajistíme, že je webserver nainstalovaný (pro demonstraci paste), např. opět přes pip:

pip install paste --user

A následně drobně modifikujeme předchozí ukázku:

# Umístěte na začátek skriptu k ostaním importům
from paste import httpserver

# Úprava funkce run() na konci skriptu
run(server='paste', host='localhost', port=8888)

A to je celé 🙂

Další tip se týká výhradně MPV a to několika argumentů, se kterými lze MPV spustit:

  • --ytdl=no – nechcete používat  youtube-dl? Pak pozor, ve výchozím stavu je tato volba zapnutá a má netriviální vliv na rychlost přepínání mezi položkami playlistu. Doporučuji přepnout na "no".
  • --hwdec=auto-safe – argument nastavuje, jaké API pro hardwarové dekódování má být použito a má proto zásadní vliv na výkon. Samozřejmě jeho použití je závislé na konkrétním hardware; po mnohém experimentování se mi nejvíce osvědčila hodnota "auto-safe".
  • --sub-codepage=+<codepage> – používáte externí soubor s titulky a chcete zvolit konkrétní znakovou sadu? Pak upozorním zvlášť na to nenápadné "+" v hodnotě argumentu. Není to překlep, vynutí použití zvolené sady nehledě na cokoliv dalšího.

A tím bych tento článek uzavřel. Osobně jsem používal výše popsaná řešení několik let a až ukončení činnosti prvního poskytovatele IPTV a zásadní změny politiky druhého (ústící v následnou nedostupnost playlistů TV stanic) mě donutila změnit přístup a použít konvenčnější řešení v podobě Android TV. Snad i tak daný postup bude někomu užitečný, osobně nyní hledám rozumnou cestu pro přehrávání hudební sbírky pomocí Raspberry Pi...

...a osvědčená řešení se jen a jen nabízejí 😉