AndroidHDMI for Channels (ah4c): A virtual channel tuner using HDMI Encoder(s) + streaming stick(s)

Beautiful! Thanks!

Under Portainer-Containers there's a "Quick Action" button to look at the logs for a given container. To look at recent history change the number of lines to look at to, say, 100000 -- and then turn Auto-Refresh off and you can scroll back as far as you like.

1 Like

Excellent, thanks again. Looks like all is working now. My scripts are pretty basic so I'll take a look at your examples and see how I can improve them. Cheers!

I think in my XFINITY usage I am better off Closing the APP ... which takes less than 30 seconds to tune .. I had one recording that got stuck on the guide it shut down and restarted correctly but it took about 1 minute all total. I have 30 seconds pre padding so starting tuning from shutdown does not affect the start of the Movie.

Understandable. I still haven't been able to get my setup to fail, so given that, I'm going to stick with the faster tuning until it lets me down. I think I'll add a SPEED_MODE environment variable that'll default to true, so for DTV and Xfinity, anybody that wants the app to be closed after each tune can set it to false -- or just use ADBTuner in compatibility mode.

New bnhf/ah4c:latest and :2024.05.18 pushed with improvements to support for DirecTV and Xfinity deeplinks. Successful tuning is confirmed by the presence of active audio in the case of Xfinity, and the absence of various guide-related words on a screen capture in the case of DTV.

For those that don't want to leave the respective apps running between virtual tunes (slower tuning speed, but very best reliability), a new env var of SPEED_MODE needs to be set to false. Here's what a docker-compose would look like to add the SPEED_MODE variable:

version: '3.9'
services:
  ah4c:
    image: bnhf/ah4c:${TAG}
    container_name: ah4c
    hostname: ah4c
    dns_search: ${DOMAIN} # Specify the name of your LAN's domain, usually local or localdomain
    ports:
      - ${ADBS_PORT}:5037 # Port used by adb-server
      - ${HOST_PORT}:7654 # Port used by this ah4c proxy
      - ${WSCR_PORT}:8000 # Port used by ws-scrcpy
    environment:
      - IPADDRESS=${IPADDRESS} # Hostname or IP address of this ah4c extension to be used in M3U file (also add port number if not in M3U)
      - NUMBER_TUNERS=${NUMBER_TUNERS} # Number of tuners you'd like defined 1, 2, 3 or 4 supported
      - TUNER1_IP=${TUNER1_IP} # Streaming device #1 with adb port in the form hostname:port or ip:port
      - TUNER2_IP=${TUNER2_IP} # Streaming device #2 with adb port in the form hostname:port or ip:port
      - TUNER3_IP=${TUNER3_IP} # Streaming device #3 with adb port in the form hostname:port or ip:port
      - TUNER4_IP=${TUNER4_IP} # Streaming device #4 with adb port in the form hostname:port or ip:port
      - ENCODER1_URL=${ENCODER1_URL} # Full URL for tuner #1 in the form http://hostname/stream or http://ip/stream
      - ENCODER2_URL=${ENCODER2_URL} # Full URL for tuner #2 in the form http://hostname/stream or http://ip/stream
      - ENCODER3_URL=${ENCODER3_URL} # Full URL for tuner #3 in the form http://hostname/stream or http://ip/stream
      - ENCODER4_URL=${ENCODER4_URL} # Full URL for tuner #4 in the form http://hostname/stream or http://ip/stream
      - STREAMER_APP=${STREAMER_APP} # Streaming device name and streaming app you're using in the form scripts/streamer/app (use lowercase with slashes between as shown)
      - CHANNELSIP=${CHANNELSIP} # Hostname or IP address of the Channels DVR server itself
      - ALERT_SMTP_SERVER=${ALERT_SMTP_SERVER} # The domainname:port of the SMTP server you'll be using like smtp.gmail.com:587. This is for sending ah4c alerts if tuning fails.
      - ALERT_AUTH_SERVER=${ALERT_AUTH_SERVER} # The auth server for the e-mail you'll be using like smtp.gmail.com
      - ALERT_EMAIL_FROM=${ALERT_EMAIL_FROM} # The e-mail address you'd like your ah4c failure alert e-mails to show as being from.
      - ALERT_EMAIL_PASS=${ALERT_EMAIL_PASS} # Gmail and Yahoo both support the creation of app-specific e-mail passwords, and this is the way to go! It's NOT recommended to use your everyday e-mail password.
      - ALERT_EMAIL_TO=${ALERT_EMAIL_TO} # The e-mail address you'd like your alert e-mails sent to.
      #- ALERT_WEBHOOK_URL=""
      - SPEED_MODE=${SPEED_MODE} # For DirecTV and Xfinity users, set to false if you want the app force-closed after each virtual tune.
      - LIVETV_ATTEMPTS=${LIVETV_ATTEMPTS} # For FireTV Live Guide tuning only, set maximum number of attempts at finding the desired channel
      - CREATE_M3US=${CREATE_M3US} # Set to true to create device-specific M3Us for use with Amazon Prime Premium channels -- requires a FireTV device
      - UPDATE_SCRIPTS=${UPDATE_SCRIPTS} # Set to true if you'd like the sample scripts and STREAMER_APP scripts updated whether they exist of not
      - UPDATE_M3US=${UPDATE_M3US} # Set to true if you'd like the sample m3us updated whether they exist of not
      - TZ=${TZ} # Your local timezone in Linux "tz" format
    volumes:
      - ${HOST_DIR}/ah4c/scripts:/opt/scripts # pre/stop/bmitune.sh scripts will be stored in this bound host directory under streamer/app
      - ${HOST_DIR}/ah4c/m3u:/opt/m3u # m3u files will be stored here and hosted at http://<hostname or ip>:7654/m3u for use in Channels DVR - Custom Channels settings
      - ${HOST_DIR}/ah4c/adb:/root/.android # Persistent data directory for adb keys
    restart: unless-stopped

And the sample env vars:

TAG=latest
DOMAIN=localdomain
ADBS_PORT=5037
HOST_PORT=7654
WSCR_PORT=7655
IPADDRESS=htpc6:7654
NUMBER_TUNERS=2
TUNER1_IP=firestick-rack1:5555
ENCODER1_URL=http://encoder_48007/0.ts
TUNER2_IP=firestick-rack2:5555
ENCODER2_URL=http://encoder_48007/4.ts
STREAMER_APP=scripts/firetv/directv
CHANNELSIP=media-server6
ALERT_SMTP_SERVER=smtp.gmail.com:587
ALERT_AUTH_SERVER=smtp.gmail.com
[email protected]
ALERT_EMAIL_PASS=xxxxxxxxxxxxxxxx
[email protected]
SPEED_MODE=true
LIVETV_ATTEMPTS=45
CREATE_M3US=false
UPDATE_SCRIPTS=true
UPDATE_M3US=true
TZ=US/Mountain
HOST_DIR=/data

Yeah, ADBTUNER seems to fit my environment using Compatibility mode.

Grrr! The variations in delays needed for tuning are driving me a bit batty. For the combination of dongle (Tivo Stream 4k) and app (PBS) I'm using, I sometimes need enough sleeps that the tuning doesn't complete before it get squashed and starts over. (I guess it must be Channels that has that overall timeout and retry. Is that right?) If I make the sleeps too short, I'm sometimes not in the right place in the app when I navigate right (or whatever).

I'm not expecting any magic solution to this. Just whining, I guess. The tweakage continues. :slight_smile:

Maybe post some specific examples of scripts you're having trouble with?

A bit in the blind here, but if you're trying to string multiple KEYCODEs in a single keyevent, you'll get inconsistent results. Much better to execute each KEYCODE behind its own input keyevent. I've had very good, and predictable, results using this approach.

Thanks for jumping in. I should have been clearer that I'm not really looking for help with the variable delays right now. Sympathy, maybe.... I'll get to something reliable if I keep fiddling.

But maybe there is something you know about. If I put in really long delays, something times out and repeatedly retries the tuning cycle. Do you know if that's Channels, the proxy, or something else?

Not something I've seen, and I've worked with some tuning scenarios that have taken as much as 45 seconds.

What kind of sleep numbers are we talking about?

What are you seeing in the ah4c and/or Portainer logs?

What are you seeing in the CDVR logs?

Definitely not as much as 45 seconds. I'll look into it more over the next day or so.

Has anyone tinkered here? I currently run a Gemini for DTV Stream, which is great, but would love to have an ATSC3 DRM stopgap, for the time being.

Don't think so. At least one reddit post says it can be put into developer mode and accessed via adb. Could be fun to try, but I get zero OTA here in the mountains.

It took me a while to track this "delays" thing down (partly due to foolishly pursuing various red herrings), but I think I understand it now. The key to it is how much delay (and processing time, of course) there is in the prebmitune.sh script.

To figure this out, I changed all 3 scripts to simply "exit 0". Channels was able to quickly tune to the "live stream" of whatever happened to be showing on the dongle. Then I did a bunch of experiments of adding simple "sleep" steps in prebmitune.sh and bmitune.sh. Sleeps in bmitune.sh didn't matter at all, regardless of how large (I figured out why later). For prebmitune.sh, "sleep 5" or smaller was consistently successful. "sleep 8" or larger was consistently failing. Between 5 and 8 was sometimes successful, sometimes faiing (probably due to vagaries of other timing things).

My surmise is that Channels has a timeout on the order of 8-10 seconds. If it hasn't received anything by that time (including not receiving HTTP response headers), it abandons the connection and tries again. I don't know how many times it will retry, but it's several. Some log snippets below show the effect. I wonder if there is a way to tune that timeout? That would be useful here.

Why does delay in prebmitune.sh matter but delay in bmitune.sh not matter? Looking at the code in main.go (even though I'm not a "go guy"), it runs the prebmitune.sh script. If that is successful, HTTP response headers are sent back to Channels and video bytes start relaying. After that, the bmitune.sh script is run. (My go-fu is a little weak to understand the exact sequence of that last part.) Since Channels is receiving the video stream all the while that bmitune.sh is running, it doesn't matter how long that takes, from the connection/session point of view.

It's not really obvious to me why we have both prebmitune.sh and bmitune.sh, but it probably matters or is at least convenient in some scenario. No criticism intended.

Channels log:

2024/06/07 14:46:06.394874 [TNR] Opened connection to M3U-ah4c for ch28 KBTC
2024/06/07 14:46:06.403820 [HLS] Starting live stream for channel 28 from 192.168.1.33
2024/06/07 14:46:06.639498 [HLS] Session ch28-dANY-ip192.168.1.33 started in 244.243644ms
2024/06/07 14:46:06.786312 [HLS] Probed live stream in 381.457083ms: h264 1920x1080 progressive 519885bps
2024/06/07 14:46:17.030491 [HLS] Stopping transcoder session ch28-dANY-ip192.168.1.33 (out=16.015999995s finished=false first_seq=1 last_seq=6)
2024/06/07 14:46:17.030790 [TNR] Closed connection to M3U-ah4c for ch28 KBTC
2024/06/07 14:46:17.036202 [HLS] Session ch28-dANY-ip192.168.1.33 stopped
2024/06/07 14:46:17.036308 [SNR] Buffer statistics for ch28 KBTC: buf=0% drop=0%
2024/06/07 14:46:38.013137 [TNR] Opened connection to M3U-ah4c for ch28 KBTC
2024/06/07 14:46:38.017235 [HLS] Starting live stream for channel 28 from 192.168.1.33
2024/06/07 14:46:38.034715 [TNR] Closed connection to M3U-ah4c for ch28 KBTC
2024/06/07 14:46:38.190760 [HLS] Session ch28-dANY-ip192.168.1.33 stopped: EOF
2024/06/07 14:46:38.210005 [HLS] Stopping transcoder session ch28-dANY-ip192.168.1.33 (out=200ms finished=true first_seq=1 last_seq=1)
2024/06/07 14:46:38.210572 [ERR] Probe failed for live stream after 192.758824ms and 140072 bytes
2024/06/07 14:46:47.315651 [TNR] Opened connection to M3U-ah4c for ch28 KBTC
2024/06/07 14:46:47.319816 [HLS] Starting live stream for channel 28 from 192.168.1.33
2024/06/07 14:46:47.339657 [TNR] Closed connection to M3U-ah4c for ch28 KBTC
2024/06/07 14:46:47.495337 [HLS] Session ch28-dANY-ip192.168.1.33 stopped: EOF
2024/06/07 14:46:47.495491 [HLS] Stopping transcoder session ch28-dANY-ip192.168.1.33 (out=200ms finished=true first_seq=1 last_seq=1)
2024/06/07 14:46:47.495936 [ERR] Probe failed for live stream after 175.389515ms and 237068 bytes
2024/06/07 14:46:56.031397 [TNR] Opened connection to M3U-ah4c for ch28 KBTC
2024/06/07 14:46:56.035851 [HLS] Starting live stream for channel 28 from 192.168.1.33
2024/06/07 14:46:56.057333 [TNR] Closed connection to M3U-ah4c for ch28 KBTC
2024/06/07 14:46:56.212757 [HLS] Session ch28-dANY-ip192.168.1.33 stopped: EOF
2024/06/07 14:46:56.224698 [HLS] Stopping transcoder session ch28-dANY-ip192.168.1.33 (out=200ms finished=true first_seq=1 last_seq=1)
2024/06/07 14:46:56.225294 [ERR] Probe failed for live stream after 188.963196ms and 159064 bytes
2024/06/07 14:47:05.844424 [HLS] Stopping transcoder session ch28-dANY-ip192.168.1.33 (out=0s finished=false first_seq=1 last_seq=0)
2024/06/07 14:47:06.046469 [TNR] Opened connection to M3U-ah4c for ch28 KBTC
2024/06/07 14:47:06.067850 [TNR] Closed connection to M3U-ah4c for ch28 KBTC

ah4c log:

2024/06/07 14:45:59 Attempting network tune for device http://hank.carpenter.org/ts/1_0 tivo4k.carpenter.org:5555 KBTC_98011_2
2024/06/07 14:45:59 [EXECUTE] Running [./scripts/chromecast/pbs/prebmitune.sh tivo4k.carpenter.org:5555 KBTC_98011_2]
2024/06/07 14:46:06 [EXECUTE] Stdout: ''
2024/06/07 14:46:06 [EXECUTE] Stderr: ''
2024/06/07 14:46:06 [EXECUTE] Finished running ./scripts/chromecast/pbs/prebmitune.sh in 7.014140522s
2024/06/07 14:46:06 [EXECUTE] Running [./scripts/chromecast/pbs/bmitune.sh KBTC_98011_2 tivo4k.carpenter.org:5555]
2024/06/07 14:46:06 [EXECUTE] Stdout: ''
2024/06/07 14:46:06 [EXECUTE] Stderr: ''
2024/06/07 14:46:06 [EXECUTE] Finished running ./scripts/chromecast/pbs/bmitune.sh in 13.490182ms
2024/06/07 14:46:17 [IO] io.Copy: write tcp 172.19.0.2:7654->192.168.1.116:37814: write: broken pipe
2024/06/07 14:46:17 [IOINFO] Successfully copied 8395988 bytes
2024/06/07 14:46:17 [IOINFO] Transfer speed: 6.3130960287535425 Mbits/second
2024/06/07 14:46:17 Performing Close() for tivo4k.carpenter.org:5555
2024/06/07 14:46:17 [EXECUTE] Running [./scripts/chromecast/pbs/stopbmitune.sh tivo4k.carpenter.org:5555 KBTC_98011_2]
2024/06/07 14:46:17 [EXECUTE] Stdout: ''
2024/06/07 14:46:17 [EXECUTE] Stderr: ''
2024/06/07 14:46:17 [EXECUTE] Finished running ./scripts/chromecast/pbs/stopbmitune.sh in 9.259429ms
2024/06/07 14:46:17 [GIN-debug] Request: 192.168.1.116 GET /play/tuner/KBTC_98011_2, latency: 17.691168323s, status: 200
2024/06/07 14:46:29 Attempting network tune for device http://hank.carpenter.org/ts/1_0 tivo4k.carpenter.org:5555 KBTC_98011_2
2024/06/07 14:46:29 [EXECUTE] Running [./scripts/chromecast/pbs/prebmitune.sh tivo4k.carpenter.org:5555 KBTC_98011_2]
2024/06/07 14:46:38 [EXECUTE] Stdout: ''
2024/06/07 14:46:38 [EXECUTE] Stderr: ''
2024/06/07 14:46:38 [EXECUTE] Finished running ./scripts/chromecast/pbs/prebmitune.sh in 8.01504821s
2024/06/07 14:46:38 [EXECUTE] Running [./scripts/chromecast/pbs/bmitune.sh KBTC_98011_2 tivo4k.carpenter.org:5555]
2024/06/07 14:46:38 [EXECUTE] Stdout: ''
2024/06/07 14:46:38 [EXECUTE] Stderr: ''
2024/06/07 14:46:38 [EXECUTE] Finished running ./scripts/chromecast/pbs/bmitune.sh in 11.839914ms
2024/06/07 14:46:38 [IOINFO] Successfully copied 237256 bytes
2024/06/07 14:46:38 [IOINFO] Transfer speed: 102.87715964754678 Mbits/second
2024/06/07 14:46:38 Performing Close() for tivo4k.carpenter.org:5555
2024/06/07 14:46:38 [EXECUTE] Running [./scripts/chromecast/pbs/stopbmitune.sh tivo4k.carpenter.org:5555 KBTC_98011_2]
2024/06/07 14:46:38 [EXECUTE] Stdout: ''
2024/06/07 14:46:38 [EXECUTE] Stderr: ''
2024/06/07 14:46:38 [EXECUTE] Finished running ./scripts/chromecast/pbs/stopbmitune.sh in 6.048391ms
2024/06/07 14:46:38 [GIN-debug] Request: 192.168.1.116 GET /play/tuner/KBTC_98011_2, latency: 8.065890216s, status: 200
2024/06/07 14:46:39 Attempting network tune for device http://hank.carpenter.org/ts/1_0 tivo4k.carpenter.org:5555 KBTC_98011_2
2024/06/07 14:46:39 [EXECUTE] Running [./scripts/chromecast/pbs/prebmitune.sh tivo4k.carpenter.org:5555 KBTC_98011_2]
2024/06/07 14:46:47 [EXECUTE] Stdout: ''
2024/06/07 14:46:47 [EXECUTE] Stderr: ''
2024/06/07 14:46:47 [EXECUTE] Finished running ./scripts/chromecast/pbs/prebmitune.sh in 8.014339628s
2024/06/07 14:46:47 [EXECUTE] Running [./scripts/chromecast/pbs/bmitune.sh KBTC_98011_2 tivo4k.carpenter.org:5555]
2024/06/07 14:46:47 [EXECUTE] Stdout: ''
2024/06/07 14:46:47 [EXECUTE] Stderr: ''
2024/06/07 14:46:47 [IOINFO] Successfully copied 237068 bytes
2024/06/07 14:46:47 [EXECUTE] Finished running ./scripts/chromecast/pbs/bmitune.sh in 17.141087ms
2024/06/07 14:46:47 [IOINFO] Transfer speed: 107.58560472768909 Mbits/second
2024/06/07 14:46:47 Performing Close() for tivo4k.carpenter.org:5555
2024/06/07 14:46:47 [EXECUTE] Running [./scripts/chromecast/pbs/stopbmitune.sh tivo4k.carpenter.org:5555 KBTC_98011_2]
2024/06/07 14:46:47 [EXECUTE] Stdout: ''
2024/06/07 14:46:47 [EXECUTE] Stderr: ''
2024/06/07 14:46:47 [EXECUTE] Finished running ./scripts/chromecast/pbs/stopbmitune.sh in 5.690968ms
2024/06/07 14:46:47 [GIN-debug] Request: 192.168.1.116 GET /play/tuner/KBTC_98011_2, latency: 8.068566429s, status: 200
2024/06/07 14:46:47 Attempting network tune for device http://hank.carpenter.org/ts/1_0 tivo4k.carpenter.org:5555 KBTC_98011_2
2024/06/07 14:46:48 [EXECUTE] Running [./scripts/chromecast/pbs/prebmitune.sh tivo4k.carpenter.org:5555 KBTC_98011_2]
2024/06/07 14:46:56 [EXECUTE] Stdout: ''
2024/06/07 14:46:56 [EXECUTE] Stderr: ''
2024/06/07 14:46:56 [EXECUTE] Finished running ./scripts/chromecast/pbs/prebmitune.sh in 8.012191557s
2024/06/07 14:46:56 [EXECUTE] Running [./scripts/chromecast/pbs/bmitune.sh KBTC_98011_2 tivo4k.carpenter.org:5555]
2024/06/07 14:46:56 [EXECUTE] Stdout: ''
2024/06/07 14:46:56 [EXECUTE] Stderr: ''
2024/06/07 14:46:56 [EXECUTE] Finished running ./scripts/chromecast/pbs/bmitune.sh in 17.049292ms
2024/06/07 14:46:56 [IOINFO] Successfully copied 237068 bytes
2024/06/07 14:46:56 [IOINFO] Transfer speed: 97.99403906246809 Mbits/second
2024/06/07 14:46:56 Performing Close() for tivo4k.carpenter.org:5555
2024/06/07 14:46:56 [EXECUTE] Running [./scripts/chromecast/pbs/stopbmitune.sh tivo4k.carpenter.org:5555 KBTC_98011_2]
2024/06/07 14:46:56 [EXECUTE] Stdout: ''
2024/06/07 14:46:56 [EXECUTE] Stderr: ''
2024/06/07 14:46:56 [EXECUTE] Finished running ./scripts/chromecast/pbs/stopbmitune.sh in 5.923799ms
2024/06/07 14:46:56 [GIN-debug] Request: 192.168.1.116 GET /play/tuner/KBTC_98011_2, latency: 8.070098522s, status: 200
2024/06/07 14:46:58 Attempting network tune for device http://hank.carpenter.org/ts/1_0 tivo4k.carpenter.org:5555 KBTC_98011_2
2024/06/07 14:46:58 [EXECUTE] Running [./scripts/chromecast/pbs/prebmitune.sh tivo4k.carpenter.org:5555 KBTC_98011_2]
2024/06/07 14:47:06 [EXECUTE] Stdout: ''
2024/06/07 14:47:06 [EXECUTE] Stderr: ''
2024/06/07 14:47:06 [EXECUTE] Finished running ./scripts/chromecast/pbs/prebmitune.sh in 8.012956169s
2024/06/07 14:47:06 [EXECUTE] Running [./scripts/chromecast/pbs/bmitune.sh KBTC_98011_2 tivo4k.carpenter.org:5555]
2024/06/07 14:47:06 [EXECUTE] Stdout: ''
2024/06/07 14:47:06 [EXECUTE] Stderr: ''
2024/06/07 14:47:06 [EXECUTE] Finished running ./scripts/chromecast/pbs/bmitune.sh in 13.745273ms
2024/06/07 14:47:06 [IOINFO] Successfully copied 242520 bytes
2024/06/07 14:47:06 [IOINFO] Transfer speed: 111.415858762528 Mbits/second
2024/06/07 14:47:06 Performing Close() for tivo4k.carpenter.org:5555
2024/06/07 14:47:06 [EXECUTE] Running [./scripts/chromecast/pbs/stopbmitune.sh tivo4k.carpenter.org:5555 KBTC_98011_2]
2024/06/07 14:47:06 [EXECUTE] Stdout: ''
2024/06/07 14:47:06 [EXECUTE] Stderr: ''
2024/06/07 14:47:06 [EXECUTE] Finished running ./scripts/chromecast/pbs/stopbmitune.sh in 5.312062ms
2024/06/07 14:47:06 [GIN-debug] Request: 192.168.1.116 GET /play/tuner/KBTC_98011_2, latency: 8.060497156s, status: 200

Not sure exactly how you're approaching this, but I think distilling things down, what you're saying is that if prebmitune.sh doesn't finishing executing in under 5 seconds then Channels DVR will attempt to tune again. That may be true, as I've never had anything in prebmitune.sh that takes that long to complete -- and you shouldn't either. :slight_smile:

Here's my most recent prembmitune.sh execution to watch the Tennis Channel earlier today:

[GIN-debug] Request: 172.28.0.1 GET /play/tuner/KPNX~eee9b0c9-1b4e-4170-8504-283fdf536d02, latency: 39.211155004s, status: 200
Attempting network tune for device http://encoder_48007/0.ts firestick-rack1:5555 TNNSHD~d33d363d-4144-4aae-be5d-debebeef2b0d 
[EXECUTE] Running [./scripts/firetv/dtvdeeplinks/prebmitune.sh firestick-rack1:5555 TNNSHD~d33d363d-4144-4aae-be5d-debebeef2b0d]
[EXECUTE] Stdout: 'already connected to firestick-rack1:5555
prebmitune.sh is exiting for firestick-rack1:5555 with exit code 0
'
[EXECUTE] Stderr: '+ streamerIP=firestick-rack1:5555
+ streamerNoPort=firestick-rack1
+ adbTarget='adb -s firestick-rack1:5555'
+ mkdir -p firestick-rack1
+ trap finish EXIT
+ main

+ adbConnect
+ adb connect firestick-rack1:5555
+ local -i adbMaxRetries=2
+ local -i adbCounter=0
+ true
+ adb -s firestick-rack1:5555 shell input keyevent KEYCODE_WAKEUP
+ local adbEventSuccess=0
+ [[ 0 -eq 0 ]]
+ break
+ finish
+ echo 'prebmitune.sh is exiting for firestick-rack1:5555 with exit code 0'
'
[EXECUTE] Finished running ./scripts/firetv/dtvdeeplinks/prebmitune.sh in 713.963601ms

The only thing it does is connect to the FireStick, wake it up, and confirm there's no error. Takes less than one second to complete.

Not sure if there's a flaw in your testing, or you've discovered an edge case of some sort here. But sleep works just fine in bmitune.sh. Again, here's my bmitune.sh output from earlier today:

[EXECUTE] Running [./scripts/firetv/dtvdeeplinks/bmitune.sh TNNSHD~d33d363d-4144-4aae-be5d-debebeef2b0d firestick-rack1:5555]
[EXECUTE] Stdout: 'Current PID for this script is 2362
Not a special channel (exit nor reboot)
Starting: Intent { act=android.intent.action.VIEW (has data) cmp=com.att.tv/com.clientapp.MainActivity }
Deeplink tuning appears to have been successful!
bmitune.sh is exiting for firestick-rack1:5555 with exit code 0
'
[EXECUTE] Stderr: '++ echo TNNSHD~d33d363d-4144-4aae-be5d-debebeef2b0d++ 
awk -F~ '{print $2}'
+ channelID=d33d363d-4144-4aae-be5d-debebeef2b0d
++ echo TNNSHD~d33d363d-4144-4aae-be5d-debebeef2b0d
++ awk -F~ '{print $1}'
+ channelName=TNNSHD
+ specialID=TNNSHD
+ streamerIP=firestick-rack1:5555
+ streamerNoPort=firestick-rack1
+ adbTarget='adb -s firestick-rack1:5555'
+ packageName=com.att.tv
+ packageAction=com.clientapp.MainActivity
+ [[ '' == '' ]]
+ speedMode=true
+ trap finish EXIT
+ main
+ updateReferenceFiles
+ mkdir -p firestick-rack1
+ [[ -f firestick-rack1/stream_stopped ]]
+ [[ -f firestick-rack1/last_channel ]]
+ echo 2362
+ echo 'Current PID for this script is 2362'
+ matchEncoderURL
+ case "$streamerIP" in
+ encoderURL=http://encoder_48007/0.ts
+ specialChannels
+ '[' TNNSHD = exit ']'
+ '[' TNNSHD = reboot ']'
+ [[ -f firestick-rack1/adbCommunicationFail ]]
+ echo 'Not a special channel (exit nor reboot)'
+ tuneChannel
+ adb -s firestick-rack1:5555 shell am start -n com.att.tv/com.clientapp.MainActivity dtvnow://deeplink.directvnow.com/play/channel/TNNSHD/d33d363d-4144-4aae-be5d-debebeef2b0d
Warning: Activity not started, its current task has been brought to the front
+ [[ true == \t\r\u\e ]]
+ tuneCheck 24
+ local sleepBeforeTuneCheck=24
+ sleep 24
+ ffmpeg -i http://encoder_48007/0.ts -frames:v 1 -y firestick-rack1/screencapture.jpg -loglevel quiet
+ tesseract firestick-rack1/screencapture.jpg firestick-rack1/screencapture
Tesseract Open Source OCR Engine v4.1.1 with Leptonica
Warning: Invalid resolution 0 dpi. Using 70 instead.
Estimating resolution as 541
Detected 6 diacritics
+ grep -q 'Guide\|WHAT'\''S\|SPORTS' firestick-rack1/screencapture.txt
+ '[' 1 == 0 ']'
+ echo 'Deeplink tuning appears to have been successful!'
+ finish
+ echo 'bmitune.sh is exiting for firestick-rack1:5555 with exit code 0'
'
[EXECUTE] Finished running ./scripts/firetv/dtvdeeplinks/bmitune.sh in 29.397638418s

As you can see the entire process took almost 30 seconds -- though the tuning itself was much faster than that (about 5 seconds). Most of the time is the result of an OCR process to confirm the stream is not stuck on the default page -- but rather actively streaming on a channel.

I'd suggest using the scripts that I, and others, have written as examples. Specifically those that use the remote control emulation style of tuning. Deeplinks have recently been figured out for DTV, but prior to that I was using remote control style commands for many months.

I've scripted this way for numerous apps, and although slower than deeplinks, I can't remember ever being unsuccessful. I'd be happy to help with specifics, if you want to post them, but I think you might be on the trail of another red herring atm.

As I think about this part, you may have answered your own question here -- which is that prebmitune.sh is intended as some relatively quick feedback to the server that tuning is in process. No one wants to wait around for a failed tune if their encoder and streaming stick setup is simply offline for some reason. This allows for a potentially longer process in bmitune.sh to be run.

Maybe a miscommunication here. I meant it doesn't matter for the purposes of Channels retrying. I agree sleep works just fine (in the shell script sense) in all three scripts.

Mine takes about 4 seconds, and I think most of that difference is due to environmental stuff. However, my scripts started as clones of the firetv/directv scripts I found in the repo a couple weeks ago (and a glance at the other scripts in the repo), which included starting the app in prebmitune.sh. I can see that there is no reason that can't be in bmitune.sh and I will move it. That will give a little more headroom.

Yes, I am using the remote emulation, which works pretty well now that I understand the timing situation that was puzzling me for a while.

@wjcarpenter When you're ready, it'd be great if you would submit your chromecast/pbs scripts and M3U for inclusion in the container and repo. You can either post them here, or submit a PR, either works.

That's my plan (a PR).