gabrielmagno / crab-dlna

A minimal UPnP/DLNA media streamer written in Rust
Other
69 stars 4 forks source link

Can't assign requested address (os error 49) #5

Open trsdln opened 2 years ago

trsdln commented 2 years ago

This is great app. I really like the idea.

list function works as expected. However, while trying to play video I got this:

crab-dlna play "test_video.mkv"  -d "http://192.168.1.105:1135/"
 INFO  crab_dlna::cli > Selecting render
 INFO  crab_dlna::devices > Render specified by location: http://192.168.1.105:1135/
 INFO  crab_dlna::cli     > Building media streaming server
 ERROR crab_dlna          > Failed to connect to remote render '192.168.1.105:0': Can't assign requested address (os error 49)

It reproduces on both macOS (M1) and GNU Linux (x86_64). My TV runs WebOS.

gabrielmagno commented 2 years ago

Hi @trsdln! Thank you for the kind words :-)

I think I have figured out the problem. I've put a candidate fix in the bugfix/get_serve_ip_port branch of the repository.

You can install from the source like this:

cargo install --git https://github.com/gabrielmagno/crab-dlna --branch bugfix/get_serve_ip_port

Would you minding installing and testing this new version?

Thank you very much!

trsdln commented 2 years ago

Hi @gabrielmagno! Thanks for quick response. Your patch resolved this issue. Unfortunately, local-ip-address does not support macOS at this point. But, on Linux it passes through original failure point. Yesterday, I managed to get same result by hardcoding streaming server IP/port at code:

    Finished dev [unoptimized + debuginfo] target(s) in 0.09s
     Running `target/debug/crab-dlna -b play -n -d 'http://192.168.1.105:1135/' test.mkv`
 INFO  crab_dlna::cli > Selecting render
 INFO  crab_dlna::devices > Render specified by location: http://192.168.1.105:1135/
 DEBUG crab_dlna::devices > Selecting device by url: http://192.168.1.105:1135/
 DEBUG hyper::client::connect::http > connecting to 192.168.1.105:1135
 DEBUG hyper::client::connect::http > connected to 192.168.1.105:1135
 DEBUG hyper::proto::h1::io         > flushed 44 bytes
 DEBUG hyper::proto::h1::io         > parsed 6 headers
 DEBUG hyper::proto::h1::conn       > incoming body is content-length (3592 bytes)
 DEBUG hyper::proto::h1::conn       > incoming body completed
 DEBUG crab_dlna::devices           > Retrieving AVTransport service from device '[urn:schemas-upnp-org:device:MediaRenderer:1] [LG] webOS TV @ http://192.168.1.105:1135/'
 INFO  crab_dlna::cli               > Building media streaming server
 DEBUG crab_dlna::streaming         > Identifying local IP address of host
 DEBUG crab_dlna::streaming         > Streaming server address: 192.168.1.102:9000
 DEBUG crab_dlna::streaming         > Creating video file route in streaming server
 DEBUG crab_dlna::streaming         > Creating subtitle file route in streaming server
 DEBUG crab_dlna::dlna              > Subtitle payload: ''
 DEBUG crab_dlna::dlna              > SetAVTransportURI payload: '
        <InstanceID>0</InstanceID>
        <CurrentURI>http://192.168.1.102:9000/test.mkv</CurrentURI>
        <CurrentURIMetaData></CurrentURIMetaData>
        '
 INFO  crab_dlna::dlna              > Starting media streaming server...
 INFO  crab_dlna::dlna              > Setting Video URI
 INFO  crab_dlna::streaming         > Video file: test.mkv
 DEBUG crab_dlna::streaming         > Serving video file: 'test.mkv' @  http://192.168.1.102:9000/test.mkv
 INFO  crab_dlna::streaming         > No subtitle file
 DEBUG hyper::client::connect::http > connecting to 192.168.1.105:1135
 INFO  warp::server                 > Server::run; addr=192.168.1.102:9000
 INFO  warp::server                 > listening on http://192.168.1.102:9000
 DEBUG hyper::client::connect::http > connected to 192.168.1.105:1135
 DEBUG hyper::proto::h1::io         > flushed 798 bytes
 DEBUG hyper::proto::h1::io         > parsed 7 headers
 DEBUG hyper::proto::h1::conn       > incoming body is content-length (442 bytes)
 DEBUG hyper::proto::h1::conn       > incoming body completed
 ERROR crab_dlna                    > Failed to set AVTransportURI: The control point responded with status code 500 Internal Server Error

I was wondering if there is a way to get more info from TV's AVTransportURI error response.

gabrielmagno commented 2 years ago

Hey @trsdln. Thanks for following this up with me.

Oh, that is too bad that local-ip-address does not work for macOS. I tought it would work because in the library description they state support for "Linux, macOS and Windows". What does it happen when you run it in macOS? Does it simply not play the video like before, or does it give some different error?

Regarding the streaming server IP, you don't need to edit in the code, you could specify it with the -H parameter:

crab-dlna -b play -n -d 'http://192.168.1.105:1135/' -H '192.168.1.102' test.mkv

Now, coming back to the SetAVTransportURI error, I've put an update to (hopefully) give us more information about the error. Could you reinstall and test it again? It should now show a message like:

 DEBUG rupnp::utils > Unexpected response [...]
trsdln commented 2 years ago

@gabrielmagno

Yes, I'm getting this message:

 DEBUG hyper::client::connect::http > connecting to 192.168.1.105:1135
 DEBUG hyper::client::connect::http > connected to 192.168.1.105:1135
 DEBUG hyper::proto::h1::io         > flushed 798 bytes
 DEBUG hyper::proto::h1::io         > parsed 3 headers
 DEBUG hyper::proto::h1::conn       > incoming body is empty
 DEBUG warp::filter::service        > rejected: Rejection(MethodNotAllowed)
 DEBUG hyper::proto::h1::io         > flushed 133 bytes
 DEBUG hyper::proto::h1::io         > parsed 7 headers
 DEBUG hyper::proto::h1::conn       > incoming body is content-length (442 bytes)
 DEBUG hyper::proto::h1::conn       > incoming body completed
 DEBUG rupnp::utils                 > Unexpected response [status=500 Internal Server Error]: Body(Streaming)
 ERROR crab_dlna                    > Failed to set AVTransportURI: The control point responded with status code 500 Internal Server Error
trsdln commented 2 years ago

What does it happen when you run it in macOS? Does it simply not play the video like before, or does it give some different error?

Doesn't look like this issue is platform related. I'm getting same 500 Error on both Linux and macOS.

Notes on local-ip-address on macOS:

Regarding the streaming server IP, you don't need to edit in the code, you could specify it with the -H parameter:

    async fn build_media_streaming_server(&self) -> Result<MediaStreamingServer> {
        info!("Building media streaming server");
        let local_ip;
        let host_ip = match self.host.as_ref() {
            Some(x) => x,
            None => {
                local_ip = get_local_ip().await?;
                &local_ip
            }
        };
// ....
gabrielmagno commented 2 years ago

@trsdln

  • I wasn't able to figure out why it produces "The current platform: macos, is not suppported". I suppose there is problem crate's maintainer is not aware of yet.

Ok! I'm affraid I will not be able to fix it right now, but after we figure out the other problem, I will try to look into the local-ip-address crate code, or maybe find another solution.

  • Specifying -H flag doesn't fix problem, because get_local_ip() is being called before -H is evaluated. I modified it a bit (I barely know Rust, so probably there is better way):

You are right, I will change this behaviour for the next release.

For now, I'have mad some other changes in our test branch. Could you update it, run, and share the debug log again?

Thanks!

trsdln commented 2 years ago

@gabrielmagno Sure. Here you go:

 DEBUG rupnp::service               > Action server response: <?xml version="1.0" encoding="UTF-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><s:Fault><faultcode>s:Client</faultcode><faultstring>UPnPError</faultstring><detail><UPnPError xmlns="urn:schemas-upnp-org:control-1-0"><errorCode>716</errorCode><errorDescription>Resource not found</errorDescription></UPnPError></detail></s:Fault></s:Body></s:Envelope>
 ERROR crab_dlna                    > Failed to set AVTransportURI: UPnPError 716: Action-specific error defined by UPnP Forum working committee.

(I posted only new part. The rest of logs are unchanged)

gabrielmagno commented 2 years ago

@trsdln

Not sure if that is really the case (probably not), but your render device is stating that it does not support SetAVTransportURI. It is weird, because if it doesn't it shouldn't appear on the list function, because supposedly we filter to show only devices that supports it. Anyhow, let's investigate it.

When you run crab-dlna list does it show other entries from the same device/IP?

Would you mind sharing the content of http://192.168.1.105:1135/? I'm expecting a XML output from it, listing the device characteristics.

Also, could you try playing the video using nano-dlna (my older Python version of crab-dlna): https://github.com/gabrielmagno/nano-dlna ?

Thanks

trsdln commented 2 years ago

@gabrielmagno

your render device is stating that it does not support SetAVTransportURI

Log says UPnPError 716 which means

The specified resource cannot be found in the network.

per http://upnp.org/specs/av/UPnP-av-AVTransport-v3-Service.pdf (page 53). Maybe streaming server is not running at the time of SetAVTransportURI request call? I'm happy to verify it from another device if you add 1+ minute delay between start of streaming server and SetAVTransportURI call.

When you run crab-dlna list does it show other entries from the same device/IP?

[urn:schemas-upnp-org:device:MediaRenderer:1][urn:schemas-upnp-org:service:AVTransport:1] [LG] webOS TV OLED48A16LA @ http://192.168.1.105:1135/
[urn:schemas-upnp-org:device:MediaRenderer:1][urn:schemas-upnp-org:service:AVTransport:1] [LG] webOS TV OLED48A16LA @ http://192.168.1.105:1135/

Would you mind sharing the content of http://192.168.1.105:1135/? I'm expecting a XML output from it, listing the device characteristics.

response.xml ```xml 1 0 urn:schemas-upnp-org:device:MediaRenderer:1 [LG] webOS TV OLED48A16LA LG Electronics. http://www.lge.com LG WebOSTV DMRplus LG TV 1.0 uuid:dbf55052-6277-864f-1d0e-4ae37e5efe1d MS_DigitalMediaDeviceClass_DMR_V001 MediaDevices Multimedia.DMR LG Digital Media Renderer TV 1.0 DMR-1.50 image/jpeg 48 48 24 /dmrIcon_48.jpeg image/jpeg 120 120 24 /dmrIcon_120.jpeg image/png 48 48 24 /dmrIcon_48.png image/png 120 120 8 /dmrIcon_120.png urn:schemas-upnp-org:service:AVTransport:1 urn:upnp-org:serviceId:AVTransport /AVTransport/dbf55052-6277-864f-1d0e-4ae37e5efe1d/scpd.xml /AVTransport/dbf55052-6277-864f-1d0e-4ae37e5efe1d/control.xml /AVTransport/dbf55052-6277-864f-1d0e-4ae37e5efe1d/event.xml urn:schemas-upnp-org:service:ConnectionManager:1 urn:upnp-org:serviceId:ConnectionManager /ConnectionManager/dbf55052-6277-864f-1d0e-4ae37e5efe1d/scpd.xml /ConnectionManager/dbf55052-6277-864f-1d0e-4ae37e5efe1d/control.xml /ConnectionManager/dbf55052-6277-864f-1d0e-4ae37e5efe1d/event.xml urn:schemas-upnp-org:service:RenderingControl:1 urn:upnp-org:serviceId:RenderingControl /RenderingControl/dbf55052-6277-864f-1d0e-4ae37e5efe1d/scpd.xml /RenderingControl/dbf55052-6277-864f-1d0e-4ae37e5efe1d/control.xml /RenderingControl/dbf55052-6277-864f-1d0e-4ae37e5efe1d/event.xml ```

Re. https://github.com/gabrielmagno/nano-dlna: I already tried it before filing this issue. It didn't work as well, but with different kind of error. I will give it another try if this troubleshooting fails.

Thank you!

gabrielmagno commented 2 years ago

@trsdln could you test something for us?

Turn on your TV, open a terminal in your PC, and then run this curl command (you don't have to have crab-dlna running):

curl -v --location --request POST 'http://192.168.1.105:1135/AVTransport/dbf55052-6277-864f-1d0e-4ae37e5efe1d/control.xml' \
--header 'CONTENT-TYPE: text/xml; charset="utf-8"' \
--header 'SOAPAction: "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI"' \
--data-raw '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
                s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <s:Body>
        <u:SetAVTransportURI xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
            <InstanceID>0</InstanceID>
            <CurrentURI>http://192.168.1.102:9000/test.mkv</CurrentURI>
            <CurrentURIMetaData></CurrentURIMetaData>
        </u:SetAVTransportURI>
    </s:Body>
</s:Envelope>'

Then post the full result/response of the command here.

trsdln commented 2 years ago

@gabrielmagno

here you go:

Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 192.168.1.105:1135...
* Connected to 192.168.1.105 (192.168.1.105) port 1135 (#0)
> POST /AVTransport/dbf55052-6277-864f-1d0e-4ae37e5efe1d/control.xml HTTP/1.1
> Host: 192.168.1.105:1135
> User-Agent: curl/7.79.1
> Accept: */*
> CONTENT-TYPE: text/xml; charset="utf-8"
> SOAPAction: "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI"
> Content-Length: 460
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 500 Internal Server Error
< DLNADeviceName.lge.com: %5bLG%5d%20webOS%20TV%20OLED48A16LA
< Ext:
< Date: Wed, 10 Aug 2022 16:57:45 GMT
< Server: Linux/i686 UPnP/1,0 DLNADOC/1.50 LGE WebOS TV/Version 0.9
< Content-Length: 442
< Content-Type: text/xml; charset="utf-8"
< Connection: close
<
<?xml version="1.0" encoding="UTF-8"?>
* Closing connection 0
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><s:Fault><faultcode>s:Client</faultcode><faultstring>UPnPError</faultstring><detail><UPnPError xmlns="urn:schemas-upnp-org:control-1-0"><errorCode>716</errorCode><errorDescription>Resource not found</errorDescription></UPnPError></detail></s:Fault></s:Body></s:Envelope>%
trsdln commented 2 years ago

just for fun I hosted video at separate server and ran similar request:

< HTTP/1.1 200 OK
< DLNADeviceName.lge.com: %5bLG%5d%20webOS%20TV%20OLED48A16LA
< Ext:
< Date: Wed, 10 Aug 2022 17:34:52 GMT
< Server: Linux/i686 UPnP/1,0 DLNADOC/1.50 LGE WebOS TV/Version 0.9
< Content-Length: 277
< Content-Type: text/xml; charset="utf-8"
< Connection: close
<
<?xml version="1.0" encoding="UTF-8"?>
* Closing connection 0
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><u:SetAVTransportURIResponse xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"/></s:Body></s:Envelope>%

Looks like streaming server is indeed non running while calling SetAVTransportURI.

gabrielmagno commented 2 years ago

@trsdln I think I figured out what is happening.

To play a video we actually have to do two DLNA commands: SetAVTransportURI and Play. The former only specify where to read the files. The second actually plays the file. My hyphotesis is that your TV is making a check right after we send the SetAVTransportURI. It happens that crab-dlna only starts actually serving the files after sending the commands.

It will not be so trivial because it will probably envolve handling async and threads. But I will think about how to handle this in code and come back to you soon.

gabrielmagno commented 2 years ago

@trsdln actually I've checked, and the server is already not blocking and is being spawned to run in a thread.

My hypothesis now is that the SetAVTransportURI is sent before warp is finished creating the server.

I added a explicit wait time now before sending the setavtransport URI. Let's see how it goes.

Could you test again from the same branch?

Thank you!

trsdln commented 2 years ago

@gabrielmagno I can confirm that streaming server is running properly before and after SetAVTransportURI call. However, my TV still responds with Error 716. Also, I tested whether I can download video from another laptop to exclude potential firewall issues - everything works fine as far as curl/browser are concerned.

Here's response headers comparison between successful and failed AVTransportURIs (as TV presumably receives it):

Gerbera (used here https://github.com/gabrielmagno/crab-dlna/issues/5#issuecomment-1211037975)

< HTTP/1.1 200 OK
< CONTENT-LENGTH: 219623563
< Accept-Ranges: bytes
< CONTENT-TYPE: video/mp4
< DATE: Thu, 11 Aug 2022 12:30:18 GMT
< LAST-MODIFIED: Sun, 05 Jun 2022 11:07:02 GMT
< SERVER: Darwin/21.6.0, UPnP/1.0, Portable SDK for UPnP devices/1.14.13
< X-User-Agent: redsonic
< contentFeatures.dlna.org: DLNA.ORG_PN=AVC_MP4_EU;DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01700000000000000000000000000000
< transferMode.dlna.org: Streaming
< CONNECTION: close
<
{ [102400 bytes data]
* Closing connection 0

crab-dlna

< HTTP/1.1 200 OK
< content-length: 219623563
< content-type: video/mp4
< accept-ranges: bytes
< last-modified: Tue, 09 Aug 2022 16:50:05 GMT
< date: Thu, 11 Aug 2022 12:41:35 GMT
<
{ [8192 bytes data]
* Connection #0 to host 192.168.1.100 left intact

Not sure if extra headers matter in this case though. So, at this point I'm out of ideas how to troubleshoot it.

UPDATE:

I suspect TV is doing unexpected requests to streaming server. Not sure what this line means:

 DEBUG warp::filter::service        > rejected: Rejection(MethodNotAllowed)

but it appears only after SetAVTransportURI. While doing regular download via browser it doesn't come up.

gabrielmagno commented 2 years ago

@trsdln

You mentioned that you could serve the media file using a separate server, right?

Let's do like we did before, but changing the CurrentURI to the actual path of the video file in your separate server.

First, do the SetAVTransportURI

curl -v --location --request POST 'http://192.168.1.105:1135/AVTransport/dbf55052-6277-864f-1d0e-4ae37e5efe1d/control.xml' \
--header 'CONTENT-TYPE: text/xml; charset="utf-8"' \
--header 'SOAPAction: "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI"' \
--data-raw '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
                s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <s:Body>
        <u:SetAVTransportURI xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
            <InstanceID>0</InstanceID>
            <CurrentURI>http://SERVER_HOST:SERVER_PORT/PATH_FILE.mp4</CurrentURI>
            <CurrentURIMetaData></CurrentURIMetaData>
        </u:SetAVTransportURI>
    </s:Body>
</s:Envelope>'

Not sure if I got it wrong, but when you do that you get a 200 response, right? Or does it still results in a 500 internal server error?

If a 200 response is returned, then do a Play request:

curl --location --request POST 'http://192.168.1.105:1135/AVTransport/dbf55052-6277-864f-1d0e-4ae37e5efe1d/control.xml' \
--header 'CONTENT-TYPE: text/xml; charset="utf-8"' \
--header 'SOAPAction: "urn:schemas-upnp-org:service:AVTransport:1#Play"' \
--data-raw ' <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
                s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <s:Body>
        <u:Play xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
            <InstanceID>0</InstanceID>
            <Speed>1</Speed>
        </u:Play>
    </s:Body>
</s:Envelope>'
trsdln commented 2 years ago

@gabrielmagno My TV doesn't cooperate.

SetAVTransportURI was successful:

> POST /AVTransport/dbf55052-6277-864f-1d0e-4ae37e5efe1d/control.xml HTTP/1.1
> Host: 192.168.1.105:1503
> User-Agent: curl/7.79.1
> Accept: */*
> CONTENT-TYPE: text/xml; charset="utf-8"
> SOAPAction: "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI"
> Content-Length: 489
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< DLNADeviceName.lge.com: %5bLG%5d%20webOS%20TV%20OLED48A16LA
< Ext:
< Date: Sun, 14 Aug 2022 07:26:16 GMT
< Server: Linux/i686 UPnP/1,0 DLNADOC/1.50 LGE WebOS TV/Version 0.9
< Content-Length: 277
< Content-Type: text/xml; charset="utf-8"
< Connection: close
<
<?xml version="1.0" encoding="UTF-8"?>
* Closing connection 0
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><u:SetAVTransportURIResponse xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"/></s:Body></s:Envelope>

But Play action failed:

<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><s:Fault><faultcode>s:Client</faultcode><faultstring>UPnPError</faultstring><detail><UPnPError xmlns="urn:schemas-upnp-org:control-1-0"><errorCode>501</errorCode><errorDescription>Action Failed</errorDescription></UPnPError></detail></s:Fault></s:Body></s:Envelope>%

After that I wanted to retry first and second request, but in both cases I'm getting this error:

< HTTP/1.1 500 Internal Server Error
< DLNADeviceName.lge.com: %5bLG%5d%20webOS%20TV%20OLED48A16LA
< Ext:
< Date: Sun, 14 Aug 2022 07:34:02 GMT
< Server: Linux/i686 UPnP/1,0 DLNADOC/1.50 LGE WebOS TV/Version 0.9
< Content-Length: 448
< Content-Type: text/xml; charset="utf-8"
< Connection: close
<
<?xml version="1.0" encoding="UTF-8"?>
* Closing connection 0
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><s:Fault><faultcode>s:Client</faultcode><faultstring>UPnPError</faultstring><detail><UPnPError xmlns="urn:schemas-upnp-org:control-1-0"><errorCode>701</errorCode><errorDescription>Transition not available</errorDescription></UPnPError></detail></s:Fault></s:Body></s:Envelope>%
gabrielmagno commented 2 years ago

@trsdln Thanks for new tests.

Your TV's behaviour is weird, but I would not put the blame totally on it. There could still be something that I'm missing about UPnP and DLNA.

Well, my last suggestion would be to try another DLNA application to stream content to your TV. The best DLNA implementation that I know (that implements the "AV Transport" DLNA function is the Android BubbleUPnP app. This is just a suggestion, there are other software that you could also try.

trsdln commented 2 years ago

@gabrielmagno Thank you. BubbleUPnP works flawlessly.