|
2 | 2 |
|
3 | 3 | All notable changes to PlayolaPlayer are documented here. This project follows |
4 | 4 | [Semantic Versioning](https://semver.org/). Versions correspond to git tags, |
5 | | -which Swift Package Manager consumers pin to. |
| 5 | +which Swift Package Manager consumers pin to. Pre-1.0, breaking changes bump the |
| 6 | +minor version. |
| 7 | + |
| 8 | +## 0.20.0 |
| 9 | + |
| 10 | +This release makes the **host app the sole owner of the `AVAudioSession`.** The |
| 11 | +SDK previously configured/activated the session and self-handled interruptions |
| 12 | +and route changes; it no longer touches `AVAudioSession` at all. This lets the |
| 13 | +SDK coexist cleanly with other audio subsystems in your app (URL streaming, |
| 14 | +recording, VoIP) instead of fighting them for the process-global session. |
| 15 | + |
| 16 | +### Removed |
| 17 | + |
| 18 | +- **The SDK no longer manages the `AVAudioSession`.** `AudioSessionManager` is |
| 19 | + gone, `PlayolaMainMixer` no longer exposes `configureAudioSession()` / |
| 20 | + `ensureAudioSessionConfigured()` / `deactivateAudioSession()`, and |
| 21 | + `PlayolaStationPlayer` no longer registers `AVAudioSession.interruptionNotification` |
| 22 | + / `routeChangeNotification` observers. The `handleAudioSessionInterruption(_:)` |
| 23 | + and `handleAudioRouteChange(_:)` methods are removed. |
| 24 | + |
| 25 | + **Source-breaking — required host changes:** |
| 26 | + |
| 27 | + 1. **Own the session.** Configure and activate it before `play(stationId:)`: |
| 28 | + `try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, policy: .longFormAudio, options: [])` |
| 29 | + then `setActive(true)`. The SDK no longer does this; without it, |
| 30 | + `play(stationId:)` fails when the engine starts (surfaced as `.error`). |
| 31 | + |
| 32 | + 2. **Drive interruptions yourself.** Observe `AVAudioSession.interruptionNotification` |
| 33 | + (and route changes as needed) and call the new `pauseForInterruption()` / |
| 34 | + `resumeAfterInterruption()` (below). Reactivate the session before calling |
| 35 | + resume. |
| 36 | + |
| 37 | + See the [Audio session](README.md#audio-session) and migration sections of the |
| 38 | + README for copy-paste host setup and a full interruption-handling example. |
| 39 | + |
| 40 | +### Added |
| 41 | + |
| 42 | +- **Host-driven interruption transport.** |
| 43 | + - `PlayolaStationPlayer.pauseForInterruption()` — silences playback, |
| 44 | + cancels scheduling/downloads, and is generation-fenced so in-flight work |
| 45 | + from before the pause can't publish state afterward. Preserves only the |
| 46 | + station identity (wall-clock radio has no frozen position). Idempotent |
| 47 | + across a double-pause. |
| 48 | + - `PlayolaStationPlayer.resumeAfterInterruption() async throws` — restarts the |
| 49 | + engine and replays the interrupted station re-synced to the live wall clock. |
| 50 | + Disarms only on success, so a failed resume (e.g. the host hasn't |
| 51 | + reactivated the session yet) stays retryable. |
| 52 | + |
| 53 | +- **`PlayolaStationPlayer.State` gained a `.paused(Spin)` case.** Published while |
| 54 | + paused for an interruption; the `Spin` carries display metadata (title, |
| 55 | + artist, artwork URL) for the track that was playing. **Source-breaking for |
| 56 | + consumers** that `switch` exhaustively over `State`: add a `case .paused` arm. |
| 57 | + |
| 58 | +- **Engine self-recovery.** The SDK now restarts and re-syncs its own engine |
| 59 | + graph on `AVAudioEngineConfigurationChange` (scoped to the SDK's own engine, |
| 60 | + so a host running a separate `AVAudioEngine` is unaffected). This is engine |
| 61 | + ownership, not session ownership — it touches no `AVAudioSession` API. |
6 | 62 |
|
7 | 63 | ## 0.19.0 |
8 | 64 |
|
|
0 commit comments