summaryrefslogtreecommitdiff
path: root/ctbtw.py
diff options
context:
space:
mode:
Diffstat (limited to 'ctbtw.py')
-rwxr-xr-xctbtw.py33
1 files changed, 23 insertions, 10 deletions
diff --git a/ctbtw.py b/ctbtw.py
index a8ae77e..92ac6fd 100755
--- a/ctbtw.py
+++ b/ctbtw.py
@@ -497,20 +497,25 @@ class SetFeatureReq(BTReq):
return "SetFeatureReq(feature=%s,value=%r)"%(self.feature,self.value)
class PairedDevice(NamedTuple):
+ """Tuple representing a paired bluetooth receiver."""
name: str
addr: BTAddr
class CTBTWDevice:
+ """Main class representing a transmitter device."""
# List of messages that can be received
MSG_TYPES = [AckMsg, GetNumPairedDevicesMsg, GetPairedDeviceDetailsMsg, GetInquiryDataMsg, GetStateMsg, GetFeatureMsg]
+
# HID report number used to both receive/send messages
REPORT_ID = 3
# Size of this report (hardcoded...)
REPORT_SIZE = 64
+ # This is the usage page for the above report_id, at least on BT-W6. Some platforms need this to be correct.
+ USAGE_PAGE = 0xFF01
# Vendor ID to search for
- CT_VENDOR_ID = 0x041e
+ VENDOR_ID = 0x041e
# Product IDs to search for. Hardcoded to [BT-W4, BT-W5, BT-W6]
- CT_PRODUCT_IDS = [0x312B, 0x3130, 0x3132]
+ PRODUCT_IDS = [0x312B, 0x3130, 0x3132]
def __init__(self, devpath, verbose=False):
self._hid = hid.device()
@@ -585,8 +590,10 @@ def codec_name(codec):
return codec.name
def find_device():
- for device in hid.enumerate(vendor_id=CTBTWDevice.CT_VENDOR_ID):
- if device['vendor_id'] == CTBTWDevice.CT_VENDOR_ID and device['product_id'] in CTBTWDevice.CT_PRODUCT_IDS:
+ for device in hid.enumerate(vendor_id=CTBTWDevice.VENDOR_ID):
+ if (device['vendor_id'] == CTBTWDevice.VENDOR_ID and
+ device['product_id'] in CTBTWDevice.PRODUCT_IDS and
+ device['usage_page'] == CTBTWDevice.USAGE_PAGE):
return device
return None
@@ -643,9 +650,8 @@ if __name__ == '__main__':
parser = ArgumentParser(prog='ctbtw', description="Control CT BT-W* Bluetooth Audio Trasmitter devices", epilog="With no arguments, show current device state")
parser.add_argument('--verbose', '-v', action='store_true', help="print protocol traces")
actions = parser.add_mutually_exclusive_group()
- actions.add_argument('--aptxll', '-l', action='store_true', help="for aptX, prefer low-latency mode")
- actions.add_argument('--aptxhq', '-q', action='store_true', help="for aptX, prefer high-quality mode (also enables aptX lossless)")
- actions.add_argument('--devices', '-s', action='store_true', help="list currently paired devices")
+ actions.add_argument('--aptx', '-x', action='store', choices=["l", "q"], help="prefer (L)atency or (Q)uality for aptX adaptative")
+ actions.add_argument('--devices', '-l', action='store_true', help="list currently paired devices")
actions.add_argument('--connect', '-c', metavar="DEV", action='store', help="connect to (already paired) device with given name/address")
actions.add_argument('--disconnect', '-d', metavar="D", action='store', nargs='?', const='*', help="disconnect from device with given name/address, or current device if no %(metavar)s")
actions.add_argument('--pair', '-p', nargs='?', metavar="ADDR", const="*", action='store', help='pair with specific bluetooth address, or any device if no %(metavar)s specified')
@@ -658,6 +664,13 @@ if __name__ == '__main__':
verbose = args.verbose
use_color = os.getenv("NO_COLOR", "") == "" and os.getenv("TERM") != "dumb" and sys.stdout.isatty()
+ if use_color:
+ try:
+ from colorama import just_fix_windows_console
+ just_fix_windows_console()
+ except Exception:
+ pass
+
devinfo = find_device()
if not devinfo:
print("Could not find device with valid vendor/product IDs")
@@ -669,9 +682,9 @@ if __name__ == '__main__':
if verbose: print("Opened device '%s'" % devinfo['product_string'])
- if args.aptxll or args.aptxhq:
- codec = BTCodec.aptXAdaptiveHighQuality if args.aptxhq else BTCodec.aptXAdaptiveLowLatency
- print("Switching preferred aptX codec to %s" % codec.name)
+ if args.aptx:
+ codec = BTCodec.aptXAdaptiveHighQuality if args.aptx.startswith("q") else BTCodec.aptXAdaptiveLowLatency
+ print("Switching aptX adaptative preference to %s" % codec.name)
msg = SetFeatureReq(BTFeatureSet.PreferredAptXCodecVariant, codec)
dev.send_msg(msg)
read_and_explain_msgs(dev, timeout_ms=1000) # Use larger timeout to give time to print final codec used, if any