| | |
| | | /* |
| | | 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.avdirektor.handler; |
| | | |
| | | import de.uhilger.avdirektor.App; |
| | | import de.uhilger.avdirektor.MeldeThread; |
| | | import de.uhilger.avdirektor.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; |
| | | |
| | |
| | | * |
| | | * @author ulrich |
| | | */ |
| | | public abstract class OMXPlayer implements ProzessLauscher { |
| | | public class OMXPlayer implements Player , ProzessLauscher { |
| | | |
| | | private static final Logger logger = Logger.getLogger(OMXPlayer.class.getName()); |
| | | |
| | | public static final String CMD_STOP = "q"; |
| | | public static final String CMD_DEC_SPEED = "1"; |
| | | public static final String CMD_INC_SPEED = "2"; |
| | | public static final String CMD_PREV_AUDIO = "j"; |
| | | public static final String CMD_NEXT_AUDIO = "k"; |
| | | public static final String CMD_PREV_CHAPTER = "i"; |
| | | public static final String CMD_NEXT_CHAPTER = "o"; |
| | | public static final String CMD_PREV_SUB = "n"; |
| | | public static final String CMD_NEXT_SUB = "m"; |
| | | public static final String CMD_TOGGLE_SUB = "s"; |
| | | public static final String CMD_PAUSE_RESUME = "p"; |
| | | public static final String CMD_DEC_VOL = "-"; |
| | | public static final String CMD_INC_VOL = "+"; |
| | | public static final String NAME = "omxplayer"; |
| | | |
| | | public static final String PFEIL_LINKS = "5b44"; |
| | | public static final String PFEIL_RECHTS = "5b43"; |
| | | 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"; |
| | | public static final String SP_RUECK_600 = "rueck600"; |
| | | |
| | | public static final String OPT_LOCAL_AUDIO = "-o%20local"; |
| | | public static final String OPT_HDMI_AUDIO = "-o%20hdmi"; |
| | | |
| | | public static final String F_PLAY = "play"; |
| | | public static final String F_SEEK = "seek"; |
| | | public static final String F_PING = "ping"; |
| | | |
| | | public static final String BLANK = " "; |
| | | |
| | | /** |
| | | * Einen Prozess zum Abspielen mit dem omxplayer starten |
| | | * @param urlStr URL der Quelle, die abgespielt werden soll |
| | | * @param token |
| | | * @return Antwort des Servers |
| | | */ |
| | | /* |
| | | public String abspielen(String urlStr, String token) { |
| | | return abspielenMitParametern(urlStr, null, token); |
| | | } |
| | | */ |
| | | |
| | | /* |
| | | public String abspielenMitRueckmeldung(String urlStr, String meldeUrlStr, String token) { |
| | | return abspielenMitParameternUndRueckmeldung(urlStr, null, meldeUrlStr, token); |
| | | } |
| | | */ |
| | | |
| | | /** |
| | | * Einen Prozess zum Abspielen mit dem omxplayer starten |
| | | * und Parameter uebergeben.Moegliche Parameter fuer das Abspielen mit dem omxplayer |
| | | beschreibt die Seite |
| | | <a href="https://github.com/huceke/omxplayer/blob/master/README.md"target="_blank">Aufstellung der Parameter</a>.Die Zeichenkette parameter enthaelt Eintraege wie z.B. |
| | | * App.OPT_LOCAL_AUDIO oder App.OPT_HDMI_AUDIO. |
| | | Mehrere Parameter werden mit App.BLANK getrennt. |
| | | * @param urlStr der URL der Quelle, die abgespielt werden soll |
| | | * @param parameter die Parameter, die vom omxplayer angewendet werden sollen |
| | | * @param token |
| | | * @return Antwort des Servers |
| | | */ |
| | | /* |
| | | public String abspielenMitParametern(String urlStr, String parameter, String token) { |
| | | return abspielenMitParameternUndRueckmeldung(urlStr, parameter, null, token); |
| | | } |
| | | */ |
| | | |
| | | @Override |
| | | public String abspielen(String urlStr, String parameter, String meldeUrlStr, String token) { |
| | | String antwort;// = null; |
| | | try { |
| | | //Object o = t.getAttribute(App.PI_PLAYER); |
| | | Process o = App.getPlayerProcess(); |
| | | if(o != null) { |
| | | tilgen(); |
| | | } |
| | | StringBuilder kommando = new StringBuilder("omxplayer "); |
| | | if(parameter != null) { |
| | | kommando.append(parameter); |
| | | kommando.append(BLANK); |
| | | } |
| | | List<String> kommando = new ArrayList(); |
| | | kommando.add(NAME); |
| | | kommando.addAll(Arrays.asList(parameter.split(BLANK))); |
| | | if(urlStr.startsWith("http")) { |
| | | kommando.append(urlStr.replace(" ", "%20")); |
| | | kommando.append("?t="); |
| | | kommando.append(token); |
| | | kommando.add(urlStr.replace(" ", "%20")); |
| | | } else { |
| | | /* |
| | | //url z.B.: Filme/H/HEAT_D2.m4v |
| | | |
| | | hier muss noch der Pfad hinzugefuegt werden, unter |
| | | dem auf dem raspi die Datenquelle via NFS eingebunden ist, |
| | | z.B. /media/mc/ |
| | | dieser Teil des Pfades muss in pirc als Init-Parameter oder |
| | | etwas aehnliches hinterlegt sein, weil es lokal zum jeweils |
| | | verwendeten raspi gehoert |
| | | |
| | | */ |
| | | |
| | | String pfad = App.getInitParameter("nfs-prefix"); |
| | | kommando.append(pfad); |
| | | |
| | | kommando.append(urlStr); |
| | | } |
| | | kommando.add(App.getInitParameter("nfs-prefix") + urlStr); |
| | | } |
| | | logger.log(Level.FINE, "parameter: {0}", parameter); |
| | | logger.log(Level.FINE, "kommando: {0}", kommando.toString()); |
| | | Process player_process = Runtime.getRuntime().exec(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.setMeldeUrl(meldeUrlStr); |
| | | mt.start(); |
| | | } |
| | | //servletContext.setAttribute(App.PI_PLAYER, player_process); |
| | | //t.setAttribute(App.PI_PLAYER, player_process); |
| | | App.setPlayerProcess(player_process); |
| | | //Runtime.getRuntime().exec("killall dbus-daemon"); |
| | | antwort = "Abspielen gestartet, url: " + urlStr; |
| | | } |
| | | catch(IOException ex) { |
| | |
| | | * |
| | | * @return die Antwort des Servers |
| | | */ |
| | | @Override |
| | | public String tilgen() { |
| | | String antwort; // = null; |
| | | try { |
| | | //Object o = t.getAttribute(App.PI_PLAYER); |
| | | Process o = App.getPlayerProcess(); |
| | | if(o == null) { |
| | | //t.setAttribute(App.PI_PLAYER, null); |
| | | App.setPlayerProcess(null); |
| | | // t.removeAttribute(App.PI_PLAYER); |
| | | antwort = "Es ist kein Player zum Beenden vorhanden, aber der Servlet-Kontext wurde bereinigt."; |
| | | antwort = "Es ist kein Player zum Beenden vorhanden."; |
| | | //App.setPlayerProcess(null); |
| | | } else { |
| | | kommando(CMD_STOP); |
| | | //t.removeAttribute(PI_PLAYER); |
| | | antwort = "Player gestoppt, Kontext bereinigt."; |
| | | kommando(CMD_STOP); // setzt den Prozess der App auf null |
| | | antwort = "Player gestoppt."; |
| | | } |
| | | } |
| | | catch(Exception ex) { |
| | |
| | | * <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); |
| | | //App.setPlayerProcess(null); |
| | | //servletContext.removeAttribute(PI_PLAYER); |
| | | //t.setAttribute(App.PI_PLAYER, null); |
| | | antwort = "Es wird nichts abgespielt dem ein Kommando gesendet werden kann."; |
| | |
| | | out.flush(); |
| | | if(k.equals(CMD_STOP)) { |
| | | out.close(); |
| | | App.setPlayerProcess(null); |
| | | |
| | | /* |
| | | 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); |
| | |
| | | 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}); |
| | | 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); |
| | | } |