Skip to content

Commit 1cb60c3

Browse files
committed
RU-T47 PR#221 fixes
1 parent 381dce2 commit 1cb60c3

File tree

2 files changed

+56
-6
lines changed

2 files changed

+56
-6
lines changed

src/services/__tests__/bluetooth-audio.service.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ jest.mock('react-native-ble-manager', () => ({
3636
getDiscoveredPeripherals: jest.fn(),
3737
removeAllListeners: jest.fn(),
3838
removePeripheral: jest.fn(),
39+
read: jest.fn(),
3940
},
4041
}));
4142

@@ -282,4 +283,35 @@ describe('BluetoothAudioService Refactoring', () => {
282283
expect(service.hasNotificationOrReadCapability({ notify: 'notify' })).toBe(true);
283284
});
284285
});
286+
287+
describe('Read polling baseline handling', () => {
288+
it('should prime first read and only dispatch after value changes', async () => {
289+
const service = bluetoothAudioService as any;
290+
const bleManagerMock = require('react-native-ble-manager').default;
291+
const mockHandleButtonEvent = jest.fn();
292+
293+
service.handleButtonEventFromCharacteristic = mockHandleButtonEvent;
294+
service.monitoredReadCharacteristics = [
295+
{
296+
serviceUuid: 'service-1',
297+
characteristicUuid: 'characteristic-1',
298+
lastHexValue: null,
299+
},
300+
];
301+
302+
bleManagerMock.read = jest.fn().mockResolvedValueOnce([0x00]).mockResolvedValueOnce([0x01]).mockResolvedValueOnce([0x01]);
303+
304+
await service.pollReadCharacteristics('device-1');
305+
expect(service.monitoredReadCharacteristics[0].lastHexValue).toBe('00');
306+
expect(mockHandleButtonEvent).not.toHaveBeenCalled();
307+
308+
await service.pollReadCharacteristics('device-1');
309+
expect(service.monitoredReadCharacteristics[0].lastHexValue).toBe('01');
310+
expect(mockHandleButtonEvent).toHaveBeenCalledTimes(1);
311+
expect(mockHandleButtonEvent).toHaveBeenCalledWith('device-1', 'service-1', 'characteristic-1', 'AQ==');
312+
313+
await service.pollReadCharacteristics('device-1');
314+
expect(mockHandleButtonEvent).toHaveBeenCalledTimes(1);
315+
});
316+
});
285317
});

src/services/bluetooth-audio.service.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,7 +1310,7 @@ class BluetoothAudioService {
13101310
}
13111311

13121312
private async startNotificationsForButtonControls(deviceId: string, peripheralInfo: PeripheralInfo): Promise<void> {
1313-
const subscribedPairs = new Set<string>();
1313+
const successfullySubscribed = new Set<string>();
13141314
this.monitoredReadCharacteristics = [];
13151315
const isSpecializedDevice = Boolean(this.connectedDevice && this.connectedDevice.id === deviceId && this.getDeviceType(this.connectedDevice) === 'specialized');
13161316

@@ -1342,7 +1342,7 @@ class BluetoothAudioService {
13421342
}
13431343

13441344
await BleManager.startNotification(deviceId, config.service, config.characteristic);
1345-
subscribedPairs.add(`${config.service.toUpperCase()}::${config.characteristic.toUpperCase()}`);
1345+
successfullySubscribed.add(`${config.service.toUpperCase()}::${config.characteristic.toUpperCase()}`);
13461346
this.registerReadPollingCharacteristic(config.service, config.characteristic);
13471347
logger.info({
13481348
message: 'Started notifications for button control',
@@ -1378,13 +1378,13 @@ class BluetoothAudioService {
13781378
const pairKey = `${String(serviceUuid).toUpperCase()}::${String(characteristicUuid).toUpperCase()}`;
13791379
const shouldSubscribe = isSpecializedDevice ? true : this.isLikelyButtonCharacteristic(serviceUuid, characteristicUuid) || this.hasNotificationOrReadCapability(characteristic?.properties);
13801380

1381-
if (!shouldSubscribe || subscribedPairs.has(pairKey)) {
1381+
if (!shouldSubscribe || successfullySubscribed.has(pairKey)) {
13821382
continue;
13831383
}
13841384

13851385
try {
13861386
await BleManager.startNotification(deviceId, serviceUuid, characteristicUuid);
1387-
subscribedPairs.add(pairKey);
1387+
successfullySubscribed.add(pairKey);
13881388

13891389
if (isSpecializedDevice || this.hasReadCapability(characteristic?.properties)) {
13901390
this.registerReadPollingCharacteristic(serviceUuid, characteristicUuid);
@@ -1422,11 +1422,16 @@ class BluetoothAudioService {
14221422
continue;
14231423
}
14241424

1425+
const pairKey = `${String(serviceUuid).toUpperCase()}::${String(characteristicUuid).toUpperCase()}`;
1426+
if (!successfullySubscribed.has(pairKey)) {
1427+
continue;
1428+
}
1429+
14251430
this.registerReadPollingCharacteristic(serviceUuid, characteristicUuid);
14261431
}
14271432
}
14281433

1429-
if (subscribedPairs.size > 0) {
1434+
if (successfullySubscribed.size > 0) {
14301435
useBluetoothAudioStore.getState().setIsHeadsetButtonMonitoring(true);
14311436
this.startReadPollingFallback(deviceId);
14321437
} else {
@@ -1488,6 +1493,11 @@ class BluetoothAudioService {
14881493
continue;
14891494
}
14901495

1496+
if (entry.lastHexValue === null) {
1497+
entry.lastHexValue = nextHexValue;
1498+
continue;
1499+
}
1500+
14911501
if (entry.lastHexValue === nextHexValue) {
14921502
continue;
14931503
}
@@ -2106,13 +2116,21 @@ class BluetoothAudioService {
21062116
}
21072117

21082118
private scheduleMicApplyRetry(enabled: boolean): void {
2119+
this.pendingMicEnabled = enabled;
2120+
21092121
if (this.micApplyRetryTimeout) {
21102122
return;
21112123
}
21122124

21132125
this.micApplyRetryTimeout = setTimeout(() => {
21142126
this.micApplyRetryTimeout = null;
2115-
this.requestMicrophoneState(enabled);
2127+
2128+
const pendingEnabled = this.pendingMicEnabled;
2129+
if (pendingEnabled === null) {
2130+
return;
2131+
}
2132+
2133+
this.requestMicrophoneState(pendingEnabled);
21162134
}, 160);
21172135
}
21182136

0 commit comments

Comments
 (0)