简体   繁体   中英

Audiokit 4.9.5 crashes in xcode 11.4 + swift 5.2, no useful error message

When importing AudioKit and trying to run a small example, I get:

Error Domain=com.apple.dt.ultraviolet.service Code=12 "Rendering service was interrupted" UserInfo={NSLocalizedDescription=Rendering service was interrupted}

After testing plenty of times, I've noticed that it only crashes in the "Preview (right sidebar)" mode, as it "Builds" and runs in the "simulator". Is it a limitation of the preview feature in Xcode? I don't know, but reported to the AudioKit team ( https://github.com/AudioKit/AudioKit/issues/2034 )

Considering the hello world published in ( https://audiokit.io/examples/HelloWorld/ ), I re-wrote it a bit differently, to fit the latest (consider the time of writing) Xcode 11.4 and Swift 5.2:

import SwiftUI
import AudioKit

struct ContentView: View {
    var oscillator = AKOscillator()
    var body: some View {
        VStack {
            Button("Play") {
                self.playSound()
            }
        }.onAppear {
            do {
                AudioKit.output = self.oscillator
                try AudioKit.start()
            } catch {
                print("audiokit init error")
            }
        }
    }

    private func playSound(){
        self.oscillator.amplitude = 1
        self.oscillator.frequency = 440
        self.oscillator.start()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

The Podfile is:

platform :ios, '11.0'

target 'AKHello' do
  use_frameworks!

  # Pods for AKHello
  pod 'AudioKit', '~> 4.9.5'

end

Is there some syntax error in the source code, or a way to get a more meaningful or useful error to fix this at all? AudioKit seems compatible with latest Xcode 11.4 considering the release notes in the github page ( https://github.com/AudioKit/AudioKit/releases , where you can read "This release is mostly to bring new binaries compatible with the latest Xcode release via CocoaPods")

Since initialising AudioKit in a View is probably not a good practice (and even though the goal is just to run a simple Hello world, just to make sure I moved that part into a struct , but the same issue happens)

// AudioPlayer.swift

import AudioKit

struct AudioPlayer {
    var oscillator = AKOscillator()
    init() {
        do {
            AudioKit.output = self.oscillator
            try AudioKit.start()
        } catch {
            print("audiokit init error")
        }
    }

    func playSound(){
        self.oscillator.amplitude = 1
        self.oscillator.frequency = 440
        self.oscillator.start()
    }
}

// ContentView.swift


import SwiftUI

struct ContentView: View {
    var audioPlayer: AudioPlayer = AudioPlayer()
    var body: some View {
        VStack {
            Button("Play") {
                self.audioPlayer.playSound()
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Also tried as an observable, with respective changes in the content view and scene delegate where I pass the new class for audio player:

// ContentView.swift

import SwiftUI

struct ContentView: View {
    @ObservedObject var audioPlayer: AudioPlayer

    var body: some View {
        VStack {
            Button("Play") {
                self.audioPlayer.playSound()
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView(audioPlayer: AudioPlayer())
    }
}

// AudioPlayer.swift

import AudioKit
import Combine

class AudioPlayer: ObservableObject {
    let objectWillChange = PassthroughSubject<AudioPlayer, Never>()
    var isPlaying = false {
        didSet {
            objectWillChange.send(self)
        }
    }
    var oscillator = AKOscillator()

    init() {
        do {
            AudioKit.output = self.oscillator
            try AudioKit.start()
            isPlaying = true
        } catch {
            print("audiokit init error")
        }
    }

    func playSound(){
        self.oscillator.amplitude = 1
        self.oscillator.frequency = 440
        self.oscillator.start()
    }
}

// SceneDelegate.swift

import UIKit
import SwiftUI

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?


    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

        let contentView = ContentView(audioPlayer: AudioPlayer())

        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: contentView)
            self.window = window
            window.makeKeyAndVisible()
        }
    }
}

I'm not sure if this is the entirety of your problem, but don't expect AudioKit to work in the Preview view. As far as I know that should just be visual SwiftUI type stuff. Your first approach where AudioKit's life cycle was tied to SwiftUI was pretty dangerous. Remember that SwiftUI will do whatever magical stuff it needs to and you shouldn't be trusting the audio system to work within it. You then moved the audio player stuff into its own class, but I still worry that you are tying the lifecycle too closely to SwiftUI structs. My approach would be to move the audio engine into its own class created within the SceneDelegate and then started on the onAppear for the main content view. See the AudioKit examples folder for iOS+Catalyst/Drums/ for an example of how you should set this up.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM