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

The tuning script is called for each of the four tuners on the card this way:

If I send the tuning command from bmitune.sh and leave the CMD field empty would that mess how ah4c is able to switch from one tuner to the next?

Here is a sample of the m3u that bmitune.sh is calling to. There is one of each tuning source (Directv, YoutubeTV, and Hbo Max app):

#EXTM3U

#EXTINF:-1 channel-id="202" channel-number="202" tvc-guide-stationid="58646" tvg-group="" tvg-logo="",CNN HD
http://{{ .IPADDRESS }}/play/tuner/dtvCNNHD~d3603aea-f5d8-e789-786c-43c5e8799428
#EXTINF:-1 channel-id="#277" channel-number="277" tvc-guide-stationid="11871" tvg-group="" tvg-logo="",ACC
#http://{{ .IPADDRESS }}/play/tuner/ytv277~YaqNgmedD7U?onboard=1
#EXTINF:-1 channel-id="818" channel-number="818" tvc-guide-stationid="" tvg-group="" tvg-logo="",HBOCOM
http://{{ .IPADDRESS }}/play/tuner/max818

Like is said, I had to revert to the contentID method for the max app because either the length of the deep link or the "/" that appears in it does not allow it to be read from the m3u file.

Apologies, but I don't recognize this UI. Where is this from?

But I get the idea -- these are the CMD1, CMD2 environment variables. Let me ponder this briefly, and I'll get back to you.

The picture is from is the "Edit ENV Configuration & tuners" page from the ah4c web interface.

I am using the non docker version.

The only way I can see out is to have a clunky script for each provider in the same way I have a TuneMaxApp.sh for hbo that takes care of the welcome screen.

I don't think that'll be necessary. I re-wrote your bmitune.sh script to clean it up, and add a new concept or two. It writes the desired sleep time to a file, with directories named by tuner IP.

I also re-worked your M3U, using another tilde(~) to better handle the data. Also, I URL encoded the slash(/) in your Max contentID value (using a %2F), which should allow it to be passed into the script. Then I URL decoded it to send via ADB.

bmitune.sh:

#!/bin/bash

provider=$(echo $1 | awk -F~ '{print $1}')
callSign=$(echo $1 | awk -F~ '{print $2}')
contentID=$(echo $1 | awk -F~ '{print $3}')
tunerIP="$2"
tunerNoPort="${tunerIP%%:*}"
    mkdir -p $tunerNoPort
adbTarget="adb -s $tunerIP shell am start -a android.intent.action.VIEW -d  "

# Adjust the desired sleep times by provider
declare -A sleepTime=(
  [dtv]=15
  [max]=15
  [yttv]=15
)

echo "${sleepTime[$provider]}" > $tunerNoPort/tune_sleep 

case "$provider" in
    "dtv")
        $adbTarget dtvnow://deeplink.directvnow.com/play/channel/$callSign/$contentID
        ;;
    "max")
        $adbTarget https://play.max.com/channel/watch/$(printf '%b\n' "${contentID//%/\\x}")
        ;;
    "yttv")
        $adbTarget https://tv.youtube.com/watch/$contentID?onboard=1 -n com.google.android.youtube.tvunplugged/com.google.android.apps.youtube.tvunplugged.activity.MainActivity
        ;;
    *)
        exit 1
        ;;
esac

magewell.m3u:

#EXTM3U

#EXTINF:-1 channel-id="202" channel-number="202" tvc-guide-stationid="58646" tvg-group="" tvg-logo="",CNN HD
http://{{ .IPADDRESS }}/play/tuner/dtv~CNNHD~d3603aea-f5d8-e789-786c-43c5e8799428

#EXTINF:-1 channel-id="277" channel-number="277" tvc-guide-stationid="11871" tvg-group="" tvg-logo="",ACC
http://{{ .IPADDRESS }}/play/tuner/yttv~~YaqNgmedD7U

#EXTINF:-1 channel-id="818" channel-number="818" tvc-guide-stationid="" tvg-group="" tvg-logo="",HBOCOM
http://{{ .IPADDRESS }}/play/tuner/max~~a903ca8a-6d5e-559b-a027-f82997397694%2F452e5d78-1cca-59a9-8508-21b25d813874

Then, rather than using an input1.sh script, I would use this directly in the CMD field (adjust by tuner #):

{ sleep $(cat 192.168.1.130/tune_sleep); bash -c "magewell2ts -i 1 -s 100 -q 12 -c h264_qsv -m "; }

This all needs to be tested of course!

Will try this out when I wake up later today and report back.

I get this for each channel on the three channels.

[START] ah4c is ready
[GIN-debug] Listening and serving HTTP on :7654
[GIN-debug] Request: 127.0.0.1 POST /configsave, latency: 158.507µs, status: 301
[GIN-debug] Request: 127.0.0.1 GET /config, latency: 1.040241ms, status: 200
Attempting network tune for device  192.168.1.130:5555 yttv~~YaqNgmedD7U 
[ERR] Failed to fetch source: Get "": unsupported protocol scheme ""
Attempting network tune for device  192.168.1.131:5555 yttv~~YaqNgmedD7U 
[ERR] Failed to fetch source: Get "": unsupported protocol scheme ""
[ERR] Failed to tune device(s) not available
[GIN-debug] Request: 192.168.1.188 GET /play/tuner/yttv~~YaqNgmedD7U, latency: 108.19µs, status: 500
Attempting network tune for device  192.168.1.130:5555 yttv~~YaqNgmedD7U 
[ERR] Failed to fetch source: Get "": unsupported protocol scheme ""
Attempting network tune for device  192.168.1.131:5555 yttv~~YaqNgmedD7U 
[ERR] Failed to fetch source: Get "": unsupported protocol scheme ""
[ERR] Failed to tune device(s) not available
[GIN-debug] Request: 192.168.1.188 GET /play/tuner/yttv~~YaqNgmedD7U, latency: 176.372µs, status: 500
[GIN-debug] Request: 192.168.1.188 GET /play/tuner/max~~a903ca8a-6d5e-559b-a027-f82997397694%2F452e5d78-1cca-59a9-8508-21b25d813874, latency: 430ns, status: 404
[GIN-debug] Request: 192.168.1.188 GET /play/tuner/max~~a903ca8a-6d5e-559b-a027-f82997397694%2F452e5d78-1cca-59a9-8508-21b25d813874, latency: 992ns, status: 404

Narrowed the issue down to the command for tuning.

{ sleep $(cat 192.168.1.130/tune_sleep); bash -c "magewell2ts -i 1 -s 100 -q 12 -c h264_qsv -m "; }

ah4c does not like this. It spits out this when I try to load it with that command in place:

christophe@christophe:~/ah4c$ ./androidhdmi-for-channels 
[START] ah4c is starting
[ENV] Loading env
[ENV] IPADDRESS                  
[ENV] ALERT_SMTP_SERVER          
[ENV] ALERT_AUTH_SERVER          
[ENV] ALERT_EMAIL_FROM           
[ENV] ALERT_EMAIL_PASS           
[ENV] ALERT_EMAIL_TO             
[ENV] ALERT_WEBHOOK_URL          
[ENV] ALLOW_DEBUG_VIDEO_PREVIEW  
panic: Could not find an environment variable named NUMBER_TUNERS

goroutine 1 [running]:
main.loadenv()
	/home/christophe/ah4c/main.go:967 +0xd0f
main.main()
	/home/christophe/ah4c/main.go:1008 +0x2b

I have resorted to simply this for debugging:

magewell2ts -i 1 -s 100 -q 12 -c h264_qsv -m

So far dtv and yttv works but hbo is still not picked up. I still get a "status : 404" when it tries to read the m3u:

[GIN-debug] Request: 192.168.1.188 GET /play/tuner/max~~a903ca8a-6d5e-559b-a027-f82997397694%2F452e5d78-1cca-59a9-8508-21b25d813874, latency: 594ns, status: 404
[GIN-debug] Request: 192.168.1.188 GET /play/tuner/max~~a903ca8a-6d5e-559b-a027-f82997397694%2F452e5d78-1cca-59a9-8508-21b25d813874, latency: 982ns, status: 404

I'll play around with putting multiple shell commands into CMD when I have a chance, but in the meantime putting them in a script is fine too.

The good news here is that the full content ID value is being passed, but the URL encoding/decoding isn't working.

I think it's safe to say that these are actually two values, given the presence of the slash (aka a separator), much like DTV requires two values.

So I'd propose replacing that slash with another tilde, and adjusting the script as follows:

#!/bin/bash

provider=$(echo $1 | awk -F~ '{print $1}')
callSign=$(echo $1 | awk -F~ '{print $2}')
contentID=$(echo $1 | awk -F~ '{print $3}')
contentID2=$(echo $1 | awk -F~ '{print $4}')
tunerIP="$2"
tunerNoPort="${tunerIP%%:*}"
    mkdir -p $tunerNoPort
adbTarget="adb -s $tunerIP shell am start -a android.intent.action.VIEW -d  "

# Adjust the desired sleep times by provider
declare -A sleepTime=(
  [dtv]=15
  [max]=15
  [yttv]=15
)

echo "${sleepTime[$provider]}" > $tunerNoPort/tune_sleep 

case "$provider" in
    "dtv")
        $adbTarget dtvnow://deeplink.directvnow.com/play/channel/$callSign/$contentID
        ;;
    "max")
        $adbTarget https://play.max.com/channel/watch/$contentID/$contentID2
        ;;
    "yttv")
        $adbTarget https://tv.youtube.com/watch/$contentID?onboard=1 -n com.google.android.youtube.tvunplugged/com.google.android.apps.youtube.tvunplugged.activity.MainActivity
        ;;
    *)
        exit 1
        ;;
esac

With the M3U adjusted to remove the URL encoded slash, and using a tilde instead:

#EXTM3U

#EXTINF:-1 channel-id="202" channel-number="202" tvc-guide-stationid="58646" tvg-group="" tvg-logo="",CNN HD
http://{{ .IPADDRESS }}/play/tuner/dtv~CNNHD~d3603aea-f5d8-e789-786c-43c5e8799428

#EXTINF:-1 channel-id="277" channel-number="277" tvc-guide-stationid="11871" tvg-group="" tvg-logo="",ACC
http://{{ .IPADDRESS }}/play/tuner/yttv~~YaqNgmedD7U

#EXTINF:-1 channel-id="818" channel-number="818" tvc-guide-stationid="" tvg-group="" tvg-logo="",HBOCOM
http://{{ .IPADDRESS }}/play/tuner/max~~a903ca8a-6d5e-559b-a027-f82997397694~452e5d78-1cca-59a9-8508-21b25d813874

In addition to the above bmitune.sh and M3U changes, try this approach in the CMD field:

"bash -c 'sleep $(cat 192.168.1.130/tune_sleep); magewell2ts -i 1 -s 100 -q 12 -c h264_qsv -m '"

It's working with the command and with the adjustment to the m3u for hbo.

I had to put the declared times between quotation marks before they registered. The tune_sleep file was coming up empty until I did that.

I am testing with vlc and I notice that the delay doesnt always work after a fresh restart of ah4c. Testing a bit more for consistency.

#!/bin/bash

provider=$(echo $1 | awk -F~ '{print $1}')
callSign=$(echo $1 | awk -F~ '{print $2}')
contentID=$(echo $1 | awk -F~ '{print $3}')
contentID2=$(echo $1 | awk -F~ '{print $4}')
tunerIP="$2"
tunerNoPort="${tunerIP%%:*}"
    mkdir -p $tunerNoPort
adbTarget="adb -s $tunerIP shell am start -a android.intent.action.VIEW -d  "

# Adjust the desired sleep times by provider
declare -A sleepTime=(
  [dtv]="8"
  [max]="15"
  [yttv]="5"
)

echo "${sleepTime[$provider]}" > $tunerNoPort/tune_sleep 

case "$provider" in
    "dtv")
        $adbTarget dtvnow://deeplink.directvnow.com/play/channel/$callSign/$contentID
        ;;
    "max")
        $adbTarget https://play.max.com/channel/watch/$contentID/$contentID2 && sh maxhello.sh $tunerIP
        ;;
    "yttv")
        $adbTarget https://tv.youtube.com/watch/$contentID?onboard=1 -n com.google.android.youtube.tvunplugged/com.google.android.apps.youtube.tvunplugged.activity.MainActivity
        ;;
    *)
        exit 1
        ;;
esac

Cool. What are you doing in maxhello.sh?

maxhello gets rid of the profile screen for the hbo app.

#!/bin/bash

adb -s $1 shell input keyevent 19
adb -s $1 shell input keyevent 19
adb -s $1 shell input keyevent 19
adb -s $1 shell input keyevent 19
adb -s $1 shell input keyevent 19
adb -s $1 shell input keyevent 19
sleep 6
adb -s $1 shell input keyevent 62
adb -s $1 shell input keyevent 66

Basically lots of spamming then pressing the select key.