# `tecs.platform.audionative`
The `tecsaudio` binding behind the audio backend contract.
Loading this module loads `libtecsaudio` through
`tecs.internal.nativelibrary`, so a build that cannot find the library raises
here rather than anywhere later. `tecs.audio` requires it through `pcall` for
exactly that reason and falls back to `tecs.platform.audiobackend.silent` when
it is absent.
Commands cross as one contiguous C array per flush and finished voices come back
as a second one. Nothing in the library ever calls a Nupp function: a `cpal`
output callback runs on a thread the Lua virtual machine never created, and
entering Nupp from there is undefined. Every observation is therefore pulled by
`drain` from the frame thread instead, which is why this binding declares no
function pointer anywhere.
```nupp
local backend = assert(tecs.platform.audionative.open(48000, 2, 32))
```
## Functions
### `devices` _function_
```nupp
function devices(): audiobackend.Devices
```
Returns the device provider backed by the library.
Building it opens nothing and lists nothing: every call on the returned
record reaches the platform, and none of them runs here. That matters
because listing devices goes through the same platform machinery an open
goes through, so resolving a provider has to stay clear of it.
#### Returns
| Type | Description |
| --- | --- |
| `audiobackend.Devices` | a provider naming the platform's devices and opening its microphones |
### `offlineDevices` _function_
```nupp
function offlineDevices(): audiobackend.Devices
```
Returns a provider whose captures touch no recording device.
Its listings are empty, and `open` answers with a capture whose frames the
caller supplies through `write`. This is what a test that has to prove the
capture seam reaches for, and it is deliberately not what `tecs.audio`
resolves: opening a real recording device can block inside the platform's
audio daemon, and a headless suite must not be able to.
#### Returns
| Type | Description |
| --- | --- |
| `audiobackend.Devices` | a provider naming no devices and opening device-free captures |
### `open` _function_
```nupp
function open(frequency: integer, channels: integer, maxVoices: integer): audiobackend.Backend?, string?
```
Opens the platform's default output and returns it as a backend.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `frequency` | `integer` | the requested output frequency in frames per second |
| `channels` | `integer` | the requested number of output channels |
| `maxVoices` | `integer` | the greatest number of voices the mixer holds at once |
#### Returns
| Type | Description |
| --- | --- |
| `audiobackend.Backend?` | the backend, or nil when the library opened nothing |
| `string?` | the reason, when the first return is nil |
### `openOffline` _function_
```nupp
function openOffline(frequency: integer, channels: integer, maxVoices: integer): audiobackend.Backend?, string?
```
Opens a backend that touches no output device.
Every command still crosses and every query still answers; the mix goes
nowhere unless the caller renders it, which nothing on this side does. This
is what a test that has to prove the seam without needing a sound card
reaches for, and it is deliberately not what `tecs.audio` opens: opening a
real output can block inside the platform's audio daemon, and a headless
suite must not be able to.
#### Arguments
| Name | Type | Description |
| --- | --- | --- |
| `frequency` | `integer` | the output frequency in frames per second |
| `channels` | `integer` | the number of output channels |
| `maxVoices` | `integer` | the greatest number of voices the mixer holds at once |
#### Returns
| Type | Description |
| --- | --- |
| `audiobackend.Backend?` | the backend, or nil when the library refused |
| `string?` | the reason, when the first return is nil |