Files

831 lines
34 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🎉 ap_ds AFS 0.0.1-AFS Pre-release — The Permanent Home of Opus Support
---
## 🔧 Version 0.0.1a3 — Bug Fix Announcement
Welcome to **0.0.1a3**! This release fixes several issues found in the previous version (0.0.1a2), focused mainly on the Opus playback engine, metadata parsing and packaging.
### ✅ What's Fixed in This Release
**Opus playback engine (`opusplayer.py`)**
- **Fade worker indentation** — `_fade_worker` was accidentally defined outside the `OpusAudio` class, causing `AttributeError` on `fadeout/fadein/fadein_pos`. It is now a proper class method.
- **Fade-in now stops and restarts** — `fadein_music` previously refused to run while playing ("Already playing"). It now stops any current playback first, starts a fresh AID, then fades in.
- **Seek now truly jumps** — `seek_audio` previously only moved the stream position without resetting the buffered audio, so jumps were not audible. It now restarts the playback thread from the new position.
- **Seek resumes after fade-out** — seeking now always restarts playback, even after a fade-out had stopped it.
- **Fade-out restores volume** — the volume was being reset to 0 after fade-out, making any later play/seek/fade-in silent. The normal volume is now restored after fade-out.
- **Boundary robustness** — `fadein_music(ms=None)`, `fadeout_music(None)` and `fadein_music_pos(position=None)` no longer crash with a TypeError; invalid values fall back safely to defaults or return an error tuple.
**Opus metadata parsing (`audio_parser.py`)**
- `open_audio(.opus)` no longer raises `ValueError`. A new `OPUSFile` parser delegates to `opusplayer`, so `get_audio_duration`, `get_audio_metadata` and `batch_get_metadata` all support Opus files.
- Directory scanning for `batch_get_metadata` now includes `.opus`.
**Audio library routing (`player.py`)**
- `get_audio_metadata_by_aid()` now routes Opus AIDs to the `OpusAudio` engine, returning consistent metadata.
**Packaging**
- Restored the main `ap_ds/__init__.py` (its exported functions had been accidentally replaced, which omitted all top-level APIs from the built package). All public APIs are exported again.
**Tests**
- CI/CD fade duration increased to 5s for a clearer audible effect.
- Added `test_opus_interactive.py` for manual Opus playback / seek / fade verification.
### 🙏 Keep Reporting Bugs
We truly value your feedback. If you encounter any issue while using the library, please don't hesitate to submit a bug report. Together we'll keep polishing the product:
📧 **Where to send (please CC both addresses to guarantee delivery):**
- **me@dvsyun.top** (primary)
- **dvs6666@163.com** (backup)
⏱️ **Our promise:** we will fix reported issues within **3 business days**.
To help us resolve issues faster, please include the following when submitting a bug report:
- Operating system and version
- Python version (`python --version`)
- The full error message
- Reproduction steps
- A sample audio file (if possible)
Every single piece of feedback drives us forward. 🎉
⚠️ **Important:** 0.0.1-AFS is a **pre-release test version** for feedback collection and bug reporting. The first stable release **1.0.0** is planned for **September 2026**.
This is the first release of the **AFS (All Format Support)** branch — a standalone fork of ap_ds ecosystem built specifically for **Opus** and all future new formats, with **permanent support commitment**.
If you encounter any issues, please contact us immediately:
📧 **Primary:** me@dvsyun.top
📧 **Backup:** dvs6666@163.com
⏱️ **We guarantee:** Fix within 3 business days
Your feedback is crucial! Together, let's polish Opus support to perfection.
> "We don't just support a new format — we open the door to higher quality, smaller size, and greater freedom." — DVS Development Team, August 2026
---
## 📦 Installation
### Install the Package
```bash
# AFS pre-release (includes Opus, for testing feedback)
pip install ap-ds-afs==0.0.1a3
# AFS stable release (coming September 2026)
pip install ap-ds-afs==1.0.0
```
### Import — Same as Always!
**No matter which package you installed** (`ap-ds` or `ap-ds-afs`), the import is **exactly the same**:
```python
from ap_ds import AudioLibrary
```
✅ Zero migration cost — just change the package name in `requirements.txt`
✅ No code changes needed — your existing code works as-is
### 🛡️ Foolproof Design — Conflict Detection
If a user accidentally installs **both** `ap-ds` and `ap-ds-afs` simultaneously, the library detects the conflict and **exits immediately** with a clear message:
```python
>>> import ap_ds
Checking for package conflicts...
WARNING: Package conflict detected!
The following packages exist simultaneously:
- ap-ds and ap-ds-afs
Please uninstall one of them.
# Python process exits directly 💀
```
This is **not a bug** — it's a **foolproof design** to prevent hard-to-debug import issues caused by conflicting packages.
---
## 🚀 Quick Start Guide
### Basic Audio Playback
```python
from ap_ds import AudioLibrary
# Initialize the library
lib = AudioLibrary()
# Play an audio file
aid = lib.play_from_file("music/song.mp3")
# Control playback
lib.pause_audio(aid) # Pause
lib.play_audio(aid) # Resume
lib.seek_audio(aid, 30.5) # Seek to 30.5s
lib.set_volume(aid, 80) # Set volume (0-128)
# Stop and get elapsed time
elapsed = lib.stop_audio(aid)
print(f"Played {elapsed:.2f} seconds")
```
### Playing Opus Files (via AudioLibrary — Recommended)
```python
from ap_ds import AudioLibrary
lib = AudioLibrary()
aid = lib.play_from_file("song.opus") # Auto-routed to Opus engine
# All control methods are identical
lib.pause_audio(aid)
lib.seek_audio(aid, 30.0)
lib.set_volume(aid, 80)
lib.stop_audio(aid)
```
### Playing Opus Files (Directly Using OpusAudio)
```python
from ap_ds import OpusAudio
opus = OpusAudio()
aid = opus.play_from_file("song.opus")
opus.pause_audio(aid)
opus.seek_audio(aid, 30.0)
opus.stop_audio(aid)
```
### Getting Audio Metadata
```python
from ap_ds import get_audio_metadata
meta = get_audio_metadata("song.opus")
print(meta["duration"]) # 265
print(meta["sample_rate"]) # 48000
print(meta["channels"]) # 2
print(meta["bitrate"]) # 105351
```
### Batch Parsing (Parallel Processing)
```python
from ap_ds import batch_get_metadata
# Parse 120 MP3s in just 0.33 seconds!
results = batch_get_metadata("/music/playlist/", max_workers=8)
for meta in results:
print(f"{meta['path']}: {meta['duration']}s, {meta['bitrate']}bps")
```
**⚠️ Windows Users:** You MUST protect your entry point with `if __name__ == "__main__"`:
```python
from ap_ds import batch_get_metadata
def main():
results = batch_get_metadata("/music/", max_workers=4)
print(f"Parsed {len(results)} files")
if __name__ == "__main__":
main()
```
### DAP Playlist System
```python
# Files are recorded automatically into DAP (DVS Audio Playlist)
aid1 = lib.play_from_file("song1.mp3")
aid2 = lib.play_from_file("song2.ogg")
# Get all recordings
recordings = lib.get_dap_recordings()
print(f"Recorded {len(recordings)} files")
# Save as JSON
lib.save_dap_to_json("my_playlist.ap-ds-dap")
```
DAP stores only metadata (path, duration, bitrate, channels), not audio data. Each record takes approximately 150 bytes of memory.
---
## 📢 A Letter to All Audio Developers
Friends, colleagues, music lovers, and everyone who has ever stayed up late wrestling with audio formats:
Today, we announce — **ap_ds AFS 0.0.1-AFS** is officially released! The **AFS (All Format Support)** branch makes its debut, providing **permanent support** for the Opus audio format for the first time!
But before excitement takes over, we must be honest with you:
**This is a pre-release version.**
What does that mean? It means:
✅ All core features are implemented and tested
✅ 229 Opus-specific tests all pass
✅ Cross-platform (Windows/Linux/macOS) playback verified
⚠️ Some edge-case bugs may still exist that we haven't found
⚠️ We need real users to test in diverse environments
So we're giving this version to **you** — our users — to help us test.
> **"AFS is the permanent home of Opus and all future new formats."**
This is part of ap_ds's dual-track strategy. We'll explain in detail in the following sections.
---
## 🚨 Important Notes on Version 0.0.1-AFS Positioning
### 1. This is a Pre-release
0.0.1-AFS is **not** an LTS or final stable version. It is a **pre-release** aimed at:
- Collecting real-world usage feedback
- Discovering edge-case bugs not covered by tests
- Verifying cross-platform compatibility
- Gathering data for the 1.0.0 stable release
### 2. AFS Branch — The Permanent Home of Opus
This is a critical statement:
**The AFS branch is the permanent home for Opus and all future new formats.**
Unlike the mainline (`ap-ds` 4.x), the AFS branch will **permanently retain** Opus support and continuously add new formats.
| Version | Opus Support | Description |
|---------|-------------|-------------|
| 0.0.1-AFS | ✅ Yes | First AFS pre-release |
| 1.0.0 (Sep 2026) | ✅ Yes | First AFS stable release |
| Future AFS | ✅ Yes | Permanent support |
| Mainline 4.2.0+ | ❌ No | Returns to lightweight positioning |
**Why?**
Because ap_ds mainline's core promise is **2.5MB lightweight**. Opus support (including DLLs) pushes the size to ~3.87MB. Mainline will remove Opus to return to 2.5MB. The AFS branch is specifically designed to carry Opus and future formats, at ~2.8-3.5MB.
So if you need Opus support:
- **Short-term testing:** Use 0.0.1-AFS pre-release
- **Long-term use:** Use AFS branch (`pip install ap-ds-afs`), with 1.0.0 stable coming in September
- Both packages use **identical imports** (`from ap_ds import AudioLibrary`) — zero migration cost
### 3. Bug Reporting & Fix Commitment
If you find any issues with 0.0.1-AFS:
📧 me@dvsyun.top
📧 dvs6666@163.com (CC both for delivery guarantee)
**We promise:**
- Fix within **3 business days**
- Patch releases will be published promptly
**When reporting, please provide:**
- OS and version
- Python version (`python --version`)
- Full error message (if any)
- Reproduction steps
- Audio file sample (if possible)
Every piece of feedback helps us build a better ap_ds. 🙏
---
## 🤔 Why Opus? — The Technical Imperative
### 1. Quality & Compression Ceiling
Opus is an open audio codec jointly developed by the Xiph.Org Foundation and IETF, combining SILK (speech) and CELT (general audio) algorithms with adaptive bitrate from 6 kbps to 510 kbps. This means:
- At low bitrates (<32 kbps), Opus voice clarity far exceeds MP3 and AAC
- At medium-high bitrates (64-128 kbps), Opus quality matches or exceeds MP3 at 320kbps
- Ultra-low latency (as low as 5ms), ideal for real-time communication and gaming
### 2. Open Source & Freedom — A Philosophical Fit
Opus uses a BSD-like license with **no patent restrictions**, completely free. This aligns perfectly with ap_ds's commitment to openness, freedom, and zero burden.
### 3. Mature Ecosystem & Clear Demand
Opus is widely used in:
- **WebRTC** (real-time audio/video communication)
- **Discord, WhatsApp, Signal** and other instant messaging apps
- **Game engines** (Unity, Unreal both support Opus)
- **Audio streaming** (broadcasting, podcasting)
- **Embedded devices** (low power, high compression)
As more audio content is published in Opus format, ap_ds as a general-purpose audio library must respond to this trend.
### 4. Paving the Way for the AFS Branch
Opus is the first member of the AFS (All Format Support) branch. Through the 0.0.1-AFS pre-release, we validate cross-platform Opus playback solutions and accumulate experience for the 1.0.0 stable release.
---
## 😅 Why Didn't We Support Opus Before? — The Upstream Dependency Story
This is a great question. Honestly, we've wanted to support Opus since ap_ds v1.0. But the reality is:
ap_ds has always relied on **SDL2 and SDL2_mixer** for audio playback.
SDL2 is an excellent cross-platform multimedia library that handles audio device abstraction, mixing, and buffering across Windows, macOS, and Linux. SDL2_mixer supports MP3, WAV, OGG, FLAC and other formats out of the box.
But the problem is — **SDL2_mixer's Opus support was never stable enough.**
| Platform | Issue |
|----------|-------|
| Windows | Official SDL2_mixer Windows binaries often lack Opus support or have incomplete compile flags, causing `Mix_LoadMUS` to return NULL for `.opus` files |
| macOS | SDL2_mixer Framework builds frequently have version mismatches and `libopusfile`/`libogg` dependency issues, causing runtime crashes |
| Linux | SDL2_mixer depends on system-installed `libopusfile-dev`, but package names and versions vary widely across distributions |
| API Inconsistency | Even when Opus loads, SDL2_mixer's metadata extraction (duration, bitrate, etc.) often returns 0 or errors |
We tried multiple approaches:
- Compiling our own Opus-enabled SDL2_mixer binaries → Bloated, high maintenance cost
- Forcing users to install `libopusfile-dev` on Linux → Poor UX, and Windows/macOS issues remained
- Waiting for upstream SDL2_mixer fixes across multiple versions → Issues persisted
**Conclusion:** SDL2_mixer's upstream support was insufficient to provide stable Opus playback.
Therefore, before AFS, we made a difficult decision — **temporarily not support Opus** to avoid giving users an unstable experience.
### How Does 0.0.1-AFS Solve This?
**Because SDL2 doesn't work, we decided to not use SDL2 at all!**
In the AFS branch, we completely bypass SDL2 and SDL2_mixer, building a **dedicated playback pipeline** for Opus:
```
User passes .opus file
↓
Detects .opus extension
↓
libopusfile decodes
↓
Cross-platform audio output engine
├── Windows → winmm waveOut
├── Linux → ALSA (libasound.so)
└── macOS → Core Audio AudioQueue
↓
Audio output to speakers
```
This pipeline is **completely independent of SDL2**, free from SDL2_mixer's limitations.
Meanwhile, Windows users don't need to hunt for DLLs — ap_ds automatically downloads the required four DLLs (`libopusfile-0.dll`, `libopus-0.dll`, `libogg-0.dll`, `libopusurl-0.dll`) on first run with **SHA256 hash verification** ensuring file integrity.
This is why AFS can support Opus, and why we couldn't before. It's not that we didn't want to — we had to find a reliable, stable, truly cross-platform solution. Now we have one.
---
## 🧬 Technical Deep Dive — What We Actually Did
### 1. New Modules & Architecture
To integrate Opus support without affecting mainline stability, we carefully designed the project structure:
| File | Responsibility | Description |
|------|---------------|-------------|
| `opusplayer.py` | Opus playback core | `OpusAudio` class — fully independent of SDL2, encapsulates all Opus playback, control, metadata and batch APIs |
| `_opusdll.py` | Opus library loader | Cross-platform loading (Windows auto-download, Linux/macOS system detection + install guide), unified libopusfile client |
| `player.py` (modified) | Opus routing integration | `AudioLibrary` auto-detects `.opus` files and forwards to `OpusAudio` sub-player, fully transparent playback |
| `__init__.py` (modified) | Export OpusAudio | Users can use `from ap_ds import OpusAudio` directly or seamlessly through `AudioLibrary` |
**Key Design: AID 1:1 Mapping**
When a user plays via `AudioLibrary.play_from_file("song.opus")`, the library internally creates an `OpusAudio` instance and generates a sub-AID, then maps the main library AID to the sub-library AID via a dictionary. All subsequent controls (pause, resume, volume, seek) route correctly to the Opus engine, completely transparent to user code.
```python
# User code — exactly the same as before!
from ap_ds import AudioLibrary
lib = AudioLibrary()
aid = lib.play_from_file("song.opus") # Auto-routed to Opus engine
lib.pause_audio(aid) # Auto-routed to Opus engine
lib.seek_audio(aid, 30.0) # Auto-routed to Opus engine
lib.stop_audio(aid) # Auto-routed to Opus engine
```
**Fully transparent, zero learning curve.**
### 2. Cross-Platform Playback Backends — Three Platform Engines Rewritten for Opus
Opus playback cannot rely on SDL2, so we decided to completely bypass SDL2 and use native OS audio APIs directly with `libopusfile` decoding.
| Platform | Playback Solution | Tech Stack |
|----------|------------------|------------|
| **Windows** | winmm waveOut | libopusfile decode → waveOutWrite multi-buffer (4 buffers, 50ms/block) |
| **Linux** | ALSA | libasound.so.2 → snd_pcm_open → snd_pcm_writei (direct PCM output) |
| **macOS** | Core Audio AudioQueue | Apple official C API → AudioQueue callback fill (consistent with official examples) |
**Platform Implementation Details:**
**Windows** (`_play_worker_windows`):
- Uses `waveOutOpen` to open default audio device
- Uses `CreateEventW` + `WaitForSingleObject` for buffer completion synchronization
- 4 buffers rotating to eliminate stuttering
- `WAVEHDR` structure with `c_void_p` for 64-bit compatibility
**Linux** (`_play_worker_linux`):
- Uses `snd_pcm_open` with "default" device
- Uses `snd_pcm_set_params` for PCM parameters (S16_LE, interleaved mode)
- Uses `snd_pcm_writei` for PCM data write
- On `-EPIPE` (buffer underrun), calls `snd_pcm_recover` for auto-recovery
**macOS** (`_play_worker_macos`):
- Uses `AudioQueueNewOutput` to create output queue
- Uses `AudioQueueAllocateBuffer` for buffer allocation
- Callback `HandleOutputBuffer` decodes Opus and fills `mAudioData`
- Uses `AudioQueueStart` to start, `AudioQueueStop` to stop
### 3. Opus-Specific Error Codes (2001-2010)
To make Opus-related errors clearer and more traceable, we added 10 dedicated error codes:
| Code | Constant | Meaning | Suggested Action |
|------|----------|---------|-----------------|
| 2001 | AP_DS_ERR_OPUS_LIB_LOAD_FAILED | libopusfile load failed | Check DLL existence/locks |
| 2002 | AP_DS_ERR_OPUS_DLL_DEPENDENCY | DLL dependency missing | Ensure libopus-0.dll and libogg-0.dll exist |
| 2003 | AP_DS_ERR_OPUS_OPEN_FAILED | Opus file open failed | File may be corrupted or not valid Opus |
| 2004 | AP_DS_ERR_OPUS_HEADER_CORRUPT | OpusHead header corrupt | Invalid or corrupted header info |
| 2005 | AP_DS_ERR_OPUS_TAGS_PARSE_FAILED | Tag parse failed | Corrupted or invalid tag data |
| 2006 | AP_DS_ERR_OPUS_DECODE_FAILED | Opus decode failed | Corrupted audio data |
| 2007 | AP_DS_ERR_OPUS_SEEK_FAILED | Opus seek failed | Stream may not support seeking to this position |
| 2008 | AP_DS_ERR_OPUS_BITRATE_UNAVAILABLE | Bitrate unavailable | Cannot determine bitrate for this Opus stream |
| 2009 | AP_DS_ERR_OPUS_NOT_SEEKABLE | Stream not seekable | This Opus stream doesn't support seeking |
| 2010 | AP_DS_ERR_OPUS_CHANNEL_INVALID | Invalid channel count | Invalid channel count in Opus stream |
All Opus errors include:
- Machine-readable error code (for programmatic handling)
- Human-readable error message (for developer understanding)
- Actionable suggestion (for user problem resolution)
### 4. Auto DLL Download & Hash Verification (Windows)
Windows users don't need to manually find DLLs. When ap_ds first detects Opus support is needed, it:
1. Checks if the 4 required DLLs exist in the package directory
2. Downloads from `https://dvsyun.top/ap_ds/download/` if missing or hash verification fails
3. Performs SHA256 hash verification after download
4. Auto-retries if hash mismatch
| File | Size | SHA256 |
|------|------|--------|
| libopusfile-0.dll | 55,884 B | fc8ff75c5e0180e73b0528dc78c51ed0fb493741375cdc227f50c2a33cabf727 |
| libopus-0.dll | 500,112 B | 90aa25a0a6525d7da48a7ae8dd3306e45b0c28ce09a73d2a02b56cd95418d5be |
| libogg-0.dll | 40,580 B | 3038ce8d161324a6349bf7c83b78493857ff6a3501e3adb3d541c6a07bd94a57 |
| libopusurl-0.dll | 76,772 B | a6cde968a23f2d0067332a13718c52e265653a2c35d65862e8dff4cf2a0346d9 |
### 5. Cross-Platform Opus Library Loading
**Windows:**
- Check package directory for DLLs → Auto-download if missing → SHA256 verify → Load via `ctypes.CDLL`
**Linux:**
- User config check (`~/.config/ap_ds/opus_paths.conf`) → System library check (`ctypes.util.find_library("opusfile")`) → Auto-install (apt-get/dnf/pacman, interactive sudo) → Interactive setup
**macOS:**
- System library detection (find_library + common Homebrew/MacPorts paths) → MacPorts auto-install (`sudo port install opus opusfile libogg`) → Homebrew auto-install (`brew install opus opusfile libogg`) → Manual installation guide
### 6. OpusAudio Class — Complete API
The `OpusAudio` class provides an API nearly identical to `AudioLibrary`, but fully based on `libopusfile` and native audio output:
| Method | Function |
|--------|----------|
| `play_from_file(file_path, loops=0, start_pos=0.0)` | Play Opus file |
| `play_from_memory(file_path, loops=0, start_pos=0.0)` | Play from cache |
| `new_aid(file_path)` | Preload Opus file |
| `play_audio(aid)` | Resume playback |
| `pause_audio(aid)` | Pause playback |
| `stop_audio(aid)` | Stop playback, return elapsed time |
| `seek_audio(aid, position)` | Seek to position (seconds) |
| `set_volume(aid, volume)` | Set volume (0-128) |
| `get_volume(aid)` | Get volume |
| `fadein_music(aid, loops=-1, ms=0)` | Fade in during playback |
| `fadein_music_pos(aid, loops=-1, ms=0, position=0.0)` | Fade in from position |
| `fadeout_music(ms=0)` | Fade out and stop |
| `is_music_playing()` | Check if playing |
| `is_music_paused()` | Check if paused |
| `get_music_fading()` | Get fade in/out status |
| `get_audio_metadata(file_path)` | Get Opus metadata |
| `get_audio_duration(file_path)` | Get Opus duration |
| `get_audio_extended_metadata(file_path)` | Get extended tags (title/artist/album etc.) |
| `batch_get_metadata(file_paths, max_workers=None)` | Batch parse Opus metadata |
| `batch_get_duration(file_paths, max_workers=None)` | Batch get Opus duration |
| `cleanup_function()` | Release all resources |
### 7. Library Size Changes
Due to the addition of `opusplayer.py` (~45KB) and `_opusdll.py` (~25KB) plus Windows DLLs (~673KB total), this 0.0.1-AFS pre-release temporarily expands to ~3.87 MB.
| Version | Opus Support | Size | Description |
|---------|-------------|------|-------------|
| 4.0.x | ❌ | ~2.5MB | Stable, no Opus |
| **AFS 0.0.1-AFS** | ✅ | **~3.87MB** | **AFS pre-release with Opus** |
| 4.2.0+ (mainline) | ❌ | ~2.5MB | Mainline returns to lightweight |
| AFS 1.0.0+ | ✅ | ~2.8-3.5MB | AFS permanent home for Opus |
---
## 🌿 AFS Branch — ap_ds's "Dual-Track" Future
### Why Split?
With Opus added, the mainline package size grew from 2.5MB to 3.87MB. Every new format will increase size. If we stuff all formats into mainline, ap_ds will eventually become a bloated monster, betraying the original "lightweight" vision.
**So we decided: split the family.**
**AFS (All Format Support)** is a brand new independent branch that will carry all new format support, "beyond the 2.5MB limit."
| Aspect | Mainline (ap-ds) | AFS Branch (ap-ds-afs) |
|--------|-----------------|----------------------|
| PyPI package | `ap-ds` | `ap-ds-afs` |
| Import name | `ap_ds` | `ap_ds` (**identical!**) |
| Version | 4.x (continues) | 0.0.1-AFS → 1.0.0+ |
| Opus support | ❌ (except 4.1.0) | ✅ **Permanent** |
| Core formats | MP3/WAV/FLAC/OGG/AAC | Same + Opus + all future formats |
| Size | ~2.5MB | ~2.8-3.5MB |
| Update strategy | Security fixes only | Mainline sync + own new formats |
| Target users | Minimalist developers | Developers needing special formats |
**Key Design: Same Import Name**
```python
# Regardless of whether user installed ap-ds or ap-ds-afs
# The import method is exactly the same!
from ap_ds import AudioLibrary
```
This means users can switch between the two packages seamlessly by just changing the package name in `requirements.txt` or `pip install`.
### Which One Should You Choose?
| Your Need | Recommendation |
|-----------|---------------|
| Only MP3/WAV/FLAC/OGG/AAC | Mainline (`ap-ds` 4.2.0+) — lightweight, stable |
| Need Opus, willing to test pre-release | AFS (`ap-ds-afs` 0.0.1-AFS) — early adopter, feedback |
| Need Opus, want long-term stability | AFS (`ap-ds-afs` 1.0.0, September 2026) — full-featured, LTS |
| Not sure about future format needs | Install mainline, switch to AFS later (same import!) |
---
## ⚠️ Windows Multiprocessing Warning
If you're using ap_ds AFS 0.0.1-AFS on Windows... please read this carefully. Your program's ability to run depends on it.
**What's the problem?**
On Windows, Python's `multiprocessing` module uses the `spawn` method to create new processes. This means each child process re-imports your main module.
If you call `batch_get_metadata()` or any batch function that uses `ProcessPoolExecutor` directly at the top level of your script, child processes will execute these calls again when re-importing, causing infinite recursion and eventually a `BrokenProcessPool` error.
**Your program will crash. Directly.**
**Affected APIs:**
- `batch_get_metadata()`
- `batch_get_duration()`
- `batch_get_metadata_by_type()`
- Opus batch parsing is also affected
**How to fix?**
Simply wrap your batch parsing code inside `if __name__ == "__main__":`.
**❌ Wrong (Will crash on Windows):**
```python
from ap_ds import batch_get_metadata
# This will crash directly on Windows!
results = batch_get_metadata("/music/", max_workers=4)
print(f"Parsed {len(results)} files")
```
**✅ Correct:**
```python
from ap_ds import batch_get_metadata
def main():
results = batch_get_metadata("/music/", max_workers=4)
print(f"Parsed {len(results)} files")
if __name__ == "__main__":
main()
```
**✅ Correct (with config function):**
```python
from ap_ds import batch_get_metadata
def load_config():
return {"audio_dir": "/music/"}
def main():
config = load_config()
results = batch_get_metadata(config["audio_dir"], max_workers=4)
print(f"Parsed {len(results)} files")
if __name__ == "__main__":
main()
```
**✅ Jupyter Notebook Users:**
Put the batch call inside a function, then execute it in a cell:
```python
def run_batch():
from ap_ds import batch_get_metadata
return batch_get_metadata("/music/", max_workers=4)
results = run_batch()
```
**Why don't Linux and macOS have this problem?**
Linux and macOS use `fork` by default to create child processes, which copy the parent process's memory space without re-executing the main module code.
However, we still recommend using `if __name__ == "__main__"` entry point protection on all platforms. It's good programming practice and ensures cross-platform compatibility.
---
## 📊 Version Comparison Overview
| Aspect | Mainline 4.0.x | AFS 0.0.1-AFS | Mainline 4.2.0+ (planned) | AFS 1.0.0 (planned) |
|--------|---------------|---------------|--------------------------|---------------------|
| Opus support | ❌ | ✅ | ❌ | ✅ |
| Playback formats | MP3/WAV/FLAC/OGG/AAC | +Opus | MP3/WAV/FLAC/OGG/AAC | +Opus + future formats |
| Playback engine | SDL2 only | SDL2 + Opus native | SDL2 only | SDL2 + Opus native |
| Opus error codes | ❌ | ✅ 2001-2010 | ❌ | ✅ 2001-2010 |
| Auto DLL download | SDL2 | SDL2 + Opus DLLs | SDL2 | SDL2 + Opus DLLs |
| AFS branch | ❌ | ✅ (AFS itself) | ❌ | ✅ (AFS itself) |
| Test coverage | 421 tests | 650+ tests | 421 tests | 650+ tests |
| Library size | ~2.5MB | ~3.87MB | ~2.5MB | ~2.8-3.5MB |
| Version status | Stable | **Pre-release** | Planned | Planned (Sep 2026) |
### Version Relationship
| Version | Type | Support Period | Use Case |
|---------|------|---------------|----------|
| v3.0.0 LTS | LTS | Until Mar 2031 | Production |
| v4.0.x | LFV | ~6 months | Early adopters |
| **AFS 0.0.1-AFS** | **Pre-release** | **~1 month** | **Opus testing & feedback** |
| AFS 1.0.0+ (planned) | Stable | TBD | Opus permanent home (Sep 2026) |
| Mainline 4.2.0+ | LFV | ~6 months | Returns to lightweight |
### Upgrade Recommendations
| User Type | Recommendation |
|-----------|---------------|
| Production | Continue with v3.0.0 LTS, or wait for AFS 1.0.0 |
| Dev/Test | Try AFS 0.0.1-AFS with Opus, help test & feedback |
| Need Opus, willing to test | Use AFS 0.0.1-AFS, report bugs |
| Need Opus, want long-term stability | Wait for AFS 1.0.0 (September 2026) |
| No Opus needed, want lightweight | Wait for mainline 4.2.0+, or continue with 4.0.x |
| Affected by v3.1.x metadata bug | Must upgrade to v4.0.0+ |
---
## 🧪 CI/CD Test Results — Comprehensive Coverage, All Passed
### Opus Test Suite (OPUS_TEST.py)
AFS 0.0.1-AFS includes a complete Opus test suite covering 16 test categories:
| Category | Test Items | Description |
|----------|-----------|-------------|
| OP-1 | Module imports/constants/error codes | Verify all Opus modules, constants, error codes |
| OP-2 | DLL loading & auto-download | Verify `_opusdll.py` loading, DLL existence, hash verification |
| OP-3 | Metadata parsing | Verify Opus duration, sample rate, channels, bitrate, extended tags |
| OP-4 | Playback functions | Verify `play_from_file`, `play_from_memory`, `new_aid` |
| OP-5 | Playback control | Verify `pause_audio`, `play_audio`, `stop_audio` |
| OP-6 | Volume control | Verify `set_volume` (0-128 boundary values) and `get_volume` |
| OP-7 | Seek functionality | Verify `seek_audio` with various positions and boundary values |
| OP-8 | Fade in/out | Verify `fadein_music`, `fadein_music_pos`, `fadeout_music` |
| OP-9 | Opus vs native format distinction | Verify `_is_opus_file` and `AudioLibrary` auto-routing |
| OP-10 | Batch parsing | Verify `batch_get_metadata`, `batch_get_duration`, `batch_by_type` |
| OP-11 | Error code triggering | Confirm all 10 Opus error codes trigger correctly |
| OP-12 | AID 1:1 mapping | Verify main AID ↔ Opus sub-AID full lifecycle |
| OP-13 | Resource management | Verify `cleanup_function` releases resources correctly |
| OP-14 | Boundary & error tests | Verify invalid parameter types, out-of-range values |
| OP-15 | DLL-specific tests | Verify DLL file sizes, hashes, load idempotency |
| OP-16 | Error code trigger specific tests | Verify each Opus error code trigger in real scenarios |
**Test Results:**
```
==================================================================
Opus Test Summary
==================================================================
Passed : 229
Failed : 0
Skipped: 0
==================================================================
```
**All 229 tests passed, 0 failed, 0 skipped.**
### Comprehensive CICD Test Suite (CI,CD_TEST.py)
```
==================================================================
CICD Test Summary
==================================================================
Passed : 650+
Failed : 0
Skipped: 0
==================================================================
```
### API Import Verification Test (IMPORT_TEST.py)
```
============================================================
📊 FINAL SUMMARY
============================================================
🎉 ALL APIs EXIST! Documentation is accurate.
============================================================
✅ Passed: 47
❌ Failed: 0
```
**All 47 API checks passed!**
---
## 📖 Technical Manual Update
`show_tech_manual()` has been updated for AFS 0.0.1-AFS with:
- **Section 2.1 OPUS SUPPORT** (New chapter) — Opus format introduction, playback backend architecture, auto DLL download, OpusAudio class API reference, AID 1:1 mapping mechanism
- **Section 10.4 Opus Error Codes** (New section) — Complete 10 Opus error codes list (2001-2010), meanings and suggested actions
- **Version History** — AFS 0.0.1-AFS entry, Opus support, cross-platform playback backend, AFS branch establishment
---
## 🌐 apds.top Is Now Live!
The ap_ds official project homepage is now live with TLS encryption!
**🎉 Visit: https://apds.top**
**Website Features:**
- 📄 Full documentation: API reference, user guide, FAQ
- 📦 Version distribution: All version download links and changelogs
- 🔗 Repository navigation: GitCode (primary), Gitee (China mirror), GitHub (compatibility mirror)
- ✉️ Feedback system: Users can submit feedback directly through the website
- 🔒 Full-site TLS encryption
---
## 📦 Repository Strategy
| Platform | Status | Purpose |
|----------|--------|---------|
| apds.top | ✅ Permanent home | Official source code, docs, downloads |
| GitCode | ✅ Primary mirror | Global code hosting |
| GitHub | ✅ Compatibility mirror | For GitHub developers (new!) |
| Gitee | ✅ China mirror | Fast access for Chinese users |
| GitLab (JiHu) | ❌ Deprecated | No longer maintained |
---
## ℹ️ Overview
**ap_ds AFS** is a lightweight (~3.87MB) Python audio library for playback and high-precision metadata parsing of MP3, FLAC, OGG, WAV, and **Opus** files. Zero external Python dependencies — only uses the Python standard library with non-blocking playback suitable for GUI applications.
**Core Features:**
- 🎵 **Native Opus support** — Dedicated playback pipeline independent of SDL2, cross-platform native audio output
- 📦 **Zero Python dependencies** — Standard library only
- 🎯 **High-precision metadata** — WAV/FLAC 100%, OGG 99.99%, MP3 >98%, Opus 100%
- ⚡ **Batch parsing** — Parallel processing of hundreds of files using `batch_get_metadata()`
- 🖥️ **Non-blocking playback** — Ideal for GUI applications
- 🌍 **Cross-platform** — Windows, macOS, Linux, embedded ARM64
- 📝 **DAP recording system** — Automatic playback history, metadata only
- 🧵 **Python 3.15t support** — No-GIL true parallelism, full multi-core performance
- 🏠 **AFS permanent support** — Permanent home for Opus and all future formats
---
## 📧 Contact & Support
📧 **License inquiries:** me@dvsyun.top or dvs6666@163.com — 7 business days response
🛠️ **Technical support:** apds.top · GitCode Issues · GitHub Issues · Gitee Issues · Email (completely free)
**Author:** DVS (DvsXT)
**Personal homepage & blog:** https://dvsx.top (under maintenance)
**Author profile:** https://dvsyun.top/me/dvs
**Email:** me@dvsyun.top · dvs6666@163.com
**ap_ds Official Portal:**
- 🎵 **Official website:** https://apds.top — Permanent official homepage, full documentation, releases, license center
- 📦 **PyPI:** https://pypi.org/project/ap_ds/
- 🌐 **Mirror docs:** https://www.dvsyun.top/ap_ds