Make AudioManager stable, testable and maintainable by separating Discord voice connection handling, ffmpeg process management, audio playback control and lifecycle cleanup.
Problem
AudioManager currently owns too many responsibilities:
Discord voice connection creation
ffmpeg process spawning
PCM stream handling
AudioResource creation
AudioPlayer creation
renewal timer handling
cleanup/dispose logic
This makes the class fragile in reconnect, error and dispose scenarios, especially for 24/7 audio playback.
Scope
Split internal responsibilities into smaller components:
VoiceConnectionService
FfmpegStreamFactory
AudioPlayerController
RenewalScheduler
Improve ffmpeg lifecycle:
terminate process cleanly
handle stderr, error, and exit
avoid zombie processes
Consolidate StopConnection() and Dispose() cleanup behavior.
Remove non-null assertions from AudioManager.
Reuse AudioPlayer instead of recreating it on each play call.
Introduce a clear internal state model.
Add unit tests for lifecycle behavior.
Acceptance Criteria
Build passes.
Lint passes.
Tests exist and pass.
StopConnection() cleans up ffmpeg and streams.
Dispose() is idempotent.
No empty catch {} blocks remain.
No non-null assertions remain in AudioManager.
Existing public API remains compatible.
## Refactor AudioManager Lifecycle & Architecture
### Goal
Make `AudioManager` stable, testable and maintainable by separating Discord voice connection handling, ffmpeg process management, audio playback control and lifecycle cleanup.
### Problem
`AudioManager` currently owns too many responsibilities:
- Discord voice connection creation
- ffmpeg process spawning
- PCM stream handling
- AudioResource creation
- AudioPlayer creation
- renewal timer handling
- cleanup/dispose logic
This makes the class fragile in reconnect, error and dispose scenarios, especially for 24/7 audio playback.
### Scope
- Split internal responsibilities into smaller components:
- `VoiceConnectionService`
- `FfmpegStreamFactory`
- `AudioPlayerController`
- `RenewalScheduler`
- Improve ffmpeg lifecycle:
- terminate process cleanly
- handle `stderr`, `error`, and `exit`
- avoid zombie processes
- Consolidate `StopConnection()` and `Dispose()` cleanup behavior.
- Remove non-null assertions from `AudioManager`.
- Reuse `AudioPlayer` instead of recreating it on each play call.
- Introduce a clear internal state model.
- Add unit tests for lifecycle behavior.
### Acceptance Criteria
- Build passes.
- Lint passes.
- Tests exist and pass.
- `StopConnection()` cleans up ffmpeg and streams.
- `Dispose()` is idempotent.
- No empty `catch {}` blocks remain.
- No non-null assertions remain in `AudioManager`.
- Existing public API remains compatible.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Refactor AudioManager Lifecycle & Architecture
Goal
Make
AudioManagerstable, testable and maintainable by separating Discord voice connection handling, ffmpeg process management, audio playback control and lifecycle cleanup.Problem
AudioManagercurrently owns too many responsibilities:This makes the class fragile in reconnect, error and dispose scenarios, especially for 24/7 audio playback.
Scope
VoiceConnectionServiceFfmpegStreamFactoryAudioPlayerControllerRenewalSchedulerstderr,error, andexitStopConnection()andDispose()cleanup behavior.AudioManager.AudioPlayerinstead of recreating it on each play call.Acceptance Criteria
StopConnection()cleans up ffmpeg and streams.Dispose()is idempotent.catch {}blocks remain.AudioManager.