iOS 13 Closing App on Background: Audio Stream Issue - ios

I'm stuck in playing audio on the background with Swift 5 and Xcode 11.
Enabling Background Mode and starting AVAudioSession no longer works and the app keeps closing after a few seconds when you leave the app.
First I get a entitlement warming, but the stream starts:
Error acquiring assertion: <NSError: 0x2829830f0; domain: RBSAssertionErrorDomain; code: 2; reason: "Required client entitlement is missing"> {
userInfo = {
RBSAssertionAttribute = <RBSLegacyAttribute: 0x1050a9040; requestedReason: MediaPlayback; reason: MediaPlayback; flags: PreventTaskSuspend | PreventTaskThrottleDown | WantsForegroundResourcePriority>;
}
When after a few seconds on the background it closes:
[ProcessSuspension] Background task expired while holding WebKit ProcessAssertion (isMainThread? 1).
If I keep the app open the audio stops anyway:
[ProcessSuspension] 0x10dfc8848 - ProcessAssertion::processAssertionWasInvalidated()
Apple loves to change this every year. Anyone got this working on iOS 13 and Xcode 11/Swift 5 so far?
Thanks!
UPDATE: I just found out this issue is affecting only audio played through WebViews. I'm not sure if this is a bug on iOS 13 or if Apple is really cutting WebViews from multitasking. So I changed my app and the audio is now being played through the AVPlayer. Background audio works again.

do you put code for resume play audio in you Appdelegate
func applicationDidEnterBackground(_ application: UIApplication) {
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers, .allowAirPlay])
try AVAudioSession.sharedInstance().setActive(true)
} catch {
print(error)
}
}
addition make audio, airplay,and picture in picture on from your target capabilities

Related

Html5 Audio stop within a second when i play in IOS [IONIC 5]

this is really frustrating and i have an ionic app where we need to play audio and we used html5 audio to play the radio with url like this.
audio = new Audio();
audio.src = url;
audio.play();
it works on android and all ios simulators without any problem but when we use physical device it start and stopped within a second and in logs it give this error.
Error acquiring assertion: <NSError: 0x282cf67c0; domain: RBSAssertionErrorDomain; code: 2; reason:
"Required client entitlement is missing"> {
userInfo = {
RBSAssertionAttribute = <RBSLegacyAttribute: 0x1592432e0; requestedReason: MediaPlayback; reason:
MediaPlayback; flags: PreventTaskSuspend | PreventTaskThrottleDown |
WantsForegroundResourcePriority>;
}
Weird thing is that sometime it works but i mean it happened like one or two occasions.
if anyone has any idea please help me out.
thanks

WKWebView with embedded iframe player causes bad access when trying to disconnect from airplay

I have a WKWebView which loads request with this url which is after loaded plays inline video and can be switched to full screen , when switched to full screen the native ios player appears, there is airplay button in that player letting user to stream video via airplay, there is no problem with connection to airplay and streaming play, pause etc.
The problem is that when i try to switch playback back to app from the airplay switch menu it causes bad access exception with log :
Error acquiring assertion: <NSError: 0x283cbe310; domain: RBSAssertionErrorDomain; code: 2; reason: "Client is missing required entitlement">
userInfo = {
RBSAssertionAttribute = <RBSLegacyAttribute: 0x108054960; requestedReason: MediaPlayback; reason: MediaPlayback; flags: PreventTaskSuspend | PreventTaskThrottleDown | WantsForegroundResourcePriority>;
}
[ProcessSuspension] 0x1183e1018 - ProcessAssertion() PID 29725 Unable to acquire assertion for process with PID 29725[![enter image description here][1]][1]
The connection indicator also looks strange when connected to airplay
Finally solved the problem was in a third part lib which has categories on NSObject which where overriding copyWithZone method and were causing BAD_ACCESS, so removing the lib and implementing its functionality on project side solved the problem.

Connecting bluetooth headphones while app is recording in the background causes the recording to stop

I am facing the following issue and hoping someone else encountered it and can offer a solution:
I am using AVAudioEngine to access the microphone. Until iOS 12.4, every time the audio route changed I was able to restart the AVAudioEngine graph to reconfigure it and ensure the input/output audio formats fit the new input/output route. Due to changes introduced in iOS 12.4 it is no longer possible to start (or restart for that matter) an AVAudioEngine graph while the app is backgrounded (unless it's after an interruption).
The error Apple now throw when I attempt this is:
2019-10-03 18:34:25.702143+0200 [1703:129720] [aurioc] 1590: AUIOClient_StartIO failed (561145187)
2019-10-03 18:34:25.702528+0200 [1703:129720] [avae] AVAEInternal.h:109 [AVAudioEngineGraph.mm:1544:Start: (err = PerformCommand(*ioNode, kAUStartIO, NULL, 0)): error 561145187
2019-10-03 18:34:25.711668+0200 [1703:129720] [Error] Unable to start audio engine The operation couldn’t be completed. (com.apple.coreaudio.avfaudio error 561145187.)
I'm guessing Apple closed a security vulnerability there. So now I removed the code to restart the graph when an audio route is changed (e.g. bluetooth headphones are connected).
It seems like when an I/O audio format changes (as happens when the user connects a bluetooth device), an .AVAudioEngingeConfigurationChange notification is fired, to allow the integrating app to react to the change in format. This is really what I should've used to handle changes in I/O formats from the beginning, instead of brute forcing restarting the graph. According to the Apple documentation - “When the audio engine’s I/O unit observes a change to the audio input or output hardware’s channel count or sample rate, the audio engine stops, uninitializes itself, and issues this notification.” (see the docs here). When this happens while the app is backgrounded, I am unable to start the audio engine with the correct audio i/o formats, because of point #1.
So bottom line, it looks like by closing a security vulnerability, Apple introduced a bug in reacting to audio I/O format changes while the app is backgrounded. Or am I missing something?
I'm attaching a code snippet to better describe the issue. For a plug-and-play AppDelegate see here - https://gist.github.com/nevosegal/5669ae8fb6f3fba44505543e43b5d54b.
class RCAudioEngine {
​
private let audioEngine = AVAudioEngine()
init() {
setup()
start()
NotificationCenter.default.addObserver(self, selector: #selector(handleConfigurationChange), name: .AVAudioEngineConfigurationChange, object: nil)
}
​
#objc func handleConfigurationChange() {
//attempt to call start()
//or to audioEngine.reset(), setup() and start()
//or any other combination that involves starting the audioEngine
//results in an error 561145187.
//Not calling start() doesn't return this error, but also doesn't restart
//the recording.
}
public func setup() {
​
//Setup nodes
let inputNode = audioEngine.inputNode
let inputFormat = inputNode.inputFormat(forBus: 0)
let mainMixerNode = audioEngine.mainMixerNode
​
//Mute output to avoid feedback
mainMixerNode.outputVolume = 0.0
​
inputNode.installTap(onBus: 0, bufferSize: 4096, format: inputFormat) { (buffer, _) -> Void in
//Do audio conversion and use buffers
}
}
​
public func start() {
RCLog.debug("Starting audio engine")
guard !audioEngine.isRunning else {
RCLog.debug("Audio Engine is already running")
return
}
​
do {
audioEngine.prepare()
try audioEngine.start()
} catch {
RCLog.error("Unable to start audio engine \(error.localizedDescription)")
}
}
}
I see only a fix that had gone into iOS 12.4. I am not sure if that causes the issue.
With the release notes https://developer.apple.com/documentation/ios_ipados_release_notes/ios_12_4_release_notes
"Resolved an issue where running an app in iOS 12.2 or later under the Leaks instrument resulted in random numbers of false-positive leaks for every leak check after the first one in a given run. You might still encounter this issue in Simulator, or in macOS apps when using Instruments from Xcode 10.2 and later. (48549361)"
You can raise issue with Apple , if you are a signed developer. They might help you if the defect is on their part.
You can also test with upcoming iOS release to check if your code works in the future release (with the apple beta program)

Required client entitlement required?

I have a wkwebview and I selected the checkbox 'inline playback' which is suppose to make any video in the wkwebview to not autoplay and stay in the webpage and not go full screen.
This worked fine for me until my Xcode updated to 11!
I now get the following error but it lets the auto playing video to go full screen, when before it wouldn't.
2019-09-27 22:26:43.654625-0400 RPD[3848:126819] [assertion] Error acquiring assertion: <NSError: 0x600000c9c7b0; domain: RBSAssertionErrorDomain; code: 2; reason: "Required client entitlement is missing"> {
userInfo = {
RBSAssertionAttribute = <RBSLegacyAttribute: 0x7fe141f30d60; requestedReason: MediaPlayback; reason: MediaPlayback; flags: PreventTaskSuspend | PreventTaskThrottleDown | WantsForegroundResourcePriority>;
}
}
I added the capability 'Background Modes' but enabling Audio, Airplay, Picture in picture does not do anything.

Chromecast Sleep/Background issue in iOS app

I am facing a very big issue while using Chromecast in my application. I am using normal GCKUICastButton to connect to the Chromecast. The video plays well.
I am using the default Cast receiver for my application. When the device goes to sleep, sometimes, Chromecast stops and sometimes, after sleep mode, the device disconnects after some time. After going through lot of forums and Stack Overflow questions, I implemented the below code
extension GCKSessionManager {
static func ignoreAppBackgroundModeChange() {
let oldMethod = class_getInstanceMethod(GCKSessionManager.self, #selector(GCKSessionManager.suspendSession(with:)))
let newMethod = class_getInstanceMethod(GCKSessionManager.self, #selector(GCKSessionManager.suspendSessionIgnoringAppBackgrounded(with:)))
method_exchangeImplementations(oldMethod, newMethod)
}
func suspendSessionIgnoringAppBackgrounded(with reason: GCKConnectionSuspendReason) -> Bool {
guard reason != .appBackgrounded else { return false }
return suspendSession(with:reason)
}
}
Then in my code I wrote the below line
GCKSessionManager.ignoreAppBackgroundModeChange()
Now suddenly, the Chromecast does not disconnect however after few minutes of sleep, it disconnects as well as, kill the app as well. How can I retain the Chromecast play session even if the device goes to sleep or goes to background.
As I am using GCKUICastButton so I am not using the GCKDeviceManager so I am unable to use the ignoreAppStateNotification using GCKDeviceManager, can you advice if I can use that as well.
I have also added the GCKCastOption code as well in AppDelegate.

Resources