1
0
mirror of https://github.com/TeamNewPipe/PipeCast synced 2025-10-05 16:02:48 +02:00

Implement basic queueing

This commit is contained in:
wb9688
2020-06-17 10:56:51 +02:00
parent 29052ce0bf
commit 0958b5492d
4 changed files with 169 additions and 22 deletions

View File

@@ -2,7 +2,9 @@ apply plugin: 'java-library'
repositories {
jcenter()
maven { url 'https://jitpack.io' }
}
dependencies {
implementation 'com.github.wb9688:nanohttpd:f23888e8b63baa6a3010d1e75ebdf3a48d14147d'
}

View File

@@ -20,5 +20,9 @@ public abstract class Device {
public abstract void play(String url, String title, String creator, MediaFormat mediaFormat) throws IOException, XMLStreamException;
public abstract void addToQueue(String url, String title, String creator, MediaFormat mediaFormat) throws IOException, XMLStreamException;
public abstract List<MediaFormat> getSupportedFormats() throws IOException, XMLStreamException, ParserConfigurationException, SAXException;
public abstract void startBackgroundWork() throws IOException;
}

View File

@@ -0,0 +1,80 @@
package org.schabi.newpipe.cast.protocols.upnp;
import org.nanohttpd.protocols.http.IHTTPSession;
import org.nanohttpd.protocols.http.NanoHTTPD;
import org.nanohttpd.protocols.http.response.Response;
import org.nanohttpd.protocols.http.response.Status;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringReader;
import java.net.Socket;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
public class GenaServer extends NanoHTTPD {
private UpnpDevice upnpDevice;
public GenaServer(UpnpDevice upnpDevice) throws IOException {
super(30303);
start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);
this.upnpDevice = upnpDevice;
String request = "SUBSCRIBE " + upnpDevice.avTransportEventUrl.getPath() + " HTTP/1.1\r\n"
+ "HOST: " + upnpDevice.avTransportEventUrl.getHost() + ":" + upnpDevice.avTransportEventUrl.getPort() + "\r\n"
+ "CALLBACK: <http://192.168.1.16:30303>\r\n"
+ "NT: upnp:event\r\n"
+ "TIMEOUT: Second-infinite\r\n\r\n"; // TODO: implement timeout properly as infinite is deprecated, also implement UNSUBSCRIBE
Socket socket = new Socket(upnpDevice.avTransportEventUrl.getHost(), upnpDevice.avTransportEventUrl.getPort());
OutputStream outputStream = socket.getOutputStream();
outputStream.write(request.getBytes());
outputStream.close();
socket.close();
}
@Override
public Response serve(IHTTPSession session) {
try {
String response = session.parseBody();
InputSource inputSource = new InputSource(new StringReader(response));
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(inputSource);
document.getDocumentElement().normalize();
Node lastChange = ((Element) document.getDocumentElement().getElementsByTagName("e:property").item(0)).getElementsByTagName("LastChange").item(0);
InputSource eventInputSource = new InputSource(new StringReader(lastChange.getTextContent()));
DocumentBuilderFactory eventDocumentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder eventDocumentBuilder = eventDocumentBuilderFactory.newDocumentBuilder();
Document eventDocument = eventDocumentBuilder.parse(eventInputSource);
eventDocument.getDocumentElement().normalize();
NodeList nextAvTransportUri = ((Element) eventDocument.getDocumentElement().getElementsByTagName("InstanceID").item(0)).getElementsByTagName("NextAVTransportURI");
if (nextAvTransportUri.getLength() == 1) {
if (((Element) nextAvTransportUri.item(0)).getAttribute("val").equals("")) {
upnpDevice.queue.remove(0);
if (!upnpDevice.queue.isEmpty()) {
upnpDevice.setNextAvTransportUri();
}
}
}
} catch (IOException | SAXException | ParserConfigurationException e) {
return Response.newFixedLengthResponse(Status.INTERNAL_ERROR, "text/plain", e.getMessage() + "\n");
}
return Response.newFixedLengthResponse("\n");
}
}

View File

@@ -1,5 +1,13 @@
package org.schabi.newpipe.cast.protocols.upnp;
import org.schabi.newpipe.cast.Device;
import org.schabi.newpipe.cast.MediaFormat;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
@@ -7,7 +15,6 @@ import java.io.OutputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
@@ -19,20 +26,16 @@ import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.schabi.newpipe.cast.Device;
import org.schabi.newpipe.cast.MediaFormat;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class UpnpDevice extends Device {
private Document description;
private Element device;
private URL avTransportUrl;
URL avTransportEventUrl;
private URL connectionManagerUrl;
List<String> queue = new ArrayList<>();
public UpnpDevice(String location) throws IOException, ParserConfigurationException, SAXException {
super(location);
getDescription();
@@ -73,6 +76,8 @@ public class UpnpDevice extends Device {
if (service.getElementsByTagName("serviceType").item(0).getTextContent().equals("urn:schemas-upnp-org:service:AVTransport:1")) {
String serviceUrl = service.getElementsByTagName("controlURL").item(0).getTextContent();
avTransportUrl = new URL(baseUrl, serviceUrl);
String serviceEventUrl = service.getElementsByTagName("eventSubURL").item(0).getTextContent();
avTransportEventUrl = new URL(baseUrl, serviceEventUrl);
} else if (service.getElementsByTagName("serviceType").item(0).getTextContent().equals("urn:schemas-upnp-org:service:ConnectionManager:1")) {
String serviceUrl = service.getElementsByTagName("controlURL").item(0).getTextContent();
connectionManagerUrl = new URL(baseUrl, serviceUrl);
@@ -122,16 +127,7 @@ public class UpnpDevice extends Device {
connection.getInputStream();
}
@Override
public void play(String url, String title, String creator, MediaFormat mediaFormat) throws IOException, XMLStreamException {
HttpURLConnection connection = (HttpURLConnection) avTransportUrl.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "text/xml;charset=utf-8");
connection.setRequestProperty("Soapaction", "\"urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI\"");
connection.setDoOutput(true);
OutputStream outputStream = connection.getOutputStream();
private String createDidl(String url, String title, String creator, MediaFormat mediaFormat) throws XMLStreamException {
StringWriter didlSw = new StringWriter();
XMLOutputFactory didlXmlof = XMLOutputFactory.newInstance();
XMLStreamWriter didlWriter = didlXmlof.createXMLStreamWriter(didlSw);
@@ -172,6 +168,19 @@ public class UpnpDevice extends Device {
didlWriter.writeEndDocument();
didlWriter.close();
return didlSw.toString();
}
@Override
public void play(String url, String title, String creator, MediaFormat mediaFormat) throws IOException, XMLStreamException {
HttpURLConnection connection = (HttpURLConnection) avTransportUrl.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "text/xml;charset=utf-8");
connection.setRequestProperty("Soapaction", "\"urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI\"");
connection.setDoOutput(true);
OutputStream outputStream = connection.getOutputStream();
StringWriter sw = new StringWriter();
XMLOutputFactory xmlof = XMLOutputFactory.newInstance();
XMLStreamWriter writer = xmlof.createXMLStreamWriter(sw);
@@ -189,7 +198,7 @@ public class UpnpDevice extends Device {
writer.writeCharacters(url);
writer.writeEndElement();
writer.writeStartElement("CurrentURIMetaData");
writer.writeCharacters(didlSw.toString());
writer.writeCharacters(createDidl(url, title, creator, mediaFormat));
writer.writeEndElement();
writer.writeEndElement();
writer.writeEndElement();
@@ -205,6 +214,55 @@ public class UpnpDevice extends Device {
play();
}
void setNextAvTransportUri() throws IOException {
HttpURLConnection connection = (HttpURLConnection) avTransportUrl.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "text/xml;charset=utf-8");
connection.setRequestProperty("Soapaction", "\"urn:schemas-upnp-org:service:AVTransport:1#SetNextAVTransportURI\"");
connection.setDoOutput(true);
OutputStream outputStream = connection.getOutputStream();
byte[] xml = queue.get(0).getBytes();
outputStream.write(xml);
outputStream.close();
connection.getInputStream();
}
@Override
public void addToQueue(String url, String title, String creator, MediaFormat mediaFormat) throws IOException, XMLStreamException {
StringWriter sw = new StringWriter();
XMLOutputFactory xmlof = XMLOutputFactory.newInstance();
XMLStreamWriter writer = xmlof.createXMLStreamWriter(sw);
writer.writeStartDocument("utf-8", "1.0");
writer.writeStartElement("s:Envelope");
writer.writeAttribute("s:encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/");
writer.writeNamespace("s", "http://schemas.xmlsoap.org/soap/envelope/");
writer.writeStartElement("s:Body");
writer.writeStartElement("u:SetNextAVTransportURI");
writer.writeNamespace("u", "urn:schemas-upnp-org:service:AVTransport:1");
writer.writeStartElement("InstanceID");
writer.writeCharacters("0");
writer.writeEndElement();
writer.writeStartElement("NextURI");
writer.writeCharacters(url);
writer.writeEndElement();
writer.writeStartElement("NextURIMetaData");
writer.writeCharacters(createDidl(url, title, creator, mediaFormat));
writer.writeEndElement();
writer.writeEndElement();
writer.writeEndElement();
writer.writeEndElement();
writer.writeEndDocument();
writer.close();
queue.add(sw.toString());
if (queue.size() == 1) {
setNextAvTransportUri();
}
}
@Override
public List<MediaFormat> getSupportedFormats() throws IOException, XMLStreamException, ParserConfigurationException, SAXException {
HttpURLConnection connection = (HttpURLConnection) connectionManagerUrl.openConnection();
@@ -243,8 +301,6 @@ public class UpnpDevice extends Device {
}
input.close();
System.out.println(response.toString());
InputSource inputSource = new InputSource(new StringReader(response.toString()));
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
@@ -270,4 +326,9 @@ public class UpnpDevice extends Device {
return supportedFormats;
}
@Override
public void startBackgroundWork() throws IOException {
new GenaServer(this);
}
}