@@ -18,6 +18,108 @@ type Address struct {
18
18
MACAddress
19
19
}
20
20
21
+ type Advertisement struct {
22
+ advertisement * advertisement.BluetoothLEAdvertisement
23
+ publisher * advertisement.BluetoothLEAdvertisementPublisher
24
+ }
25
+
26
+ // DefaultAdvertisement returns the default advertisement instance but does not
27
+ // configure it.
28
+ func (a * Adapter ) DefaultAdvertisement () * Advertisement {
29
+ if a .defaultAdvertisement == nil {
30
+ a .defaultAdvertisement = & Advertisement {}
31
+ }
32
+
33
+ return a .defaultAdvertisement
34
+ }
35
+
36
+ // Configure this advertisement.
37
+ // on Windows we're only able to set "Manufacturer Data" for advertisements.
38
+ // https://learn.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.advertisement.bluetoothleadvertisementpublisher?view=winrt-22621#remarks
39
+ // following this c# source for this implementation: https://github.com/microsoft/Windows-universal-samples/blob/main/Samples/BluetoothAdvertisement/cs/Scenario2_Publisher.xaml.cs
40
+ // adding service data / localname leads to errors when starting the advertisement.
41
+ func (a * Advertisement ) Configure (options AdvertisementOptions ) error {
42
+ // we can only advertise manufacturer / company data on windows, so no need to continue if we have none
43
+ if len (options .ManufacturerData ) == 0 {
44
+ return nil
45
+ }
46
+
47
+ if a .publisher != nil {
48
+ a .publisher .Release ()
49
+ }
50
+
51
+ if a .advertisement != nil {
52
+ a .advertisement .Release ()
53
+ }
54
+
55
+ pub , err := advertisement .NewBluetoothLEAdvertisementPublisher ()
56
+ if err != nil {
57
+ return err
58
+ }
59
+
60
+ a .publisher = pub
61
+
62
+ ad , err := a .publisher .GetAdvertisement ()
63
+ if err != nil {
64
+ return err
65
+ }
66
+
67
+ a .advertisement = ad
68
+
69
+ vec , err := ad .GetManufacturerData ()
70
+ if err != nil {
71
+ return err
72
+ }
73
+
74
+ for _ , optManData := range options .ManufacturerData {
75
+ writer , err := streams .NewDataWriter ()
76
+ if err != nil {
77
+ return err
78
+ }
79
+ defer writer .Release ()
80
+
81
+ err = writer .WriteBytes (uint32 (len (optManData .Data )), optManData .Data )
82
+ if err != nil {
83
+ return err
84
+ }
85
+
86
+ buf , err := writer .DetachBuffer ()
87
+ if err != nil {
88
+ return err
89
+ }
90
+
91
+ manData , err := advertisement .BluetoothLEManufacturerDataCreate (optManData .CompanyID , buf )
92
+ if err != nil {
93
+ return err
94
+ }
95
+
96
+ if err = vec .Append (unsafe .Pointer (& manData .IUnknown .RawVTable )); err != nil {
97
+ return err
98
+ }
99
+ }
100
+
101
+ return nil
102
+ }
103
+
104
+ // Start advertisement. May only be called after it has been configured.
105
+ func (a * Advertisement ) Start () error {
106
+ // publisher will be present if we actually have manufacturer data to advertise.
107
+ if a .publisher != nil {
108
+ return a .publisher .Start ()
109
+ }
110
+
111
+ return nil
112
+ }
113
+
114
+ // Stop advertisement. May only be called after it has been started.
115
+ func (a * Advertisement ) Stop () error {
116
+ if a .publisher != nil {
117
+ return a .publisher .Stop ()
118
+ }
119
+
120
+ return nil
121
+ }
122
+
21
123
// Scan starts a BLE scan. It is stopped by a call to StopScan. A common pattern
22
124
// is to cancel the scan when a particular device has been found.
23
125
func (a * Adapter ) Scan (callback func (* Adapter , ScanResult )) (err error ) {
0 commit comments