Skip to content

Releases: mijahauan/ka9q-python

v3.4.2: Bug Fixes and Enhanced Documentation

05 Feb 12:40

Choose a tag to compare

Release v3.4.2: Bug Fixes and Enhanced Documentation

This release focuses on improving the user experience through bug fixes, comprehensive documentation, and better organization of examples.

πŸ› Bug Fixes

Fixed stream_example.py Bug

Fixed a critical bug in examples/stream_example.py where the code incorrectly iterated over the dictionary returned by discover_channels(). The example now correctly accesses ChannelInfo objects, preventing an AttributeError and allowing the example to run as intended.

This was a high-impact bug that would have prevented new users from successfully running one of the key examples.

πŸ“š Documentation Enhancements

New Getting Started Guide

Added a comprehensive docs/GETTING_STARTED.md file that serves as the primary entry point for new users. This guide includes:

  • Step-by-step installation instructions
  • A simple, annotated first program (creating an AM radio channel)
  • Detailed explanations of core concepts (RadiodControl, ChannelInfo, stream abstraction layers)
  • A comparison table of the three stream APIs (RTPRecorder, RadiodStream, ManagedStream)
  • Complete working examples with ManagedStream
  • Common troubleshooting tips

Examples Organization

Added a new examples/README.md that transforms the examples directory into a structured learning resource:

  • Categorizes examples by complexity (basic, intermediate, advanced)
  • Provides detailed descriptions for each example (what it does, concepts demonstrated, how to run it)
  • Recommends a learning path for new users
  • Includes usage instructions and expected output for each example

Updated API Documentation

The documentation for create_channel() in docs/API_REFERENCE.md has been updated to match the actual implementation:

  • Added missing destination parameter (for RTP destination multicast address)
  • Added missing encoding parameter (for output encoding like F32, S16LE, OPUS)
  • Corrected parameter order to match the actual function signature
  • Added return type documentation (returns int SSRC)
  • Enhanced examples with both basic and advanced usage patterns

Updated Main README

The main README.md now links prominently to the new Getting Started guide, making it easier for new users to find the beginner-friendly tutorial.

πŸ“Š Impact

These changes significantly improve the user onboarding experience:

  • For new users: Clear, guided path from installation to first working application
  • For existing users: No breaking changes, just better documentation and a bug fix
  • For contributors: Better structure makes it easier to understand and contribute

πŸ“¦ Installation

pip install ka9q-python==3.4.2

Or upgrade from a previous version:

pip install --upgrade ka9q-python

πŸ”— Links

πŸ“ Full Changelog

Added

  • Comprehensive Getting Started Guide: Added docs/GETTING_STARTED.md with step-by-step tutorial for new users
  • Examples README: Added examples/README.md to organize examples by complexity and provide learning path

Fixed

  • stream_example.py Bug: Fixed incorrect dictionary iteration that caused AttributeError

Changed

  • Updated API Documentation: Complete documentation for create_channel() including all parameters
  • Updated README: Added link to Getting Started guide

Full Changelog: v3.4.1...v3.4.2

v3.3.0: ManagedStream for self-healing RTP streams

18 Dec 19:02

Choose a tag to compare

New Features

  • ManagedStream class: Wraps RadiodStream with automatic drop detection and channel restoration when radiod restarts
  • StreamState enum: Track stream health (STOPPED, STARTING, HEALTHY, DROPPED, RESTORING)
  • ManagedStreamStats: Monitor drops, restorations, and healthy/dropped durations
  • Callbacks: Get notified on stream drop and restoration events

Usage

from ka9q import RadiodControl, ManagedStream

stream = ManagedStream(
    control=control,
    frequency_hz=14.074e6,
    preset='usb',
    sample_rate=12000,
    on_samples=callback,
    on_stream_dropped=on_drop,
    on_stream_restored=on_restore,
    drop_timeout_sec=3.0,
    restore_interval_sec=1.0,
)
channel = stream.start()

This enables robust streaming applications that automatically recover from radiod restarts without manual intervention.

Installation

pip install ka9q-python==3.3.0

v3.2.7

17 Dec 10:51

Choose a tag to compare

Added

  • ChannelMonitor: New service that provides automatic recovery from radiod restarts. It monitors registered channels and automatically invokes ensure_channel to restore them if they disappear.
    • Usage: monitor = ChannelMonitor(control); monitor.start(); monitor.monitor_channel(...)

v3.2.6

17 Dec 03:21

Choose a tag to compare

Added

  • Output Encoding Support: Added complete support for specifying output encoding (e.g., F32, S16LE, OPUS) in ensure_channel and create_channel.
    • create_channel now automatically sends the required follow-up OUTPUT_ENCODING command to radiod.
    • ensure_channel verifies the encoding of existing channels and reconfigures them if different from the requested encoding.
    • ChannelInfo now includes the encoding field for discovered channels.

Release v3.2.5

17 Dec 02:49

Choose a tag to compare

Added

  • Destination-Aware Channels: ka9q-python now supports unique destination IP addresses per client application. The ensure_channel and create_channel methods now accept a destination parameter.
  • Unique IP Generation: Added generate_multicast_ip(unique_id) helper function to deterministically map application IDs to the 239.0.0.0/8 multicast range.
  • Improved SSRC Allocation: allocate_ssrc now includes the destination address in its hash calculation, ensuring that streams with different destinations get unique SSRCs.

v3.2.4 - Fix resequencer for fragmented IQ packets

16 Dec 19:15

Choose a tag to compare

Fixed

  • Resequencer Fragmented IQ Support - Fixed resequencer to correctly handle fragmented IQ packets from radiod. The resequencer now uses actual packet sample count for timestamp tracking instead of the fixed samples_per_packet value. This prevents false gap detection when radiod fragments large IQ payloads (e.g., IQ 20kHz F32 fragments into 1440+1440+320 byte packets).

Added

  • Channel Verification Test Suite - Comprehensive test suite (tests/test_channel_verification.py) that verifies radiod channel creation, encoding, sample rate, and destination configuration.

Install

pip install ka9q-python==3.2.4

v3.2.3: Fix socket reconnection vulnerability

16 Dec 12:05

Choose a tag to compare

Fixed

  • Socket Reconnection Vulnerability - Fixed vulnerability where socket errors would terminate the receive loop permanently. Both RadiodStream and RTPRecorder now implement automatic reconnection with exponential backoff (1s to 60s max). This provides robustness against:
    • Network interface restarts
    • Multicast group membership drops
    • Transient network errors

ka9q-python v3.2.0 - RadiodStream API

01 Dec 17:59

Choose a tag to compare

ka9q-python v3.2.0 Release Notes

🌊 RadiodStream API - Continuous Sample Delivery with Quality Tracking

This release adds a high-level streaming API that delivers continuous sample streams with comprehensive quality metadata. Designed for applications like GRAPE, WSPR, CODAR, and SuperDARN that need reliable data capture with gap detection and quality metrics.

Installation

pip install ka9q-python
# or
pip install git+https://github.com/mijahauan/ka9q-python.git

What's New

RadiodStream - High-Level Streaming

from ka9q import RadiodStream, StreamQuality, discover_channels

def on_samples(samples, quality: StreamQuality):
    print(f"Got {len(samples)} samples, {quality.completeness_pct:.1f}% complete")

channels = discover_channels('radiod.local')
stream = RadiodStream(channel=channels[10000000], on_samples=on_samples)
stream.start()
# ... your application runs ...
final_quality = stream.stop()

StreamQuality - Comprehensive Metrics

Every callback receives quality metadata:

Metric Description
completeness_pct Percentage of expected samples received
total_gap_events Number of distinct gaps detected
total_gaps_filled Total zero-fill samples inserted
rtp_packets_received Packets received from multicast
rtp_packets_lost Packets never received (sequence gaps)
rtp_packets_resequenced Out-of-order packets that were resequenced
first_rtp_timestamp RTP timestamp of first packet (for precise timing)

GapEvent - Gap Classification

for gap in quality.batch_gaps:
    print(f"Gap at sample {gap.position_samples}")
    print(f"  Type: {gap.source.value}")  # network_loss, resequence_timeout, etc.
    print(f"  Duration: {gap.duration_samples} samples")

PacketResequencer - Reliable Delivery

  • Circular buffer handles network jitter (configurable, default 64 packets)
  • KA9Q-style signed 32-bit timestamp arithmetic for wrap handling
  • Zero-fills gaps to maintain sample count integrity
  • Detects and logs out-of-order and lost packets

Architecture

radiod β†’ Multicast β†’ RadiodStream β†’ PacketResequencer β†’ App Callback
                          ↓
                    StreamQuality (per batch + cumulative)

Core (ka9q-python) delivers:

  • Continuous sample stream (gaps zero-filled)
  • Quality metadata with every callback
  • RTP timestamps for precise timing

Applications handle:

  • Segmentation (1-minute NPZ, 2-minute WAV, etc.)
  • Format conversion
  • App-specific gap classification

Examples

Two new examples demonstrate the API:

  • examples/stream_example.py - Basic streaming with quality reporting
  • examples/grape_integration_example.py - Two-phase recording (startup buffer β†’ recording)

New Exports

from ka9q import (
    # Stream API (NEW)
    RadiodStream,
    StreamQuality,
    GapSource,
    GapEvent,
    PacketResequencer,
    RTPPacket,
    ResequencerStats,
    
    # Existing
    RadiodControl,
    discover_channels,
    ChannelInfo,
    # ...
)

Compatibility

  • Python 3.8+
  • Linux, macOS, Windows (multicast support)
  • Works with ka9q-radio (radiod)

Full Changelog

See CHANGELOG.md for complete release history.

ka9q-python v3.1.0

01 Dec 14:59

Choose a tag to compare

ka9q-python v3.1.0 🎯

SSRC Abstraction - Simplified Channel Creation

This release removes SSRC from application concerns. Applications now specify what they want (frequency, mode, sample rate) and the system handles SSRC allocation internally.

πŸš€ What's New

SSRC-Free API

No more manual SSRC management! The create_channel() method now automatically allocates SSRCs when not specified:

from ka9q import RadiodControl

# New simplified API (recommended)
with RadiodControl("radiod.local") as control:
    ssrc = control.create_channel(
        frequency_hz=14.074e6,
        preset="usb",
        sample_rate=12000
    )
    print(f"Created channel with SSRC: {ssrc}")

Key Features:

  • 🎯 Optional SSRC - Method returns the SSRC (useful when auto-allocated)
  • πŸ”„ Deterministic allocation - Same parameters always produce the same SSRC
  • 🀝 Cross-library compatibility - Matches signal-recorder's allocation algorithm
  • πŸ“‘ Stream sharing - Multiple apps can share the same stream automatically

New allocate_ssrc() Function

For advanced use cases requiring coordination:

from ka9q import allocate_ssrc

# Pre-allocate SSRC for coordination
ssrc = allocate_ssrc(
    frequency_hz=10.0e6,
    preset="iq",
    sample_rate=16000
)
# Use with create_channel() or share with other apps

πŸ”„ API Changes

create_channel() signature updated:

  • frequency_hz is now the first required parameter
  • ssrc moved to the end and made optional
  • Method now returns the SSRC (int) instead of None

Before (v3.0.0):

control.create_channel(ssrc=12345, frequency_hz=14.074e6, preset="usb")

After (v3.1.0):

# Auto-allocate (recommended)
ssrc = control.create_channel(frequency_hz=14.074e6, preset="usb")

# Or specify manually (still supported)
ssrc = control.create_channel(frequency_hz=14.074e6, preset="usb", ssrc=12345)

🀝 Cross-Library Compatibility

The SSRC allocation algorithm matches signal-recorder's StreamSpec.ssrc_hash():

key = (round(frequency_hz), preset.lower(), sample_rate, agc, round(gain, 1))
return hash(key) & 0x7FFFFFFF

Benefits:

  • Same parameters β†’ same SSRC in both libraries
  • Automatic stream sharing across applications
  • No coordination overhead needed

πŸ’‘ Use Cases

Simple Channel Creation:

# Just specify what you want - SSRC handled automatically
ssrc = control.create_channel(14.074e6, "usb", 12000)

Stream Sharing Between Apps:

# App 1: Creates channel
ssrc1 = control.create_channel(7.074e6, "usb", 12000)

# App 2: Same parameters β†’ same SSRC β†’ shared stream
ssrc2 = control.create_channel(7.074e6, "usb", 12000)
# ssrc1 == ssrc2 (stream is shared!)

Coordinated Recording:

# Both ka9q-python and signal-recorder use the same SSRC
ssrc = allocate_ssrc(14.074e6, "usb", 12000)
# Now both apps receive the same RTP stream

βœ… Backward Compatibility

100% backward compatible - Existing code with explicit SSRCs continues to work without modification. The SSRC parameter is still supported, just optional.

πŸ“¦ Installation

pip install ka9q==3.1.0

Or upgrade:

pip install --upgrade ka9q

πŸ“– Documentation

  • CHANGELOG.md - Complete version history
  • README.md - Updated with new API examples

πŸ™ Credits

SSRC allocation algorithm inspired by Phil Karn's ka9q-radio project.

πŸ› Issues & Feedback

Found a bug or have a feature request? Please open an issue on GitHub:
https://github.com/mijahauan/ka9q-python/issues


Full Changelog: https://github.com/mijahauan/ka9q-python/blob/main/CHANGELOG.md

ka9q-python v3.0.0

01 Dec 14:09

Choose a tag to compare

ka9q-python v3.0.0 πŸŽ‰

Complete RadioD Feature Exposure

This major release provides comprehensive control over all ka9q-radio features through the Python interface. We've exposed 20 new control methods, covering everything from satellite tracking to spectrum analysis.

πŸš€ What's New

20 New Control Methods

Satellite & Advanced Tuning

  • πŸ›°οΈ set_doppler() - Real-time Doppler tracking for satellites
  • πŸ“‘ set_first_lo() - Direct hardware tuner control

Signal Processing

  • πŸ”„ set_pll() - Phase-locked loop for carrier tracking
  • πŸ”‡ set_squelch() - SNR-based squelch with hysteresis
  • πŸ“» set_envelope_detection() - AM envelope vs synchronous detection
  • 🎚️ set_independent_sideband() - ISB mode (USB/LSB to L/R)
  • πŸ“Ά set_fm_threshold_extension() - Weak FM signal improvement

Audio & Output

  • πŸ”Š set_output_channels() - Mono/stereo control
  • 🎡 set_output_encoding() - Format selection (PCM, Opus)
  • πŸ’Ώ set_opus_bitrate() - Opus quality control
  • πŸ“¦ set_packet_buffering() - Latency vs packet rate trade-off
  • 🌐 set_destination() - Dynamic output routing

Filtering & Analysis

  • πŸŽ›οΈ set_filter2() - Secondary filter for selectivity
  • πŸ“Š set_spectrum() - Spectrum analyzer configuration
  • 🎯 set_agc_threshold() - AGC activation tuning

System Control

  • βš™οΈ set_status_interval() - Status reporting rate
  • πŸ”€ set_demod_type() - Dynamic mode switching
  • πŸ“» set_rf_gain() / set_rf_attenuation() - RF hardware control
  • πŸ”¬ set_options() - Experimental features

πŸ“š Documentation

New Guides:

  • NEW_FEATURES.md - Detailed documentation with examples
  • QUICK_REFERENCE.md - Quick lookup guide
  • examples/advanced_features_demo.py - Working demo script

πŸ’‘ Example Use Cases

Satellite Tracking:

from ka9q import RadiodControl

control = RadiodControl("radiod.local")
control.set_doppler(
    ssrc=12345, 
    doppler_hz=-5000, 
    doppler_rate_hz_per_sec=100
)

Coherent AM Reception:

# Enable PLL for carrier tracking
control.set_pll(ssrc=12345, enable=True, bandwidth_hz=50)
control.set_envelope_detection(ssrc=12345, enable=False)

ISB Mode (USB & LSB simultaneously):

control.set_independent_sideband(ssrc=12345, enable=True)
control.set_output_channels(ssrc=12345, channels=2)

High-Quality Opus Streaming:

from ka9q.types import Encoding

control.set_output_encoding(ssrc=12345, encoding=Encoding.OPUS)
control.set_opus_bitrate(ssrc=12345, bitrate=128000)

Spectrum Analysis:

control.set_spectrum(
    ssrc=12345, 
    bin_bw_hz=100, 
    bin_count=512,
    kaiser_beta=6.0
)

βœ… Complete Feature Coverage

This release provides comprehensive coverage of radiod's TLV command set:

βœ… All 35+ radiod commands now supported
βœ… Doppler tracking for satellite reception
βœ… PLL carrier tracking
βœ… SNR squelch with hysteresis
βœ… Independent sideband mode
βœ… FM threshold extension
βœ… Secondary filtering
βœ… Spectrum analyzer
βœ… Output encoding control
βœ… RF hardware controls
βœ… Experimental options

πŸ”„ Backward Compatibility

100% backward compatible - All existing code continues to work without modification. All changes are additive.

πŸ“¦ Installation

pip install ka9q==3.0.0

Or upgrade:

pip install --upgrade ka9q

πŸ§ͺ Testing

Run the demo script to see all new features:

python3 examples/advanced_features_demo.py

πŸ“– Full Documentation

  • NEW_FEATURES.md - Complete feature documentation
  • QUICK_REFERENCE.md - Quick reference with examples
  • CHANGELOG.md - Detailed changelog
  • RADIOD_FEATURES_SUMMARY.md - Implementation details

πŸ™ Credits

Thanks to Phil Karn (KA9Q) for creating ka9q-radio and making its source code available for analysis.

πŸ› Issues & Feedback

Found a bug or have a feature request? Please open an issue on GitHub:
https://github.com/mijahauan/ka9q-python/issues


Full Changelog: https://github.com/mijahauan/ka9q-python/blob/main/CHANGELOG.md