jellyfin / jellyfin-androidtv

Android TV Client for Jellyfin
https://jellyfin.org
GNU General Public License v2.0
2.92k stars 495 forks source link

Android TV app will not connect if HTTPS is enabled on the server #2493

Closed iampegram closed 4 months ago

iampegram commented 1 year ago

Describe the bug

  1. Enable HTTPS on server (certificate is provided)
  2. Attempt to connect on Android TV via auto discovered server

    Failed

  3. Attempt to manually enter server domain name or IP address on Android TV

    Failed

  4. Connect from any other client on my network

    Succeed

  5. Disable HTTPS on server
  6. Attempt to connect on Android TV via auto discovered server

    Succeed

Logs

No response

Application version

0.15.3

Where did you install the app from?

Google Play

Device information

Google Chromecast with Google TV (4K and HD)

Android version

Android 12

Jellyfin server version

10.8.8

itslukebtw commented 1 year ago

Experiencing the same issue

yusanxing commented 1 year ago

Experiencing the same issue

DavidFair commented 1 year ago

We really need the logs from logcat to be able to tell what's going on, otherwise we're just blindly guessing here.

Some simple checks you can do to verify if it is the app or your setup:

If any of these steps fail it's likely your setup, this is something you'll have to ask for support for the community with outside of this issue, as it's out of scope for us.

If you can do all of these it likely points to the app and we'd need the logs to look into it for you.

onedr0p commented 1 year ago

The Android TV app refuses to connect to my local only instance of Jellyfin via a domain. It works fine when connecting to the http://<IP>:8096

I have confirmed that:

I have also tried forcing DNS on everything in my network to use my local DNS server, yet jellyfin refuses to connect via my local-only domain.

jzazo commented 1 year ago

Hi! I am experiencing the same problem, cannot connect with AndroidTV with https connection. It works on my phone, and it works on AndroidTV with http.

I am using Let's encrypt certificates, provided automatically by Tailscale. I built my pk12 with: openssl pkcs12 -export -out $p12 -in $certificate.crt -inkey $key.key -passout pass:

I don't know if I am missing intermediate or root certificates, as these posts seem to suggest: 1, 2.

I don't know how to incorporate them. I tried the following, without success:

wget https://letsencrypt.org/certs/lets-encrypt-r3.pem
openssl pkcs12 -export -out $p12 -in $certificate.crt -inkey $key.key -certfile lets-encrypt-r3.pem -passout pass:
chmod 777 pkcs12

The pk12 was still working in my browser, but it still didn't work on my AndroidTV.

Do you think the intermediate certificates might be the root issue? Any chance this type of support could be addressed by the app? I couldn't get any logs, none of the attempts to try to connect created any logs, can you advice me on how to get them?

Thanks.

jzazo commented 1 year ago

Ok, I think I have realized the root problem. Trying from my phone app, I could connect to the server via https if I connected using the correct domain address. On the contrary, the connection would be rejected if I used local IP address instead. This makes sense, the certificate is valid for the domain, not the IP.

However, I wonder if the clients could still make a secure connection via https even if the certificate cannot be validated. Does this make sense? Like when Firefox issues a warning about making an exception to connect. Do you think supporting that feature would be a nice feature to have? Thanks!

ModestTG commented 1 year ago

I am also having this issue. I cannot get my Android TV instances to connect to Jellyfin in any capacity. I have a wildcard cert using LetsEncrypt and the server is running in K8S. I can connect to the HTTPS endpoint using Google TV dongle, but not the Nvidia Shields. No idea what's going on.

onedr0p commented 1 year ago

@DavidFair can you try to replicate this issue on your end? I bet if you tried you would spot the problem. I guess you don't use the JF app and connect to a domain over HTTPS?

DavidFair commented 1 year ago

I am using Let's encrypt certificates, provided automatically by Tailscale. I built my pk12 with: openssl pkcs12 -export -out $p12 -in $certificate.crt -inkey $key.key -passout pass:

You shouldn't need to build export the certificate by hand, Tailscale should just do the correct thing using the DNS challenge. This means if the cert is about to expire / is revoked ....etc. it will sort itself out.

Also your command looks suspect, assuming Caddy it should be a .PEM file. In that case it's simply opening both files and copying everything from the intermediate LE certificate and your issued one into the same file

However, I wonder if the clients could still make a secure connection via https even if the certificate cannot be validated.

I don't have any involvement with the project, but IMO it's not the way to go. The problem is people will reach for the skip validation option by default instead of solving the underlying problem. If you then have a MITM, (e.g. someone goes to a hotel and try to log into their instance over public wifi) the certificate error is just suppressed as that's what you asked for, and now they potentially have your password too...

@DavidFair can you try to replicate this issue on your end? I bet if you tried you would spot the problem. I guess you don't use the JF app and connect to a domain over HTTPS?

You have to use the domain over HTTPS, there's no way not to. I have a publicly registered domain and a wildcard certificate to connect in so I know it's working with the Nvidia Shield. I use Traefik personally but (IIRC) they all use certbot to handle the certificates anyway so it should work.


For the last few people who've asked how to diagnose this, I'll give some pointers for my go-to diagnostic tool but I'm trying to not fall afoul of providing support in issues:

I would use curl as a diagnostic tool, it will show if something is up with your certificate or setup and acts as my source of truth for these sort of problems.

If your on Linux/*BSD it's almost certainly installed by default, otherwise you can grab the 64-bit binary from the project. Ensure you're on the same network as the device your connecting (e.g. use a wi-fi hotspot if it's external), then run in a terminal/command prompt:

curl -v https://example.com Where you put the domain name you're trying to use instead of example.com. This should match what your putting into Android, including the port if you're using one. If you need to use an IP or a different name locally to test then your problem is likely DNS records and you need to get that sorted too.

The interesting part is the first lines of the output, you can see for example.com we negotiate and validate the certificate:

*   Trying 2606:2800:220:1:248:1893:25c8:1946:443...
* Connected to example.com (2606:2800:220:1:248:1893:25c8:1946) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.0 (OUT), TLS header, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (OUT), TLS header, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS header, Finished (20):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: C=US; ST=California; L=Los Angeles; O=Internet�Corporation�for�Assigned�Names�and�Numbers; CN=www.example.org
*  start date: Jan 13 00:00:00 2023 GMT
*  expire date: Feb 13 23:59:59 2024 GMT
*  subjectAltName: host "example.com" matched cert's "example.com"
*  issuer: C=US; O=DigiCert Inc; CN=DigiCert TLS RSA SHA256 2020 CA1
*  SSL certificate verify ok.

If you're not seeing the SSL certificate verify ok. it's a problem with the setup HTTPS endpoint and you'll need to go and fix that based on what output curl is giving. There will almost certainly be someone else online with the same error message and a solution if you search around.

If it's not working, I would also start small and build the security in layers too. Get TLS working with the curl test for just Caddy on it's own by installing another copy of the Jellyfin server, and expose that to the internet (with no media if you're paranoid) and check if you can login using this app. Once that's working add in things like WireGuard/Tailscale to the server with no media. Finally, switch to your real machine. The scientific approach will help uncover where you might have multiple problems in your setup hiding together.

If you see verify ok and the app is still falling over then it's definitely the app, and that is something that would be worth looking into with logs.

onedr0p commented 1 year ago

You have to use the domain over HTTPS, there's no way not to. I have a publicly registered domain and a wildcard certificate to connect in so I know it's working with the Nvidia Shield. I use Traefik personally but (IIRC) they all use certbot to handle the certificates anyway so it should work.

With what I mentioned here... https://github.com/jellyfin/jellyfin-androidtv/issues/2493#issuecomment-1457426406 Are you doing any sort or split DNS or tried a internal only domain? I feel like that has to be part of the issue. My jellyfin subdomain is only accessible on my internal network and dns server and does not resolve on a public DNS (e.g. 1.1.1.1)

Maybe you can build in better error messages when it can't connect that could help pin point the issue?

DavidFair commented 1 year ago

With what I mentioned here... #2493 (comment) Are you doing any sort or split DNS or tried a internal only domain? I feel like that has to be part of the issue. My jellyfin subdomain is only accessible on my internal network and dns server and does not resolve on a public DNS (e.g. 1.1.1.1)

With this issue I'm assuming most people are using ACME challenges for automatic certificates. Does your certificate include the internal DNS name you would use? The common name (CN) or subject alternate name (SAN) needs to contain the internal domain you are using for it to be valid. Sorry if this is obvious, but it's always worth mentioning.

You can do it, but AFAIK you need to go down either the wildcard DNS ACME challenge or paid certificate route and still own the public domain name even if you don't publish public DNS records. Personally I just add the records to public records as a wildcard CNAME instead: someone with the IP could still route to your machine if the firewall is open by manually adding the DNS record to their hosts file (I've seen a friend get burnt by this in the past). Additionally, this avoids you explicitly saying what you are running at that service point too:

My records look like: CNAME: *.example.com -> traefik.example.com A + AAAA records: traefik.example.com

If you're paranoid about leaking names and you want multiple services, buy a dedicated domain for JF since they can be purchased cheap and it's what you value your time at....

This can then be either a firewall or VPN endpoint (mine is Firewall + Traefik + Authelia) depending on how you want to isolate yourself from the wider network. It's perfectly valid to just have a deny all for everything but Wireguard to actually do the final routing, eliminating the problems with split-brain DNS and all the fun that brings.

Remember what I said, start small, keep it simple then build up your security layer by layer, especially if you've not deployed a similar network layout before. Also if it's internal network only I would completely strip out the TLS, put the server on a static internal IP and just go by IP and port direct to the machine.

Maybe you can build in better error messages when it can't connect that could help pin point the issue?

It should give the exceptions in the logs. Ultimately, this isn't really the apps responsibility since we're talking about opening and securing a public web server in-effect. This is the downside of self-hosting and one of the main reasons (IMO) people go with other "media streaming" platforms, where they give up privacy for convenience. If we could give hints it would turn into a web server audit tool effectively. IMO, the best you can do is give a error message if a lot of people keep falling into the same mistake.

This is one where I think the documentation on the JF server should be linked and improve it there if that's lacking. As these problems will affect all clients connecting to a misconfigured server, not just the Android TV.

onedr0p commented 1 year ago

Does your certificate include the internal DNS name you would use?

Yes it sure does, like I mentioned the Android mobile app and web app has no issues connecting to https://jellyfin.domain.tld when I am on my internal network, only the Android TV app has an issue when trying to use that domain.

curl

✖ curl -v https://jellyfin.domain.tld
* processing: https://jellyfin.domain.tld
*   Trying 192.168.42.200:443...
* Connected to jellyfin.domain.tld (192.168.42.200) port 443
* ALPN: offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=domain.tld
*  start date: Jul 13 23:55:23 2023 GMT
*  expire date: Oct 11 23:55:22 2023 GMT
*  subjectAltName: host "jellyfin.domain.tld" matched cert's "*.domain.tld"
*  issuer: C=US; O=Let's Encrypt; CN=R3
*  SSL certificate verify ok.
* using HTTP/2
* h2 [:method: GET]
* h2 [:scheme: https]
* h2 [:authority: jellyfin.domain.tld]
* h2 [:path: /]
* h2 [user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11.2; rv:86.0) Gecko/20100101 Firefox/86.0]
* h2 [accept: */*]
* Using Stream ID: 1
> GET / HTTP/2
> Host: jellyfin.domain.tld
> User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11.2; rv:86.0) Gecko/20100101 Firefox/86.0
> Accept: */*
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
< HTTP/2 302
< date: Sat, 09 Sep 2023 11:53:47 GMT
< content-length: 0
< location: /web/index.html
< strict-transport-security: max-age=31449600; includeSubDomains
<
* Connection #0 to host jellyfin.domain.tld left intact

dig

❯ dig jellyfin.domain.tld

; <<>> DiG 9.18.18 <<>> jellyfin.domain.tld
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 20105
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 58819993853258d80100000064fc5d0f6ca02c4fe62b533b (good)
;; QUESTION SECTION:
;jellyfin.domain.tld.       IN  A

;; ANSWER SECTION:
jellyfin.domain.tld.    0   IN  A   192.168.42.200

;; Query time: 3 msec
;; SERVER: 192.168.254.2#53(192.168.254.2) (UDP)
;; WHEN: Sat Sep 09 07:54:55 EDT 2023
;; MSG SIZE  rcvd: 90
lallinger commented 1 year ago

Awful hack, but working: On your public DNS set an A record pointing to your local jellyfin ip (e.g. 192.0.0.20). Seems like jellyfin on the shield somehow ignores the local DNS settings

onedr0p commented 1 year ago

That's hilarious and if it works pretty much confirms my problem.

nodje commented 1 year ago

Not sure it can be of help, but I stumble upon this thread for the same issue, after and android TV system upgrade Looking at the curl -v output just rang a bell.

I happened to turn on a TLS hardening on my front reverse proxy (traefik) just before the system upgrade:

[tls.options]
  [tls.options.default]
    minVersion = "VersionTLS13"

  [tls.options.tls12]
    minVersion = "VersionTLS12"
    cipherSuites = [
      "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
      "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
      "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
      "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
      "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
      "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305"
    ]

It doesn't seem very extreme to me but Android TV just didn't like it. Deactivating this hardening just made everything work again.

So maybe you could be looking at what your TLS protocol and ciphers your server can offer.

bazirico commented 11 months ago

No problem on any of my devices (iPhone, iPad, Macbook) from anywhere (browser and apps) except from my Xgimi Elfin projector running on AndroidTV 10.

My home services are accessed through a traefik reverse proxy, using letsencrypt certificates.

Awful hack, but working: On your public DNS set an A record pointing to your local jellyfin ip (e.g. 192.0.0.20). Seems like jellyfin on the shield somehow ignores the local DNS settings

Confirmed here : Adding the DNS A record jellyfin.domain.tld pointing to my local traefik IP works. Why ?

DNS servers for my clients are set by my DHCP server. Just to be sure I've enforced on AndroidTV static IP and set the DNS server manually to be sure it points to my local AdGuardHome DNS.

I don't think the problem is on the Jellyfin app side. I did another test accessing another local service using a browser from AndroidTV :

Without public DNS record :

IMG_4021

Adding public DNS record, waiting for propagation and refresh :

IMG_4022

It seems that some requests are still made to my registrar public DNS at least for certificate validation.

Don't know how this works to be honest. Again no problem on any of my other devices.

major-mayer commented 9 months ago

I also only experience problems on my Shield android TV app and the workaround of using the internal ip address works in my case.

penrose72 commented 5 months ago

I also had the same problem. And it seems as if the AndroidTV version does not support SNI protocol. So all https with virtualhost name-based don't work.

major-mayer commented 5 months ago

This would make sense because my jellyfin instance is of course also running on a server that hosts multiple services with different subdomains using a single ip address. But I can't believe that my shield from 2018/9 (?) is not supporting a protocol that which was first introduced in 1999 (as an optional extension to TLS). Do you have any reference for that?

penrose72 commented 4 months ago

This would make sense because my jellyfin instance is of course also running on a server that hosts multiple services with different subdomains using a single ip address. But I can't believe that my shield from 2018/9 (?) is not supporting a protocol that which was first introduced in 1999 (as an optional extension to TLS). Do you have any reference for that?

It's not a problem with Android TV, but with the version of Jellyfin for Android TV. If you use the web browser or the smartphone version of Jellyfin on Android TV, then everything works in https sni too.

bazirico commented 4 months ago

Ok, so what can we do here ? Migrate on Apple so things always works ? 😊

brianjmurrell commented 4 months ago

I have this problem also. It's something unique to trying to connect to the HTTPS port of a server found during autodiscovery. Connecting to the JF server with HTTPS from any other regular client, when using the hostname that is in the subject name of the certificate seems to work fine. Certificate validates, etc.

Looking at the logcat output, I suspect what is happening is that the autodiscovery connection mechanism is falling back to trying to connect with the IP address found during the autodiscovery instead of trying to use an FQDN. Here's what logcat says about it all:

07-30 18:56:57.195 32675  9058 I org.jellyfin.sdk.discovery.LocalServerDiscovery: Starting discovery with timeout of 500ms
07-30 18:56:57.196 32675  9058 D org.jellyfin.sdk.discovery.LocalServerDiscovery: Discovering via /255.255.255.255
07-30 18:56:57.196 32675  9058 D org.jellyfin.sdk.discovery.LocalServerDiscovery: Finished sending broadcast, listening for responses
07-30 18:56:57.196 32675  9058 D org.jellyfin.sdk.discovery.LocalServerDiscovery: Reading reply...
07-30 18:56:57.200 32675  9058 D org.jellyfin.sdk.discovery.LocalServerDiscovery: Received message "{"Address":"https://10.75.22.2:443","Id":"9be14d61c64b452eb0fe38a39d2022a8","Name":"videoserver.example.com","EndpointAddress":null}"
07-30 18:56:57.205 32675  9058 D org.jellyfin.sdk.discovery.LocalServerDiscovery: Reading reply...
07-30 18:56:57.706 32675  9058 D org.jellyfin.sdk.discovery.LocalServerDiscovery: Reading reply...
07-30 18:56:58.207 32675  9058 D org.jellyfin.sdk.discovery.LocalServerDiscovery: Reading reply...
07-30 18:56:58.708 32675  9058 D org.jellyfin.sdk.discovery.LocalServerDiscovery: Reading reply...
07-30 18:56:59.209 32675  9058 D org.jellyfin.sdk.discovery.LocalServerDiscovery: Reading reply...
07-30 18:56:59.710 32675  9058 D org.jellyfin.sdk.discovery.LocalServerDiscovery: Reading reply...
07-30 18:57:00.211 32675  9058 D org.jellyfin.sdk.discovery.LocalServerDiscovery: Reading reply...
07-30 18:57:00.712 32675  9058 D org.jellyfin.sdk.discovery.LocalServerDiscovery: Reading reply...
07-30 18:57:01.213 32675  9058 D org.jellyfin.sdk.discovery.LocalServerDiscovery: Reading reply...
07-30 18:57:01.714 32675  9058 D org.jellyfin.sdk.discovery.LocalServerDiscovery: Reading reply...
07-30 18:57:02.215 32675  9058 D org.jellyfin.sdk.discovery.LocalServerDiscovery: Reading reply...
07-30 18:57:02.715 32675  9058 D org.jellyfin.sdk.discovery.LocalServerDiscovery: Reading reply...
07-30 18:57:03.216 32675  9058 D org.jellyfin.sdk.discovery.LocalServerDiscovery: Reading reply...
07-30 18:57:03.717 32675  9058 D org.jellyfin.sdk.discovery.LocalServerDiscovery: Reading reply...
07-30 18:57:04.219 32675  9058 D org.jellyfin.sdk.discovery.LocalServerDiscovery: End
07-30 18:57:12.984 32675 32675 D org.jellyfin.sdk.discovery.AddressCandidateHelper: Input is https://10.75.22.2:443
07-30 18:57:12.984 32675 32675 D org.jellyfin.sdk.discovery.AddressCandidateHelper: Adding common candidates
07-30 18:57:12.984 32675 32675 D org.jellyfin.sdk.discovery.AddressCandidateHelper: Adding protocol candidates
07-30 18:57:12.984 32675 32675 D org.jellyfin.sdk.discovery.AddressCandidateHelper: Adding port candidates
07-30 18:57:12.986 32675  5354 I org.jellyfin.sdk.discovery.RecommendedServerDiscovery: Requesting public system info for https://10.75.22.2:8096
07-30 18:57:12.989 32675   803 I org.jellyfin.sdk.discovery.RecommendedServerDiscovery: Requesting public system info for https://10.75.22.2:8920
07-30 18:57:12.989 32675  8958 I org.jellyfin.sdk.discovery.RecommendedServerDiscovery: Requesting public system info for https://10.75.22.2:443
07-30 18:57:12.990 32675  8958 I org.jellyfin.sdk.api.client.KtorClient: GET https://10.75.22.2/System/Info/Public
07-30 18:57:12.990 32675  5354 I org.jellyfin.sdk.api.client.KtorClient: GET https://10.75.22.2:8096/System/Info/Public
07-30 18:57:12.997 32675   803 I org.jellyfin.sdk.api.client.KtorClient: GET https://10.75.22.2:8920/System/Info/Public
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient: Connection failed
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient: java.net.ConnectException: Failed to connect to /10.75.22.2:8096
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.kt:297)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:207)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:226)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:74)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:255)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:517)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at java.lang.Thread.run(Thread.java:920)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient: Caused by: java.net.ConnectException: failed to connect to /10.75.22.2 (port 8096) from /10.75.22.183 (port 57282) after 3500ms: isConnected failed: ECONNREFUSED (Connection refused)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at libcore.io.IoBridge.isConnected(IoBridge.java:349)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at libcore.io.IoBridge.connectErrno(IoBridge.java:238)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at libcore.io.IoBridge.connect(IoBridge.java:180)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:142)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:390)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:230)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:212)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:436)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at java.net.Socket.connect(Socket.java:621)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.platform.Platform.connectSocket(Platform.kt:128)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.kt:295)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    ... 18 more
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient: Caused by: android.system.ErrnoException: isConnected failed: ECONNREFUSED (Connection refused)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    at libcore.io.IoBridge.isConnected(IoBridge.java:336)
07-30 18:57:13.022 32675  9111 D org.jellyfin.sdk.api.client.KtorClient:    ... 28 more
07-30 18:57:13.029 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery: Could not connect to https://10.75.22.2:8096
07-30 18:57:13.029 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery: org.jellyfin.sdk.api.client.exception.TimeoutException: Connection failed
07-30 18:57:13.029 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at org.jellyfin.sdk.api.client.KtorClient.request$suspendImpl(KtorClient.kt:126)
07-30 18:57:13.029 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at org.jellyfin.sdk.api.client.KtorClient$request$1.invokeSuspend(Unknown Source:19)
07-30 18:57:13.029 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
07-30 18:57:13.029 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:194)
07-30 18:57:13.029 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith(SuspendFunctionGun.kt:15)
07-30 18:57:13.029 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:89)
07-30 18:57:13.029 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
07-30 18:57:13.029 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:194)
07-30 18:57:13.030 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith(SuspendFunctionGun.kt:15)
07-30 18:57:13.030 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:89)
07-30 18:57:13.030 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
07-30 18:57:13.030 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:194)
07-30 18:57:13.030 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith(SuspendFunctionGun.kt:15)
07-30 18:57:13.030 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:89)
07-30 18:57:13.030 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
07-30 18:57:13.030 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:194)
07-30 18:57:13.030 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith(SuspendFunctionGun.kt:15)
07-30 18:57:13.030 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:89)
07-30 18:57:13.030 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
07-30 18:57:13.030 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
07-30 18:57:13.030 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
07-30 18:57:13.030 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:103)
07-30 18:57:13.030 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
07-30 18:57:13.030 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient: Connection failed
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient: java.net.ConnectException: Failed to connect to /10.75.22.2:8920
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.kt:297)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:207)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:226)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:74)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:255)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:517)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at java.lang.Thread.run(Thread.java:920)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient: Caused by: java.net.ConnectException: failed to connect to /10.75.22.2 (port 8920) from /10.75.22.183 (port 38010) after 3500ms: isConnected failed: ECONNREFUSED (Connection refused)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at libcore.io.IoBridge.isConnected(IoBridge.java:349)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at libcore.io.IoBridge.connectErrno(IoBridge.java:238)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at libcore.io.IoBridge.connect(IoBridge.java:180)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:142)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:390)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:230)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:212)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:436)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at java.net.Socket.connect(Socket.java:621)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.platform.Platform.connectSocket(Platform.kt:128)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.kt:295)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    ... 18 more
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient: Caused by: android.system.ErrnoException: isConnected failed: ECONNREFUSED (Connection refused)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    at libcore.io.IoBridge.isConnected(IoBridge.java:336)
07-30 18:57:13.034 32675  8958 D org.jellyfin.sdk.api.client.KtorClient:    ... 28 more
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery: Could not connect to https://10.75.22.2:8920
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery: org.jellyfin.sdk.api.client.exception.TimeoutException: Connection failed
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at org.jellyfin.sdk.api.client.KtorClient.request$suspendImpl(KtorClient.kt:126)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at org.jellyfin.sdk.api.client.KtorClient$request$1.invokeSuspend(Unknown Source:19)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:194)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith(SuspendFunctionGun.kt:15)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:89)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:194)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith(SuspendFunctionGun.kt:15)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:89)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:194)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith(SuspendFunctionGun.kt:15)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:89)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:194)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith(SuspendFunctionGun.kt:15)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:89)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:103)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery: Caused by: java.net.ConnectException: Failed to connect to /10.75.22.2:8920
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.kt:297)
07-30 18:57:13.036 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:207)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:226)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:74)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:255)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:517)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at java.lang.Thread.run(Thread.java:920)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery: Caused by: java.net.ConnectException: failed to connect to /10.75.22.2 (port 8920) from /10.75.22.183 (port 38010) after 3500ms: isConnected failed: ECONNREFUSED (Connection refused)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at libcore.io.IoBridge.isConnected(IoBridge.java:349)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at libcore.io.IoBridge.connectErrno(IoBridge.java:238)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at libcore.io.IoBridge.connect(IoBridge.java:180)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:142)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:390)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:230)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:212)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:436)
07-30 18:57:13.037 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at java.net.Socket.connect(Socket.java:621)
07-30 18:57:13.039 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.platform.Platform.connectSocket(Platform.kt:128)
07-30 18:57:13.039 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.kt:295)
07-30 18:57:13.039 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     ... 18 more
07-30 18:57:13.039 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery: Caused by: android.system.ErrnoException: isConnected failed: ECONNREFUSED (Connection refused)
07-30 18:57:13.039 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at libcore.io.IoBridge.isConnected(IoBridge.java:336)
07-30 18:57:13.039 32675  8958 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     ... 28 more
07-30 18:57:13.039 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
07-30 18:57:13.039 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)
07-30 18:57:13.039 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery: Caused by: java.net.ConnectException: Failed to connect to /10.75.22.2:8096
07-30 18:57:13.039 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.kt:297)
07-30 18:57:13.039 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:207)
07-30 18:57:13.039 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:226)
07-30 18:57:13.039 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106)
07-30 18:57:13.039 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:74)
07-30 18:57:13.039 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:255)
07-30 18:57:13.039 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
07-30 18:57:13.039 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:517)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at java.lang.Thread.run(Thread.java:920)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery: Caused by: java.net.ConnectException: failed to connect to /10.75.22.2 (port 8096) from /10.75.22.183 (port 57282) after 3500ms: isConnected failed: ECONNREFUSED (Connection refused)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at libcore.io.IoBridge.isConnected(IoBridge.java:349)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at libcore.io.IoBridge.connectErrno(IoBridge.java:238)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at libcore.io.IoBridge.connect(IoBridge.java:180)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:142)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:390)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:230)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:212)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:436)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at java.net.Socket.connect(Socket.java:621)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.platform.Platform.connectSocket(Platform.kt:128)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.kt:295)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     ... 18 more
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery: Caused by: android.system.ErrnoException: isConnected failed: ECONNREFUSED (Connection refused)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at libcore.io.IoBridge.isConnected(IoBridge.java:336)
07-30 18:57:13.040 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     ... 28 more
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient: Unknown SSL error occurred
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient: javax.net.ssl.SSLPeerUnverifiedException: Hostname 10.75.22.2 not verified:
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:     certificate: sha256/[redacted]
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:     DN: CN=pvr.example.com
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:     subjectAltNames: [pvr.example.com, videoserver.example.com]
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.kt:389)
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.kt:337)
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:209)
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:226)
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106)
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:74)
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:255)
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:    at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:517)
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient:    at java.lang.Thread.run(Thread.java:920)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery: Unable to get response from https://10.75.22.2:443
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery: org.jellyfin.sdk.api.client.exception.SecureConnectionException: Unknown SSL error occurred
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at org.jellyfin.sdk.api.client.KtorClient.request$suspendImpl(KtorClient.kt:135)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at org.jellyfin.sdk.api.client.KtorClient$request$1.invokeSuspend(Unknown Source:19)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:194)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith(SuspendFunctionGun.kt:15)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:89)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:194)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith(SuspendFunctionGun.kt:15)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:89)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:194)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith(SuspendFunctionGun.kt:15)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:89)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:194)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith(SuspendFunctionGun.kt:15)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:89)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:103)
07-30 18:57:13.106 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
07-30 18:57:13.107 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
07-30 18:57:13.107 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
07-30 18:57:13.107 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)
07-30 18:57:13.107 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery: Caused by: javax.net.ssl.SSLPeerUnverifiedException: Hostname 10.75.22.2 not verified:
07-30 18:57:13.107 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     certificate: sha256/[redacted]
07-30 18:57:13.107 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     DN: CN=pvr.example.com
07-30 18:57:13.107 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     subjectAltNames: [pvr.example.com, videoserver.example.com]
07-30 18:57:13.107 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.kt:389)
07-30 18:57:13.107 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.kt:337)
07-30 18:57:13.107 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:209)
07-30 18:57:13.107 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:226)
07-30 18:57:13.107 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106)
07-30 18:57:13.107 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:74)
07-30 18:57:13.107 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:255)
07-30 18:57:13.107 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
07-30 18:57:13.108 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.108 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
07-30 18:57:13.108 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.108 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
07-30 18:57:13.108 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.108 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
07-30 18:57:13.108 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
07-30 18:57:13.108 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
07-30 18:57:13.108 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:517)
07-30 18:57:13.108 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
07-30 18:57:13.108 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
07-30 18:57:13.108 32675  9111 D org.jellyfin.sdk.discovery.RecommendedServerDiscovery:     at java.lang.Thread.run(Thread.java:920)
07-30 18:57:13.274 32675  9111 I org.jellyfin.sdk.api.sockets.OkHttpWebsocketSession: Sending (raw) message {"MessageType":"KeepAlive","Data":{}}
07-30 18:57:13.279 32675  8965 I org.jellyfin.sdk.api.sockets.OkHttpWebsocketSession: Receiving (raw) message {"MessageId":"9d73ad6a549f4f51a007bfdee9c331bd","MessageType":"KeepAlive"}

It's interesting that the client tries to connect to ports 8096 and 8920 before connecting to the port that JF is actually being run on and which is being advertised in the discovery response:

07-30 18:56:57.200 32675  9058 D org.jellyfin.sdk.discovery.LocalServerDiscovery: Received message "{"Address":"https://10.75.22.2:443","Id":"9be14d61c64b452eb0fe38a39d2022a8","Name":"videoserver.example.com","EndpointAddress":null}"

but regardless it does finally connect using port 443 where JF is running and ends up tripping over:

07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient: Unknown SSL error occurred
07-30 18:57:13.104 32675  9111 E org.jellyfin.sdk.api.client.KtorClient: javax.net.ssl.SSLPeerUnverifiedException: Hostname 10.75.22.2 not verified:

which indicates to me that the client is trying to connect using the IP address and not the FQDN which of course fails the SSL certificate validation. The client needs to use the FQDN in the connection URL, not the IP address.

nielsvanvelzen commented 4 months ago

You can use our chat or forum to help with troubleshooting network issues.

onedr0p commented 4 months ago

@nielsvanvelzen this is not a network issue, this is a bug with the software. Please reopen.

nielsvanvelzen commented 4 months ago

I don't see any bug in the app with https certificates. Me and thousands of others are able to connect without any problem. As I said, use our chat/forum for help with network configurations and such. If you do find a bug with the app you can open a new issue for that specific bug you find. I don't see any evidence of that in this post though.

brianjmurrell commented 4 months ago

@nielsvanvelzen This is is very clearly NOT a simple networking issue. The logcat I pasted very clearly shows that it's a bug in that the client is trying to verify the certificate presented by the server against the http:/// url that it's trying to connect to and very unsurprisingly it does not validate because the IP ADDRESS is not in the subject name of the certificate.

Please re-open this to address that bug.

I don't see any bug in the app with https certificates. Me and thousands of others are able to connect without any problem.

Are you connecting to an HTTPS server as a result of autodiscovery or are you simply typing the (FQDN) HTTPS URL into the address input? Because entering the FQDN URL works. That proves that the both the certificate and the network are functioning. It's trying to connect with autodiscovery that fails because it's trying to use the IP address of the autodiscovered server and not the FQDN.

I don't see any evidence of that in this post though.

I thought I was pretty clear and detailed in presenting that. The app, on the Android TV reports:

07-30 18:57:13.104 32675 9111 E org.jellyfin.sdk.api.client.KtorClient: javax.net.ssl.SSLPeerUnverifiedException: Hostname 10.75.22.2 not verified:

You can see that it's trying to use a host name of 10.75.22.2 in the URL instead of the FQDN and then it's no surprise that the SSL validation fails.

Again, please reopen this ticket to address that specific issue.

nielsvanvelzen commented 4 months ago

If you set your published URL incorrectly that is an server configuration issue, not an app issue.

brianjmurrell commented 4 months ago

The published URL is set correctly. You can even see it is set correctly in the logcat output:

07-30 18:56:57.200 32675  9058 D org.jellyfin.sdk.discovery.LocalServerDiscovery: Received message "{"Address":"https://10.75.22.2:443","Id":"9be14d61c64b452eb0fe38a39d2022a8","Name":"videoserver.example.com","EndpointAddress":null}"

The Name is the published URL from: image

Additionally, the logcat output I pasted above is rife with URL references that use IP addresses in them, and completely void of any URLs with the (published URL) FQDN. It's very clear that the client/SDK is using the IP address returned in that Received message above in connection URLs and not the Name.

You never did answer my question, when you claimed this was working for you:

Are you connecting to an HTTPS server as a result of autodiscovery or are you simply typing the (FQDN) HTTPS URL into the address input?

Because that (autodiscovery not working) is the entire point of this ticket, not simply just trying to connect to the HTTPS URL (i.e. by typing in the URL -- that clearly works).

nielsvanvelzen commented 4 months ago

The server name is a name, it should never be interpreted as something else. The address property is what a client must use to connect. So the client is doing exactly what it should do, connect to the returned address.

I'll say this one more time: use our chat/forum for troubleshooting network issues. This is not an issue in the app.

brianjmurrell commented 4 months ago

I am sure you know this, but SSL connection verification needs to use a name not an IP address. So the JF client must use the name in the URL it uses to try to connect to the the JF server. But in the logcat you can see it doesn't. It is full of URLs of the format https://10.75.22.2/. That will fail to validate the SSL connection on Android just as it would in your browser on your favourite desktop OS. I.e.:

image

The errors in the logcat above are Android's version of what Chrome is reporting above. When using the name instead of the IP address, the SSL verification is successful:

image

So there is NOTHING wrong with the server or network.

bazirico commented 4 months ago

If you set your published URL incorrectly that is an server configuration issue, not an app issue.

My setup works fine using browsers/macOS app/iOS app. The only thing not working with this exact same setup is my AndroidTV videoprojector.

Thank you guys for the deep dive, logs seems pretty explicits.

onedr0p commented 4 months ago

It's also worth noting with the same server URL used, this is not an issue on the Android mobile app, only the androidtv app. Something is clearly afoot. Again, it's not a network or misconfiguration issue.

brianjmurrell commented 4 months ago

It's also worth noting with the same server URL used, this is not an issue on the Android mobile app,

Does the Android mobile app even have autodiscovery? If so, how'd you get to it? I signed out but I am still connected to the same server. Because, once again, just to be perfectly clear, this entire ticket is not about the simple act of connecting to an HTTPS server (by using it's URL) but rather trying to connect to a server that is found with autodiscovery on the Android TV app.

onedr0p commented 4 months ago

this entire ticket is not about the simple act of connecting to an HTTPS server (by using it's URL) but rather trying to connect to a server that is found with autodiscovery on the Android TV app.

Maybe the two issues are related? I'm setting the https URL (not an IP address, a domain) manually and see the same symptoms.

brianjmurrell commented 4 months ago

How is https://github.com/jellyfin/jellyfin-androidtv/issues/2493#issuecomment-2260419218 off-topic? It's an explanation/example of exactly what the problem is here.

It's just a (well-known) fact that you cannot complete SSL connections (with certificate validation) by IP address but only by using the FQDN -- that comment demonstrates visually what the Jellyfin Android TV client is running into by trying to connect with a URL that uses an IP address rather than a FQDN (that is in the certificate CN or SAN).

mcarlton00 commented 4 months ago

It's offtopic because if you're receiving an IP address in your autodiscovery payload, you have not configured your server properly. End of discussion. No ifs, ands, or buts.

A display name is just a display name. That's it. Do you think all of google's thousands of servers are all named 'google.com'? No, that's silly, they name the servers whatever they want and then configure the user facing domains elsewhere. The name displayed on the dashboard is a display name, not a DNS name.

Niels already pointed out that your published server URL isn't configured correctly. You can set it as an environment variable in the docker config. You can change it with a launch parameter in the systemd file. You can change it on the networking page in the admin dashboard. Not a client issue, not a bug. All clients behave the same where autodiscovery is concerned, and they all fail when this is configured incorrectly.

brianjmurrell commented 4 months ago

Finally a useful answer! Thanks @mcarlton00 (and @crobibero from #jellyfin-troubleshooting).

You can change it on the networking page in the admin dashboard

For anyone/everyone else: it's the Firewall and Proxy Settings and you need to set it to something like all=videoserver.example.com where of course you use your FQDN (as specified in the certificate) after the =.

I never bothered with that because my use-case here is local network only. There are no firewalls and no proxy servers (not even a reverse proxy to JF, which I have always considered a pointless additional point of failure) involved so why would I think that option is relevant to me, based on the name of the option?

That said, having to fill this field in (for this functionality) seems unintuitive and unnecessary IMHO. Given that https:// certificates are not allowed with private ip address space (no CA should be issuing them) in the CN/SAN and beyond that generally speaking, https:// with IP addresses is just generally known not to work at all well, when the client is trying to use an https:// URL, it should use a name automatically (or at least in addition to IP addresses). It's not like one is not provided by the server:

(01:16:14 PM) shred00: 07-30 18:56:57.200 32675  9058 D org.jellyfin.sdk.discovery.LocalServerDiscovery: Received message "{"Address":"https://10.75.22.2:443","Id":"9be14d61c64b452eb0fe38a39d2022a8","Name":"videoserver.example.com","EndpointAddress":null}"

Is the Name value correct? Maybe. Maybe not. But it probably is and is worth trying before outright failing. I mean heck, the client is already stabbing in the dark at ports 8920 and 8096 when the Address component of the above message is saying https://10.75.22.2:443 (with a port), so why not another stab using the Name? There's nothing to lose and everything to gain.