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"""LE Audio - Telephony and Media Audio Profile""" 16 17# ----------------------------------------------------------------------------- 18# Imports 19# ----------------------------------------------------------------------------- 20import enum 21import logging 22import struct 23 24from bumble.gatt import ( 25 TemplateService, 26 Characteristic, 27 DelegatedCharacteristicAdapter, 28 InvalidServiceError, 29 GATT_TELEPHONY_AND_MEDIA_AUDIO_SERVICE, 30 GATT_TMAP_ROLE_CHARACTERISTIC, 31) 32from bumble.gatt_client import ProfileServiceProxy, ServiceProxy 33 34 35# ----------------------------------------------------------------------------- 36# Logging 37# ----------------------------------------------------------------------------- 38logger = logging.getLogger(__name__) 39 40 41# ----------------------------------------------------------------------------- 42# Classes 43# ----------------------------------------------------------------------------- 44class Role(enum.IntFlag): 45 CALL_GATEWAY = 1 << 0 46 CALL_TERMINAL = 1 << 1 47 UNICAST_MEDIA_SENDER = 1 << 2 48 UNICAST_MEDIA_RECEIVER = 1 << 3 49 BROADCAST_MEDIA_SENDER = 1 << 4 50 BROADCAST_MEDIA_RECEIVER = 1 << 5 51 52 53# ----------------------------------------------------------------------------- 54class TelephonyAndMediaAudioService(TemplateService): 55 UUID = GATT_TELEPHONY_AND_MEDIA_AUDIO_SERVICE 56 57 def __init__(self, role: Role): 58 self.role_characteristic = Characteristic( 59 GATT_TMAP_ROLE_CHARACTERISTIC, 60 Characteristic.Properties.READ, 61 Characteristic.READABLE, 62 struct.pack('<H', int(role)), 63 ) 64 65 super().__init__([self.role_characteristic]) 66 67 68# ----------------------------------------------------------------------------- 69class TelephonyAndMediaAudioServiceProxy(ProfileServiceProxy): 70 SERVICE_CLASS = TelephonyAndMediaAudioService 71 72 role: DelegatedCharacteristicAdapter 73 74 def __init__(self, service_proxy: ServiceProxy): 75 self.service_proxy = service_proxy 76 77 if not ( 78 characteristics := service_proxy.get_characteristics_by_uuid( 79 GATT_TMAP_ROLE_CHARACTERISTIC 80 ) 81 ): 82 raise InvalidServiceError('TMAP Role characteristic not found') 83 84 self.role = DelegatedCharacteristicAdapter( 85 characteristics[0], 86 decode=lambda value: Role( 87 struct.unpack_from('<H', value, 0)[0], 88 ), 89 ) 90