831 lines
34 KiB
Markdown
831 lines
34 KiB
Markdown
# 🎉 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
|