Skip to content

Wi Fi Direct

Marco Ceccon edited this page Oct 12, 2026 · 2 revisions

Wi-Fi Direct is the second link to the glasses, next to Bluetooth. The phone owns a Wi-Fi Direct group, the glasses join it, and the same session then runs over TCP. Bulk media and live video use it, because Bluetooth is too slow for either.

Why Wi-Fi

Bluetooth carries about 120 to 165 KB/s of media. Over Wi-Fi Direct the same media moves about 10 MB/s. A 4 Mbit/s HEVC stream does not fit in the Bluetooth figure of about 1 Mbit/s, which is unconfirmed. See Throughput.

Service 10 messages

Service 10 is ATC LinkManager2. It moves the glasses onto a network. It needs a scoped link, which the session gets at EndLinkSetup. The join carries a v4 UUID of its own as well. See Link-setup-and-AirShield.

Type Name Direction Use
0x1010 JoinAccessPoint phone to glasses Puts the glasses on the phone's group
0x1011 JoinAccessPointResult glasses to phone Status, address and port
0x1012 LeaveAccessPoint phone to glasses Sent before the group goes, empty body

JoinWifiDirectGroup (0x100b) fails with status 3 (JOIN_FAILED). The phone uses JoinAccessPoint instead.

An unknown type gets answer 0xd001. A known type with a body that will not parse gets 0xd010.

JoinAccessPoint fields

The phone sends the join over the Bluetooth session.

Field Type Content Rule
1 string SSID The group name the phone chose
2 string Passphrase 20 characters
3 bytes, 16 UUID Must be version 4: byte 6 high nibble 0x4, byte 8 high bits 10
4 varint Bandwidth 0 unspecified, 1 20 MHz, 2 40 MHz, 3 80 MHz

A join without a valid v4 UUID gets status 2 and never reaches the radio. The rule is the same one EndLinkSetup needs.

Field 4 is sent but has no effect on a join. The glasses use the bandwidth only for a SoftAP of their own. A join that asked for 20 MHz still brought the group up at 80 MHz.

JoinAccessPointResult fields

Field Type Content Notes
1 varint Status 1 SUCCESS, 2 INTERNAL_ERROR, 3 JOIN_FAILED, 4 UNAVAILABLE, 5 BAD_INPUT, 6 TIMED_OUT, 7 CANCELLED, 8 BUSY, 9 WIFI_NOT_ENABLED, 10 THROTTLED_THERMAL, 11 THROTTLED_LOW_BATTERY
2 message, repeated Addresses Each NetworkAddress holds the address as text in field 3
3 varint Port Chosen by the glasses for each join

A usable result has status 1, an address and a port above zero.

After a Wi-Fi firmware restart the join answers INTERNAL_ERROR for 15 to 45 s. See The 80 MHz firmware hang.

Who owns the group

The phone owns the group. The glasses only join.

The glasses have a client that joins a group. No request makes them create one. The Meta app works the same way: the phone is the group owner and gives the glasses a client address. The phone's group-owner address is usually 192.168.49.1. The glasses report their own address in the join result.

Switch from Bluetooth to Wi-Fi

The phone starts the group, asks for the join over Bluetooth, connects TCP, and only then pauses Bluetooth.

sequenceDiagram
    participant Phone
    participant Glasses
    Note over Phone: group up with SSID and passphrase
    Phone->>Glasses: 0x1010 JoinAccessPoint over Bluetooth
    Glasses-->>Phone: 0x1011 status 1, address, port
    Phone->>Glasses: TCP connect to address and port
    Phone->>Glasses: AirShield handshake, trust, EndLinkSetup
    Glasses-->>Phone: EndLinkSetup, services ready
    Note over Phone: Bluetooth session paused
    Note over Glasses: leaves Bluetooth once on Wi-Fi
Loading

The steps in order:

  1. The phone starts the group with its SSID and passphrase.
  2. The phone sends JoinAccessPoint over Bluetooth. Once the glasses are on Wi-Fi they leave Bluetooth, and a later request on Bluetooth never arrives.
  3. The glasses answer with JoinAccessPointResult. A usable result has status 1, an address and a port.
  4. The phone opens TCP to the address and port. The socket carries raw SDUs with no length prefix, framed as on RFCOMM. See Transport-and-framing.
  5. The phone runs the normal session over TCP: AirShield, trust, EndLinkSetup. The glasses answer with EndLinkSetup and services ready.
  6. Only then does the phone pause the Bluetooth session.

Going back to Bluetooth:

  1. The phone sends LeaveAccessPoint over Wi-Fi. The Meta app sends it before the group goes.
  2. The phone stops the TCP session and removes the group.
  3. The phone resumes the Bluetooth session.

One session at a time

The glasses hold one AirShield session across all their links. A new session closes the old one.

An RFCOMM session that reaches READY while an LE session is ready closes the LE session within 50 ms. Each retry repeats this. A Wi-Fi session closes the LE session. An LE reconnect then closes the Wi-Fi session in the middle of a transfer.

So the phone pauses the Bluetooth session for the whole Wi-Fi job. The LE GATT link stays up. Only the session is paused.

A Live AI session is the exception. It runs over the Bluetooth session and does not pause it. See Live-stream.

Throughput

Path Rate
Media over Wi-Fi Direct, 1.1 MB file 10,036 KB/s
Media over Wi-Fi Direct, 20.8 MB video 10,480 KB/s, about 2 s
Same media over Bluetooth Classic 120 to 165 KB/s
1080p at 4 Mbit/s HEVC on a 2.4 GHz group Runs at 30 fps
Bluetooth link for video About 1 Mbit/s, unconfirmed

The rate does not fall as files get bigger. The 20 MB transfer ran slightly faster per byte than the 1 MB one.

The 80 MHz firmware hang

On 5 GHz the video stream stops every time. The fault is in the glasses' Wi-Fi firmware.

  • The group follows the phone's own Wi-Fi. On 5180 MHz the group runs at 80 MHz. Each join logs "Configured bandwidth is 80000000".
  • The firmware logs "Received firmware hang event", then RDDM, then a subsystem restart. The phone sees the stream stall at that same moment.
  • On 5 GHz the stream stops 6 to 15 s after it starts, every time.
  • Right after the restart, JoinAccessPoint answers INTERNAL_ERROR for 15 to 45 s.
  • A bulk transfer at 5 GHz did not hit the hang. The fault is in the video stream, not in throughput alone.
  • On a 2.4 GHz group (20 MHz), 1080p at 4 Mbit/s runs clean.
  • Setting field 4 of the join to 20 MHz does not prevent the hang.

Reference code: Wifi.kt

Open questions

  • Unconfirmed: whether 5 GHz at 20 or 40 MHz avoids the hang.
  • Unconfirmed: whether a long bulk transfer at 5 GHz can hit the hang.
  • Unconfirmed: whether LeaveAccessPoint is needed for the next join to succeed.
  • Why the join answers INTERNAL_ERROR for up to 45 s after a restart is unknown.
  • The effect of SetSessionInfo (0x1009) on a join is unknown. The phone does not send it.
  • Unconfirmed: whether the group-owner address is 192.168.49.1 on every phone.

Clone this wiki locally