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

The end result is fantastic though! It puts a smile on my face every time I tune a channel. A tricky job well executed.

I'm so happy it made you happy. That means a lot. I stayed up so late doing that! It was really not a fun one but I'm glad someone enjoys it!

I actually had to shut it off because it made my wife think the TV was broken.

She wasn't a fan, so I have to leave mine disabled. Maybe I'll have some fun with her and put some test color bars up or something. :joy:

3 Likes

The old Indian head test pattern.

@daldana7296 This comment has been stuck in my head, and today I passed a couple of the same Capture Cards you're using through to my Channels DVR LXC in Proxmox.

Testing both using VLC as a client (as I can specify the virtual tuner number I want to use in ah4c), with DirecTV via FastChannels, my tune times were in the same ~4 second range that I see with my network encoders.

We should probably revisit your setup as some point, if you're still seeing those long tune times, as something isn't right. Even without FastChannels, my tune times were ~10 seconds using deep links with the DTV app.

Using FastChannels, with just the Single HDMI Encoder running, my tune times are around 5-6 seconds, so I'm really happy with that! I'm not sure what the big difference is between the single encoder and the FC integration with ah4c that would cause such a difference.

I do know that I don't see the DTV splash screen or the guide page with the single encoder setup, whereas I did with the ah4c integration.

Yeah, from sleep to wake with an Osprey, I get about 7 to 8 seconds. So that is right on par, I would say.

There's no difference between the single encoder and the ah4c bridge when using FastChannels for both -- you're comparing two different things.

The FastChannels bridge does not use the DTV app (which is where the splash screen comes from), which is what slows down tuning when using deeplinks. I'm sure neither of us has plans to go back to tuning "the old way" using deeplinks, so your long tune times using that method is probably a mystery we'll never solve.

It is good to know that this option exists if DirecTV ever kills the Osprey line.
I have 10 of them, so there is no point in switching to the bridge right now, but it is really good to know that this is an alternative to getting fast tunes.

Absolutely!

There are a couple of issues to address with ah4c. The first is the View & control window isn't working with my virtual encoders. It works initially (for maybe a second), but then goes gray with a spinning circle. The virtual encoder URL looks like this:

http://channels:8089/devices/M3U-Capture/channels/90474/stream.mpg?format=ts&codec=copy

The second is that our attempt at changing tuner numbers from starting with 0 to starting with 1 is a bit of a bust, as if you want to target a specific tuner (for testing or whatever), it's done by /play/tunerx/. And, as you might imagine, it's a bit confusing when looking at Activity-Tuners. Apparently changing the way the tuners are referenced, internal to the program, is no small task. I propose we revert this.

I'm happy to take a look at these issues myself, but if you'd prefer to dig into them, that's great too.

I am just the teeniest bit burnt out right now, so I might have to take a little bit of a breather and then look at it another time. I also have not set this up yet, so I would have to maybe look into setting up a test Channels server. I do not want to keep interrupting people while I test various things related to Channels, so it would probably be best if I take my spare LinkPis that I have lying around and look into setting up a spare Channels/ah4c server with those extra encoders at some point.

No problem. I'll see if I can make any inroads on either issue tomorrow. View & control seem the most pressing, so I'll look at that first.

1 Like

That's exactly my thought as well!

looks like everything worked good for me this last week unsupervised. :slight_smile: :camping:
i'll wait till another day to try any updates.

this does make since, and i'm capable of opting out.

I was worried about that and hesitated even saying something, i think its fine if everything starts at zero, just wanted the env and gui to match. :wink:

So you got my curiosity going and I tried ah4c outside of FC and tune time was around 20 seconds to the video actually starting. I tried tuning to Fail Army to make sure it wasn't a network subscription thing. Below is the ah4c log file;

2026/09/08 14:13:31 [EXECUTE] Stderr: '+ streamerIP=192.168.88.113:5555

+ streamerNoPort=192.168.88.113

+ adbTarget='adb -s 192.168.88.113:5555'

+ packageName=com.att.tv

+ mkdir -p 192.168.88.113

+ trap finish EXIT

+ main

+ adbConnect

+ adb connect 192.168.88.113:5555

+ local -i adbMaxRetries=2

+ local -i adbCounter=0

+ true

+ adb -s 192.168.88.113:5555 shell input keyevent KEYCODE_WAKEUP

+ local adbEventSuccess=0

+ [[ 0 -eq 0 ]]

+ break

+ forceStopApp

+ adb -s 192.168.88.113:5555 shell am force-stop com.att.tv

+ finish

+ echo 'prebmitune.sh is exiting for 192.168.88.113:5555 with exit code 0'

'

2026/09/08 14:13:31 [EXECUTE] Finished running ./scripts/firetv/dtvstreamdeeplinks/prebmitune.sh in 2.195112575s

2026/09/08 14:13:31 [EXECUTE] Running [./scripts/firetv/dtvstreamdeeplinks/bmitune.sh FLARMY~5b2cc61c-32c8-42db-8c2e-ec527e55f1fa 192.168.88.113:5555]

2026/09/08 14:13:31 [EXECUTE] Stdout: 'Current PID for this script is 281

Starting: Intent { act=android.intent.action.VIEW (has data) cmp=com.att.tv/com.clientapp.MainActivity }

bmitune.sh is exiting for 192.168.88.113:5555 with exit code 0

'

2026/09/08 14:13:31 [EXECUTE] Stderr: '++ echo FLARMY~5b2cc61c-32c8-42db-8c2e-ec527e55f1fa

++ awk -F~ '{print $2}'

+ channelID=5b2cc61c-32c8-42db-8c2e-ec527e55f1fa

++ echo FLARMY~5b2cc61c-32c8-42db-8c2e-ec527e55f1fa

++ awk -F~ '{print $1}'

+ channelName=FLARMY

+ streamerIP=192.168.88.113:5555

+ streamerNoPort=192.168.88.113

+ adbTarget='adb -s 192.168.88.113:5555'

+ packageName=com.att.tv

+ packageAction=com.clientapp.MainActivity

+ trap finish EXIT

+ main

+ updateReferenceFiles

+ mkdir -p 192.168.88.113

+ [[ -f 192.168.88.113/stream_stopped ]]

+ [[ -f 192.168.88.113/last_channel ]]

+ echo 281

+ echo 'Current PID for this script is 281'

+ tuneChannel

+ adb -s 192.168.88.113:5555 shell am start -n com.att.tv/com.clientapp.MainActivity dtvnow://deeplink.directvnow.com/play/channel/FLARMY/5b2cc61c-32c8-42db-8c2e-ec527e55f1fa

+ finish

+ echo 'bmitune.sh is exiting for 192.168.88.113:5555 with exit code 0'

'

2026/09/08 14:13:31 [EXECUTE] Finished running ./scripts/firetv/dtvstreamdeeplinks/bmitune.sh in 433.260841ms

2026/09/08 14:14:02 Tuner 0 is active - skipping

2026/09/08 14:14:02 [ERR] Failed to tune device(s) not available

2026/09/08 14:14:02 [GIN-debug] Request: 172.27.0.1 GET /play/tuner/FLARMY~5b2cc61c-32c8-42db-8c2e-ec527e55f1fa, latency: 314.372µs, status: 500

2026/09/08 14:14:02 [IO] io.Copy: write tcp 172.27.0.2:7654->172.27.0.1:49982: write: broken pipe

2026/09/08 14:14:02 [IOINFO] Successfully copied 25697752 bytes

2026/09/08 14:14:02 [IOINFO] Transfer speed: 6.555588450881878 Mbits/second

2026/09/08 14:14:02 Performing Close() for 192.168.88.113:5555

2026/09/08 14:14:02 [EXECUTE] Running [./scripts/firetv/dtvstreamdeeplinks/stopbmitune.sh 192.168.88.113:5555 FLARMY~5b2cc61c-32c8-42db-8c2e-ec527e55f1fa]

2026/09/08 14:14:09 [EXECUTE] Stdout: 'Streaming stopped for 192.168.88.113:5555

Sleep initiated for 192.168.88.113:5555

192.168.88.113/stream_stopped written with epoch stop time

'

2026/09/08 14:14:09 [EXECUTE] Stderr: '+ streamerIP=192.168.88.113:5555

+ streamerNoPort=192.168.88.113

+ adbTarget='adb -s 192.168.88.113:5555'

+ packageName=com.att.tv

+ main

+ bmituneDone

+ bmitunePID=281

+ ps -p 281

+ adbStop

+ stop='input keyevent KEYCODE_BACK; input keyevent KEYCODE_HOME'

+ adb -s 192.168.88.113:5555 shell input keyevent 'KEYCODE_BACK;' input keyevent KEYCODE_HOME

+ sleep 2

+ echo 'Streaming stopped for 192.168.88.113:5555'

+ adbSleep

+ sleep='input keyevent KEYCODE_SLEEP'

+ adb -s 192.168.88.113:5555 shell input keyevent KEYCODE_SLEEP

+ echo 'Sleep initiated for 192.168.88.113:5555'

+ date +%s

+ echo '192.168.88.113/stream_stopped written with epoch stop time'

'

2026/09/08 14:14:09 [EXECUTE] Finished running ./scripts/firetv/dtvstreamdeeplinks/stopbmitune.sh in 6.894563499s

2026/09/08 14:14:09 [GIN-debug] Request: 172.27.0.1 GET /play/tuner/FLARMY~5b2cc61c-32c8-42db-8c2e-ec527e55f1fa, latency: 40.464696268s, status: 200

FastChannels/ah4c integration is working really, really well. If your provider is DTV, Sling or Philo it'd be well worth your time to migrate over (not including those with Ospreys). Here's are few recent screenshots and details:

I'll take my two remaining Onn 4K boxes that I didn't give to my mom and set those up with the bridge.

I do have 3 ENC1-V3's just lying around now :joy:.

Where do I get the APK for this, by the way?

1 Like

When you setup the FastChannels ah4c bridge, you'll see there's a button to install the FC Player. It's all pretty easy.

EDIT: You don't need to bother with downloading scripts/firetv/fastchannels from FastChannels. Those same script will be installed automatically in ah4c when you use that as a STREAMER_APP value. Also, don't forget to set the new FASTCHANNELS_URL env var.

1 Like

May have made a discovery with DirecTV and the Osprey issues related to the HEARTBEAT_INTERVAL. It may no longer be needed more than once. I believe that it could be useful to prevent the box from shutting off after 4 hours if you have the energy saver turned on. So, therefore, it's optional. Therefore, maybe set it to like 3 hours or something like that. But I am testing it now with just sending that key code once in the script.

It's been working so far flawlessly. But if I don't have it in there, it does retune with the blue screen.

The other thing I noticed is the readiness gate that I added is very complex, and seemingly I've been able to also use that key code in place of the readiness gate, and it seems to work as a blocker to prevent the tune from executing too quickly. So I'm going to test that over the weekend, and if it works, I'll submit a PR to update the scripts.

Could also be useful for the Osprey ADB Tuner configs.

not sure it's the latest pushed, but using ah4c v2026.08.28.1306 since released and have had no problems (no heartbeat, only cc) but caught this messup today. (the 356 did not take and cdvr recorded 30mins of accuweather)


I have 2 identical passes with different padding and channel #'s so the tuner is switched every half hour. the only thing ah4c has been recording all day is ch# 356, I actually have not tuned to 361 for weeks. I'm not sure how the osprey got set on 361, and my logs only seem to go back 1.5hr.

edit. closest thing I can think of is the 2 channels in my m3u are 60.356 and 61.356 and this was the 61.356 . that is the only way I can see how a 61 got in there. still doesn't make sense, but :person_shrugging:

Are you on my latest scripts?

Because this is just the Ospreys wigging out. They are. They have been really buggy lately. And there have been reports on Reddit as well. It's not just us.

I've actually like escalated through the ranks of direct TV because I'm pissed off. Not mentioning anything related to channels or anything like that, just the fact that these issues are occurring with the Ospreys and we pay so much for TV service.

There are multiple reports on Reddit of random weird issues like this. I also just found a bug with AH4C if your boxes are asleep and null frame insertion is off. I'm hacking away at a solution, but it's not a simple one.