App zur Steuerung des mpv Mediaplayers auf einem Raspberry Pi über HTTP
ulrich
2021-03-24 0af362883d659d9481a7f2bf6cf0c7459997f5e2
commit | author | age
8e2038 1 package de.uhilger.avdirektor.handler;
U 2
3 import de.uhilger.avdirektor.App;
4 import de.uhilger.avdirektor.MeldeThread;
5 import de.uhilger.avdirektor.ProzessLauscher;
6 import java.io.BufferedWriter;
7 import java.io.IOException;
8 import java.io.OutputStream;
9 import java.io.OutputStreamWriter;
10 import java.io.Writer;
11 import java.net.HttpURLConnection;
12 import java.net.URL;
13 import java.util.logging.Level;
14 import java.util.logging.Logger;
15
16 /**
cc2a32 17  * Methoden zur Ausfuehrung des Programmes omxplayer des Raspberry Pi 
U 18  * sowie zum Senden von Kommandos an eine laufende Instanz des 
19  * omxplayer.
20  * 
21  * Die Klasse OMXPlayer stellt als abstrakte Basisklasse ihre Methoden 
22  * den Handler-Klassen zur Verfuegung.
8e2038 23  *
U 24  * @author ulrich
25  */
26 public abstract class OMXPlayer implements ProzessLauscher {
27   
28   private static final Logger logger = Logger.getLogger(OMXPlayer.class.getName());
0c8d27 29   
0af362 30   public static final String CMD_STOP = "q";
U 31   public static final String CMD_DEC_SPEED = "1";
32   public static final String CMD_INC_SPEED = "2";
33   public static final String CMD_PREV_AUDIO = "j";
34   public static final String CMD_NEXT_AUDIO = "k";
35   public static final String CMD_PREV_CHAPTER = "i";
36   public static final String CMD_NEXT_CHAPTER = "o";
37   public static final String CMD_PREV_SUB = "n";
38   public static final String CMD_NEXT_SUB = "m";
39   public static final String CMD_TOGGLE_SUB = "s";
40   public static final String CMD_PAUSE_RESUME = "p";
41   public static final String CMD_DEC_VOL = "-";
42   public static final String CMD_INC_VOL = "+";
43   
44   public static final String PFEIL_LINKS = "5b44";
45   public static final String PFEIL_RECHTS = "5b43";
46   public static final String PFEIL_HERAUF = "5b41";
47   public static final String PFEIL_HERUNTER = "5b42";
48   
49   public static final String SP_RUECK_30 = "rueck30";
50   public static final String SP_VOR_30 = "rueck30";
51   public static final String SP_VOR_600 = "vor600";
52   public static final String SP_RUECK_600 = "rueck600";  
53
54   public static final String OPT_LOCAL_AUDIO = "-o%20local";
55   public static final String OPT_HDMI_AUDIO = "-o%20hdmi";
56   
57   public static final String F_PLAY = "play";
58   public static final String F_SEEK = "seek";
59   public static final String F_PING = "ping";
60
61   public static final String BLANK = " ";
62
8e2038 63   /**
U 64    * Einen Prozess zum Abspielen mit dem omxplayer starten
65    * @param urlStr  URL der Quelle, die abgespielt werden soll
66    * @param token
67    * @return Antwort des Servers
68    */
b6a8f0 69   /*
a7f0a1 70   public String abspielen(String urlStr, String token) {
U 71     return abspielenMitParametern(urlStr, null, token);
8e2038 72   }
b6a8f0 73   */
8e2038 74   
b6a8f0 75   /*
a7f0a1 76   public String abspielenMitRueckmeldung(String urlStr, String meldeUrlStr, String token) {
U 77     return abspielenMitParameternUndRueckmeldung(urlStr, null, meldeUrlStr, token);
8e2038 78   }
b6a8f0 79   */
8e2038 80   
U 81   /**
82    * Einen Prozess zum Abspielen mit dem omxplayer starten 
83    * und Parameter uebergeben.Moegliche Parameter fuer das Abspielen mit dem omxplayer 
84  beschreibt die Seite 
85   <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.
86    * App.OPT_LOCAL_AUDIO oder App.OPT_HDMI_AUDIO.
87  Mehrere Parameter werden mit App.BLANK getrennt.
88    * @param urlStr  der URL der Quelle, die abgespielt werden soll
89    * @param parameter  die Parameter, die vom omxplayer angewendet werden sollen
90    * @param token
91    * @return Antwort des Servers
92    */
b6a8f0 93   /*
a7f0a1 94   public String abspielenMitParametern(String urlStr, String parameter, String token) {
U 95     return abspielenMitParameternUndRueckmeldung(urlStr, parameter, null, token);
8e2038 96   }
b6a8f0 97   */
8e2038 98   
b6a8f0 99   public String abspielen(String urlStr, String parameter, String meldeUrlStr, String token) {
8e2038 100     String antwort;// = null;
U 101     try {
a7f0a1 102       //Object o = t.getAttribute(App.PI_PLAYER);
U 103       Process o = App.getPlayerProcess();
8e2038 104       if(o != null) {
a7f0a1 105         tilgen();        
8e2038 106       }
U 107       StringBuilder kommando = new StringBuilder("omxplayer ");
108       if(parameter != null) {
109         kommando.append(parameter);
0af362 110         kommando.append(BLANK);
8e2038 111       }
U 112       if(urlStr.startsWith("http")) {
113         kommando.append(urlStr.replace(" ", "%20"));
114         kommando.append("?t=");
115         kommando.append(token);
116       } else {
117         /*
118           //url z.B.: Filme/H/HEAT_D2.m4v
119         
120           hier muss noch der Pfad hinzugefuegt werden, unter 
121           dem auf dem raspi die Datenquelle via NFS eingebunden ist,
122           z.B. /media/mc/
123           dieser Teil des Pfades muss in pirc als Init-Parameter oder 
124           etwas aehnliches hinterlegt sein, weil es lokal zum jeweils 
125           verwendeten raspi gehoert
126   
127         */
128         
129         String pfad = App.getInitParameter("nfs-prefix");
130         kommando.append(pfad);
131         
132         kommando.append(urlStr);
133       }
134       logger.log(Level.FINE, "kommando: {0}", kommando.toString());
135       Process player_process = Runtime.getRuntime().exec(kommando.toString());
136       if(meldeUrlStr != null) {
137         MeldeThread mt = new MeldeThread();
138         mt.setProcess(player_process);
139         mt.lauscherHinzufuegen(this);
140         mt.setMeldeUrl(meldeUrlStr);
141         mt.start();
142       }
143       //servletContext.setAttribute(App.PI_PLAYER, player_process);
a7f0a1 144       //t.setAttribute(App.PI_PLAYER, player_process);
U 145       App.setPlayerProcess(player_process);
8e2038 146       //Runtime.getRuntime().exec("killall dbus-daemon");
U 147       antwort = "Abspielen gestartet, url: " + urlStr;
148     }
149     catch(IOException ex) {
150       antwort = "Fehler: " + ex.getMessage();
151     }
152     return antwort;
153   }
154     
155   /**
156    * Einen eventuell laufenden Abspielprozess beenden und den 
157    * Servlet-Kontext bereinigen.Diese Methode kann auch verwendet werden, wenn es beim normalen
158  Abspielen zu Fehlern kommt und womoeglich der Servlet-Kontext noch 
159  eine Referenz zu einem Abspielprozess enthaelt, die nicht mehr 
160  aktuell ist.
161    * 
162    * Mit der Methode tilgen kann man eine solche Referenz 
163  entfernen und gibt so das Objekt wieder frei fuer die Ausfuehrung 
164  weiterer Kommandos.
165    *
166    * @return die Antwort des Servers
167    */
a7f0a1 168   public String tilgen() {
8e2038 169     String antwort; // = null;
U 170     try {
a7f0a1 171       //Object o = t.getAttribute(App.PI_PLAYER);
U 172       Process o = App.getPlayerProcess();
8e2038 173       if(o == null) {
a7f0a1 174         //t.setAttribute(App.PI_PLAYER, null);
U 175         App.setPlayerProcess(null);
8e2038 176         // t.removeAttribute(App.PI_PLAYER);
U 177         antwort = "Es ist kein Player zum Beenden vorhanden, aber der Servlet-Kontext wurde bereinigt.";
178       } else {
0af362 179         kommando(CMD_STOP);
8e2038 180         //t.removeAttribute(PI_PLAYER);
U 181         antwort = "Player gestoppt, Kontext bereinigt.";
182       }
183     } 
184     catch(Exception ex) {
185       antwort = "Fehler: " + ex.getMessage();
186     }
187     return antwort;
188   }
189   
190   
191   /**
192    * Dem laufenden Abspielprozess ein Kommando uebermitteln
193    * @param k  das Kommando laut 
194    * <a href="https://github.com/huceke/omxplayer/blob/master/README.md" target="_blank">Liste der Kommandos</a>
195    * @return die Antwort des Servers
196    */
a7f0a1 197   public String kommando(String k) {
8e2038 198     String antwort; // = null;
U 199     try {
a7f0a1 200       //Object o = t.getAttribute(App.PI_PLAYER);
U 201       Process o = App.getPlayerProcess();
8e2038 202       if(o == null) {
a7f0a1 203         App.setPlayerProcess(null);
8e2038 204         //servletContext.removeAttribute(PI_PLAYER);
a7f0a1 205         //t.setAttribute(App.PI_PLAYER, null);
8e2038 206         antwort = "Es wird nichts abgespielt dem ein Kommando gesendet werden kann.";
U 207       } else {
a7f0a1 208         Process player_process = o;
8e2038 209         OutputStream os = player_process.getOutputStream();
U 210         Writer out = new BufferedWriter(new OutputStreamWriter(os));
211         out.write(k);
212         out.flush();
0af362 213         if(k.equals(CMD_STOP)) {
8e2038 214           out.close();
a7f0a1 215           App.setPlayerProcess(null);
8e2038 216           //player_process.destroy();
U 217           //player_process = null;
a7f0a1 218           //t.setAttribute(App.PI_PLAYER, null);
8e2038 219           //servletContext.removeAttribute(PI_PLAYER);
U 220         }
221         antwort = "Kommando '" + k + "' ausgefuehrt.";
222       }
223     } 
224     catch(IOException ex) {
225       antwort = "Fehler: " + ex.getMessage();
226     }
227     return antwort;
228   }
229   
230   /* ------ Implementierung ProzessLauscher ----------------- */
231   
232   @Override
233   public void prozessBeendet(String meldeUrlStr) {
234     try {
235       HttpURLConnection conn = (HttpURLConnection) new URL(meldeUrlStr).openConnection();
236       conn.setRequestMethod("GET");
237       conn.connect();
238       int status = conn.getResponseCode();
239       logger.log(Level.INFO, "Abspielen beendet, Meldung an {0} mit Statuscode {1} gesendet.", new Object[]{meldeUrlStr, status});
240     } catch(IOException ex) {
241       logger.log(Level.INFO, ex.getMessage(), ex);
242     }
243   }
244   
245 }