2

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.

Andrew Duncan
  • 3,553
  • 4
  • 28
  • 55
  • FWIW, I see this behavior on iOS 12/13 simulators, but it appears to work on actual iOS 13.4 device. (FWIW, I’m using `AVPlayer` and `AVPlayerLayer`, playing video, but I'm assuming it is the same issue as the above. Exact same errors.) Looks like a simulator bug to me, though I don't see this explicitly addressed in the [Xcode release notes](https://developer.apple.com/documentation/xcode-release-notes). – Rob Mar 13 '21 at 00:09
  • Thanks Rob, I am hoping that is the case. DTS asked me to file a feedback, which I did at https://feedbackassistant.apple.com/feedback/9012209. I am still getting analytics from live apps that wind up at the `$$$` line of code, so i am still worried. This code does run correctly on BitBar's free iPhone SE 2020 A2296 13.4.1 though. – Andrew Duncan Mar 14 '21 at 01:20
  • I've started seeing the same thing. Just one of many, many spurious warnings and errors that the simulator is barfing and drowning out the debugging output that I want to see. – NRitH Jun 11 '21 at 17:40
  • I discussed this with Apple in a WWDC lab. Their perspective was: 1) Known bug on Simulator. 2) If it were widely prevalent in live devices, we would all know. 3) My 5 second delay may be too tight for the first time a 3-second clip plays, due to one-time startup costs, leading to false positives 4) I could try using`AVAudioSession` to hint to the OS about what is ahead. Will add to this when/if I have more results. – Andrew Duncan Jun 12 '21 at 18:35

0 Answers0