Audio Streaming¶
Audio RX/TX via the Icom audio UDP port (default 50003).
Naming Map¶
Low-level Opus methods are now explicitly suffixed with _opus.
High-level PCM APIs are available for both RX and TX.
| Scope | Preferred method names |
|---|---|
| Low-level Opus (current) | start_audio_rx_opus, stop_audio_rx_opus, start_audio_tx_opus, push_audio_tx_opus, stop_audio_tx_opus, start_audio_opus, stop_audio_opus |
| High-level PCM | start_audio_rx_pcm, stop_audio_rx_pcm, start_audio_tx_pcm, push_audio_tx_pcm, stop_audio_tx_pcm |
Deprecated aliases still work during the deprecation window (two minor releases):
start_audio_rx, stop_audio_rx, start_audio_tx, push_audio_tx, stop_audio_tx, start_audio, stop_audio.
AudioStream¶
rigplane.audio.lan_stream.AudioStream
¶
Manages audio RX/TX on the Icom audio UDP port.
Uses an :class:IcomTransport for the underlying UDP communication
(discovery, pings, retransmit). Audio-specific packet framing is
handled here.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
transport
|
IcomTransport
|
Connected IcomTransport for the audio port. |
required |
Example::
stream = AudioStream(audio_transport)
await stream.start_rx(my_callback)
# ... later
await stream.stop_rx()
state
property
¶
Current audio stream state.
transport
property
¶
Underlying transport.
add_rx_tap(callback)
¶
Add an additional RX listener (tap) that receives all audio packets.
get_audio_stats()
¶
Return runtime audio stats for the current stream.
Metrics and units:
rx_packets_received/rx_packets_delivered/tx_packets_sent: packet counters (>= 0).packets_lost: inferred missing RX packets (>= 0).packet_loss_percent: percentage in [0.0, 100.0].reorder_depth_ema_ms/jitter_max_ms: reorder-depth EMA and peak deviation estimates in ms (>= 0.0). Despite the legacyjitter_max_msname, both are reorder-depth metrics, not RFC 3550 jitter.underrun_count/overrun_count: jitter-buffer event counters (>= 0).estimated_latency_ms: current buffering latency estimate in ms (>= 0.0).jitter_buffer_depth_packets/jitter_buffer_pending_packets: packet counts (>= 0).
push_tx(audio_data)
async
¶
Send an audio frame to the radio.
Large payloads (e.g. raw PCM) are automatically chunked to fit the IC-7610 maximum audio payload size (1364 bytes per UDP packet), matching the wfview chunking behaviour.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
audio_data
|
bytes
|
Payload encoded with the negotiated TX audio codec. |
required |
Raises:
| Type | Description |
|---|---|
AudioNotStartedError
|
If not in transmitting state. |
remove_rx_tap(callback)
¶
Remove an RX tap.
start_rx(callback, *, jitter_depth=None)
async
¶
Start receiving audio from the radio.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
callback
|
Callable[[AudioPacket | None], None]
|
Called with each decoded :class: |
required |
jitter_depth
|
int | None
|
Override jitter buffer depth (0 to disable). Defaults to the value set at construction time. |
None
|
Raises:
| Type | Description |
|---|---|
AudioAlreadyStartedError
|
If already receiving or transmitting. |
start_tx()
async
¶
Start transmitting audio to the radio.
Can be called while already receiving (full-duplex).
Raises:
| Type | Description |
|---|---|
AudioAlreadyStartedError
|
If already transmitting. |
stop_rx()
async
¶
Stop receiving audio and flush remaining buffered packets.
stop_tx()
async
¶
Stop transmitting audio.
If RX is still active, state reverts to RECEIVING.
Runtime Audio Stats (get_audio_stats)¶
Use get_audio_stats() on AudioStream or on the Radio (from create_radio) to retrieve a JSON-friendly
snapshot of live stream quality metrics.
Metrics, Units, Bounds¶
| Field | Unit | Bounds | Notes |
|---|---|---|---|
active |
boolean | true/false |
Whether stream state is not idle |
state |
string | idle / receiving / transmitting |
Current stream state |
rx_packets_received |
packets | >= 0 |
Parsed RX audio packets |
rx_packets_delivered |
packets | >= 0 |
RX packets delivered to callback |
tx_packets_sent |
packets | >= 0 |
TX packets sent |
packets_lost |
packets | >= 0 |
Inferred missing RX packets |
packet_loss_percent |
percent | 0.0..100.0 |
packets_lost / (delivered + lost) |
reorder_depth_ema_ms |
milliseconds | >= 0.0 |
EMA of reorder depth (not RFC 3550 jitter) |
jitter_max_ms |
milliseconds | >= 0.0 |
Peak observed reorder-depth deviation |
underrun_count |
events | >= 0 |
Jitter-buffer underrun events |
overrun_count |
events | >= 0 |
Jitter-buffer overrun events |
estimated_latency_ms |
milliseconds | >= 0.0 |
Estimated buffering delay |
jitter_buffer_depth_packets |
packets | >= 0 |
Configured jitter depth (0 when disabled) |
jitter_buffer_pending_packets |
packets | >= 0 |
Currently buffered packets |
duplicates_dropped |
packets | >= 0 |
Duplicate RX packets dropped |
stale_packets_dropped |
packets | >= 0 |
Stale/old RX packets dropped |
out_of_order_packets |
packets | >= 0 |
RX packets observed out of sequence |
Capture Health And Bridge Metrics¶
PortAudio-backed capture and the PCM TX bridge expose a second set of metrics
that answer a different question from get_audio_stats(): whether the local
OS audio callback and the bridge TX path are keeping up.
Capture callback health (RxStreamHealth)¶
RxStreamHealth snapshots input-side callback delivery for RX-only and
full-duplex capture streams.
| Field | Unit | Meaning | Typical next step |
|---|---|---|---|
frames_delivered |
frames | PCM frames successfully handed to the bridge/callback | Confirms the callback is running at all |
input_overflow_events |
events | PortAudio reported captured input was dropped because the process/backend could not keep up | Check host CPU pressure, device/driver stability, and callback cadence before blaming RigPlane TX |
input_underflow_events |
events | PortAudio reported the input callback arrived without enough fresh captured samples | Check capture device/driver health and OS scheduling; this is still capture-side, not radio TX failure |
callback_errors |
events | Callback-level errors while processing capture frames | Inspect logs for the paired exception or status context |
callback_status_flags |
map | Per-flag totals such as input_overflow / input_underflow |
Use the exact flag mix to separate capture starvation from other failures |
Bridge TX path health (BridgeMetrics)¶
These counters are surfaced on AudioBridge.metrics, AudioBridge.stats, and
runtime bridge-status consumers such as the Web server's audio_bridge_stats.
| Field | Unit | Meaning | Not the same as |
|---|---|---|---|
capture_input_overflows |
events | Cumulative RxStreamHealth.input_overflow_events observed by the active bridge capture stream |
tx_overruns queue drops |
capture_input_underflows |
events | Cumulative RxStreamHealth.input_underflow_events observed by the active bridge capture stream |
TX playback underruns or radio write failures |
capture_callback_status_flags |
map | Bridge-side rollup of capture callback flags, for example {"input_overflow": 3} |
Silence gating decisions |
tx_silence_suppressed |
frames | Frames intentionally skipped because captured PCM stayed below the bridge silence/noise-gate threshold | Capture overrun or lost OS buffers |
tx_overruns |
events | Bridge TX queue drops: RigPlane evicted stale queued frames to preserve bounded latency before push_audio_tx_pcm() |
PortAudio callback overflow |
TX playback write health (TxStreamHealth)¶
These counters live on the writable PortAudio TX stream itself and describe playback-side queue pressure after audio has already left the bridge queue.
| Field | Unit | Meaning | Not the same as |
|---|---|---|---|
frames_queued |
frames | Total frames accepted from the producer/write side | Callback playback completions |
enqueued_audio_ms |
milliseconds | Total audio duration accepted from producer writes | Current live queue depth |
buffered_audio_ms |
milliseconds | Current queued playback audio still buffered in the writable stream | Cumulative accepted or consumed audio |
frames_dropped |
frames | TX playback frames dropped by the writable stream while preserving bounded latency | Silence gating or radio write failure |
dropped_audio_ms |
milliseconds | Total duration represented by dropped playback frames | Callback underruns |
enqueue_overrun_events |
events | TX playback queue overflow events on the writable stream | BridgeMetrics.tx_overruns bridge queue drops |
enqueue_overrun_audio_ms |
milliseconds | Total playback-queue audio duration dropped during TX stream overflow handling | Bridge capture callback overflow |
write_attempts |
callbacks | Total playback callback attempts / output fill cycles | Producer write() calls |
writes_completed |
callbacks | Playback callbacks that completed their output fill path | Producer enqueue success count |
write_failures |
events | Playback callback failures or fake-stream write failures | Queue overflow or underrun counters |
callback_consumed_audio_ms |
milliseconds | Audio duration actually consumed from the queued ring by the playback callback | Silence padded during underrun |
callback_output_audio_ms |
milliseconds | Total output duration the callback filled, including silence on underrun | Audio duration consumed from the queue |
callback_underrun_events |
events | Playback callbacks that had to pad with silence because queued audio ran short | Bridge queue overflow |
callback_underrun_audio_ms |
milliseconds | Total silence-padded output duration caused by playback underruns | Queue drops on producer overflow |
callback_calls_per_sec_ewma |
callbacks/sec | Smoothed callback cadence estimate for the active PortAudio stream | Producer write rate |
callback_errors |
events | Callback-level errors while filling playback output | Bridge capture callback errors |
callback_status_flags |
map | Per-flag totals such as output_underflow from PortAudio status callbacks |
Bridge metrics or radio send errors |
last_error |
string or null |
Most recent callback/write failure summary | Callback status flag counts |
Canonical producer/callback names above are the stable contract. Legacy aliases
remain available on TxStreamHealth attributes and in TxStreamHealth.to_dict()
for compatibility during the deprecation window:
queued_audio_ms->enqueued_audio_msconsumed_audio_ms->callback_consumed_audio_mswritten_audio_ms->callback_output_audio_msoverrun_audio_ms->enqueue_overrun_audio_msoverrun_events->enqueue_overrun_eventsunderrun_audio_ms->callback_underrun_audio_msunderrun_events->callback_underrun_eventswrite_calls_per_sec_ewma->callback_calls_per_sec_ewma
PortAudio-backed TX streams populate write_attempts, writes_completed,
callback cadence, and the callback-duration fields from actual playback-callback
activity. Fake TX/test-double streams are compatibility helpers rather than
PortAudio callback simulators: FakeTxStream keeps its historical producer-write
accounting, while duplex test doubles may only report captured write frames and
leave callback attempt, duration, or cadence fields at their defaults unless
they explicitly simulate playback.
Interpretation Rules¶
capture_input_overflows > 0means the OS capture callback already lost input before RigPlane could bridge it. Start with local capture/device pressure.tx_overruns > 0with zero capture overflow means capture kept running, but the bridge TX queue backed up and RigPlane dropped stale frames on purpose.TxStreamHealth.enqueue_overrun_events > 0,enqueue_overrun_audio_ms > 0, orframes_dropped > 0mean the writable TX playback queue overflowed later in the path; that is distinct from bridge queue pressure and uses different counters. Legacy alias names still report the same values.tx_silence_suppressed > 0means quiet frames were filtered by policy. This is expected during RX silence and is not evidence of callback starvation.- Downstream TX push/write failures live elsewhere:
TxStreamHealth.write_failures,last_error, or radio/backend error logs indicate that RigPlane tried to send audio onward and that stage failed after capture succeeded.
AudioPacket¶
rigplane.audio.lan_stream.AudioPacket
dataclass
¶
Parsed audio packet.
Attributes:
| Name | Type | Description |
|---|---|---|
ident |
int
|
Audio stream identifier (0x0080 for TX, varies for RX). |
send_seq |
int
|
Audio-level sequence number. |
data |
bytes
|
Raw audio payload (format depends on negotiated codec — PCM16, uLaw, or Opus). Bytes after Icom LAN header. |
AudioState¶
rigplane.audio.lan_stream.AudioState
¶
Bases: StrEnum
Audio stream state.
JitterBuffer¶
rigplane.audio.lan_stream.JitterBuffer
¶
Reorder-and-delay buffer for incoming audio packets.
Collects packets and delivers them in sequence-number order after
a configurable depth of buffering. Handles out-of-order packets,
duplicates, and gaps (delivering None for missing packets).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
depth
|
int
|
Number of packets to buffer before delivery (default 5, which is ~100 ms at 20 ms/packet). |
5
|
Example::
jb = JitterBuffer(depth=5)
for pkt in jb.push(audio_packet):
if pkt is None:
# gap — insert silence
...
else:
play(pkt.data)
depth
property
¶
Configured buffer depth (number of packets).
duplicate_count
property
¶
Count of duplicate packets dropped.
gap_count
property
¶
Count of inferred missing packets (gap placeholders).
overrun_count
property
¶
Count of jitter-buffer overrun events.
pending
property
¶
Number of packets currently held in the buffer.
stale_count
property
¶
Count of stale/old packets dropped.
underrun_count
property
¶
Count of jitter-buffer underrun events.
flush()
¶
Flush all buffered packets in order (for stream end).
Returns:
| Type | Description |
|---|---|
list[AudioPacket | None]
|
Remaining packets in order (None for gaps). |
push(packet)
¶
Insert a packet and return any packets ready for delivery.
Packets are delivered in order. If a gap is detected (missing
sequence number), None is yielded in its place.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
packet
|
AudioPacket
|
Incoming audio packet. |
required |
Returns:
| Type | Description |
|---|---|
list[AudioPacket | None]
|
List of packets (or None for gaps) ready for playback. |
list[AudioPacket | None]
|
May be empty if more buffering is needed. |
Packet Functions¶
rigplane.audio.lan_stream.parse_audio_packet(data)
¶
Parse a raw UDP audio packet into an :class:AudioPacket.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
bytes
|
Raw UDP packet bytes (must be > 0x18 bytes). |
required |
Returns:
| Type | Description |
|---|---|
AudioPacket | None
|
Parsed AudioPacket, or None if the packet is too short or |
AudioPacket | None
|
is a control/retransmit packet (type != DATA). |
rigplane.audio.lan_stream.build_audio_packet(audio_data, *, sender_id, receiver_id, send_seq, ident=TX_IDENT)
¶
Build a raw UDP audio packet from negotiated-codec audio data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
audio_data
|
bytes
|
Audio payload encoded with the negotiated stream codec. |
required |
sender_id
|
int
|
Our connection ID. |
required |
receiver_id
|
int
|
Radio's connection ID. |
required |
send_seq
|
int
|
Audio-level sequence number. |
required |
ident
|
int
|
Audio ident field (default TX_IDENT=0x0080). |
TX_IDENT
|
Returns:
| Type | Description |
|---|---|
bytes
|
Complete UDP packet bytes ready to send. |
Internal Transcoder Layer¶
rigplane now includes an internal PCM<->Opus transcoder foundation used for
future high-level PCM APIs.
- Module:
rigplane._audio_transcoder(internal, no stability guarantee yet) - Backend: optional
opuslib(pip install rigplane[audio]) - Typed failures:
AudioCodecBackendErrorfor missing backendAudioFormatErrorfor invalid PCM/Opus frame formatsAudioTranscodeErrorfor codec encode/decode failures
AudioBus (pub/sub multi-consumer)¶
rigplane.audio.bus.AudioBus
¶
Fan-out distribution bus for radio audio packets.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
radio
|
Any
|
A radio instance implementing AudioCapable. |
required |
jitter_depth
|
int
|
Jitter buffer depth passed to radio RX start. |
5
|
last_rx_frame_monotonic
property
¶
time.monotonic() of the most recent RX fan-out, or None.
RX liveness heartbeat (MOR-564): observability only, no watchdog.
restart_rx()
async
¶
Re-establish RX on the radio using the bus's own callback.
Used after a half-duplex TX cycle (e.g. the web poller's PTT-off
transition on Icom CI-V backends): the radio's single-slot RX
callback must be restored to :meth:_on_opus_packet so subscribers
keep receiving frames. No-op when the bus has no active subscribers.
A re-arm failure is non-fatal for the established session (a hiccup
must not crash healthy subscribers) but never masked as success:
rx_active drops to False so stats and the recovery watchdog see
the dead RX leg (MOR-582). The typed already-started case is benign
— RX stayed live through the TX cycle (LAN) and remains wired to
this bus, so it stays marked live.
stop()
async
¶
Stop the bus and all subscribers.
subscribe(name='', queue_size=_DEFAULT_QUEUE_SIZE)
¶
Create a new subscription (not yet active — call start() or use as context manager).
taps(stage)
¶
Return the :class:TapRegistry for a named RX stage on this bus.
Only STAGE_RX_PCM is hosted here; reserved stage names raise
KeyError. Taps are attachable/detachable at runtime and add no
cost when empty (the registry no-ops without subscribers).
rigplane.audio.bus.AudioSubscription
¶
A single subscriber to the audio bus.
Receives copies of every audio packet via an internal asyncio.Queue.
Can be iterated with async for or read manually with :meth:get.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
bus
|
AudioBus
|
Parent AudioBus. |
required |
name
|
str
|
Human-readable subscriber name (for logging). |
''
|
queue_size
|
int
|
Maximum buffered packets before dropping. |
_DEFAULT_QUEUE_SIZE
|
aclose(timeout=_DEFAULT_CLOSE_TIMEOUT)
async
¶
Deactivate this subscription and await bus removal.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeout
|
float | None
|
Maximum seconds to wait for teardown. |
_DEFAULT_CLOSE_TIMEOUT
|
deliver(packet)
¶
Called by the bus to deliver a packet (non-blocking).
get(timeout=None)
async
¶
Get the next packet (blocks until available or timeout).
get_nowait()
¶
Get a packet without blocking (raises QueueEmpty).
start()
async
¶
Activate this subscription (registers with the bus).
Raises if this subscription's demand triggers the radio RX start and the start fails (MOR-582): the subscription is left inactive and unregistered — never "attached" to a bus that is not receiving.
stop()
¶
Deactivate this subscription and schedule bus removal.
This method is intentionally synchronous for backward compatibility.
Prefer :meth:aclose in async teardown paths when callers need to know
removal has completed.
The AudioBus provides pub/sub distribution for radio RX audio. Multiple consumers (WebSocket broadcaster, audio bridge, recorders) share a single radio RX stream.
Basic Usage¶
from rigplane import create_radio, LanBackendConfig
config = LanBackendConfig(host="192.168.1.100", username="u", password="p")
async with create_radio(config) as radio:
# Subscribe to audio bus
async with radio.audio_bus.subscribe(name="my-app") as sub:
async for packet in sub:
if packet is not None:
process(packet.data) # opus bytes
Multiple Consumers¶
bus = radio.audio_bus
# Web UI gets audio
web = bus.subscribe(name="web-audio")
await web.start()
# Bridge gets audio simultaneously
bridge = bus.subscribe(name="audio-bridge")
await bridge.start()
# Both receive the same packets independently
# First subscriber triggers radio.start_audio_rx_opus()
# Last awaited close triggers radio.stop_audio_rx_opus()
await web.aclose()
await bridge.aclose()
Subscriptions support async with, await sub.aclose(), and the older
sub.stop() convenience path. Prefer async with or await aclose() when
coordinating restart/teardown: the awaited close path removes the subscriber
before the caller proceeds, so bridge or WebSocket restarts do not race a stale
subscriber.
Properties¶
| Property | Type | Description |
|---|---|---|
subscriber_count |
int |
Number of active subscribers |
rx_active |
bool |
Whether radio RX is currently streaming |
Queue And Frame Semantics¶
Audio queues are bounded to preserve real-time behavior. When the bridge TX
queue overflows, RigPlane drops the oldest queued audio and keeps the newest
live frame. Diagnostics count that bridge-side event as tx_overruns.
When the writable TX playback queue overflows later in the path, TxStreamHealth
tracks it separately via enqueue_overrun_events,
enqueue_overrun_audio_ms, and frames_dropped. Those playback counters are
not reported as tx_overruns. Legacy aliases overrun_events and
overrun_audio_ms still mirror the canonical values for compatibility.
Do not confuse bridge queue drops with PortAudio capture callback overflow:
tx_overruns means RigPlane chose to evict stale already-captured audio,
whereas capture_input_overflows / input_overflow_events mean the OS/backend
capture callback reported lost input before the bridge queue decision.
PortAudio capture uses engine-native callback periods (blocksize=0) and then
losslessly re-chunks the continuous callback stream into fixed frame_ms
frames before handing it to PCM TX validators. At 48 kHz, 16-bit mono,
frame_ms=20 means each emitted TX frame is 1920 bytes. Consumers should still
treat WebSocket/DataChannel frame_ms as an advisory label and derive actual
duration from payload size and metadata.
Module Constants¶
MAX_AUDIO_PAYLOAD¶
Maximum audio payload in bytes per TX UDP packet.
The IC-7610 silently drops TX audio UDP packets whose payload exceeds 1364 bytes. This limit is undocumented but observed empirically and matches the wfview source:
push_tx() automatically chunks oversized payloads:
push_tx(pcm_frame) # 1920-byte 20ms PCM frame @ 48kHz/16-bit
→ chunk 0: bytes [0 : 1364] → 1364-byte UDP payload ✓
→ chunk 1: bytes [1364 : 1920] → 556-byte UDP payload ✓
The two chunk sizes — 1364 and 556 bytes — correspond to the fixed audio payload sizes
documented in wfview for the IC-7610. Low-level callers do not need to pre-chunk payloads.
The high-level push_audio_tx_pcm() API still requires one complete PCM frame at the
configured sample rate, channel count, and frame duration.
Usage¶
RX Audio (callback-based)¶
from rigplane import create_radio, LanBackendConfig
config = LanBackendConfig(host="192.168.1.100", username="u", password="p")
async with create_radio(config) as radio:
received = []
def on_audio(pkt):
if pkt is not None: # None = gap (missing packet)
received.append(pkt.data)
await radio.start_audio_rx_opus(on_audio)
await asyncio.sleep(10)
await radio.stop_audio_rx_opus()
RX Audio (high-level PCM)¶
config = LanBackendConfig(host="192.168.1.100", username="u", password="p")
async with create_radio(config) as radio:
def on_pcm(frame: bytes | None) -> None:
if frame is None:
return # gap placeholder from jitter buffer
# frame is 16-bit little-endian PCM for configured format
process_pcm(frame)
await radio.start_audio_rx_pcm(
on_pcm,
sample_rate=48000,
channels=1,
frame_ms=20,
jitter_depth=5,
)
await asyncio.sleep(10)
await radio.stop_audio_rx_pcm()
TX Audio (push-based)¶
config = LanBackendConfig(host="192.168.1.100", username="u", password="p")
async with create_radio(config) as radio:
await radio.start_audio_tx_opus()
await radio.push_audio_tx_opus(audio_payload)
await radio.stop_audio_tx_opus()
The low-level method names are historical. For direct Icom LAN sessions,
rigplane currently negotiates TX as PCM_1CH_16BIT, so the TX payload sent to
the radio is raw PCM16LE. Opus TX payloads are only valid for endpoints that
negotiate an Opus TX codec, such as wfview-compatible server paths.
TX Audio (high-level PCM)¶
config = LanBackendConfig(host="192.168.1.100", username="u", password="p")
async with create_radio(config) as radio:
await radio.start_audio_tx_pcm(sample_rate=48000, channels=1, frame_ms=20)
await radio.push_audio_tx_pcm(pcm_frame) # one 20ms PCM frame (1920 bytes)
await radio.stop_audio_tx_pcm()
Full-Duplex¶
config = LanBackendConfig(host="192.168.1.100", username="u", password="p")
async with create_radio(config) as radio:
await radio.start_audio_opus(rx_callback=on_audio, tx_enabled=True)
# ... push TX frames, receive RX via callback ...
await radio.stop_audio_opus()
Codec Selection¶
from rigplane import create_radio, LanBackendConfig, AudioCodec
config = LanBackendConfig(
host="192.168.1.100",
username="u",
password="p",
audio_codec=AudioCodec.PCM_1CH_16BIT, # default
audio_sample_rate=48000,
)
async with create_radio(config) as radio:
...
Capability Introspection¶
Use the capability API to inspect negotiated client-side audio options and defaults. The same API is available on the Radio returned by create_radio and on IcomRadio (legacy):
from rigplane import create_radio, get_audio_capabilities, LanBackendConfig
config = LanBackendConfig(host="192.168.1.100", username="u", password="p")
# Static defaults (no connection required):
caps = get_audio_capabilities()
print(caps.supported_codecs)
print(caps.supported_sample_rates_hz)
print(caps.supported_channels)
print(caps.default_codec, caps.default_sample_rate_hz, caps.default_channels)
For legacy LAN-only code, IcomRadio.audio_capabilities() returns the same structure.
Deterministic default selection rules:
- Codec: first supported codec in rigplane preference order.
- Sample rate: highest supported sample rate.
- Channels: the channel count implied by default codec (fallback: minimum supported channels).
Opus codecs
OPUS_1CH (0x40) and OPUS_2CH (0x41) are only supported when
the radio reports connection_type == "WFVIEW". Standard connections
use LPCM16 (0x04).
Migration¶
Use the explicit _opus methods now:
| Deprecated alias | Replacement |
|---|---|
start_audio_rx |
start_audio_rx_opus |
stop_audio_rx |
stop_audio_rx_opus |
start_audio_tx |
start_audio_tx_opus |
push_audio_tx |
push_audio_tx_opus |
stop_audio_tx |
stop_audio_tx_opus |
start_audio |
start_audio_opus |
stop_audio |
stop_audio_opus |
For RX PCM, migrate callback-side decoding to the built-in API:
- Before:
start_audio_rx_opus()+ manual Opus decode in callback. - Now:
start_audio_rx_pcm()and receivebytes | Nonedirectly.
For TX PCM, migrate manual Opus encoding to the built-in API:
- Before: manually prepare the low-level negotiated-codec payload and call
push_audio_tx_opus(). - Now:
start_audio_tx_pcm()andpush_audio_tx_pcm()with fixed-size PCM frames.