Explore ShazamKit
Audio & Video 入门 22m

探索 ShazamKit

Explore ShazamKit

2021年6月10日

在 Apple 官方观看视频

一句话判断

ShazamKit 把 Shazam 的音频指纹识别能力开放给所有开发者了——不只是识别歌曲,还能用自定义音频库匹配任何声音,但别忘了 Apple 收取的 API 调用限制。

这场 Session 讲了什么

ShazamKit 是 WWDC 2021 最让人兴奋的新框架之一。它把 Shazam 的核心技术——音频指纹匹配——以 SDK 的形式开放给第三方开发者。你可以在自己的 app 中实现「听音识曲」功能,而不需要自建音频识别引擎。

ShazamKit 支持两种使用模式。第一种是使用 Apple 的 Shazam 音乐目录(包含数百万首歌曲),适合做音乐识别类 app。第二种是使用自定义音频目录(Custom Catalog),你可以上传自己的音频文件生成参考指纹,然后匹配任何声音——比如广告监测、电视节目同步、线下活动互动。

技术架构上,ShazamKit 的工作原理是:录制一段几秒的音频,提取频谱特征生成指纹,然后与目录中的指纹进行比对。匹配速度非常快(通常在 1-2 秒内),而且可以离线运行(使用 Custom Catalog 时)。

值得深挖的点

Custom Catalog 的适用场景

Custom Catalog 是 ShazamKit 最有价值的能力。想象一下:一个电视节目可以把自己的音频生成指纹目录,观众打开 app 识别当前正在播放的片段,app 可以展示相关的互动内容(投票、问答、购买链接)。这在国外被称为「第二屏体验」。

生成 Custom Catalog 需要使用 ShazamKit 的命令行工具或者 API,把音频文件转换为 .shazamsignature 格式。每个音频文件生成一个 Reference Signature,然后打包成 Catalog。Catalog 文件可以打包到 app 中离线使用,也可以托管在服务端按需下载。

匹配精度与音频长度的关系

ShazamKit 的匹配精度取决于录制的音频长度。Session 建议:音乐识别至少需要 3 秒的录制,Custom Catalog 匹配建议 5 秒以上。录制时间越长,匹配越准确。但在嘈杂环境中,即使录制 10 秒也可能匹配失败——ShazamKit 对背景噪音的抗干扰能力有限。

代码片段

// 基础音乐识别
import ShazamKit

class MusicRecognizer: NSObject, SHSessionDelegate {
    let session = SHSession()
    let audioEngine = AVAudioEngine()
    
    override init() {
        super.init()
        session.delegate = self
    }
    
    func startListening() {
        let audioSession = AVAudioSession.sharedInstance()
        try? audioSession.setCategory(.record)
        try? audioSession.setActive(true)
        
        let inputNode = audioEngine.inputNode
        let format = inputNode.outputFormat(forBus: 0)
        
        inputNode.installTap(onBus: 0, bufferSize: 4096, format: format) { 
            [weak self] buffer, time in
            self?.session.matchStreamingBuffer(buffer, 
                                                at: time)
        }
        
        try? audioEngine.start()
    }
    
    func stopListening() {
        audioEngine.inputNode.removeTap(onBus: 0)
        audioEngine.stop()
    }
    
    // SHSessionDelegate 回调
    func session(_ session: SHSession, didFind match: SHMatch) {
        guard let item = match.items.first?.mediaItem else { return }
        
        let title = item.title ?? "未知歌曲"
        let artist = item.artist ?? "未知艺术家"
        let artwork = item.artworkURL
        
        print("识别到: \(title) - \(artist)")
    }
    
    func session(_ session: SHSession, didNotFindMatchFor signature: SHSignature, error: Error?) {
        print("未找到匹配")
    }
}
// 使用 Custom Catalog 匹配自定义音频
func setupCustomCatalog() {
    // 从 app bundle 中加载预生成的 catalog
    guard let catalogURL = Bundle.main.url(
        forResource: "MyCustomCatalog",
        withExtension: "shazamcatalog"
    ) else { return }
    
    do {
        let catalog = try SHCustomCatalog(contentsOf: catalogURL)
        let session = SHSession()
        session.delegate = self
        
        // 将自定义目录添加到 session
        // session 会同时匹配 Shazam 目录和自定义目录
        try catalog.add(to: session)
    } catch {
        print("加载自定义目录失败: \(error)")
    }
}
// 从音频文件生成 Custom Catalog(通常在服务端完成)
// 使用 ShazamKit 的命令行工具:
// shazamkit catalog create --input audio/ --output catalog.shazamcatalog
//
// 或者在 macOS 上用代码生成:
func generateSignature(from audioURL: URL) -> SHSignature? {
    let asset = AVAsset(url: audioURL)
    let generator = SHSignatureGenerator()
    
    // 这个方法只在 macOS 上可用
    // iOS 上需要使用预生成的 catalog
    return try? generator.signature(from: asset)
}

最佳实践

不要持续运行音频录制。ShazamKit 的麦克风使用是高功耗操作。建议让用户手动触发识别(点击按钮开始,再次点击停止),或者设置一个 10-15 秒的超时自动停止。

如果你的 app 使用 Custom Catalog,把 catalog 文件压缩后放在 CDN 上按需下载。一个包含 100 首歌的 catalog 大约 5-10MB。首次下载后缓存到本地,后续匹配就不需要网络了。

还有什么值得关注

  • ShazamKit 支持同步获取歌曲的 Apple Music 链接,如果你的 app 集成了 MusicKit,可以直接播放识别到的歌曲。
  • SHMediaItem 包含了丰富的元数据:歌曲名、艺术家、专辑、发行年份、流派等。
  • Custom Catalog 支持增量更新——可以只下载新增的音频指纹,不需要重新下载整个 catalog。
WWDC 2021