🚀 クイックスタート

iOS SDK のクイックスタートをベースに、SkyWay iOS SDK と AI Noise Canceller ライブラリを使った簡単なアプリケーションを作成します。

動作環境

  • 対応 OS バージョン: iOS 15, iPadOS 15 以降

通話アプリの作成

クイックスタート の手順に従って SkyWay を使った通話アプリを作成してください。

重要: AI Noise Canceller を利用するには SkyWay iOS SDK v3.0.0 以降 が必要です。SDK をインストールする際はバージョンを必ず確認してください。

音声の確認方法

1 人で動作を確認する際に出力音声へ影響を与えないよう、イヤホンの利用を推奨します。

AI Noise Canceller を組み込んだアプリへ改修

ライブラリのインストール

1. 環境変数の設定

ライブラリをインストールする前に、環境変数を設定する必要があります。 appId と secret の値を差し替えて、以下のコマンドを実行してください。

export SKYWAY_APP_ID="your-app-id" export SKYWAY_SECRET_KEY="your-app-secret"

2. ダウンロードスクリプトの実行

以下のコマンドを実行して、ライブラリをダウンロードします。

curl -fsSL https://raw.githubusercontent.com/skyway/ai-noise-canceller/refs/heads/main/tools/ios/download.sh | bash

上記のコマンドにより、tmp ディレクトリに最新版バージョンの AI Noise Canceller がダウンロードされます。 環境に合わせて Project に追加してください。

上記で実行するシェルスクリプトは、 端末内で SkyWay Admin Auth Token を生成※しライブラリ取得の認証に利用しています。 この SkyWay Admin Auth Token は、アプリケーションの管理者(サーバー)用APIを利用する際に必要なトークンであり、本トークンが流出した場合は第三者に管理者(サーバー)用APIを悪用されてしまう恐れがあります。 取り扱いには十分に気をつけてください。

※ SkyWay Admin Auth Token の有効期限は1時間です

3. Swift Package Manager での導入

Swift Package Manager を用いる場合、Xcode から Project を選択し、 Package Dependencies を選択します。

左下 + ボタンからパッケージ検索のモーダルを表示させ、画面下の Add Local... を押下します。

ダウンロードした skyway-ai-noise-canceller ディレクトリを選択し Add Package を押下します。

SkyWayAINoiseCanceller と voiceomnia を追加する Target を設定し、 Add Package を押下します。

ノイズ抑制のセットアップ

SkyWayAuthToken の設定

ノイズ抑制の機能を利用する際は認可を追加する必要があります。SkyWayAuthTokenscope へ以下のように noiseCancelling の項目を追加します。

const token = new SkyWayAuthToken({ ... scope: { ... analytics: { enabled: true }, noiseCancelling: { enabled: true } }, }).encode(secret);

サンプリングレートの設定

ノイズ抑制では、通話品質および処理の最適化のためにサンプリングレートは 16kHz にすることを推奨します。

RoomViewModel.swift にて、サンプリングレートを 16kHz に設定します。 実行タイミングは音声疎通の前となりますが、今回は SkyWay のセットアップ直後に設定します。

// SkyWayのセットアップ let contextOptions: ContextOptions = .init() contextOptions.logLevel = .trace try? await Context.setupForDev(withAppId: appId, secretKey: secretKey, options: contextOptions) AudioSettings.setPreferredSampleRate(16000.0)

サンプリングレートについて、詳しくは開発ガイドを参照してください。

セットアップの実装

SkyWayAINoiseCanceller をインポートします。

import SkyWayAINoiseCanceller

SkyWay のセットアップが成功した後に、SkyWayNoiseCanceller.shared.setup によりノイズ抑制処理のセットアップを行います。 SkyWayNoiseCanceller はシングルトンインスタンスで管理しています。

// SkyWayのセットアップ let contextOptions: ContextOptions = .init() contextOptions.logLevel = .trace try? await Context.setupForDev(withAppId: appId, secretKey: secretKey, options: contextOptions) AudioSettings.setPreferredSampleRate(16000.0) _ = await SkyWayNoiseCanceller.shared.setup()

セットアップ後は SkyWayNoiseCanceller.shared.start() / stop() でノイズ抑制の ON/OFF を切り替えられます。

ノイズ抑制の ON/OFF 切り替え

RoomViewModelenableNoiseCanceller()disableNoiseCanceller() を追加します。

また、 ContentView にノイズ抑制の Toggle を追加し、ノイズ抑制の ON/OFF 切り替えを実装します。

RoomViewModel.swift

func enableNoiseCanceller() { _ = SkyWayNoiseCanceller.shared.start() } func disableNoiseCanceller() { _ = SkyWayNoiseCanceller.shared.stop() }

ContentView.swift

@State private var isNoiseCancellerEnabled: Bool = false // ... Toggle("ノイズ抑制", isOn: $isNoiseCancellerEnabled) .onChange(of: isNoiseCancellerEnabled) { newValue in if newValue { viewModel.enableNoiseCanceller() } else { viewModel.disableNoiseCanceller() } }

アプリをビルドし、前述[音声の確認方法]に従って、発話しながらマウスクリックやキータイプを行うことで、ノイズ付きの音声を確認できます。

Toggle を操作することで、聞き比べながらノイズが低減されることが確認できます。

ノイズ抑制の強度変更

次に、ノイズ抑制の強度を変更できるように実装を変更します。

RoomViewModelsetNoiseCancellerStrength() を追加します。

また、 ContentView にノイズ抑制の強度を変更するための Slider を追加します。 最小値は1、最大値は100に設定し、初期値は100にします。

RoomViewModel.swift

func setNoiseCancellerStrength(_ strength: Int) { _ = SkyWayNoiseCanceller.shared.changeStrength(strength) }

ContentView.swift

@State private var strength: Float = 100.0 // ... HStack { Text("ノイズ抑制の強度: \(Int(strength))") Slider(value: $strength, in: 1...100, step: 1) .onChange(of: strength) { newValue in viewModel.setNoiseCancellerStrength(Int(newValue)) } }

変更が完了したら、もう一度アプリをビルドし、端末にインストールして動作を確認してみましょう。

Slider を操作することでノイズ抑制の強度を変更できます。処理強度を変更しながら出力音声を確認するとノイズ抑制の効果がわかりやすくなります。

はじめに一度だけノイズ抑制強度を変更すれば良い場合、init の引数から設定できます。 詳しい使い方は API リファレンスをご参照ください。

ノイズ抑制の解除(Dispose)

Room 退出時や音声の Unpublish 時など、ノイズ抑制が不要になったタイミングで SkyWayNoiseCanceller.shared.dispose() を呼び出してください。

Tutorial 完成コード

RoomViewModel.swift

import Foundation import SkyWayAINoiseCanceller import SkyWayRoom @MainActor final class RoomViewModel: ObservableObject, RoomDelegate { @Published var localVideoStream: LocalVideoStream? @Published var remoteVideoStream: RemoteVideoStream? private var localAudioStream: LocalAudioStream? private var room: Room? private var localRoomMember: LocalRoomMember? func start(roomName: String) async { let appId = "アプリケーションIDを入力してください" let secretKey = "シークレットキーを入力してください" // SkyWayのセットアップ let contextOptions: ContextOptions = .init() contextOptions.logLevel = .trace try? await Context.setupForDev(withAppId: appId, secretKey: secretKey, options: contextOptions) AudioSettings.setPreferredSampleRate(16000.0) _ = await SkyWayNoiseCanceller.shared.setup() // Roomの作成 let roomInit: Room.InitOptions = .init() roomInit.name = roomName guard let room = try? await Room.findOrCreate(with: roomInit) else { print("[Tutorial] Creating room failed.") return } self.room = room // Roomへの参加 let memberInit: Room.MemberInitOptions = .init() memberInit.name = "member_\(UUID().uuidString)" guard let member = try? await room.join(with: memberInit) else { print("[Tutorial] Join failed.") return } localRoomMember = member // カメラからの映像取得とUIへの表示 // カメラリソースの取得 if let camera = CameraVideoSource.supportedCameras().first(where: { $0.position == .front }) { // カメラ映像のキャプチャを開始します try? await CameraVideoSource.shared().startCapturing(with: camera, options: nil) } else { print("[Tutorial] Supported camera is not found.") } // 描画やPublishが可能なStreamを作成します // @Publishedプロパティを更新し、ContentViewのLocalVideoViewで描画します localVideoStream = CameraVideoSource.shared().createStream() // マイクからの音声取得 // Publishが可能なStreamを作成します localAudioStream = MicrophoneAudioSource().createStream() // StreamのPublish _ = try? await member.publish(localVideoStream!, options: nil) _ = try? await member.publish(localAudioStream!, options: nil) // Room内でStreamがPublishされるとroom(_:didPublishStreamOf:)が呼ばれるようにdelegateを登録します room.delegate = self // PublicationのSubscribe // 入室時に他のMemberのPublicationをSubscribeします for publication in room.publications { await subscribe(publication) } } // Room内のMemberがPublishしているPublicationをSubscribeします private func subscribe(_ publication: RoomPublication) async { // 自身のPublicationは除く if publication.publisher == localRoomMember { return } // PublicationをSubscribeします guard let subscription = try? await localRoomMember?.subscribe(publicationId: publication.id, options: nil) else { return } // Videoの場合はremoteVideoStreamを更新して描画します if let videoStream = subscription.stream as? RemoteVideoStream { self.remoteVideoStream = videoStream } } func enableNoiseCanceller() { _ = SkyWayNoiseCanceller.shared.start() } func disableNoiseCanceller() { _ = SkyWayNoiseCanceller.shared.stop() } func setNoiseCancellerStrength(_ strength: Int) { _ = SkyWayNoiseCanceller.shared.changeStrength(strength) } // MARK: - RoomDelegate nonisolated func room(_ room: Room, didPublishStreamOf publication: RoomPublication) { Task { await subscribe(publication) } } }

ContentView.swift

import SwiftUI struct ContentView: View { @StateObject private var viewModel = RoomViewModel() @State private var roomName: String = "" @State private var isNoiseCancellerEnabled: Bool = false @State private var strength: Float = 100.0 var body: some View { VStack { HStack { TextField("Room name", text: $roomName) .textFieldStyle(.roundedBorder) Button("Join") { Task { await viewModel.start(roomName: roomName) } } .buttonStyle(.borderedProminent) .disabled(roomName.isEmpty) } Toggle("ノイズ抑制", isOn: $isNoiseCancellerEnabled) .onChange(of: isNoiseCancellerEnabled) { newValue in if newValue { viewModel.enableNoiseCanceller() } else { viewModel.disableNoiseCanceller() } } HStack { Text("ノイズ抑制の強度: \(Int(strength))") Slider(value: $strength, in: 1...100, step: 1) .onChange(of: strength) { newValue in viewModel.setNoiseCancellerStrength(Int(newValue)) } } LocalVideoView(stream: viewModel.localVideoStream) .frame(maxWidth: .infinity, maxHeight: .infinity) RemoteVideoView(stream: viewModel.remoteVideoStream) .frame(maxWidth: .infinity, maxHeight: .infinity) } .padding() } }

おわりに

以上がノイズ抑制機能の基本的な使い方となります。

さらに詳しい API の説明や注意事項は API リファレンスを参照してください。