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

For those dealing with the Cox Spectrum merger, I ported over my PyATV scripts and M3Us yesterday to use the Spectrum Apple TV app instead of the Cox Contour app. They actually are a lot simpler using deep links, which the contour app did not support.

Thank you @ChannelSam for the scripts , but I put in some minor tweaks to make clearer

bmitune:

#!/bin/bash
# Channels DVR invocation contract: bmitune.sh <channelId> <atvHost>
#   $1 = channelId (Gracenote/TMS station ID, from tvc-guide-stationid in M3U)
#   $2 = atvHost    (IP of the Apple TV assigned as this tuner)
channelId="$1"
atvHost="$2"

/usr/local/bin/atvremote --storage-filename /root/.android/.pyatv.conf \
  -s "$atvHost" launch_app="spectrumTV://watch.spectrum.net/livetv/${channelId}"

I had to add force quit logic to the stopbmitune to accommodate multiple tuners and avoid streaming limit errors from spectrum.

stopbmitine:

#!/bin/bash
set -e

# Channels DVR invocation contract: stopbmitune.sh <atvHost> <channelId>
#   $1 = atvHost    (IP of the Apple TV assigned as this tuner)
#   $2 = channelId  (Gracenote/TMS station ID, from tvc-guide-stationid in M3U)
# NOTE: argument order is REVERSED from bmitune.sh - this is the Channels DVR
# pre/stop contract, not a bug. Do not "align" this with bmitune.sh's order.
atvHost="$1"
channelId="$2"

pyatvCredentials="/root/.android/.pyatv.conf"
ATV_CMD="/usr/local/bin/atvremote --storage-filename ${pyatvCredentials} -s ${atvHost}"

# Tunable delays - measure per-ATV, don't assume Cox's timing applies here.
FC_SHORT_DELAY=0.6
SWIPE_PASSES=3   # start smaller than Cox's 5; raise only if one pass isn't enough

echo "📺 Force Quit Spectrum App on ${atvHost} (was tuned to ${channelId})"

echo "🔁 Opening app switcher..."
eval "$ATV_CMD home home" >/dev/null 2>&1 || true
sleep "$FC_SHORT_DELAY"

# NOTE: no "left" press here - Spectrum should already be the frontmost,
# focused card since it's the most-recently-used app on this ATV. If testing
# shows the wrong app gets swiped, that's the signal to add navigation back.

i=1
while [ "$i" -le "$SWIPE_PASSES" ]; do
  echo "🧹 Swiping up to force-quit the app... (Pass $i)"
  eval "$ATV_CMD up up" >/dev/null 2>&1 || true
  sleep "$FC_SHORT_DELAY"
  i=$((i + 1))
done

echo "🏡 Returning to Home Screen..."
eval "$ATV_CMD home" >/dev/null 2>&1 || true
sleep "$FC_SHORT_DELAY"

echo "✅ Spectrum app force-quit, ATV in idle state"

Heres a sample M3U:

#EXTM3U


#EXTINF:-1 channel-id="56905" channel-number="3024" tvg-name="DSCHD" tvc-guide-stationid="56905",Discovery
http://{{ .IPADDRESS }}/play/tuner/56905

#EXTINF:-1 channel-id="59337" channel-number="3025" tvg-name="AMCHD" tvc-guide-stationid="59337",AMC
http://{{ .IPADDRESS }}/play/tuner/59337

#EXTINF:-1 channel-id="59186" channel-number="3026" tvg-name="PARHD" tvc-guide-stationid="59186",Paramount
http://{{ .IPADDRESS }}/play/tuner/59186

#EXTINF:-1 channel-id="58623" channel-number="3032" tvg-name="SYFYHD" tvc-guide-stationid="58623",SYFY
http://{{ .IPADDRESS }}/play/tuner/58623

#EXTINF:-1 channel-id="57708" channel-number="3041" tvg-name="HSTRYHD" tvc-guide-stationid="57708",History
http://{{ .IPADDRESS }}/play/tuner/57708

#EXTINF:-1 channel-id="49788" channel-number="3044" tvg-name="HGTVD" tvc-guide-stationid="49788",HGTV
http://{{ .IPADDRESS }}/play/tuner/49788

#EXTINF:-1 channel-id="60179" channel-number="3046" tvg-name="FNCHD" tvc-guide-stationid="60179",Fox_News
http://{{ .IPADDRESS }}/play/tuner/60179

#EXTINF:-1 channel-id="64241" channel-number="3047" tvg-name="MSNBC" tvc-guide-stationid="16300",MSNOW
http://{{ .IPADDRESS }}/play/tuner/64241

#EXTINF:-1 channel-id="58646" channel-number="3049" tvg-name="CNNHD" tvc-guide-stationid="58646",CNN
http://{{ .IPADDRESS }}/play/tuner/58646

#EXTINF:-1 channel-id="58812" channel-number="3051" tvg-name="WEATHHD" tvc-guide-stationid="58812",The_Weather_Channel
http://{{ .IPADDRESS }}/play/tuner/58812

#EXTINF:-1 channel-id="58574" channel-number="3053" tvg-name="FXHD" tvc-guide-stationid="58574",FX
http://{{ .IPADDRESS }}/play/tuner/58574

#EXTINF:-1 channel-id="62420" channel-number="3058" tvg-name="CCHD" tvc-guide-stationid="62420",Comedy_Central
http://{{ .IPADDRESS }}/play/tuner/62420

#EXTINF:-1 channel-id="68344" channel-number="3076" tvg-name="CSPANHD" tvc-guide-stationid="68344",C-SPAN
http://{{ .IPADDRESS }}/play/tuner/68344

#EXTINF:-1 channel-id="49438" channel-number="3083" tvg-name="NGCHD" tvc-guide-stationid="49438",National_Geographic
http://{{ .IPADDRESS }}/play/tuner/49438

#EXTINF:-1 channel-id="66268" channel-number="3090" tvg-name="HALLHD" tvc-guide-stationid="66268",HALLMARK
http://{{ .IPADDRESS }}/play/tuner/66268

#EXTINF:-1 channel-id="46710" channel-number="3091" tvg-name="HMMHD" tvc-guide-stationid="46710",Hallmark_Movies_Mysteries
http://{{ .IPADDRESS }}/play/tuner/46710

#EXTINF:-1 channel-id="57390" channel-number="3100" tvg-name="SCIHD" tvc-guide-stationid="57390",Science
http://{{ .IPADDRESS }}/play/tuner/57390

#EXTINF:-1 channel-id="64492" channel-number="3158" tvg-name="BBCAHD" tvc-guide-stationid="64492",BBC_America
http://{{ .IPADDRESS }}/play/tuner/64492

@bnhf just flagging you in case you want to add these tweaks for these scripts into the latest repo.

Im going to built a completely new container from scratch and test the appletv pairing and script deployment using fastchannels , etc within a day or two, Can we push these latest scripts into the repo? Then Ill test everything with a totally new host directory and keep my old "production" tuner suspended while I test all the new changes.

Actually, the latest scripts/atv/spectrum in the repo are only from August, and were from @PSPS as shown here:

@PSPS reported these scripts were working well for him at the time, so maybe we can get some quick coordination on this? I hate to replace working scripts, unless there's a proven reason.

1 Like

Blame uncle Claude!!! :rofl:

2 Likes

Thanks for pointing this out. I was using a old spectrum scripts that were hanging around on my system since June of 2025 and had to tweak them. I'll take a look at the @PSPS scripts. Hopefully they dont have any emojis @anon38303228

I will test this with the new container deployment in a totally new HOSTDIR area on my machine I can test up to beta4 release easily in my portainer/docker Mac environment within the next few days. Happy to stress test everything.

Are there significant changes pending? I dont have the whole repo cloned here, Ive been using the docker/portainer method to deploy. I can start looking into cloning the repo and all that but am stretched thin here for the next few days and defiantly dont want to break my working production tuners..... Is there a workaround within portainer/docker to deploy what @anon38303228 has released that is after beta4

Otherwise I have a learning curve with uncle Claude on how to grab the full repo locally here without portainer - which has made life incredibly easy, but Id prefer not to have Claude drag me down into a rabbit hole and break my production tuners (lol) . No emoji.

I spent a number of hours trying to figure out a way to make the View & control feature work with "virtual encoders" (Capture Cards with a CDVR Custom Source transcoding their streams), but was unable to make any meaningful progress.

For some reason the viewer starts displaying the virtual encoder output, but then quickly decides it's no good and grays it out, followed by a spinning circle.

It's not a huge deal for me, but as more people discover just how fab the FastChannels ah4c bridge is, I think we'll see more new users wanting to manage multiple Capture Card solutions using ah4c.

Anyway, if you're up for yet another challenge :slight_smile:, it'd be great if you could take a look at this -- as I'm sure it'll come-up as an issue in the future otherwise.

You could use a $10 one, or if you DM me your shipping address, I'll have Amazon ship a slightly nicer $25 one to you -- the same one I'm using. I'm passing a couple of these through to a Channels DVR LXC, so they play nice with Linux:

https://www.amazon.com/dp/B097DKNS1M

And, I can walk you through the process either for Windows or Linux. In fact, my Proxmox write-up on installing these would probably be close to what you'd need:

I know right? FastChannels is a no-go for using sub-channels, so I've been living with not having DTV numbering. My current plan is try the @babsonnexus Playlist Manager, as I believe that would work well for getting the channel numbers as we'd like them, plus allowing for seamless multiple source fallback.

I worked on a FastChannels PR for a bit, on this very subject -- but, abandoned it once the scope of the change became apparent. It only made sense to me if we could match the approach we used in ah4c (or ADBTuner and APITuner for that matter), by converting duplicate channel numbers to sub-channels. The duplicate channel number problem is even worse for DTV Satellite customers.

I think PLM can handle this without requiring a significant change to FastChannels, with the added bonus of having a queue of sources to fallback on.

That wouldn't be difficult to implement, other than keeping up with line-up changes. FastChannels does this for you, so the trick would be to come-up with a mechanism so one didn't have to do this manually.

OK. I've deployed your new stack.

The Apple TV pairing is freakin awesome! I just used VLC to monitor the pairing codes from my two Apple TVs. One possible improvement during pairing of the Apple TV, and possibly even for adb pairing as well. Could you open the same encoder streaming window that you use in the activity and logs tuner "view and control". Then you wouldn't even need VLC to view the displays in another room, or need to use the linkpi dashboard.

After some fumbling I was able to load my custom M3U. Once I did that I didnt even have to change anything in Channels DVR - it found the correct M3U and opened the tuner and tuned to a channel after a ton of delay.

Ive got two tuners running in Channels Multiview.

However @bnhf, the spectrum script files need to be looked at. I am not using sleep at all on my ATVs, they are always on. I noticed that the channels tuned with a lot of delay, and the stopbmitune didnt work at all.

When I shoehorned in my working scripts that I posted above, my system tunes lightning fast.

Please advise on the scripts.

Is there anything else you need me to stress test @anon38303228 ?

It seems odd these were reported as working a little over a month ago, but if you're confident they don't, I'll swap them out for yours.

EDIT: I'm not seeing your prebmitune.sh...

Mine is just the null empty prebmitune.sh

#!/bin/bash

# Nothing needed in this file!

What im wondering about is the “wake from sleep” issue. If others need that functionality then the tuning scripts i posted above wont work for them. Mine assume always on ATV. The force quit takes less than a second, and the tuning is almost as fast as a standard native 6xxx channels DVR TVE tuning , but using the spectrum app.

edit:

Give me some time to look at the scripts from last month , and continue to stress test the new container deployment . Perhaps. I can modify to have both sleep and always on usage incorporated.

Lesson #1:
After uploading m3u, ensure to toggle the Update Sample m3u's to No. But the good news was that it's real easy to re-upload m3u's. Perhaps a future update will pop up a warning after the m3u is updated or changes the value to No.

Guide Issues:
This is probably due to me also having an Osprey ah4c source in Channels.
The guide populates fine on the webui. On clients, the choice is to stack duplicates by either Channel number or guide data. If you select Channel number all show up and channels guide shows all options and you get additional (repetitive) channels showing in the guide. If you stack by guide data, none of the channels in the new source show up because they are duplicates of existing channels of a higher priority.

My quick idea was to just create a new collection to test. After adding the new encoder channels to the collection, they show as correct then switch to the higher priority source channels.

This is not really a concern since I'll add another stick and move to test the FC ah4c bridge. @bnhf Should I expect a similar experience with FC.

@anon38303228 Your redesign and simplicity is superb. This will make life easy for those who don't understand how to use environmental variables but like webui's.

1 Like

is this a production issue or testing issue? is there a reason when watching tv to pick the source of the channel?
if your just trying to view a channel from a specific source for testing purposes you'll have to disable the sources you don't want for that client (via client or webui)
not sure if your workstation is a mac or pc, but there are a few client apps for windows made by the community and DVRDesk will let you pick the source although I think it will fall back to other sources if the one you pick fails.

:point_up: ditto also for those who do, but still like webui's :slight_smile:

1 Like

Perfect! been on my todo list, but now it's next if I don't have to reread those threads first! but it's late, so not now..

I thought that was a IDtenT error. :rofl:

It's a little of both. I'm trying to test and keep the wife happy. Adjusting the source priority at the client appears to fix the issue. Disabling the Osprey at this time is a no-go as the new source is tuner limited (1).

I tried out the pair button with preview. Bravo. I couldnt test the wizard, because I already had the tuners paired. But I was able to create a new tuner and pair with my front of house Apple TV. Very slick interface, I love it.

Hate to open a can of worms for ya. but when I enabled closed captioning, Im observing long delays again ( 10 seconds vs 4 on my production tuner) using the same parakeet model and default settings. Ive confirmed this by going back to my production container and tuning to the same channel. Not sure what's going on there. The only difference, is my production container has all the models downloaded when I played around with all of them. On this new release I only downloaded the CPU and the parakeet default models.

I also tried having ah4c add the custom source directly into channels, that worked nicely and is a great feature.

bnhf/ah4c:beta5 pushed this morning including all current PRs from @anon38303228 as of this posting, plus update atv/spectrum scripts from @mnwxman132

1 Like

If this question addressed to me, Ive always used CPU only. Im on apple silicon Mac.