Skip to content

Conversation

jyasskin
Copy link
Member

@jyasskin jyasskin commented May 9, 2016

scanning.bs Outdated
</p>
<ol>
<li>
If |event| doesn't <a for="BluetoothLEScanFilter">match</a>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that this leaves no way to do a completely open scan. It has to be filtered for some UUID or Manufacturer ID. Is that OK, or do we need an extra filter type to match everything? (I don't want to make no-filters the sign for completely-open because that makes the API non-monotonic: reducing the number of filters would match less, less, less, and then more advertisements.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to #234 I think developers will have good use cases for matching everything.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@beaufortfrancois
Copy link
Member

I wonder why developers would use requestDevice rather than requestLEScan. The latter seems more powerful and better in terms of UX. Could you comment on the drawbacks?

@jyasskin
Copy link
Member Author

@beaufortfrancois At the moment, requestLEScan gets you a bunch of BluetoothDevice objects, but all of their .gatt fields are null (unless you already had permission to communicate with them), so you have to use requestDevice to communicate. I think it's worthwhile to give folks a way to upgrade, but we need to ask the security UI folks what it should look like, and it'll probably be designed to push people toward just using requestDevice() if they don't really need to control the scan.

@beaufortfrancois
Copy link
Member

beaufortfrancois commented May 13, 2016

This makes more sense now ;)
Thank you @jyasskin!

So once you have a BluetoothDevice object, the way to know if you have to use requestDevice is to check device.gatt... but how do you make sure that only this device will be shown in the bluetooth chooser?

navigator.bluetooth.requestLEScan({
  filters: [{manufacturerData: 0x004C}]
}).then(() => {
  navigator.bluetooth.addEventListener('advertisementreceived', event => {
    if (!event.device.gatt) {
      // How do I connect to this device specifically?
    }
  })
})

@jyasskin
Copy link
Member Author

There's no API for that yet, and I've mailed the security UI folks to ask their opinion on it. The benefits of the chooser are that 1) the user has to pay enough attention to make a choice, and 2) the user can override the page's idea of which device is best. If we ensure that exactly one device appears in the chooser that opens as a result of an advertisement, then we lose both of those. On the other hand, we might be able to add a hint field to RequestDeviceOptions, which could ensure that the preferred device is listed first if it matches the other filters.

@Vudentz
Copy link

Vudentz commented May 20, 2016

Some devices may use non-connectable flag, e.g. broadcaster, in that case requestDevice might actually not work in the end so perhaps we need some field to indicate this to the application.

@beaufortfrancois
Copy link
Member

beaufortfrancois commented May 25, 2016

The connectable field would be indeed valuable to add to the BluetoothDevice object. Thanks @Vudentz!
I wonder however if that would be as simple as a boolean field. There are actually two kinds of connectable there: ADV_IND and ADV_DIRECT_IND
@jyasskin Any thoughts?

@jyasskin
Copy link
Member Author

I think we don't need to distinguish between ADV_IND and ADV_DIRECT_IND: the difference is whether the controller can send a SCAN_REQ in response, but the advertising event should just combine data from the advertisement with the SCAN_RSP, so websites don't need to react to the difference.

Do we want to mark this in the advertising event or on the device? I'd initially thought the advertising event, but since we always have to wait for a subsequent advertisement in order to connect, it probably makes sense to turn it to 'true' on the device as soon as we see any connectable advertisement from that device.

scanning.bs Outdated
navigator.bluetooth.<a idl for="Bluetooth" lt="requestLEScan()">requestLEScan</a>({
filters: [{manufacturerData: 0x004C}],
options: {
keepDuplicates: true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/keepDuplicates/keepRepeatedDevices/

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, thanks.

@jyasskin jyasskin force-pushed the scanning branch 6 times, most recently from 04e61ff to d971187 Compare July 21, 2016 23:37
@Vudentz
Copy link

Vudentz commented Jul 22, 2016

Im quite concerned with these APIs, it is quite low level which may lead us to need to expose scanning intervals which depending on the duty cycle can block other traffic such as GATT to happen. Im also not quite sure how to interpret the aggregation of scan response, there could be other advertisements in the meantime shall the stacks hold the results until it gets a scan response, for requestDevice that may be fine because the API don't except individual reports just a device, but here the holding of events may change the sequence. Perhaps if this is done via device object, so the scan response wouldn't matter and only advertisement would actually cause events.

@krantik
Copy link

krantik commented Jul 22, 2016

How about timeout? Is the call expected to constantly scan or stop after sometime? Some of the devices(iOS for example) doesn't constantly scan and backs off after some period. Is the same expected here?

@krantik
Copy link

krantik commented Jul 22, 2016

Is the event expected to have parsed data with separate values for name etc., or raw data and JS side to interpret it?

@jyasskin
Copy link
Member Author

jyasskin commented Jul 22, 2016

@Vudentz

Im quite concerned with these APIs, it is quite low level which may lead us to need to expose scanning intervals which depending on the duty cycle can block other traffic such as GATT to happen.

In order to compete with [Android](https://developer.android.com/reference/android/bluetooth/le/ScanCallback.html#onScanResult%28int, android.bluetooth.le.ScanResult%29) and Mac, I think BlueZ is going to have to report information with this much detail. We can limit the load websites are allowed to put on the system, but beacon use cases definitely need to enable duplicate events, and seem to need the timing of the last advertisement in order to know when things are stale.

If BlueZ doesn't start reporting advertising events, we can infer some of this from changes in the Device object, but it's going to work less well than other platforms.

Im also not quite sure how to interpret the aggregation of scan response, there could be other advertisements in the meantime shall the stacks hold the results until it gets a scan response, for requestDevice that may be fine because the API don't except individual reports just a device, but here the holding of events may change the sequence. Perhaps if this is done via device object, so the scan response wouldn't matter and only advertisement would actually cause events.

It seems ok to delay the event until after the SCAN_RSP, although maybe we'll find use cases that prefer to get both events. The uses will have to be ok with whatever Android and Mac do, since it's harder to change them.

@krantik

How about timeout? Is the call expected to constantly scan or stop after sometime? Some of the devices(iOS for example) doesn't constantly scan and backs off after some period. Is the same expected here?

I could let the UA stop a scan if it's been running "too long". Advertisements aren't reliable anyway, so iOS's periodic scan probably already satisfies the spec, but I could add explicit wording to allow that.

I don't think having folks pass a timeout to requestLEScan() will help, since iOS will throttle the scan when it wants regardless of whether the site passed its own timeout. I expect folks to use setTimeout(()=>scan.stop(), xxx) to time out their scans.

Is the event expected to have parsed data with separate values for name etc., or raw data and JS side to interpret it?

Parsed data. See https://webbluetoothcg.github.io/web-bluetooth/#fire-an-advertisementreceived-event for the parsing. We're nervous about exposing the raw data, both because we can't implement that on Mac, and because some of the fields, like the public addresses, hold data that we're not sure websites should know.

@Vudentz
Copy link

Vudentz commented Jul 25, 2016

@jyasskin

In order to compete with Android and Mac, I think BlueZ is going to have to report information with this much detail. We can limit the load websites are allowed to put on the system, but beacon use cases definitely need to enable duplicate events, and seem to need the timing of the last advertisement in order to know when things are stale.

BlueZ is used in very different systems as Android, it is quite common to have multiple applications using the API in parallel, perhaps we could compare it to Mac but looking at its API it seems to be very similar to the kind of access BlueZ offers with StartDiscovery combined with SetDiscoveryFilter. Btw, it is already possibility to enable duplicated reports, in that case the RSSI property is emitted every time we receive a report from the peripheral, similar to what is stated in the Mac documentation.

It seems ok to delay the event until after the SCAN_RSP, although maybe we'll find use cases that prefer to get both events. The uses will have to be ok with whatever Android and Mac do, since it's harder to change them.

Well we do wait for the scan response so the applications can see the device name, etc, which is quite convenient for requestDevice but it perhaps wouldn't be for requestLEScan, anyway as long as it not strictly forbidden I guess we can live with that.

Btw, we also have to keep in mind there could be peripherals connected which makes requestLEScan even less reliable as it cannot use very high scan duty cycle in such cases.

scanning.bs Outdated
</li>
<li>
If <code>|filter|.connectable</code> is `true`,
|event| has either the <a>ADV_IND</a>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.