Skip to content

Commit

Permalink
feat: resume after interruptions on iOS (#20)
Browse files Browse the repository at this point in the history
* feat: resume after interruptions on iOS

* chore: release 1.0.4-beta.0
  • Loading branch information
itsramiel authored Jan 23, 2025
1 parent 777f9bd commit ee823be
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 6 deletions.
8 changes: 4 additions & 4 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1242,7 +1242,7 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-audio-playback (1.0.0):
- react-native-audio-playback (1.0.3):
- DoubleConversion
- glog
- hermes-engine
Expand Down Expand Up @@ -1789,7 +1789,7 @@ SPEC CHECKSUMS:
fmt: 10c6e61f4be25dc963c36bd73fc7b1705fe975be
glog: 08b301085f15bcbb6ff8632a8ebaf239aae04e6a
hermes-engine: 3852e37f6158a2fcfad23e31215ed495da3a6a40
RCT-Folly: bf5c0376ffe4dd2cf438dcf86db385df9fdce648
RCT-Folly: 84578c8756030547307e4572ab1947de1685c599
RCTDeprecation: d575d28132f93e5deef4849d5afffb4ac4e63226
RCTRequired: e2e5df1df76aac8685aabfebca389e6bec64792b
RCTTypeSafety: 30e36ceafa26979860e13fb3f234fb61692924c2
Expand Down Expand Up @@ -1818,7 +1818,7 @@ SPEC CHECKSUMS:
React-logger: addd140841248966c2547eb94836399cc1061f4d
React-Mapbuffer: 029b5332e78af8c67c4b5e65edfc717068b8eac1
React-microtasksnativemodule: f30949ee318ba90b9668de1e325b98838b9a4da2
react-native-audio-playback: 2e227d97930550dc443ae76be9a07b25f51c469e
react-native-audio-playback: 3aa13924ebd09343ce93ab18e89a99536db42134
react-native-slider: d1a9121980fc81678c6d30b82f312c778fba563c
React-nativeconfig: 470fce6d871c02dc5eff250a362d56391b7f52d6
React-NativeModulesApple: 1586448c61a7c2bd4040cc03ccde66a72037e77e
Expand Down Expand Up @@ -1852,4 +1852,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: db41a2e031518fb452cb8d57b6501f7d2b8a89b0

COCOAPODS: 1.15.2
COCOAPODS: 1.14.3
43 changes: 42 additions & 1 deletion ios/AudioEngine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ enum AudioStreamState {
case initialized, opened, closed, paused
}

struct InterruptionState {
let wasOpen: Bool
}

enum AudioEngineError: LocalizedError {
case audioStreamAlreadyInitialized
case failedToSetupAudioStream(reason: String)
Expand Down Expand Up @@ -52,12 +56,49 @@ class AudioEngine {
private var audioUnit: AudioUnit?
private var players = [String: Player]()
private var audioStreamState: AudioStreamState = .closed
private var interruptionState: InterruptionState?

init() {
// configure Audio Session
let audioSession = AVAudioSession.sharedInstance()
try? audioSession.setCategory(.playback)
try? audioSession.setActive(true)

NotificationCenter.default.addObserver(
self,
selector: #selector(handleAudioSessionInterruption),
name: AVAudioSession.interruptionNotification,
object: nil
)
}

@objc private func handleAudioSessionInterruption(notification: Notification) {
guard let userInfo = notification.userInfo,
let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
let type = AVAudioSession.InterruptionType(rawValue: typeValue) else {
return
}

switch type {
case .began:
let isOpen = audioStreamState == .opened
if isOpen {
try? pauseAudioStream()
}
self.interruptionState = .init(wasOpen: isOpen)
case .ended:
guard let optionsValue = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt, let interruptionState else { return }
let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue)
if options.contains(.shouldResume)
&& audioStreamState != .closed
&& interruptionState.wasOpen {
try? openAudioStream()
}

self.interruptionState = nil
@unknown default:
break
}
}

public func setupAudioStream(sampleRate: Double, channelCount: Int) throws {
Expand Down Expand Up @@ -145,7 +186,6 @@ class AudioEngine {

let audioPlayer = Unmanaged<AudioEngine>.fromOpaque(inRefCon).takeUnretainedValue()
guard let outputBuffer = ioData?.pointee.mBuffers.mData?.assumingMemoryBound(to: Float32.self) else {
print("Audio buffer is nil")
return noErr
}

Expand All @@ -160,6 +200,7 @@ class AudioEngine {
}

@objc public func openAudioStream() throws {
print(audioStreamState)
guard audioStreamState == .initialized || audioStreamState == .paused else {
throw AudioEngineError.failedToOpenAudioStream(reason: "Stream is not initialized")
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-native-audio-playback",
"version": "1.0.3",
"version": "1.0.4-beta.0",
"description": "Play sounds with lowest latency in React Native using Google Oboe for Android and Audio Unit for iOS",
"source": "./src/index.tsx",
"main": "./lib/commonjs/index.js",
Expand Down

0 comments on commit ee823be

Please sign in to comment.