WWDC Quick Look 💓 By SwiftGGTeam
Create custom audio experiences with ShazamKit

Create custom audio experiences with ShazamKit

元の動画を見る

ハイライト

このコードは、ShazamKit のカスタム カタログを使用して教育コンパニオン アプリを構築する方法を示しています。Apple TV は説明ビデオを再生し、iPhone はマイクを介して音声を認識し、インタラクティブな質問を同時に表示し、一時停止、早送り、再生をサポートします。

主な内容

遠隔教育の最大の問題点は、生徒が注意力をそらされがちであることです。教師は画面の反対側でそのテーマについて講義し、生徒は反対側でソーシャルメディアをスクロールします。学生の iPhone がビデオ コンテンツに続いてインタラクティブな質問を自動的にポップアップ表示できるようになれば、状況はまったく異なるものになるでしょう。

ShazamKit のカスタム ディレクトリ認識により、このシナリオが現実になります。Shazam 音楽ライブラリの認識とは異なり、カスタム カタログはデバイス上で完全にローカルに実行され、ネットワークを必要としません。任意の音声 (教育ビデオ、テレビ番組、ポッドキャスト) から署名を生成し、ディレクトリに保存すると、アプリがリアルタイムで署名を照合します。

(01:20) このセッションのデモは、FoodMath という教育アプリです。Apple TV は数学の教育ビデオを再生し、iPhone はマイクを通してテレビの音声を監視し、現在再生されているエピソードの番号と進行状況を識別して、対応する数学の問題を同時に表示します。

中心的なメカニズムは次のとおりです。predictedCurrentMatchOffset参照署名内の現在の一致点の時間オフセット (秒単位) を返します。アプリはこのオフセットを使用して、対応するQuestionオブジェクト。どのコンテンツを表示するかを決定します。生徒がビデオを一時停止したり、早送りや巻き戻しをしたりしても、アプリはリアルタイムで対応できます。

(14:15) この「オーディオはリモコン」モデルにより、クロスデバイス エクスペリエンスが非常にシンプルになります。Bluetooth のペアリングや同じ Wi-Fi は必要ありません。デバイスがサウンドを聞くことができれば、同期されます。

##詳細

音声ファイルから参照署名を生成

カスタム ディレクトリの中核は参照署名です。オーディオ ファイルから生成することも、直接ロードすることもできます.shazamsignature書類。

let signatureGenerator = SHSignatureGenerator()

// 从 AVAudioEngine 的 inputNode 捕获音频
audioEngine.inputNode.installTap(onBus: 0, bufferSize: 2048, format: audioFormat) { buffer, audioTime in
    try? signatureGenerator.append(buffer, at: audioTime)
}

let signature = signatureGenerator.signature()

キーポイント:

  • SHSignatureGeneratorオーディオバッファを署名に変換する
  • installTapからinputNode音声をキャプチャし、bufferはいAVAudioPCMBuffer
  • audioTimeバッファがキャプチャされた時点であり、音声の連続性を確保するために使用されます。
  • オーディオ形式は PCM であり、サンプルレートはサポートされている範囲内である必要があります。
  • 生成された署名は参照署名と呼ばれ、カスタム ディレクトリに追加できます。

カスタム カタログを構築し、メタデータを関連付ける

// 从文件加载签名
let signatureURL = Bundle.main.url(forResource: "FoodMath", withExtension: "shazamsignature")!
let signature = try SHSignature(data: Data(contentsOf: signatureURL))

// 定义自定义媒体项属性
extension SHMediaItemProperty {
    static let teacher = SHMediaItemProperty("teacher")
    static let episode = SHMediaItemProperty("episode")
}

// 创建媒体项元数据
let mediaItem = SHMediaItem(properties: [
    .title: "Count on Me",
    .subtitle: "Addition",
    .teacher: "Neil",
    .episode: 3
])

// 创建目录并添加签名
let customCatalog = SHCustomCatalog()
try customCatalog.addReferenceSignature(signature, representing: [mediaItem])

キーポイント:

  • .shazamsignatureデバイス間で共有できる不透明なファイル形式です
  • SHMediaItemPropertyカスタムキーはサポートされていますが、値は有効なプロパティリストタイプである必要があります
  • addReferenceSignature署名をメタデータに関連付け、一致が成功した場合にこれらのメタデータを返します。
  • カスタム ディレクトリは完全にローカルで実行され、ネットワーク接続は必要ありません

マイクによるリアルタイムマッチング

let session = SHSession(catalog: customCatalog)
session.delegate = self

// 开始捕获麦克风音频
audioEngine.inputNode.installTap(onBus: 0, bufferSize: 2048, format: audioFormat) { buffer, audioTime in
    session.matchStreamingBuffer(buffer, at: audioTime)
}

try audioEngine.start()

キーポイント:

  • SHSession(catalog:)デフォルトの Shazam クラウド ライブラリの代わりにカスタム ディレクトリを指定します
  • matchStreamingBufferリアルタイムのオーディオストリーミング用に最適化されており、署名は自動的に生成および更新されます。
  • 着信audioTime非常に重要です。セッションでは音声の連続性が確認されます。
  • Info.plist にマイク使用の説明を追加する必要があります

一致結果を処理し、コンテンツを同期する

extension ViewController: SHSessionDelegate {
    func session(_ session: SHSession, didFind match: SHMatch) {
        guard let matchedMediaItem = match.mediaItems.first else { return }

        // predictedCurrentMatchOffset 是自动更新的匹配时间偏移(秒)
        let currentOffset = matchedMediaItem.predictedCurrentMatchOffset

        // 找到当前偏移对应的 Question
        let currentQuestion = questions.last { $0.offset <= currentOffset }

        DispatchQueue.main.async {
            self.updateUI(with: currentQuestion, mediaItem: matchedMediaItem)
        }
    }
}

キーポイント:

  • predictedCurrentMatchOffsetはいSHMatchedMediaItemの固有の属性。参照署名内の現在位置を示します。
  • この値はオーディオの再生時に自動的に更新されるため、再照合する必要はありません。
  • session(_:didFind:)複数回呼び出される場合もあります。重複する質問をフィルタリングすることをお勧めします。
  • 時間オフセットによってコンテンツを検索し、秒単位で正確な同期を実現します

ディレクトリの分散とキャッシュ

(14:27) カスタム ディレクトリを渡すことができます.shazamcatalogファイル形式はディスクに保存され、ネットワーク経由で配布することもできます。

// 保存目录到本地
let catalogURL = documentsURL.appendingPathComponent("lessons.shazamcatalog")
try customCatalog.write(to: catalogURL)

// 从网络下载后加载
let downloadedCatalog = try SHCustomCatalog(contentsOf: downloadedURL)

キーポイント:

  • カタログ ファイルはインターネット経由でオンデマンドでダウンロードできるため、アプリのサイズが小さくなります。
  • ネットワークが利用できない場合でも通常どおり使用できる、ローカルのフォールバック ディレクトリを提供することをお勧めします。
  • エピソード/チャプターごとにディレクトリを分割し、現在必要なコンテンツのみをダウンロードできます

重要ポイント

  1. フィットネスコース同期アシスタント
  • 何をすべきか: フィットネス アプリは、ユーザーが再生したトレーニング ビデオに基づいて、現在のアクションの名前、番号、キー ポイントを自動的に表示します。
  • 実行する価値がある理由: ユーザーが手動でページをめくったり、進行状況を覚えたりする必要はありません。ビデオが再生されるたびにプロンプ​​トが表示されます。
  • 開始方法: フィットネス ビデオのオーディオ用のカスタム ディレクトリを生成し、各アクション クリップを対応するガイダンス コンテンツに関連付けます。使用predictedCurrentMatchOffsetドライバーUIのアップデート
  1. ポッドキャストのチャプターナビゲーション
  • 内容: ポッドキャスト プレーヤーは、現在再生中のコンテンツに基づいて、チャプター タイトル、ゲスト情報、関連リンクを自動的に表示します。
  • 価値がある理由: ポッドキャストには通常、正確なチャプター マーカーがありませんが、ShazamKit はオーディオ コンテンツに基づいて任意の精度の時間位置を実現できます。
  • 開始方法: ポッドキャスト音声の署名ディレクトリをチャプターごとに生成し、照合して使用しますpredictedCurrentMatchOffset対応する章のメタデータを検索して表示します
  1. オフラインアクティビティインタラクティブウォール
  • やるべきこと: 展示会やイベントでは、訪問者はアプリを開くことで、現在の展示品の詳細情報やインタラクティブなコンテンツを取得できます。
  • 実行する価値がある理由: NFC タグや QR コードは必要なく、音声自体がコンテンツ エントリとなり、導入コストが非常に低くなります
  • 開始方法: 各ブースの紹介ビデオ/音声から署名が生成され、ディレクトリに保存されます。視聴者が近づくと、アプリが自動的に認識し、対応するコンテンツを表示します。
  1. 多言語字幕の同期
  • 内容: ビデオ プレーヤーは、現在の再生の進行状況に基づいて、対応する時点で字幕を自動的にロードして表示します。
  • 価値がある理由: オーディオ マッチングにより、ビデオ ファイル自体に字幕トラックが埋め込まれていない場合でも、正確な字幕同期が可能になります。
  • 開始方法: ビデオの音声を使用してカスタム ディレクトリを生成します。字幕ファイルはタイムスタンプによって分割されます。マッチング後、predictedCurrentMatchOffset対応する字幕をロードする

関連セッション

コメント

GitHub Issues · utterances