ka9q-python 3.7.0__tar.gz → 3.7.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/CHANGELOG.md +15 -0
  2. {ka9q_python-3.7.0/ka9q_python.egg-info → ka9q_python-3.7.1}/PKG-INFO +1 -1
  3. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/ka9q/managed_stream.py +6 -1
  4. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/ka9q/stream.py +18 -4
  5. {ka9q_python-3.7.0 → ka9q_python-3.7.1/ka9q_python.egg-info}/PKG-INFO +1 -1
  6. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/pyproject.toml +1 -1
  7. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/LICENSE +0 -0
  8. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/MANIFEST.in +0 -0
  9. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/README.md +0 -0
  10. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/RELEASE_NOTES_v3.5.0.md +0 -0
  11. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/API_REFERENCE.md +0 -0
  12. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/ARCHITECTURE.md +0 -0
  13. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/CHANGELOG.md +0 -0
  14. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/CROSS_PLATFORM_SUPPORT.md +0 -0
  15. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/DISTRIBUTION_RECOMMENDATION.md +0 -0
  16. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/GETTING_STARTED.md +0 -0
  17. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/INSTALLATION.md +0 -0
  18. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/MULTI_HOMED_QUICK_REF.md +0 -0
  19. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/NATIVE_DISCOVERY.md +0 -0
  20. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/PYPI_PUBLICATION_GUIDE.md +0 -0
  21. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/QUICK_REFERENCE.md +0 -0
  22. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/RTP_RECORDER_PASS_ALL_PACKETS.md +0 -0
  23. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/RTP_TIMING_IMPLEMENTATION.md +0 -0
  24. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/RTP_TIMING_SUPPORT.md +0 -0
  25. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/SECURITY.md +0 -0
  26. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/SSRC_COLLISION_PREVENTION.md +0 -0
  27. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/TESTING_GUIDE.md +0 -0
  28. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/TESTING_SUMMARY.md +0 -0
  29. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/TEST_RESULTS.md +0 -0
  30. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/WEB_UI_ENHANCEMENT_GUIDE.md +0 -0
  31. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/WEB_UI_ENHANCEMENT_IMPLEMENTED.md +0 -0
  32. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/WEB_UI_ESCAPE_SEQUENCE_FIX.md +0 -0
  33. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/WEB_UI_FUNCTIONALITY_REVIEW.md +0 -0
  34. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/WEB_UI_IMPLEMENTATION_STATUS.md +0 -0
  35. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/WEB_UI_INTERACTIVE_COMPLETE.md +0 -0
  36. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/CHANGES_SUMMARY.md +0 -0
  37. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/CHANNEL_CLEANUP_ADDITION.md +0 -0
  38. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/CHANNEL_CLEANUP_COMPLETE.md +0 -0
  39. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/CHANNEL_TUNING_DIAGNOSTICS.md +0 -0
  40. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/CODE_REVIEW_RECOMMENDATIONS.md +0 -0
  41. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/CODE_REVIEW_SUMMARY.md +0 -0
  42. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/COMMIT_SUMMARY.md +0 -0
  43. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/CRITICAL_FIXES_CHECKLIST.md +0 -0
  44. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/FINAL_SUMMARY.md +0 -0
  45. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/FIXES_SUMMARY.md +0 -0
  46. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/GIT_STATUS_SUMMARY.md +0 -0
  47. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/IMPLEMENTATION_COMPLETE.md +0 -0
  48. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/IMPLEMENTATION_STATUS.md +0 -0
  49. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/IMPLEMENTATION_SUMMARY.md +0 -0
  50. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/IMPLEMENTATION_SUMMARY_v2.2.0.md +0 -0
  51. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/IMPROVEMENTS_IMPLEMENTED.md +0 -0
  52. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/MULTI_HOMED_ACTION_PLAN.md +0 -0
  53. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/MULTI_HOMED_IMPLEMENTATION_COMPLETE.md +0 -0
  54. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/MULTI_HOMED_SUPPORT_REVIEW.md +0 -0
  55. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/PACKAGE_STATUS.md +0 -0
  56. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/PACKAGE_VERIFICATION.md +0 -0
  57. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/PERFORMANCE_FIXES_APPLIED.md +0 -0
  58. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/PERFORMANCE_REVIEW.md +0 -0
  59. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/PERFORMANCE_REVIEW_V2.md +0 -0
  60. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/PERFORMANCE_SUMMARY.md +0 -0
  61. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/QUICK_ACTION_ITEMS.md +0 -0
  62. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/QUICK_START_DIAGNOSIS.md +0 -0
  63. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/RELEASE_CHECKLIST_v3.0.0.md +0 -0
  64. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/SUMMARY.md +0 -0
  65. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/SUMMARY_WEB_UI_FIXES.md +0 -0
  66. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/TUNE_IMPLEMENTATION.md +0 -0
  67. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/WEBUI_SUMMARY.md +0 -0
  68. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/development/WEB_UI_ENHANCEMENTS_COMPLETE.md +0 -0
  69. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/features/CONTROL_COMPARISON.md +0 -0
  70. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/features/DESTINATION_AWARE_CHANNELS.md +0 -0
  71. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/features/NEW_FEATURES.md +0 -0
  72. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/features/RADIOD_FEATURES_SUMMARY.md +0 -0
  73. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/features/RTP_DESTINATION_FEATURE.md +0 -0
  74. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/releases/GITHUB_RELEASE_INSTRUCTIONS.md +0 -0
  75. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/releases/GITHUB_RELEASE_v2.2.0.md +0 -0
  76. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/releases/GITHUB_RELEASE_v2.4.0.md +0 -0
  77. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/releases/GITHUB_RELEASE_v2.5.0.md +0 -0
  78. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/releases/GITHUB_RELEASE_v3.0.0.md +0 -0
  79. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/releases/GITHUB_RELEASE_v3.1.0.md +0 -0
  80. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/releases/GITHUB_RELEASE_v3.2.0.md +0 -0
  81. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/releases/RELEASE_NOTES.md +0 -0
  82. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/releases/RELEASE_NOTES_v2.1.0.md +0 -0
  83. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/releases/RELEASE_NOTES_v2.2.0.md +0 -0
  84. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/releases/RELEASE_NOTES_v2.3.0.md +0 -0
  85. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/releases/RELEASE_NOTES_v2.4.0.md +0 -0
  86. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/docs/releases/RTP_TIMING_RELEASE_NOTES.md +0 -0
  87. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/examples/advanced_features_demo.py +0 -0
  88. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/examples/channel_cleanup_example.py +0 -0
  89. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/examples/codar_oceanography.py +0 -0
  90. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/examples/diagnostics/diagnose_packets.py +0 -0
  91. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/examples/diagnostics/repro_utc_bug.py +0 -0
  92. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/examples/discover_example.py +0 -0
  93. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/examples/grape_integration_example.py +0 -0
  94. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/examples/hf_band_scanner.py +0 -0
  95. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/examples/rtp_recorder_example.py +0 -0
  96. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/examples/simple_am_radio.py +0 -0
  97. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/examples/stream_example.py +0 -0
  98. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/examples/superdarn_recorder.py +0 -0
  99. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/examples/test_channel_operations.py +0 -0
  100. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/examples/test_improvements.py +0 -0
  101. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/examples/test_timing_fields.py +0 -0
  102. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/examples/tune.py +0 -0
  103. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/examples/tune_example.py +0 -0
  104. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/ka9q/__init__.py +0 -0
  105. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/ka9q/addressing.py +0 -0
  106. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/ka9q/compat.py +0 -0
  107. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/ka9q/control.py +0 -0
  108. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/ka9q/discovery.py +0 -0
  109. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/ka9q/exceptions.py +0 -0
  110. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/ka9q/monitor.py +0 -0
  111. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/ka9q/pps_calibrator.py +0 -0
  112. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/ka9q/resequencer.py +0 -0
  113. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/ka9q/rtp_recorder.py +0 -0
  114. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/ka9q/stream_quality.py +0 -0
  115. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/ka9q/types.py +0 -0
  116. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/ka9q/utils.py +0 -0
  117. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/ka9q_python.egg-info/SOURCES.txt +0 -0
  118. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/ka9q_python.egg-info/dependency_links.txt +0 -0
  119. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/ka9q_python.egg-info/requires.txt +0 -0
  120. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/ka9q_python.egg-info/top_level.txt +0 -0
  121. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/ka9q_radio_compat +0 -0
  122. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/scripts/sync_types.py +0 -0
  123. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/setup.cfg +0 -0
  124. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/setup.py +0 -0
  125. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/__init__.py +0 -0
  126. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/conftest.py +0 -0
  127. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_addressing.py +0 -0
  128. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_channel_verification.py +0 -0
  129. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_create_split_encoding.py +0 -0
  130. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_decode_functions.py +0 -0
  131. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_encode_functions.py +0 -0
  132. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_encode_socket.py +0 -0
  133. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_ensure_channel_encoding.py +0 -0
  134. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_integration.py +0 -0
  135. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_iq_20khz_f32.py +0 -0
  136. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_listen_multicast.py +0 -0
  137. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_managed_stream_recovery.py +0 -0
  138. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_monitor.py +0 -0
  139. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_multihomed.py +0 -0
  140. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_native_discovery.py +0 -0
  141. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_performance_fixes.py +0 -0
  142. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_protocol_compat.py +0 -0
  143. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_remove_channel.py +0 -0
  144. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_rtp_recorder.py +0 -0
  145. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_security_features.py +0 -0
  146. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_ssrc_dest_unit.py +0 -0
  147. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_ssrc_encoding_unit.py +0 -0
  148. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_ssrc_radiod_host_unit.py +0 -0
  149. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_ttl_warning.py +0 -0
  150. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_tune.py +0 -0
  151. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_tune_cli.py +0 -0
  152. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_tune_debug.py +0 -0
  153. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_tune_live.py +0 -0
  154. {ka9q_python-3.7.0 → ka9q_python-3.7.1}/tests/test_tune_method.py +0 -0
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.7.1] - 2026-04-12
4
+
5
+ ### Fixed
6
+
7
+ - **S16BE/S16LE audio parsing in `RadiodStream`**: `_parse_samples()` always decoded audio-mode RTP payloads as float32, regardless of the channel's actual encoding. When encoding was S16BE (used by FT4/FT8 channels at 12 kHz), a 240-byte payload containing 120 int16 samples was misinterpreted as 60 float32 values. The `PacketResequencer` then reported a 120-sample gap on every packet (~2500 gaps/minute), reducing stream completeness to ~37% and making the stream unusable for downstream consumers like `decode_ft8`. Now dispatches on `channel.encoding`: S16BE (`>i2`), S16LE (`<i2`), F32BE (`>f4`), and default F32LE (`np.float32`). All int16 formats are normalized to float32 (÷32768) in the callback.
8
+ - **`ManagedStream` now accepts `encoding` parameter**: Added `encoding: int = 0` to `__init__()`, passed through to both `ensure_channel()` call sites (initial provisioning and stream restoration). Without this, `ManagedStream` would re-provision a channel without encoding on restore, causing format mismatches. Clients using non-default encoding (S16BE, S16LE, F32BE) should pass `encoding=` to the constructor. This eliminates the need for hf-timestd's `RobustManagedStream` workaround.
9
+
10
+ ### Client migration
11
+
12
+ - **Clients using `ManagedStream` with non-default encoding**: Pass `encoding=<int>` to the constructor. Example: `ManagedStream(control=ctl, frequency_hz=14.074e6, preset="usb", sample_rate=12000, encoding=2)` for S16BE.
13
+ - **Clients using bare `RadiodStream` with S16BE/S16LE**: No code change needed — samples are now correctly decoded to float32 in the callback. Note that if client code was compensating for the old bug (e.g., manually byte-swapping), that workaround should be removed.
14
+ - **hf-timestd**: Can replace `RobustManagedStream` (stream_recorder_v2.py lines 40-195) with `ka9q.ManagedStream(encoding=Encoding.F32)` and delete the wrapper class.
15
+
16
+ ---
17
+
3
18
  ## [3.7.0] - 2026-04-12
4
19
 
5
20
  ### Changed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ka9q-python
3
- Version: 3.7.0
3
+ Version: 3.7.1
4
4
  Summary: Python interface for ka9q-radio control and monitoring
5
5
  Home-page: https://github.com/mijahauan/ka9q-python
6
6
  Author: Michael Hauan AC0G
@@ -123,6 +123,7 @@ class ManagedStream:
123
123
  agc_enable: int = 0,
124
124
  gain: float = 0.0,
125
125
  destination: Optional[str] = None,
126
+ encoding: int = 0,
126
127
  on_samples: Optional[SampleCallback] = None,
127
128
  on_stream_dropped: Optional[StreamDroppedCallback] = None,
128
129
  on_stream_restored: Optional[StreamRestoredCallback] = None,
@@ -135,7 +136,7 @@ class ManagedStream:
135
136
  ):
136
137
  """
137
138
  Initialize ManagedStream.
138
-
139
+
139
140
  Args:
140
141
  control: RadiodControl instance for channel management
141
142
  frequency_hz: Center frequency in Hz
@@ -144,6 +145,7 @@ class ManagedStream:
144
145
  agc_enable: Enable AGC (0=off, 1=on)
145
146
  gain: Manual gain in dB (when AGC off)
146
147
  destination: RTP destination multicast address (optional)
148
+ encoding: Output encoding (0=none, 1=S16LE, 2=S16BE, 4=F32LE, etc.)
147
149
  on_samples: Callback(samples, quality) for sample delivery
148
150
  on_stream_dropped: Callback(reason) when stream drops
149
151
  on_stream_restored: Callback(channel) when stream is restored
@@ -161,6 +163,7 @@ class ManagedStream:
161
163
  self._agc_enable = agc_enable
162
164
  self._gain = gain
163
165
  self._destination = destination
166
+ self._encoding = encoding
164
167
 
165
168
  # Callbacks
166
169
  self._on_samples = on_samples
@@ -232,6 +235,7 @@ class ManagedStream:
232
235
  agc_enable=self._agc_enable,
233
236
  gain=self._gain,
234
237
  destination=self._destination,
238
+ encoding=self._encoding,
235
239
  )
236
240
 
237
241
  # Start the underlying stream
@@ -414,6 +418,7 @@ class ManagedStream:
414
418
  agc_enable=self._agc_enable,
415
419
  gain=self._gain,
416
420
  destination=self._destination,
421
+ encoding=self._encoding,
417
422
  timeout=self._restore_interval_sec * 2, # Give it some time
418
423
  )
419
424
 
@@ -350,7 +350,7 @@ class RadiodStream:
350
350
  ).isoformat()
351
351
 
352
352
  def _parse_samples(self, payload: bytes) -> Optional[np.ndarray]:
353
- """Parse samples from RTP payload."""
353
+ """Parse samples from RTP payload based on channel encoding."""
354
354
  try:
355
355
  if self._is_iq:
356
356
  # IQ mode: float32 interleaved I/Q -> complex64
@@ -362,9 +362,23 @@ class RadiodStream:
362
362
  samples = floats[0::2] + 1j * floats[1::2]
363
363
  return samples.astype(np.complex64)
364
364
  else:
365
- # Audio mode: float32 mono
366
- return np.frombuffer(payload, dtype=np.float32)
367
-
365
+ # Audio mode: parse according to encoding
366
+ enc = getattr(self.channel, 'encoding', 0)
367
+ if enc == 2:
368
+ # S16BE: 16-bit big-endian signed integers -> float32
369
+ int16_samples = np.frombuffer(payload, dtype='>i2')
370
+ return (int16_samples / 32768.0).astype(np.float32)
371
+ elif enc == 1:
372
+ # S16LE: 16-bit little-endian signed integers -> float32
373
+ int16_samples = np.frombuffer(payload, dtype='<i2')
374
+ return (int16_samples / 32768.0).astype(np.float32)
375
+ else:
376
+ # F32LE (4), F32BE (8), or default: float32
377
+ if enc == 8:
378
+ return np.frombuffer(payload, dtype='>f4').astype(np.float32)
379
+ else:
380
+ return np.frombuffer(payload, dtype=np.float32)
381
+
368
382
  except Exception as e:
369
383
  logger.error(f"Failed to parse payload: {e}")
370
384
  return None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ka9q-python
3
- Version: 3.7.0
3
+ Version: 3.7.1
4
4
  Summary: Python interface for ka9q-radio control and monitoring
5
5
  Home-page: https://github.com/mijahauan/ka9q-python
6
6
  Author: Michael Hauan AC0G
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ka9q-python"
7
- version = "3.7.0"
7
+ version = "3.7.1"
8
8
  description = "Python interface for ka9q-radio control and monitoring"
9
9
  readme = "README.md"
10
10
  authors = [
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes