ShazamKit match(SHSignature) not working on IOS 16

I am trying to use ShazamKit to detect the song in a local audio file. When I call match(SHSignature), nothing happens. Neither delegate function ever gets called, and nothing is printed to the console. I don't know what went wrong, how to fix it or even how to debug this further.

Here is some sample code where the issue is occurring. You will need to place a song.m4a audio file in your xcode project for this to work. Your song.m4a file must be 3-12 seconds in length. The code will fail if the audio file exceeds 12 seconds for reasons discussed here.

import SwiftUI
import ShazamKit

@main
struct ShazamKitTestExApp: App {
    var body: some Scene {
        WindowGroup {
            ContentViewTrio()
        }
    }
}

struct ContentViewTrio: View {
    @StateObject private var detectSong: DetectSongEx = DetectSongEx()
    
    var body: some View {
        VStack {
            Text("ShazamKitTestEx")
            Button {
                print("Detecting Song")
                Task {
                    if let url = Bundle.main.url(forResource: "song", withExtension: "m4a") {
                        print(url.absoluteString)
                        await detectSong.matchSong(from: url)
                    }
                }
            } label: {
                Text("Detect Song from Audio File")
            }
        }
    }
}

class DetectSongEx: NSObject, ObservableObject, SHSessionDelegate {
    func matchSong(from url: URL) async {
        let session = SHSession()
        session.delegate = self
        let asset = AVURLAsset(url: url)
        do {
            let signature = try await SHSignatureGenerator.signature(from: asset)
            print("Calling session match method")
            session.match(signature)
        } catch {
            print("Failed to generate signature")
        }
    }
    
    func session(_ session: SHSession, didFind match: SHMatch) {
        print("session delegate - DidFindMatch")
    }
    
    func session(_ session: SHSession, didNotFindMatchFor signature: SHSignature, error: Error?) {
        print("session delegate called - DidNotFindMatch")
        if let shError = error as? SHError {
            print(shError.localizedDescription)
        }
    }
}

Notes

Yes, I have added ShazamKit to my App ID using the instructions here.

Device Test Results

I tried this on a Mac (macOS 13.0.1), on a physical iPhone (iOS 16.4.1) and a physical iPad (iPadOS 16.1.1). Unfortunately, I don't have any hardware running iOS 15 or macOS 12.

When I use an audio file with a length of 6 seconds with the sample code (on all devices), neither delegate ever gets called and match(SHSignature) just silently fails.

If I use an audio file of length > 12s then the DidNotFindMatch delegate does get called with the error "The operation couldn’t be completed. (com.apple.ShazamKit error 201.)" as expected.

iOS 15

I have used ShazamKit before prior to iOS 16 being released. Back then, I used the the code found here to match a song from a local audio file, since the new iOS 16 simple api didn't exist. I was able to successfully use match(SHSignature) back then and the DidFindMatch delegate was called as expected giving me a match. When I tried this old code now on iOS 16, without any changes, it didn't work. Everything complied fine but the same thing happened as described at the beginning of this post, match(SHSignature) would silently fail and neither delegate is ever called.

Simulator Test Results

I am aware that ShazamKit does not work from within the simulator. However, since I have no access to iOS 15 hardware, this is my only option to compare the code on iOS 15.5 vs iOS 16.4. The results were odd.

When I tried my old code in the simulator running iOS 15.5, the DidNotFindMatch delegate does get called with the error "The operation couldn’t be completed. (com.apple.ShazamKit error 202.)". Based on other forum posts, I believe this is the expected error when trying to run ShazamKit from the simulator.

However, when I tried my old code in the simulator running iOS 16.4, the DidNotFindMatch delegate does not get called, match(SHSignature) would silently fail and neither delegate is ever called. This is strange, I expected the result to be the same as when I ran the old code in the 15.5 simulator.

Conclusion

If anyone has an ideas what is going on or how to test this further, I am all ears. It seems kind of crazy to me that this was broken in iOS 16.0 and has never been fixed. Has anyone run into anything similar? Or is the sample code working on your iOS 16 device?

Accepted Answer

The sample code above does not work because it contains a bug.

The session variable should not be declared inside of func matchSong(from url: URL) async. Session is going out of scope and being destroyed so the delegates are never called.

Instead it should be a class variable of DetectSongEx.

Once the bug is fixed, match(SHSignature) is working as expected on IOS 16.

ShazamKit match(SHSignature) not working on IOS 16
 
 
Q