146 lines
3.7 KiB
Markdown
146 lines
3.7 KiB
Markdown
# Music Assistant Audio Streaming Integration
|
|
|
|
## Übersicht
|
|
|
|
Um Audio vom Music Assistant Server auf dem iPhone abzuspielen, müssen wir:
|
|
1. Stream-URL vom Server anfordern
|
|
2. AVPlayer mit dieser URL konfigurieren
|
|
3. Playback-Status zum Server zurückmelden
|
|
|
|
## Stream-URL erhalten
|
|
|
|
### API Call: `player_queues/cmd/get_stream_url`
|
|
|
|
```swift
|
|
func getStreamURL(queueId: String, queueItemId: String) async throws -> URL {
|
|
let response = try await webSocketClient.sendCommand(
|
|
"player_queues/cmd/get_stream_url",
|
|
args: [
|
|
"queue_id": queueId,
|
|
"queue_item_id": queueItemId
|
|
]
|
|
)
|
|
|
|
guard let result = response.result,
|
|
let urlString = result.value as? String,
|
|
let url = URL(string: urlString) else {
|
|
throw ClientError.serverError("Invalid stream URL")
|
|
}
|
|
|
|
return url
|
|
}
|
|
```
|
|
|
|
### Beispiel Stream-URL Format
|
|
|
|
```
|
|
http://MA_SERVER:8095/api/stream/<queue_id>/<queue_item_id>
|
|
```
|
|
|
|
## Implementierungsschritte
|
|
|
|
### 1. Stream-URL in MAService hinzufügen
|
|
|
|
```swift
|
|
// In MAService.swift
|
|
func getStreamURL(queueId: String, queueItemId: String) async throws -> URL {
|
|
let response = try await webSocketClient.sendCommand(
|
|
"player_queues/cmd/get_stream_url",
|
|
args: [
|
|
"queue_id": queueId,
|
|
"queue_item_id": queueItemId
|
|
]
|
|
)
|
|
|
|
guard let result = response.result else {
|
|
throw MAWebSocketClient.ClientError.serverError("No result")
|
|
}
|
|
|
|
// Try to extract URL from response
|
|
if let urlString = result.value as? String,
|
|
let url = URL(string: urlString) {
|
|
return url
|
|
}
|
|
|
|
throw MAWebSocketClient.ClientError.serverError("Invalid stream URL format")
|
|
}
|
|
```
|
|
|
|
### 2. Integration in MAAudioPlayer
|
|
|
|
```swift
|
|
// In MAAudioPlayer.swift
|
|
func playQueueItem(_ item: MAQueueItem, queueId: String) async throws {
|
|
logger.info("Playing queue item: \(item.name)")
|
|
|
|
// Get stream URL from server
|
|
let streamURL = try await service.getStreamURL(
|
|
queueId: queueId,
|
|
queueItemId: item.queueItemId
|
|
)
|
|
|
|
// Load and play
|
|
loadAndPlay(item: item, streamURL: streamURL)
|
|
}
|
|
```
|
|
|
|
### 3. Status-Updates zum Server senden
|
|
|
|
```swift
|
|
// Player-Status synchronisieren
|
|
func syncPlayerState() async throws {
|
|
try await service.webSocketClient.sendCommand(
|
|
"players/cmd/update_state",
|
|
args: [
|
|
"player_id": "ios_device",
|
|
"state": isPlaying ? "playing" : "paused",
|
|
"current_time": currentTime,
|
|
"volume": Int(volume * 100)
|
|
]
|
|
)
|
|
}
|
|
```
|
|
|
|
## Format-Unterstützung
|
|
|
|
AVPlayer unterstützt nativ:
|
|
- ✅ MP3
|
|
- ✅ AAC
|
|
- ✅ M4A
|
|
- ✅ WAV
|
|
- ✅ AIFF
|
|
- ✅ HLS Streams
|
|
|
|
Für FLAC benötigt man:
|
|
- ⚠️ Server-seitige Transcoding (MA kann das automatisch)
|
|
- 🔧 Oder: Third-party Decoder (z.B. via AudioToolbox)
|
|
|
|
## Authentifizierung für Stream-URLs
|
|
|
|
Stream-URLs erfordern möglicherweise den Auth-Token:
|
|
|
|
```swift
|
|
var request = URLRequest(url: streamURL)
|
|
if let token = service.authManager.currentToken {
|
|
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
|
|
}
|
|
|
|
let playerItem = AVPlayerItem(asset: AVURLAsset(url: streamURL, options: [
|
|
"AVURLAssetHTTPHeaderFieldsKey": request.allHTTPHeaderFields ?? [:]
|
|
]))
|
|
```
|
|
|
|
## Nächste Schritte
|
|
|
|
1. ✅ Implementiere `getStreamURL()` in MAService
|
|
2. ✅ Update `MAAudioPlayer.playQueueItem()`
|
|
3. ✅ Teste mit verschiedenen Audio-Formaten
|
|
4. ✅ Implementiere Player-State-Sync zum Server
|
|
5. ✅ Handle Netzwerk-Fehler & Buffering
|
|
|
|
## Referenzen
|
|
|
|
- [MA Server API Docs](http://YOUR_SERVER:8095/api-docs)
|
|
- [AVPlayer Documentation](https://developer.apple.com/documentation/avfoundation/avplayer)
|
|
- [AVAudioSession Best Practices](https://developer.apple.com/documentation/avfaudio/avaudiosession)
|