BarcodeDetector API for LE Audio
Tags: webcapabilities, leaudio, barcodedetector
Published: 2024-07-14 19:22:55

---
title: BarcodeDetector API for LE Audio
published: true
description: Using the BarcodeDetector to read a Broadcast Audio URI
tags: WebCapabilities, LEAudio, BarcodeDetector
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/soho5chrqy8668dj7fnc.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2024-07-14 18:15 +0000
---

As mentioned in my post on [building a Broadcast Audio Source](https://dev.to/denladeside/broadcast-audio-uri-1kkd) the [Broadcast Audio URI (BAU)](https://www.bluetooth.com/specifications/specs/broadcast-audio-uri-2/) spec allows sharing information about broadcast sources through QR codes, NFC tags and more.

In this post, I'll show how you can make a web application that can read and parse the Broadcast Audio URI QR codes.

# BarcodeDetector API
Reading barcodes directly in the browser is made possible with the introduction of the [BarcodeDetector API](https://developer.mozilla.org/en-US/docs/Web/API/BarcodeDetector) and in this post, I will show an example of how it can be used to read the Broadcast Audio URI QR code with a few lines of JavaScript.

> NOTE: The BarcodeDetector API is [not yet available in all browsers](https://caniuse.com/mdn-api_barcodedetector).  For this reason, a [polyfill](https://github.com/undecaf/barcode-detector-polyfill) will be used where support is still missing.

Reading barcodes with this API is extremely simple. It only requires passing an image source to the [`detect()`](https://developer.mozilla.org/en-US/docs/Web/API/BarcodeDetector/detect) function, which returns a Promise that fulfills with an array of `DetectedBarcode` objects.

> Even though we are only focused on QR codes in this post, the API supports [many commonly used formats](https://developer.mozilla.org/en-US/docs/Web/API/Barcode_Detection_API#supported_barcode_formats).

# Lights, Camera, Action!
First, the camera needs to be switched on and streaming a video feed to an `HTMLVideoElement`:

```html
...
<video id="camera"
       muted
       autoplay="autoplay"
       playsinline="playsinline">
</video>
...
```

and 

```javascript
...
const camera = document.querySelector('#camera');
const constraints = {video: true, audio: false};
let stream = await navigator.mediaDevices.getUserMedia(constraints);

camera.srcObject = stream;
...
```

We also need to make a barcode detector object:

```javascript
const barcodeDetector = new window.BarcodeDetector();
```

In order for the detection to work as expected, the `detect` function needs to be called at regular intervals to scan images captured with the camera:

```javascript
let lastCode = "";

async function decodeQr(){
  const barcodes = await barcodeDetector.detect(camera);
  
  if (barcodes?.length) {
    for (const barcode of barcodes) {
      // Try to parse the URI string
      const decoded = parseBroadcastURI(barcode.rawValue);
      
      if (decoded?.length) {
        // Avoid repainting if the data is already shown
        if (lastCode == barcode.rawValue) {
          break;
        }
        
        lastCode = barcode.rawValue;
        
        // Display the parsed info
        showBroadcastInfo(decoded);
        
        break; // Only use the first code found
      }
    }
  } else {
    lastCode = "";
  }
  
  // Try again in 100ms
  setTimeout(this.decodeQr, 100);
}
```

# Parsing the Broadcast Audio URI
The scanned code should contain a string, starting with `BLUETOOTH:`, followed by a number of fields as listed in the [Broadcast Audio URI spec](https://www.bluetooth.com/specifications/specs/broadcast-audio-uri-2/). 

A QR code example from the spec: 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aodcm2qe8edu74vcm819.png)

, containing the following data:

```
BLUETOOTH:UUID:184F;BN:SG9ja2V5;SQ:1;AT:0;AD:AABBCC001122;AS:1;BI:DE51E9;PI:F
FFF;NS:1;BS:1;;
```

roughly translates to:

"Related to the 0x184F UUID (Broadcast Audio Scan Service), there is a Standard Quality mono channel broadcast at addresss AA:BB:CC:00:11:22 with Broadcast ID 0x0E51E9 and the Broadcast name 'Hockey'"

For this PoC, I created a very simple function to parse the most common fields:

```javascript
const BROADCAST_AUDIO_URI_SCHEME = 'BLUETOOTH:';

const parseBroadcastURI = (str) => {
  if (!str.startsWith(BROADCAST_AUDIO_URI_SCHEME)) {
    return [];
  }
  
  const result = [];
  
  // split sections (;)
  const sections = str.substring(BROADCAST_AUDIO_URI_SCHEME.length).split(';');
  
  sections.forEach(section => {
    const [key, value] = section.split(':');
    
    switch (key) {
      case 'UUID':
      result.push({
        type: key,
        name: 'UUID',
        value: `0x${value}`
      });
      break;
      case 'BI': // Broadcast ID
      result.push({
        type: key,
        name: 'Broadcast ID',
        value: `0x${value.padStart(6,0)}`
      });
      case 'BN': // Broadcast name
      result.push({
        type: key,
        name: 'Broadcast Name',
        value: new TextDecoder().decode(base64ToBytes(value))
      });
      break;
      // ... (more fields in full scouce)
    }
  });
  
  return result;
}
```

# QR Scanner component
In order to make it possible for others to more easily embed the BAU QR scanner in a web application, I decided to create a [web component](https://developer.mozilla.org/en-US/docs/Web/API/Web_components) that encapsulates the logic to control the video feed and display the information found in an overlay info box.

In order to use it in a page, just add the following:

```html
<bau-scanner></bau-scanner>
<script type="module" src="./bau-scanner.js"></script>
```

The element has functions to start and stop the scanning (and camera feed), which can be hooked up to button events, e.g.:

```html
...
<button id="start_scanner">Start scanner</button>
<button id='stop_scanner'>Stop scanner</button>
...
```

and 

```javascript
...
const startScan = document.querySelector('#start_scanner');
const stopScan = document.querySelector('#stop_scanner');

scanner = document.querySelector('bau-scanner');

startScan.addEventListener('click', scanner.startCamera);
stopScan.addEventListener('click', scanner.stopCamera);
...
```

An example `index.html` together with the `bau-scanner.js` component can be found here: https://github.com/larsgk/bau-source

# See it in action
For demonstration purposes, I decided to use two QR codes from the Broadcast Audio URI spec plus a dynamic one, generated with the Broadcast Audio Source sample covered in [another post](https://dev.to/denladeside/broadcast-audio-uri-1kkd).

Here is the scanner in action, running on a mobile phone: 

{% youtube tO0uh2rrVfg %}

You can try it yourself by opening this link, where the demo page is hosted: https://larsgk.github.io/bau-source/

Enjoy ;)