Audio Streaming¶
Audio RX/TX via the Icom audio UDP port (default 50003).
AudioStream¶
icom_lan.audio.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.
push_tx(opus_data)
async
¶
Send an Opus-encoded audio frame to the radio.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
opus_data
|
bytes
|
Opus-encoded audio data. |
required |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If not in transmitting state. |
start_rx(callback, *, jitter_depth=None)
async
¶
Start receiving audio from the radio.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
callback
|
Callable[[AudioPacket], 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 |
|---|---|
RuntimeError
|
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 |
|---|---|
RuntimeError
|
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.
AudioPacket¶
icom_lan.audio.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
|
Opus-encoded audio data (raw bytes after header). |
AudioState¶
icom_lan.audio.AudioState
¶
Bases: StrEnum
Audio stream state.
JitterBuffer¶
icom_lan.audio.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).
pending
property
¶
Number of packets currently held in the buffer.
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¶
icom_lan.audio.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). |
icom_lan.audio.build_audio_packet(opus_data, *, sender_id, receiver_id, send_seq, ident=TX_IDENT)
¶
Build a raw UDP audio packet from Opus data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
opus_data
|
bytes
|
Opus-encoded audio frame. |
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. |
Usage¶
RX Audio (callback-based)¶
async with IcomRadio("192.168.1.100", username="u", password="p") 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(on_audio)
await asyncio.sleep(10)
await radio.stop_audio_rx()
TX Audio (push-based)¶
async with IcomRadio("192.168.1.100", username="u", password="p") as radio:
await radio.start_audio_tx()
await radio.push_audio_tx(opus_frame)
await radio.stop_audio_tx()
Full-Duplex¶
async with IcomRadio("192.168.1.100", username="u", password="p") as radio:
await radio.start_audio(rx_callback=on_audio, tx_enabled=True)
# ... push TX frames, receive RX via callback ...
await radio.stop_audio()
Codec Selection¶
from icom_lan import IcomRadio, AudioCodec
radio = IcomRadio(
"192.168.1.100",
audio_codec=AudioCodec.PCM_1CH_16BIT, # default
audio_sample_rate=48000,
)
Opus codecs
OPUS_1CH (0x40) and OPUS_2CH (0x41) are only supported when
the radio reports connection_type == "WFVIEW". Standard connections
use LPCM16 (0x04).