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