ADBTuner: A "channel tuning" application for networked Google TV / Android TV devices

Back in the USA now, so I was able to test this out. And, with a fully up-to-date FireStick 4K Max (2nd Gen), I had no problem connecting via Ethernet with ADB enabled. It worked with this stick 3 months ago before left, and it still works now.

I have 4 Firesticks attached to a switch using Ethernet with ADB enabled and plugged into my encoder.

Ok thanks . Can it be used with other apps like kodi , vlc etc without channels installed?

Yes, same with me.

The implication I was trying to address is that the "latest" FireSticks (which I assume to mean the 4K Max Gen 2 units) had the same failing as the onn 4K sticks as far as ADB and Ethernet being mutually exclusive. This is not the case, at least in my testing.

Are the sticks you mentioned above Gen 2?

1 Like

Those are 4K Max's I have a 4KMAX 2nd Gen hooked up to my TV with ethernet and ADB enabled ... which I also use for ADB command testing.

I don't see why not. I just tried one of the virtual channel URLs from my ah4c M3U in VLC, and it both tuned and played fine.

EDIT: Everything looks as per usual in the docker container log as well:

Attempting network tune for device http://encoder_48007/0.ts firestick-rack1:5555 8 
[EXECUTE] Running [./scripts/firetv/directv/prebmitune.sh firestick-rack1:5555]
[EXECUTE] Stdout: 'already connected to firestick-rack1:5555
Starting: Intent { cmp=com.att.tv/com.clientapp.MainActivity }
Starting com.att.tv on 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=25
+ local -i adbCounter=0
+ true
+ adb -s firestick-rack1:5555 shell input keyevent KEYCODE_WAKEUP
+ local adbEventSuccess=0
+ [[ 0 -eq 0 ]]
+ break

e
+ packageLaunch=com.clientapp.MainActivity
+ packageName=com.att.tv
++ adb -s firestick-rack1:5555 shell pidof com.att.tv
+ packagePID=
+ '[' '!' -z ']'
+ adb -s firestick-rack1:5555 shell input keyevent KEYCODE_WAKEUP
+ adb -s firestick-rack1:5555 shell am start -n com.att.tv/com.clientapp.MainActivity
+ echo 'Starting com.att.tv on firestick-rack1:5555'
+ finish
+ echo 'prebmitune.sh is exiting for firestick-rack1:5555 with exit code 0'
'
[EXECUTE] Finished running ./scripts/firetv/directv/prebmitune.sh in 2.346058621s
[EXECUTE] Running [./scripts/firetv/directv/bmitune.sh 8 firestick-rack1:5555]
[EXECUTE] Stdout: 'Current PID for this script is 1117
Not a special channel (exit nor reboot)
Current app in focus is mCurrentFocus=null
Active audio stream not yet detected -- loudness is -70.0 LUF. Continuing...
Active audio stream not yet detected -- loudness is -70.0 LUF. Continuing...
Active audio stream not yet detected -- loudness is -70.0 LUF. Continuing...
Active audio stream detected with -21.5 LUF.
Active audio stream detected with -20.3 LUF.
bmitune.sh is exiting for firestick-rack1:5555 with exit code 0
'
[EXECUTE] Stderr: '+ channelID='"8"'
+ specialID=8
+ streamerIP=firestick-rack1:5555
+ streamerNoPort=firestick-rack1
+ adbTarget='adb -s firestick-rack1:5555'
+ packageName=com.att.tv
+ m3uName=directv.m3u
+ trap finish EXIT
+ main
+ updateReferenceFiles
+ mkdir -p firestick-rack1
+ [[ -f firestick-rack1/stream_stopped ]]
+ [[ -f firestick-rack1/last_channel ]]
+ echo 1117
+ echo 'Current PID for this script is 1117'
+ matchEncoderURL
+ case "$streamerIP" in
+ encoderURL=http://encoder_48007/0.ts
+ specialChannels
+ '[' 8 = exit ']'
+ '[' 8 = reboot ']'
+ [[ -f firestick-rack1/adbCommunicationFail ]]
+ echo 'Not a special channel (exit nor reboot)'
++ adb -s firestick-rack1:5555 shell dumpsys window windows
++ grep -E mCurrentFocus
++ cut -d / -f1
++ sed 's/.* //g'
+ appFocus=mCurrentFocus=null
+ echo 'Current app in focus is mCurrentFocus=null'
+ launchDelay
+ local lastChannel
+ local lastAwake
+ local timeNow
+ local timeElapsed
+ local maxTime=14400
+ lastChannel=217
+ lastAwake=1706101203
++ date +%s
+ timeNow=1706138398
+ timeElapsed=37195
+ ((  217 == 8  ))
+ '[' -f firestick-rack1/adbAppRunning ']'
+ ((  37195 < 14400  ))
+ activeAudioCheck 42 true 0 1
++ date +%s
+ local startTime=1706138398
+ local maxDuration=42
+ local minimumLoudness=-50
+ local sleepBeforeAudioCheck=0
+ local sleepAfterAudioCheck=1
+ local preTuneAudioCheck=true
+ true

0
++ ffmpeg -t 1 -i http://encoder_48007/0.ts -filter:a ebur128 -map 0:a -f null -hide_banner -
++ awk '/I:        /{print $2}'
+ checkLoudness=-70.0
++ date +%s
+ ((  1706138404 - 1706138398 > 42  ))
++ echo '-70.0 > -50'
++ bc -l
+ ((  0  ))
+ echo 'Active audio stream not yet detected -- loudness is -70.0 LUF. Continuing...'

1
+ true

0
++ ffmpeg -t 1 -i http://encoder_48007/0.ts -filter:a ebur128 -map 0:a -f null -hide_banner -
++ awk '/I:        /{print $2}'
+ checkLoudness=-70.0
++ date +%s
+ ((  1706138410 - 1706138398 > 42  ))
++ echo '-70.0 > -50'
++ bc -l
+ ((  0  ))
+ echo 'Active audio stream not yet detected -- loudness is -70.0 LUF. Continuing...'

1
+ true

0
++ ffmpeg -t 1 -i http://encoder_48007/0.ts -filter:a ebur128 -map 0:a -f null -hide_banner -
++ awk '/I:        /{print $2}'
+ checkLoudness=-70.0
++ date +%s
+ ((  1706138416 - 1706138398 > 42  ))
++ echo '-70.0 > -50'
++ bc -l
+ ((  0  ))
+ echo 'Active audio stream not yet detected -- loudness is -70.0 LUF. Continuing...'

1
+ true

0
++ ffmpeg -t 1 -i http://encoder_48007/0.ts -filter:a ebur128 -map 0:a -f null -hide_banner -
++ awk '/I:        /{print $2}'
+ checkLoudness=-21.5
++ date +%s
+ ((  1706138423 - 1706138398 > 42  ))
++ echo '-21.5 > -50'
++ bc -l
+ ((  1  ))
+ echo 'Active audio stream detected with -21.5 LUF.'
+ break
+ echo 8
+ tuneChannel
++ awk -F, '/channel-id="8"/ {print $2}' m3u/directv.m3u
+ channelName='KAET PBS 8'
++ echo KAET PBS 8
++ sed 's/^/"/;s/$/"/'
+ channelName='"KAET PBS 8"'
+ numberOfBackspaces=25

++ (( i=0 ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
++ echo -n ' KEYCODE_MEDIA_REWIND'

++ (( i++ ))
++ (( i<25 ))
+ clearSearchBackspaces=' KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND'
+ directvMenu='input keyevent KEYCODE_MENU; sleep 6'
+ directvSearch='input keyevent KEYCODE_DPAD_LEFT;                  input keyevent KEYCODE_DPAD_UP;                  input keyevent KEYCODE_DPAD_CENTER; sleep 1;                  input keyevent KEYCODE_DPAD_CENTER; sleep 1'
+ directvClearSearch='input keyevent KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND'
+ directvTune='input keyevent KEYCODE_MEDIA_PLAY_PAUSE; sleep 1;                input keyevent KEYCODE_DPAD_DOWN;                input keyevent KEYCODE_DPAD_DOWN;                input keyevent KEYCODE_DPAD_DOWN;                input keyevent KEYCODE_DPAD_CENTER'
+ adb -s firestick-rack1:5555 shell input keyevent 'KEYCODE_MENU;' sleep 6
+ adb -s firestick-rack1:5555 shell input keyevent 'KEYCODE_DPAD_LEFT;' input keyevent 'KEYCODE_DPAD_UP;' input keyevent 'KEYCODE_DPAD_CENTER;' sleep '1;' input keyevent 'KEYCODE_DPAD_CENTER;' sleep 1
+ adb -s firestick-rack1:5555 shell input keyevent KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND KEYCODE_MEDIA_REWIND
+ adb -s firestick-rack1:5555 shell input text '"KAET PBS 8"'
+ adb -s firestick-rack1:5555 shell input keyevent 'KEYCODE_MEDIA_PLAY_PAUSE;' sleep '1;' input keyevent 'KEYCODE_DPAD_DOWN;' input keyevent 'KEYCODE_DPAD_DOWN;' input keyevent 'KEYCODE_DPAD_DOWN;' input keyevent KEYCODE_DPAD_CENTER
+ activeAudioCheck 24 false 5 1
++ date +%s
+ local startTime=1706138445
+ local maxDuration=24
+ local minimumLoudness=-50
+ local sleepBeforeAudioCheck=5
+ local sleepAfterAudioCheck=1
+ local preTuneAudioCheck=false
+ true

5
++ ffmpeg -t 1 -i http://encoder_48007/0.ts -filter:a ebur128 -map 0:a -f null -hide_banner -
++ awk '/I:        /{print $2}'
+ checkLoudness=-20.3
++ date +%s
+ ((  1706138455 - 1706138445 > 24  ))
++ echo '-20.3 > -50'
++ bc -l
+ ((  1  ))
+ echo 'Active audio stream detected with -20.3 LUF.'
+ break
+ finish
+ echo 'bmitune.sh is exiting for firestick-rack1:5555 with exit code 0'
'
[EXECUTE] Finished running ./scripts/firetv/directv/bmitune.sh in 56.781617415s
[IO] io.Copy: write tcp 192.168.176.2:7654->192.168.176.1:56051: write: broken pipe
[IOINFO] Successfully copied 15006764 bytes
[IOINFO] Transfer speed: 1.5912688629305276 Mbits/second
Performing Close() for firestick-rack1:5555
[EXECUTE] Running [./scripts/firetv/directv/stopbmitune.sh firestick-rack1:5555]
[EXECUTE] Stdout: 'Streaming stopped for firestick-rack1:5555
Sleep initiated for firestick-rack1:5555
firestick-rack1/stream_stopped written with epoch stop time
'
[EXECUTE] Stderr: '+ streamerIP=firestick-rack1:5555
+ streamerNoPort=firestick-rack1
+ adbTarget='adb -s firestick-rack1:5555'
+ main
+ bmituneDone
+ bmitunePID=1117

+ ps -p 1117

p
+ stop='input keyevent KEYCODE_HOME'
+ adb -s firestick-rack1:5555 shell input keyevent KEYCODE_HOME

2
+ echo 'Streaming stopped for firestick-rack1:5555'
+ adbSleep
+ sleep='input keyevent KEYCODE_SLEEP'
+ adb -s firestick-rack1:5555 shell input keyevent KEYCODE_SLEEP
+ echo 'Sleep initiated for firestick-rack1:5555'
+ date +%s
+ echo 'firestick-rack1/stream_stopped written with epoch stop time'
'
[EXECUTE] Finished running ./scripts/firetv/directv/stopbmitune.sh in 3.668481385s
[GIN-debug] Request: 192.168.176.1 GET /play/tuner/8, latency: 1m21.5179651s, status: 200

EDIT2: @Bossmann If you want to discuss this further, let's move this discussion over to the hdmi for channels thread:

1 Like

I tried the ADBTUNER With EMBY Nextpvr and it worked on them ... great piece of software.

Is there an easy way to find the package name of an app? I've been trying to get the npo app to open with adbtuner but haven't been able to do it.

you got to extract the apk file and look inside the AndroidManifest.xml for that

Run the following from a shell first, then launch the app on your streaming device:

adb logcat | grep "ActivityManager: START.*cmp="

You should log line output that will show the package name.

More importantly though, do you know if the app you're trying to use supports deep links?

The “select from installed” option should show all of the installed apps. Is this not working?

Thanks, Today the select from Installed is working, it wasn't working yesterday for some reason. Anyway, I did find the app, but adbtuner is not opening it. Now I wonder if the link is not correct. Back to the drawing board :slight_smile:

That really does not show what to launch all the time for example XFINITY ... The Cmd @bnhf posted is how I found what to launch.

image

This is what I launch ....
'


That's true, but ADBTuner will trigger the default activity for the defined scheme/host which is correct 99% of the time and a good starting point for someone looking into a new app. Often if you need to specify the activity you are using the wrong URL or scheme.

This one is interesting, because based on the android manifest for that package what you are doing should just open the app as the action triggered by that activity is android.intent.action.MAIN instead of android.intent.action.VIEW.

There are activities for /stream/live and /stream/watch (com.xfinity.cloudtvr.tenfoot.deeplinkingFull) that should just work, but they seem to be restricted in some way? It seems that you might have found a clever workaround, but getting this far into the weeds as a starting point is not recommended.

Filtering the logs that way is helpful if you are opening the app using Google's grid guide as that is what we are looking to duplicate. It will get you the package name regardless, but the activity used internally when manually using the app isn't guaranteed to be correct for external links.

adb shell dumpsys package <package name> will get you some helpful information in the Activity Resolver section under Schemes. If the scheme (ex https), domain (Authority here), and path match, the action specified will automatically be triggered.

I don't have the Comcast app, but an example:


$ adb shell dumpsys package com.google.android.youtube.tvunplugged

Activity Resolver Table:
  Schemes:
      http:
        5c2acc0 com.google.android.youtube.tvunplugged/com.google.android.apps.youtube.tvunplugged.activity.MainActivity filter e20713e
          Action: "android.intent.action.VIEW"
          Action: "android.media.action.MEDIA_PLAY_FROM_SEARCH"
          Category: "android.intent.category.DEFAULT"
          Category: "android.intent.category.BROWSABLE"
          Scheme: "http"
          Scheme: "https"
          Authority: "tv.youtube.com": -1
          Path: "PatternMatcher{GLOB: .*}"
      https:
        5c2acc0 com.google.android.youtube.tvunplugged/com.google.android.apps.youtube.tvunplugged.activity.MainActivity filter e20713e
          Action: "android.intent.action.VIEW"
          Action: "android.media.action.MEDIA_PLAY_FROM_SEARCH"
          Category: "android.intent.category.DEFAULT"
          Category: "android.intent.category.BROWSABLE"
          Scheme: "http"
          Scheme: "https"
          Authority: "tv.youtube.com": -1
          Path: "PatternMatcher{GLOB: .*}"
        5c2acc0 com.google.android.youtube.tvunplugged/com.google.android.apps.youtube.tvunplugged.activity.MainActivity filter a454b9f
          Action: "com.google.android.gms.cast.tv.action.LAUNCH"
          Category: "android.intent.category.DEFAULT"
          Scheme: "https"
          Authority: "www.youtube.com": -1
          Path: "PatternMatcher{GLOB: .*}"

This is what I get ...

Can't find service: com.xfinity.cloudtvr.tenfoot

I guess you are on FireTV since you have the Xfinity app? I wonder if this command isn't available on that version of Android. I will check later. I know you have a working solution, but honestly I'm just curious why it's working the way it is lol.

It took me a lot of trial and error to get XFINITY to work. Yes on FireTV only Android that has XFINITY APP.

I have no idea, but I'm about to try out that command to see what is going on when I open that app. Thanks.

So, apparently I did have the package name correct. Here's what the log showed:
01-25 14:42:05.659 617 684 I ActivityTaskManager: START u0 {act=android.intent.action.VIEW dat=https://npo.nl/... flg=0x10000000 pkg=nl.uitzendinggemist} from uid 2000
Then there was something else:
Line 3347: 01-25 15:09:55.996 617 1038 I ActivityTaskManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LEANBACK_LAUNCHER] flg=0x10000000 pkg=nl.uitzendinggemist cmp=nl.uitzendinggemist/.tv.presentation.splash.StartupActivity (has extras)} from uid 10052

So you think I should use the one with the ./tv.presentation link?

This is what you would normally use, but @Edwin_Perez might have a recommendation for you based on his experiences.

Keep in mind, opening the app is the easy part, it's the deep links that typically require some detective work -- and they may or may not even exist. If your app doesn't support deep links, you'll want to use the ah4c project as that allows for controlling the app using a virtual remote control approach. ah4c will work with pretty much any app.