Last active
July 7, 2024 15:01
-
-
Save pgaskin/37553eba141c26029e68140ee5215e04 to your computer and use it in GitHub Desktop.
Controlling the Anker Soundcore P20i gaming mode (i.e., low latency mode) on Linux.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"encoding/hex" | |
"net" | |
"os" | |
"golang.org/x/sys/unix" | |
) | |
func main() { | |
var cmd string | |
if len(os.Args) > 1 { | |
cmd = os.Args[1] | |
} | |
switch cmd { | |
case "on", "1": | |
cmd = "08ee00000001870b00018a" | |
case "off", "0": | |
cmd = "08ee00000001870b000089" | |
default: | |
panic("invalid command") | |
} | |
cmdBuf, err := hex.DecodeString(cmd) | |
if err != nil { | |
panic(err) | |
} | |
var mac string | |
if len(os.Args) > 2 { | |
mac = os.Args[2] | |
} | |
if mac == "" { | |
mac = "F0:AE:66:B2:4E:95" | |
} | |
macAddr, err := net.ParseMAC(mac) | |
if err != nil { | |
panic(err) | |
} | |
if len(macAddr) != 6 { | |
panic("invalid mac address") | |
} | |
macBuf := [6]uint8{macAddr[5], macAddr[4], macAddr[3], macAddr[2], macAddr[1], macAddr[0]} | |
fd, err := unix.Socket(unix.AF_BLUETOOTH, unix.SOCK_STREAM, unix.BTPROTO_RFCOMM) | |
if err != nil { | |
panic(err) | |
} | |
// p20i rfcomm stuff is always on channel 10 | |
if err := unix.Connect(fd, &unix.SockaddrRFCOMM{Addr: macBuf, Channel: 10}); err != nil { | |
panic(err) | |
} | |
f := os.NewFile(uintptr(fd), "bluetooth rfcomm "+macAddr.String()) | |
defer f.Close() | |
if _, err := f.Write(cmdBuf); err != nil { | |
panic(err) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"encoding/hex" | |
"fmt" | |
"net" | |
"time" | |
"golang.org/x/sys/unix" | |
) | |
/* | |
- adb root | |
- enable bluetooth | |
- enable bluetooth hci snooping in dev options | |
- disable bluetooth | |
- enable bluetooth | |
- do stuff | |
- adb pull /data/misc/bluetooth/logs/btsnoop_hci.log | |
- disable bluetooth hci snooping in dev options | |
- disable bluetooth | |
- enable bluetooth | |
- disable bluetooth | |
- wireshark | |
*/ | |
func main() { | |
mac, err := net.ParseMAC("F0:AE:66:B2:4E:95") // soundcore P20i | |
if err != nil { | |
panic(err) | |
} | |
addr := [6]uint8{mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]} | |
fd, err := unix.Socket(unix.AF_BLUETOOTH, unix.SOCK_STREAM, unix.BTPROTO_RFCOMM) | |
if err != nil { | |
panic(err) | |
} | |
// p20i rfcomm stuff is always on channel 10 | |
if err := unix.Connect(fd, &unix.SockaddrRFCOMM{Addr: addr, Channel: 10}); err != nil { | |
panic(err) | |
} | |
fmt.Println("get device info") | |
if buf, err := hex.DecodeString("08ee00000001010a0002"); err != nil { | |
panic(err) | |
} else if _, err := unix.Write(fd, buf); err != nil { | |
panic(err) | |
} | |
{ | |
tmp := make([]byte, 98) | |
n, err := unix.Read(fd, tmp) | |
if err != nil { | |
panic(err) | |
} | |
fmt.Println(hex.Dump(tmp[:n])) | |
} | |
fmt.Println("gaming mode off") | |
if buf, err := hex.DecodeString("08ee00000001870b000089"); err != nil { | |
panic(err) | |
} else if _, err := unix.Write(fd, buf); err != nil { | |
panic(err) | |
} | |
time.Sleep(time.Second * 5) | |
fmt.Println("gaming mode on") | |
if buf, err := hex.DecodeString("08ee00000001870b00018a"); err != nil { | |
panic(err) | |
} else if _, err := unix.Write(fd, buf); err != nil { | |
panic(err) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment