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