Changes to be committed:
modified: cmd/pmomusic/main.go new file: internal/netutils/ip_detect.go new file: internal/netutils/list_all_ip.go modified: internal/soap/soap.go modified: internal/ssdp/responder.go modified: internal/ssdp/ssdp.go modified: internal/upnp/http.go new file: internal/upnp/server.go new file: internal/upnp/xml/AVTransport.xml new file: internal/upnp/xml/ConnectionManager.xml new file: internal/upnp/xml/RenderingControl.xml
This commit is contained in:
@@ -2,30 +2,16 @@ package upnp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"gargoton.petite-maison-orange.fr/eric/pmomusic/internal/soap"
|
||||
)
|
||||
|
||||
func StartHTTPServer(usn string) {
|
||||
http.HandleFunc("/description.xml", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/xml")
|
||||
w.Write([]byte(generateDeviceDescription(usn)))
|
||||
})
|
||||
|
||||
http.HandleFunc("/upnp/control/AVTransport", soap.HandleSOAP)
|
||||
|
||||
log.Fatal(http.ListenAndServe(":1400", nil))
|
||||
}
|
||||
|
||||
func generateDeviceDescription(usn string) string {
|
||||
func generateDeviceDescription(usn, ip string, port uint) string {
|
||||
return fmt.Sprintf(`<?xml version="1.0"?>
|
||||
<root xmlns="urn:schemas-upnp-org:device-1-0">
|
||||
<specVersion>
|
||||
<major>1</major>
|
||||
<minor>0</minor>
|
||||
</specVersion>
|
||||
<URLBase>http://%s:%d/</URLBase>
|
||||
<device>
|
||||
<deviceType>urn:schemas-upnp-org:device:MediaRenderer:1</deviceType>
|
||||
<friendlyName>pmomusic Fake Renderer</friendlyName>
|
||||
@@ -36,7 +22,7 @@ func generateDeviceDescription(usn string) string {
|
||||
<modelNumber>1.0</modelNumber>
|
||||
<modelURL>http://example.com/model</modelURL>
|
||||
<UDN>%s</UDN>
|
||||
<presentationURL>http://%s</presentationURL>
|
||||
<presentationURL>http://%s:%d</presentationURL>
|
||||
<serviceList>
|
||||
<service>
|
||||
<serviceType>urn:schemas-upnp-org:service:AVTransport:1</serviceType>
|
||||
@@ -61,5 +47,5 @@ func generateDeviceDescription(usn string) string {
|
||||
</service>
|
||||
</serviceList>
|
||||
</device>
|
||||
</root>`, usn, "127.0.0.1:1400") // à adapter à ton IP:port réel
|
||||
</root>`, ip, port, usn, ip, port)
|
||||
}
|
||||
|
||||
45
internal/upnp/server.go
Normal file
45
internal/upnp/server.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package upnp
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"gargoton.petite-maison-orange.fr/eric/pmomusic/internal/soap"
|
||||
)
|
||||
|
||||
//go:embed xml/*.xml
|
||||
var embeddedXML embed.FS
|
||||
|
||||
// ServeStaticXML mounts handlers for SCPD XML files.
|
||||
func ServeStaticXML(mux *http.ServeMux) {
|
||||
subFS, err := fs.Sub(embeddedXML, "xml")
|
||||
if err != nil {
|
||||
panic("failed to create sub FS: " + err.Error())
|
||||
}
|
||||
mux.Handle("/scpd/", http.StripPrefix("/scpd/", http.FileServer(http.FS(subFS))))
|
||||
}
|
||||
|
||||
func StartHTTPServer(usn, ip string, port uint) {
|
||||
mux := http.NewServeMux()
|
||||
|
||||
// Device description
|
||||
mux.HandleFunc("/description.xml", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/xml")
|
||||
w.Write([]byte(generateDeviceDescription(usn, ip, port)))
|
||||
})
|
||||
|
||||
// SOAP control endpoints
|
||||
mux.HandleFunc("/upnp/control/AVTransport", soap.HandleSOAP)
|
||||
mux.HandleFunc("/upnp/control/RenderingControl", soap.HandleSOAP)
|
||||
mux.HandleFunc("/upnp/control/ConnectionManager", soap.HandleSOAP)
|
||||
|
||||
// Serve static SCPD XML files
|
||||
ServeStaticXML(mux)
|
||||
|
||||
addr := fmt.Sprintf("%s:%d", ip, port)
|
||||
log.Printf("Serving UPnP fake renderer at http://%s", addr)
|
||||
log.Fatal(http.ListenAndServe(addr, mux))
|
||||
}
|
||||
81
internal/upnp/xml/AVTransport.xml
Normal file
81
internal/upnp/xml/AVTransport.xml
Normal file
@@ -0,0 +1,81 @@
|
||||
<?xml version="1.0"?>
|
||||
<scpd xmlns="urn:schemas-upnp-org:service-1-0">
|
||||
<specVersion>
|
||||
<major>1</major>
|
||||
<minor>0</minor>
|
||||
</specVersion>
|
||||
<actionList>
|
||||
<action>
|
||||
<name>SetAVTransportURI</name>
|
||||
<argumentList>
|
||||
<argument>
|
||||
<name>InstanceID</name>
|
||||
<direction>in</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>CurrentURI</name>
|
||||
<direction>in</direction>
|
||||
<relatedStateVariable>AVTransportURI</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>CurrentURIMetaData</name>
|
||||
<direction>in</direction>
|
||||
<relatedStateVariable>AVTransportURIMetaData</relatedStateVariable>
|
||||
</argument>
|
||||
</argumentList>
|
||||
</action>
|
||||
|
||||
<action>
|
||||
<name>Play</name>
|
||||
<argumentList>
|
||||
<argument>
|
||||
<name>InstanceID</name>
|
||||
<direction>in</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>Speed</name>
|
||||
<direction>in</direction>
|
||||
<relatedStateVariable>TransportPlaySpeed</relatedStateVariable>
|
||||
</argument>
|
||||
</argumentList>
|
||||
</action>
|
||||
|
||||
<action>
|
||||
<name>Stop</name>
|
||||
<argumentList>
|
||||
<argument>
|
||||
<name>InstanceID</name>
|
||||
<direction>in</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
|
||||
</argument>
|
||||
</argumentList>
|
||||
</action>
|
||||
</actionList>
|
||||
|
||||
<serviceStateTable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>A_ARG_TYPE_InstanceID</name>
|
||||
<dataType>ui4</dataType>
|
||||
</stateVariable>
|
||||
|
||||
<stateVariable sendEvents="no">
|
||||
<name>AVTransportURI</name>
|
||||
<dataType>string</dataType>
|
||||
</stateVariable>
|
||||
|
||||
<stateVariable sendEvents="no">
|
||||
<name>AVTransportURIMetaData</name>
|
||||
<dataType>string</dataType>
|
||||
</stateVariable>
|
||||
|
||||
<stateVariable sendEvents="no">
|
||||
<name>TransportPlaySpeed</name>
|
||||
<dataType>string</dataType>
|
||||
<allowedValueList>
|
||||
<allowedValue>1</allowedValue>
|
||||
</allowedValueList>
|
||||
</stateVariable>
|
||||
</serviceStateTable>
|
||||
</scpd>
|
||||
31
internal/upnp/xml/ConnectionManager.xml
Normal file
31
internal/upnp/xml/ConnectionManager.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0"?>
|
||||
<scpd xmlns="urn:schemas-upnp-org:service-1-0">
|
||||
<specVersion><major>1</major><minor>0</minor></specVersion>
|
||||
<actionList>
|
||||
<action>
|
||||
<name>GetProtocolInfo</name>
|
||||
<argumentList>
|
||||
<argument>
|
||||
<name>Source</name>
|
||||
<direction>out</direction>
|
||||
<relatedStateVariable>SourceProtocolInfo</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>Sink</name>
|
||||
<direction>out</direction>
|
||||
<relatedStateVariable>SinkProtocolInfo</relatedStateVariable>
|
||||
</argument>
|
||||
</argumentList>
|
||||
</action>
|
||||
</actionList>
|
||||
<serviceStateTable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>SourceProtocolInfo</name>
|
||||
<dataType>string</dataType>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>SinkProtocolInfo</name>
|
||||
<dataType>string</dataType>
|
||||
</stateVariable>
|
||||
</serviceStateTable>
|
||||
</scpd>
|
||||
43
internal/upnp/xml/RenderingControl.xml
Normal file
43
internal/upnp/xml/RenderingControl.xml
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0"?>
|
||||
<scpd xmlns="urn:schemas-upnp-org:service-1-0">
|
||||
<specVersion><major>1</major><minor>0</minor></specVersion>
|
||||
<actionList>
|
||||
<action>
|
||||
<name>SetVolume</name>
|
||||
<argumentList>
|
||||
<argument>
|
||||
<name>InstanceID</name>
|
||||
<direction>in</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_InstanceID</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>Channel</name>
|
||||
<direction>in</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_Channel</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>DesiredVolume</name>
|
||||
<direction>in</direction>
|
||||
<relatedStateVariable>Volume</relatedStateVariable>
|
||||
</argument>
|
||||
</argumentList>
|
||||
</action>
|
||||
</actionList>
|
||||
<serviceStateTable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>A_ARG_TYPE_InstanceID</name>
|
||||
<dataType>ui4</dataType>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>A_ARG_TYPE_Channel</name>
|
||||
<dataType>string</dataType>
|
||||
<allowedValueList>
|
||||
<allowedValue>Master</allowedValue>
|
||||
</allowedValueList>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>Volume</name>
|
||||
<dataType>ui2</dataType>
|
||||
</stateVariable>
|
||||
</serviceStateTable>
|
||||
</scpd>
|
||||
Reference in New Issue
Block a user