Skip to content

Commit 175bcd9

Browse files
edwinwugoogcopybara-github
authored andcommitted
Implement GNCPeripheralManagerMultiplexer.
PiperOrigin-RevId: 874333229
1 parent 6308d5f commit 175bcd9

File tree

5 files changed

+742
-0
lines changed

5 files changed

+742
-0
lines changed

internal/platform/implementation/apple/Mediums/BLE/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ objc_library(
3939
"GNCMConnection.m",
4040
"GNCPeripheral.m",
4141
"GNCPeripheralManager.m",
42+
"GNCPeripheralManagerMultiplexer.m",
4243
"NSData+GNCBase85.mm",
4344
"NSData+GNCWebSafeBase64.m",
4445
],
@@ -59,6 +60,7 @@ objc_library(
5960
"GNCMConnection.h",
6061
"GNCPeripheral.h",
6162
"GNCPeripheralManager.h",
63+
"GNCPeripheralManagerMultiplexer.h",
6264
"NSData+GNCBase85.h",
6365
"NSData+GNCWebSafeBase64.h",
6466
],
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2026 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+
#import "internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManager.h"
16+
17+
NS_ASSUME_NONNULL_BEGIN
18+
19+
/**
20+
* A multiplexer that forwards @c CBPeripheralManagerDelegate and @c GNCPeripheralManagerDelegate
21+
*/
22+
@interface GNCPeripheralManagerMultiplexer : NSObject <GNCPeripheralManagerDelegate>
23+
24+
/**
25+
* Initializes the multiplexer.
26+
*
27+
* @param callbackQueue The queue to use for forwarding delegate callbacks.
28+
*/
29+
- (instancetype)initWithCallbackQueue:(dispatch_queue_t)callbackQueue;
30+
31+
/**
32+
* Adds a listener to the multiplexer. Listeners are held weakly.
33+
34+
/**
35+
* Adds a listener to the multiplexer. Listeners are held weakly.
36+
*
37+
* @param listener The listener to add.
38+
*/
39+
- (void)addListener:(id<GNCPeripheralManagerDelegate>)listener;
40+
41+
/**
42+
* Removes a listener from the multiplexer.
43+
*
44+
* @param listener The listener to remove.
45+
*/
46+
- (void)removeListener:(id<GNCPeripheralManagerDelegate>)listener;
47+
48+
@end
49+
50+
NS_ASSUME_NONNULL_END
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
// Copyright 2026 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+
#import "internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManagerMultiplexer.h"
16+
17+
#import <CoreBluetooth/CoreBluetooth.h>
18+
#import <Foundation/Foundation.h>
19+
20+
#import "internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManager.h"
21+
22+
NS_ASSUME_NONNULL_BEGIN
23+
24+
@implementation GNCPeripheralManagerMultiplexer {
25+
NSHashTable<id<GNCPeripheralManagerDelegate>> *_listeners;
26+
dispatch_queue_t _callbackQueue;
27+
dispatch_queue_t _syncQueue;
28+
}
29+
30+
- (instancetype)initWithCallbackQueue:(dispatch_queue_t)callbackQueue {
31+
self = [super init];
32+
if (self) {
33+
_listeners = [NSHashTable weakObjectsHashTable];
34+
_callbackQueue = callbackQueue;
35+
_syncQueue = dispatch_queue_create("com.google.nearby.GNCPeripheralManagerMultiplexerSync",
36+
DISPATCH_QUEUE_SERIAL);
37+
}
38+
return self;
39+
}
40+
41+
- (instancetype)init {
42+
return [self initWithCallbackQueue:dispatch_get_main_queue()];
43+
}
44+
45+
- (void)addListener:(id<GNCPeripheralManagerDelegate>)listener {
46+
dispatch_async(_syncQueue, ^{
47+
[self->_listeners addObject:listener];
48+
});
49+
}
50+
51+
- (void)removeListener:(id<GNCPeripheralManagerDelegate>)listener {
52+
dispatch_async(_syncQueue, ^{
53+
[self->_listeners removeObject:listener];
54+
});
55+
}
56+
57+
- (NSArray<id<GNCPeripheralManagerDelegate>> *)allListeners {
58+
__block NSArray<id<GNCPeripheralManagerDelegate>> *listeners;
59+
dispatch_sync(_syncQueue, ^{
60+
listeners = [self->_listeners allObjects];
61+
});
62+
return listeners;
63+
}
64+
65+
#pragma mark - GNCPeripheralManagerDelegate
66+
67+
- (void)gnc_peripheralManagerDidUpdateState:(id<GNCPeripheralManager>)peripheral {
68+
NSArray<id<GNCPeripheralManagerDelegate>> *listeners = [self allListeners];
69+
dispatch_async(_callbackQueue, ^{
70+
for (id<GNCPeripheralManagerDelegate> listener in listeners) {
71+
[listener gnc_peripheralManagerDidUpdateState:peripheral];
72+
}
73+
});
74+
}
75+
76+
- (void)gnc_peripheralManagerDidStartAdvertising:(id<GNCPeripheralManager>)peripheral
77+
error:(nullable NSError *)error {
78+
NSArray<id<GNCPeripheralManagerDelegate>> *listeners = [self allListeners];
79+
dispatch_async(_callbackQueue, ^{
80+
for (id<GNCPeripheralManagerDelegate> listener in listeners) {
81+
if ([listener respondsToSelector:@selector(gnc_peripheralManagerDidStartAdvertising:error:)]) {
82+
[listener gnc_peripheralManagerDidStartAdvertising:peripheral error:error];
83+
}
84+
}
85+
});
86+
}
87+
88+
- (void)gnc_peripheralManager:(id<GNCPeripheralManager>)peripheral
89+
didAddService:(CBService *)service
90+
error:(nullable NSError *)error {
91+
NSArray<id<GNCPeripheralManagerDelegate>> *listeners = [self allListeners];
92+
dispatch_async(_callbackQueue, ^{
93+
for (id<GNCPeripheralManagerDelegate> listener in listeners) {
94+
if ([listener respondsToSelector:@selector(gnc_peripheralManager:didAddService:error:)]) {
95+
[listener gnc_peripheralManager:peripheral didAddService:service error:error];
96+
}
97+
}
98+
});
99+
}
100+
101+
- (void)gnc_peripheralManager:(id<GNCPeripheralManager>)peripheral
102+
didReceiveReadRequest:(CBATTRequest *)request {
103+
NSArray<id<GNCPeripheralManagerDelegate>> *listeners = [self allListeners];
104+
dispatch_async(_callbackQueue, ^{
105+
for (id<GNCPeripheralManagerDelegate> listener in listeners) {
106+
if ([listener respondsToSelector:@selector(gnc_peripheralManager:didReceiveReadRequest:)]) {
107+
[listener gnc_peripheralManager:peripheral didReceiveReadRequest:request];
108+
}
109+
}
110+
});
111+
}
112+
113+
- (void)gnc_peripheralManager:(id<GNCPeripheralManager>)peripheral
114+
didPublishL2CAPChannel:(CBL2CAPPSM)PSM
115+
error:(nullable NSError *)error {
116+
NSArray<id<GNCPeripheralManagerDelegate>> *listeners = [self allListeners];
117+
dispatch_async(_callbackQueue, ^{
118+
for (id<GNCPeripheralManagerDelegate> listener in listeners) {
119+
if ([listener respondsToSelector:@selector(gnc_peripheralManager:didPublishL2CAPChannel:error:)]) {
120+
[listener gnc_peripheralManager:peripheral didPublishL2CAPChannel:PSM error:error];
121+
}
122+
}
123+
});
124+
}
125+
126+
- (void)gnc_peripheralManager:(id<GNCPeripheralManager>)peripheral
127+
didUnpublishL2CAPChannel:(CBL2CAPPSM)PSM
128+
error:(NSError *)error {
129+
NSArray<id<GNCPeripheralManagerDelegate>> *listeners = [self allListeners];
130+
dispatch_async(_callbackQueue, ^{
131+
for (id<GNCPeripheralManagerDelegate> listener in listeners) {
132+
if ([listener respondsToSelector:@selector(gnc_peripheralManager:didUnpublishL2CAPChannel:error:)]) {
133+
[listener gnc_peripheralManager:peripheral didUnpublishL2CAPChannel:PSM error:error];
134+
}
135+
}
136+
});
137+
}
138+
139+
- (void)gnc_peripheralManager:(id<GNCPeripheralManager>)peripheral
140+
didOpenL2CAPChannel:(nullable CBL2CAPChannel *)channel
141+
error:(nullable NSError *)error {
142+
NSArray<id<GNCPeripheralManagerDelegate>> *listeners = [self allListeners];
143+
dispatch_async(_callbackQueue, ^{
144+
for (id<GNCPeripheralManagerDelegate> listener in listeners) {
145+
if ([listener respondsToSelector:@selector(gnc_peripheralManager:didOpenL2CAPChannel:error:)]) {
146+
[listener gnc_peripheralManager:peripheral didOpenL2CAPChannel:channel error:error];
147+
}
148+
}
149+
});
150+
}
151+
152+
#pragma mark - CBPeripheralManagerDelegate
153+
154+
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral {
155+
[self gnc_peripheralManagerDidUpdateState:peripheral];
156+
}
157+
158+
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral
159+
error:(nullable NSError *)error {
160+
[self gnc_peripheralManagerDidStartAdvertising:peripheral error:error];
161+
}
162+
163+
- (void)peripheralManager:(CBPeripheralManager *)peripheral
164+
didAddService:(CBService *)service
165+
error:(nullable NSError *)error {
166+
[self gnc_peripheralManager:peripheral didAddService:service error:error];
167+
}
168+
169+
- (void)peripheralManager:(CBPeripheralManager *)peripheral
170+
didReceiveReadRequest:(CBATTRequest *)request {
171+
[self gnc_peripheralManager:peripheral didReceiveReadRequest:request];
172+
}
173+
174+
- (void)peripheralManager:(CBPeripheralManager *)peripheral
175+
didPublishL2CAPChannel:(CBL2CAPPSM)PSM
176+
error:(nullable NSError *)error {
177+
[self gnc_peripheralManager:peripheral didPublishL2CAPChannel:PSM error:error];
178+
}
179+
180+
- (void)peripheralManager:(CBPeripheralManager *)peripheral
181+
didUnpublishL2CAPChannel:(CBL2CAPPSM)PSM
182+
error:(nullable NSError *)error {
183+
[self gnc_peripheralManager:peripheral didUnpublishL2CAPChannel:PSM error:error];
184+
}
185+
186+
- (void)peripheralManager:(CBPeripheralManager *)peripheral
187+
didOpenL2CAPChannel:(nullable CBL2CAPChannel *)channel
188+
error:(nullable NSError *)error {
189+
[self gnc_peripheralManager:peripheral didOpenL2CAPChannel:channel error:error];
190+
}
191+
192+
@end
193+
194+
NS_ASSUME_NONNULL_END

internal/platform/implementation/apple/Mediums/BLE/Tests/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ objc_library(
4444
"GNCMBleUtilsTest.m",
4545
"GNCMConnectionsTest.m",
4646
"GNCMFakeConnection.mm",
47+
"GNCPeripheralManagerMultiplexerTest.m",
4748
"GNCPeripheralManagerTest.m",
4849
"GNCPeripheralTest.m",
4950
"NSData+GNCBase85Test.m",

0 commit comments

Comments
 (0)