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