---
url: https://corewire.dev/protocols/discovery.md
---
# Discovery

```ts
import { Discovery, mdnsMulticast, mdnsUnicast } from '@corewire/core/discovery';
```

`@corewire/core/discovery` has its own DNS encoder and decoder, with no dependencies. It sends DNS-SD queries over multicast or unicast from a socket per network interface.

## The Discovery class

A `Discovery` searches for one service type.

```ts
import { Discovery } from '@corewire/core/discovery';

const airplay = new Discovery('_airplay._tcp.local');

const all = await airplay.find();
const one = await airplay.findUntil('Living-Room.local');
const byAddress = await airplay.findByAddress('192.168.1.20');

console.log(all.length, one.address, byAddress?.service.port);
```

| Method | Meaning |
| --- | --- |
| `find(useCache = true)` | One multicast scan; a scan less than 30 seconds old is reused |
| `findUntil(id, tries = 10, timeout = 1000)` | Scans without cache until the id shows up, waiting `timeout` ms between tries; throws `DiscoveryError` after the last try |
| `findByAddress(address, timeout = 4, wakePorts = [])` | A unicast query to one address; null when it does not answer |
| `Discovery.findServices(services, useCache = true)` | One multicast scan for several service types, as a map |
| `Discovery.clearCache()` | Forgets every cached scan |
| `Discovery.wake(address, ports)` | Knocks on each port to wake a sleeping device |

A `DiscoveryResult` has the `id`, `address`, `txt` record, `fqdn` and the `service` port, protocol and type. The model identifier is in the TXT record, as `txt.model` or `txt.am`.

`DiscoverOptions` (`{useCache?: boolean}`) lives here once. The `discover()` of every protocol package and of `@corewire/devices` takes it.

The service constants live in the protocol packages: `AIRPLAY_SERVICE` in `@corewire/airplay`, `RAOP_SERVICE` in `@corewire/airplay/raop` and `COMPANION_LINK_SERVICE` in `@corewire/companion-link`. Each package also has a `discover()` of its own.

## Raw queries

`mdnsMulticast(services, timeout = 4)` and `mdnsUnicast(hosts, services, timeout = 4, wakePorts = [])` return `MdnsService` records with `name`, `type`, `address`, `port` and `properties`. Timeouts are in seconds.

```ts
import { mdnsUnicast } from '@corewire/core/discovery';

const services = await mdnsUnicast(['192.168.1.20'], ['_airplay._tcp.local', '_companion-link._tcp.local'], 5, [7000]);

for (const service of services) {
    console.log(service.type, service.port);
}
```

## Advertising

`MdnsResponder` advertises one service with periodic multicasts and answers queries for its type. It does not fully parse DNS questions, so keep it to quiet test networks.

```ts
import { MdnsResponder } from '@corewire/core/discovery';
import { Context } from '@corewire/core/transport';

const responder = new MdnsResponder(new Context('test').logger, {
    instance: 'Test Receiver',
    type: '_airplay._tcp.local',
    host: 'test-receiver.local',
    port: 7000,
    txt: {model: 'AppleTV14,1'}
});

responder.start();
```
