/*
|
AV-Direktor - Control OMXPlayer on Raspberry Pi via HTTP
|
Copyright (C) 2021 Ulrich Hilger
|
|
This program is free software: you can redistribute it and/or modify
|
it under the terms of the GNU Affero General Public License as
|
published by the Free Software Foundation, either version 3 of the
|
License, or (at your option) any later version.
|
|
This program is distributed in the hope that it will be useful,
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
GNU Affero General Public License for more details.
|
|
You should have received a copy of the GNU Affero General Public License
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
*/
|
|
package de.uhilger.calypso.handler;
|
|
import de.uhilger.calypso.App;
|
import de.uhilger.calypso.MeldeThread;
|
import de.uhilger.calypso.ProzessLauscher;
|
import java.io.BufferedWriter;
|
import java.io.File;
|
import java.io.IOException;
|
import java.io.OutputStream;
|
import java.io.OutputStreamWriter;
|
import java.io.Writer;
|
import java.net.HttpURLConnection;
|
import java.net.URL;
|
import java.util.ArrayList;
|
import java.util.Arrays;
|
import java.util.List;
|
import java.util.logging.Level;
|
import java.util.logging.Logger;
|
|
/**
|
* Methoden zur Ausfuehrung des Programmes omxplayer des Raspberry Pi
|
* sowie zum Senden von Kommandos an eine laufende Instanz des
|
* omxplayer.
|
*
|
* Die Klasse OMXPlayer stellt als abstrakte Basisklasse ihre Methoden
|
* den Handler-Klassen zur Verfuegung.
|
*
|
* @author ulrich
|
*/
|
public class OMXPlayer implements Player , ProzessLauscher {
|
|
private static final Logger logger = Logger.getLogger(OMXPlayer.class.getName());
|
|
public static final String NAME = "omxplayer";
|
|
public static final String BLANK = " ";
|
public static final String CMD_DEC_SPEED = "1";
|
public static final String CMD_DEC_VOL = "-";
|
public static final String CMD_INC_SPEED = "2";
|
public static final String CMD_INC_VOL = "+";
|
public static final String CMD_NEXT_AUDIO = "k";
|
public static final String CMD_NEXT_CHAPTER = "o";
|
public static final String CMD_NEXT_SUB = "m";
|
public static final String CMD_PAUSE_RESUME = "p";
|
public static final String CMD_PREV_AUDIO = "j";
|
public static final String CMD_PREV_CHAPTER = "i";
|
public static final String CMD_PREV_SUB = "n";
|
public static final String CMD_STOP = "q";
|
public static final String CMD_TOGGLE_SUB = "s";
|
public static final String F_PING = "ping";
|
public static final String F_PLAY = "play";
|
public static final String F_PLAY_ON = "playon";
|
public static final String F_SEEK = "seek";
|
public static final String OPT_HDMI_AUDIO = "-o%20hdmi";
|
public static final String OPT_LOCAL_AUDIO = "-o%20local";
|
public static final String PFEIL_HERAUF = "5b41";
|
public static final String PFEIL_HERUNTER = "5b42";
|
public static final String PFEIL_LINKS = "5b44";
|
public static final String PFEIL_RECHTS = "5b43";
|
public static final String SP_RUECK_30 = "rueck30";
|
public static final String SP_RUECK_600 = "rueck600";
|
public static final String SP_VOR_30 = "rueck30";
|
public static final String SP_VOR_600 = "vor600";
|
|
@Override
|
public String abspielen(String urlStr, String parameter, String meldeUrlStr, String token) {
|
String antwort;// = null;
|
try {
|
Process o = App.getPlayerProcess();
|
if(o != null) {
|
tilgen();
|
}
|
List<String> kommando = new ArrayList();
|
kommando.add(NAME);
|
kommando.addAll(Arrays.asList(parameter.split(BLANK)));
|
if(urlStr.startsWith("http")) {
|
kommando.add(urlStr.replace(" ", "%20"));
|
} else {
|
kommando.add(App.getInitParameter("nfs-prefix") + urlStr);
|
}
|
logger.log(Level.FINE, "parameter: {0}", parameter);
|
logger.log(Level.FINE, "kommando: {0}", kommando.toString());
|
ProcessBuilder pb = new ProcessBuilder(kommando);
|
pb.directory(new File(System.getProperty("omx.wd")));
|
Process player_process = pb.start();
|
if(meldeUrlStr != null) {
|
MeldeThread mt = new MeldeThread();
|
mt.setProcess(player_process);
|
mt.lauscherHinzufuegen(this);
|
mt.setMeldeUrl(meldeUrlStr);
|
mt.start();
|
}
|
App.setPlayerProcess(player_process);
|
antwort = "Abspielen gestartet, url: " + urlStr;
|
}
|
catch(IOException ex) {
|
antwort = "Fehler: " + ex.getMessage();
|
}
|
return antwort;
|
}
|
|
/**
|
* Einen eventuell laufenden Abspielprozess beenden und den
|
* Servlet-Kontext bereinigen.Diese Methode kann auch verwendet werden, wenn es beim normalen
|
Abspielen zu Fehlern kommt und womoeglich der Servlet-Kontext noch
|
eine Referenz zu einem Abspielprozess enthaelt, die nicht mehr
|
aktuell ist.
|
*
|
* Mit der Methode tilgen kann man eine solche Referenz
|
entfernen und gibt so das Objekt wieder frei fuer die Ausfuehrung
|
weiterer Kommandos.
|
*
|
* @return die Antwort des Servers
|
*/
|
@Override
|
public String tilgen() {
|
String antwort; // = null;
|
try {
|
Process o = App.getPlayerProcess();
|
if(o == null) {
|
antwort = "Es ist kein Player zum Beenden vorhanden.";
|
//App.setPlayerProcess(null);
|
} else {
|
kommando(CMD_STOP); // setzt den Prozess der App auf null
|
antwort = "Player gestoppt.";
|
}
|
}
|
catch(Exception ex) {
|
antwort = "Fehler: " + ex.getMessage();
|
}
|
return antwort;
|
}
|
|
|
/**
|
* Dem laufenden Abspielprozess ein Kommando uebermitteln
|
* @param k das Kommando laut
|
* <a href="https://github.com/huceke/omxplayer/blob/master/README.md" target="_blank">Liste der Kommandos</a>
|
* @return die Antwort des Servers
|
*/
|
@Override
|
public String kommando(String k) {
|
String antwort; // = null;
|
try {
|
//Object o = t.getAttribute(App.PI_PLAYER);
|
Process o = App.getPlayerProcess();
|
if(o == null) {
|
//App.setPlayerProcess(null);
|
//servletContext.removeAttribute(PI_PLAYER);
|
//t.setAttribute(App.PI_PLAYER, null);
|
antwort = "Es wird nichts abgespielt dem ein Kommando gesendet werden kann.";
|
} else {
|
Process player_process = o;
|
OutputStream os = player_process.getOutputStream();
|
Writer out = new BufferedWriter(new OutputStreamWriter(os));
|
out.write(k);
|
out.flush();
|
if(k.equals(CMD_STOP)) {
|
out.close();
|
|
/*
|
fuer den Fall, dass ein Stopp-Signal den Player nicht erreicht
|
oder dort nicht funktioniert, gibt es keine Moeglichkeit festzustellen,
|
dass der Player noch spielt. Damit in einem solchen Fall der Zeiger
|
auf den Abspielprozess nicht verloren geht, wird der Zeiger nicht
|
auf null gesetzt.
|
*/
|
|
//App.setPlayerProcess(null);
|
//player_process.destroy();
|
//player_process = null;
|
//t.setAttribute(App.PI_PLAYER, null);
|
//servletContext.removeAttribute(PI_PLAYER);
|
}
|
antwort = "Kommando '" + k + "' ausgefuehrt.";
|
}
|
}
|
catch(IOException ex) {
|
antwort = "Fehler: " + ex.getMessage();
|
}
|
return antwort;
|
}
|
|
/* ------ Implementierung ProzessLauscher ----------------- */
|
|
@Override
|
public void prozessBeendet(String meldeUrlStr) {
|
try {
|
HttpURLConnection conn = (HttpURLConnection) new URL(meldeUrlStr).openConnection();
|
conn.setRequestMethod("GET");
|
conn.connect();
|
int status = conn.getResponseCode();
|
logger.log(Level.INFO,
|
"Abspielen beendet, Meldung an {0} mit Statuscode {1} gesendet.",
|
new Object[]{meldeUrlStr, status});
|
/*
|
fuer den Fall, dass ein Stopp-Signal den Player nicht erreicht
|
oder dort nicht funktioniert, gibt es keine Moeglichkeit festzustellen,
|
dass der Player noch spielt. Damit in einem solchen Fall der Zeiger
|
auf den Abspielprozess nicht verloren geht, wird der Zeiger nicht
|
auf null gesetzt.
|
*/
|
//App.setPlayerProcess(null);
|
} catch(IOException ex) {
|
logger.log(Level.INFO, ex.getMessage(), ex);
|
}
|
}
|
|
}
|