-
Notifications
You must be signed in to change notification settings - Fork 76
Expand file tree
/
Copy pathAudioPlayerState.swift
More file actions
145 lines (129 loc) · 4.95 KB
/
Copy pathAudioPlayerState.swift
File metadata and controls
145 lines (129 loc) · 4.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//
// Created by Dimitrios Chatzieleftheriou on 02/06/2020.
// Copyright © 2020 Decimal. All rights reserved.
//
import Foundation
// MARK: Internal State
extension AudioPlayer {
struct InternalState: OptionSet {
var rawValue: Int
static let initial = InternalState([])
static let running = InternalState(rawValue: 1)
static let playing = InternalState(rawValue: (1 << 1) | InternalState.running.rawValue)
static let rebuffering = InternalState(rawValue: (1 << 2) | InternalState.running.rawValue)
static let waitingForData = InternalState(rawValue: (1 << 3) | InternalState.running.rawValue)
static let waitingForDataAfterSeek = InternalState(rawValue: (1 << 4) | InternalState.running.rawValue)
static let paused = InternalState(rawValue: (1 << 5) | InternalState.running.rawValue)
static let stopped = InternalState(rawValue: 1 << 9)
static let pendingNext = InternalState(rawValue: 1 << 10)
static let disposed = InternalState(rawValue: 1 << 30)
static let error = InternalState(rawValue: 1 << 31)
static let waiting = [.waitingForData, waitingForDataAfterSeek, .rebuffering]
}
}
/// Helper method that returns `AudioPlayerState` and `StopReason` based on the given `InternalState`
/// - Parameter internalState: A value of `InternalState`
/// - Returns: A tuple of `(AudioPlayerState, AudioPlayerStopReason)`
func playerStateAndStopReason(
for internalState: AudioPlayer.InternalState
) -> (state: AudioPlayerState, stopReason: AudioPlayerStopReason?) {
switch internalState {
case .initial:
return (.ready, AudioPlayerStopReason.none)
case .running, .playing, .waitingForDataAfterSeek:
return (.playing, AudioPlayerStopReason.none)
case .pendingNext, .rebuffering, .waitingForData:
return (.bufferring, AudioPlayerStopReason.none)
case .stopped:
return (.stopped, nil)
case .paused:
return (.paused, AudioPlayerStopReason.none)
case .disposed:
return (.disposed, .userAction)
case .error:
return (.error, AudioPlayerStopReason.error)
default:
return (.ready, AudioPlayerStopReason.none)
}
}
// MARK: Public States
public enum AudioPlayerState: Equatable, Sendable {
case ready
case running
case playing
case bufferring
case paused
case stopped
case error
case disposed
}
public enum AudioPlayerStopReason: Equatable, Sendable {
case none
case eof
case userAction
case error
case disposed
}
public enum AudioPlayerError: LocalizedError, Equatable, Sendable {
case streamParseBytesFailure(AudioFileStreamError)
case audioSystemError(AudioSystemError)
case codecError
case dataNotFound
case networkError(NetworkError)
case other
public var errorDescription: String? {
switch self {
case let .streamParseBytesFailure(status):
return "Couldn't parse the bytes from the stream. Status: \(status)"
case let .audioSystemError(error):
return error.errorDescription
case .codecError:
return "Codec error while parsing data packets"
case .dataNotFound:
return "No data supplied from network stream"
case let .networkError(error):
return error.localizedDescription
case .other:
return "Audio Player error"
}
}
}
public struct AudioSystemErrorDetails: Equatable, Sendable {
public let description: String
public let domain: String
public let code: Int
init(error: Error) {
let nsError = error as NSError
description = error.localizedDescription
domain = nsError.domain
code = nsError.code
}
}
public enum AudioSystemError: LocalizedError, Equatable, Sendable {
case engineFailure(AudioSystemErrorDetails?)
case playerNotFound(AudioSystemErrorDetails?)
case playerStartError(AudioSystemErrorDetails?)
case fileStreamError(AudioFileStreamError)
case converterError(AudioConverterError)
case codecError
public var errorDescription: String? {
switch self {
case let .engineFailure(error):
return detailedDescription(prefix: "Audio engine couldn't start", error: error)
case let .playerNotFound(error):
return detailedDescription(prefix: "Player not found", error: error)
case let .playerStartError(error):
return detailedDescription(prefix: "Player couldn't start", error: error)
case let .fileStreamError(error):
return "Audio file stream errored: \(error)"
case let .converterError(error):
return "Audio converter errored: \(error)"
case .codecError:
return "Audio codec error"
}
}
}
private func detailedDescription(prefix: String, error: AudioSystemErrorDetails?) -> String {
guard let error else { return prefix }
return "\(prefix): \(error.description) [\(error.domain):\(error.code)]"
}