iOS playing audio in iOS 13 throws C++ exception, freezes app

Viewed 542

TL;DR:

The code below (all ten lines of it, apart from debugging)

  • fails (UI freezes) on iOS 13.x (Simulator)
  • succeeds (audio plays) on 14.x (Simulator and devices)

I don't have any devices with iOS 13.x. But...analytics from live apps suggest it is failing in the field on both iOS 13 and 14 devices. False positives? (See line of code commented with $$$.)

Steps To Reproduce

Create a new SwiftUI project that can run in iOS 13. Replace the text in ContentView.swift with the code below. Add an audio resource named clip.mp3. Build and run.

I am using Xcode 12.4, macOS 11.1, Swift 5.

See Also

Code

import SwiftUI
import AVKit

struct ContentView: View {
    var body: some View {
        Text("Boo!").onAppear { playClip() }
    }
}

var clipDelegate: AudioTimerDelegate!   // Hold onto it to forestall GC.
var player      : AVAudioPlayer!        // Ditto.

func playClip() {
    let u = Bundle.main.url(forResource: "clip", withExtension: "mp3")!
    player = try! AVAudioPlayer(contentsOf: u)
    clipDelegate = AudioTimerDelegate()  // Wait till now to instantiate, for correct timing.
    player.delegate = clipDelegate
    player.prepareToPlay()
    NSLog("*** Starting clip play")    // NSLog so we get timestamp.
    player.play()

    // Wait 5 seconds and see if audioPlayerDidFinishPlaying.
    DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
        if let d = clipDelegate.clipDuration {
            NSLog("*** Caller   clip duration = \(d)")
        } else {
            NSLog("!!! Caller found nil clip duration")
            // $$$ In live app, post audio-freeze event to analytics.
        }
    }
}

class AudioTimerDelegate: NSObject, AVAudioPlayerDelegate {
    private var startTime : Double
    var clipDuration: Double?
    override init() {
        self.startTime = CFAbsoluteTimeGetCurrent()
        super.init()
    }
    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
        clipDuration = CFAbsoluteTimeGetCurrent() - startTime
        NSLog("*** Delegate clip duration = \(clipDuration!)")
    }
}

Console Output

Simulator iOS 14.4

The audio plays and the Console (edited for brevity) reads:

14:33:17  [plugin] AddInstanceForFactory: No factory registered for ... F8BB1C28-...
14:33:17  *** Starting clip play
14:33:19  *** Delegate clip duration = 1.692...
14:33:22  *** Caller   clip duration = 1.692...

I gather that the first line is innocuous and related to the Simulator's sound drivers. Is anyone else getting this console message with AVAudioPlayer in Xcode 11 (and 11.1)?

Device 14.4

Results are the same, without the AddInstanceForFactory complaint.

Simulator 13.6

Audio never sounds, the delegate callback never runs, and in the Console I get:

14:30:10  [plugin] AddInstanceForFactory: No factory registered for ... F8BB1C28-...
14:30:11  HALB_IOBufferManager_Client::GetIOBuffer: the stream index is out of range
14:30:11  HALB_IOBufferManager_Client::GetIOBuffer: the stream index is out of range
14:30:11  [aqme] AQME.h:254:IOProcFailure: AQDefaultDevice (1): output stream 0: null buffer
14:30:11  [aqme] AQMEIO_HAL.cpp:1774:IOProc: EXCEPTION thrown (-50): error != 0

14:30:26  [aqme] AQMEIO.cpp:179:AwaitIOCycle: timed out after 15.000s (0 1); suspension count=0 (IOSuspensions: )
14:30:26  CA_UISoundClient.cpp:241:StartPlaying_block_invoke: CA_UISoundClientBase::StartPlaying: AddRunningClient failed (status = -66681).
14:30:26  *** Starting clip play
14:30:26  HALB_IOBufferManager_Client::GetIOBuffer: the stream index is out of range
14:30:26  HALB_IOBufferManager_Client::GetIOBuffer: the stream index is out of range
14:30:26  [aqme] AQME.h:254:IOProcFailure: AQDefaultDevice (1): output stream 0: null buffer
14:30:26  [aqme] AQMEIO_HAL.cpp:1774:IOProc: EXCEPTION thrown (-50): error != 0

14:30:41  [aqme] AQMEIO.cpp:179:AwaitIOCycle: timed out after 15.000s (1 2); suspension count=0 (IOSuspensions: )
14:30:46  !!! Caller found nil clip duration

Remarks

It seems that there are two fifteen-second delays going on in the failure case.

0 Answers
Related