1# Copyright 2021-2022 Google LLC 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15# ----------------------------------------------------------------------------- 16# Imports 17# ----------------------------------------------------------------------------- 18import asyncio 19import sys 20import os 21import logging 22 23from bumble.device import Device 24from bumble.transport import open_transport_or_link 25from bumble.sdp import ( 26 DataElement, 27 ServiceAttribute, 28 SDP_PUBLIC_BROWSE_ROOT, 29 SDP_BROWSE_GROUP_LIST_ATTRIBUTE_ID, 30 SDP_SERVICE_RECORD_HANDLE_ATTRIBUTE_ID, 31 SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID, 32 SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID, 33 SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID 34) 35from bumble.core import ( 36 BT_AUDIO_SINK_SERVICE, 37 BT_L2CAP_PROTOCOL_ID, 38 BT_AVDTP_PROTOCOL_ID, 39 BT_ADVANCED_AUDIO_DISTRIBUTION_SERVICE 40) 41 42# ----------------------------------------------------------------------------- 43SDP_SERVICE_RECORDS = { 44 0x00010001: [ 45 ServiceAttribute(SDP_SERVICE_RECORD_HANDLE_ATTRIBUTE_ID, DataElement.unsigned_integer_32(0x00010001)), 46 ServiceAttribute(SDP_BROWSE_GROUP_LIST_ATTRIBUTE_ID, DataElement.sequence([ 47 DataElement.uuid(SDP_PUBLIC_BROWSE_ROOT) 48 ])), 49 ServiceAttribute( 50 SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID, 51 DataElement.sequence([DataElement.uuid(BT_AUDIO_SINK_SERVICE)]) 52 ), 53 ServiceAttribute( 54 SDP_PROTOCOL_DESCRIPTOR_LIST_ATTRIBUTE_ID, 55 DataElement.sequence([ 56 DataElement.sequence([ 57 DataElement.uuid(BT_L2CAP_PROTOCOL_ID), 58 DataElement.unsigned_integer_16(25) 59 ]), 60 DataElement.sequence([ 61 DataElement.uuid(BT_AVDTP_PROTOCOL_ID), 62 DataElement.unsigned_integer_16(256) 63 ]) 64 ]) 65 ), 66 ServiceAttribute( 67 SDP_BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRIBUTE_ID, 68 DataElement.sequence([ 69 DataElement.sequence([ 70 DataElement.uuid(BT_ADVANCED_AUDIO_DISTRIBUTION_SERVICE), 71 DataElement.unsigned_integer_16(256) 72 ]) 73 ]) 74 ) 75 ] 76} 77 78 79# ----------------------------------------------------------------------------- 80async def main(): 81 if len(sys.argv) < 3: 82 print('Usage: run_classic_discoverable.py <device-config> <transport-spec>') 83 print('example: run_classic_discoverable.py classic1.json usb:04b4:f901') 84 return 85 86 print('<<< connecting to HCI...') 87 async with await open_transport_or_link(sys.argv[2]) as (hci_source, hci_sink): 88 print('<<< connected') 89 90 # Create a device 91 device = Device.from_config_file_with_hci(sys.argv[1], hci_source, hci_sink) 92 device.classic_enabled = True 93 device.sdp_service_records = SDP_SERVICE_RECORDS 94 await device.power_on() 95 96 # Start being discoverable and connectable 97 await device.set_discoverable(True) 98 await device.set_connectable(True) 99 100 await hci_source.wait_for_termination() 101 102# ----------------------------------------------------------------------------- 103logging.basicConfig(level = os.environ.get('BUMBLE_LOGLEVEL', 'DEBUG').upper()) 104asyncio.run(main()) 105