APIリファレンス
コアコンポーネント
KlleonOndeviceSdk
すべての機能を提供するメインSDKクラスです。
// シングルトンで管理(推奨)
object SdkConfig {
val sdk = KlleonOndeviceSdk()
}
val klleonOndeviceSdk = SdkConfig.sdk
KlleonSdkView
SDKコンテンツをレンダリングするためのカスタムAndroid Viewです。
@Composable
fun SdkViewComponent() {
var workerView by remember { mutableStateOf<KlleonSdkView?>(null) }
AndroidView(
factory = { context ->
KlleonSdkView(context).also { view ->
workerView = view
}
},
modifier = Modifier.fillMaxSize()
)
}
setRenderRotation()
TVなどで画面回転が必要な場合に使用します。
klleonSdkView.setRenderRotation(270) // 0, 90, 270度をサポート
ResourceManager
リソースの初期化および解放を担当するクラスです。play() の前に必ず init() でリソースを準備する必要があります。
val resourceManager = ResourceManager()
init()
アバターリソースをキャッシュディレクトリにコピーし、YUV変換およびネイティブメモリロードを実行します。
resourceManager.init(
context: Context,
mp4FileName: String,
npzFileName: String,
styleFileName: String = "",
avatarId: String = "",
onSuccess: () -> Unit,
onError: (Throwable) -> Unit
)
パラメータ:
| パラメータ | 型 | 必須 | 説明 |
|---|---|---|---|
context | Context | O | 現在のコンテキスト |
mp4FileName | String | O | アバターMP4ファイル名(assets内) |
npzFileName | String | O | アバターNPZファイル名(assets内) |
styleFileName | String | X | スタイルファイル名(デフォルト: "") |
avatarId | String | X | アバターID。同一アバター再進入時にバッファを再利用して即座に onSuccess を返します |
onSuccess | () -> Unit | O | リソース準備完了コールバック |
onError | (Throwable) -> Unit | O | エラーコールバック |
例:
resourceManager.init(
context = this,
mp4FileName = "loop_sample.mp4",
npzFileName = "loop_sample.npz",
styleFileName = "loop_sample.style",
avatarId = "character_001",
onSuccess = {
// 準備完了 — play()はsuspendのためコルーチン内で呼び出し
CoroutineScope(Dispatchers.IO).launch {
klleonOndeviceSdk.play(context, sdkView, sdkKey, avatarId, language)
}
},
onError = { error ->
Log.e("SDK", "リソース準備失敗", error)
}
)
同一アバター(avatarId)で init() を再呼び出しすると、既に準備されたバッファを再利用して即座に onSuccess を返します。異なるアバターに切り替える場合は、以前のバッファを解放して新たに割り当てます。
deinit()
ネイティブYUVバッファメモリを解放し、リソース状態を初期化します。
resourceManager.deinit()
deinit() は複数回呼び出しても安全です。既に解放された状態で呼び出すとno-opとなります。
呼び出し規則
init()— アバター選択完了時に呼び出し。アバター変更時に以前のバッファを自動解放します。play()—init()のonSuccessコールバックが来た時のみ呼び出し可能deinit()— アプリ完全終了時に呼び出し。finish()はバッファを維持して同一アバター再進入を最適化します。
SDKメソッド
play()
AIアバタービデオ再生を開始します。suspend 関数のため、コルーチン内で呼び出す必要があります。
suspend fun play(
context: Context,
klleonSdkViewInstance: KlleonSdkView?,
sdkKey: String,
avatarId: String,
language: String
)
パラメータ:
| パラメータ | 型 | 必須 | 説明 |
|---|---|---|---|
context | Context | O | 現在のコンテキスト |
klleonSdkViewInstance | KlleonSdkView? | O | レンダリングビュー |
sdkKey | String | O | SDK認証キー |
avatarId | String | O | AIアバターID |
language | String | O | 言語コード (ko_kr, en_us, ja_jp) |
例:
CoroutineScope(Dispatchers.IO).launch {
workerView?.let { view ->
klleonOndeviceSdk.play(
context = this@Activity,
klleonSdkViewInstance = view,
sdkKey = "YOUR_SDK_KEY",
avatarId = "character_001",
language = "ko_kr"
)
}
}
connect()
WebSocketの再接続を実行します。
klleonOndeviceSdk.connect()
finish()
SDKを停止し、すべてのリソースを整理します。suspend 関数のため、コルーチン内で呼び出す必要があります。
内部バッファは同一アバター再進入時の再利用のために維持されます(ソフトリセット)。
// Activity終了時
CoroutineScope(Dispatchers.Default).launch {
klleonOndeviceSdk.finish()
}
awaitFinish()
進行中の finish() が完了するまで待機します。終了中でなければ即座に返されます。
finish() 後すぐに play() を再呼び出しする場合、ResourceManager.init() の前に呼び出してリソース競合を防止します。
// 高速再進入時
CoroutineScope(Dispatchers.Default).launch {
klleonOndeviceSdk.awaitFinish() // 前回の終了完了を待機
ResourceManager.init(context, ...)
}
メッセージAPI
sendMessage()
SDKのメッセージングシステムを通じてメッセージを送信します。
klleonOndeviceSdk.sendMessage(text: String)
例:
klleonOndeviceSdk.sendMessage("こんにちは")
sendMessageEcho()
入力テキストをそのままTTS + リップシンクで再生します(LLMバイパス)。固定案内メッセージなどに使用します。
klleonOndeviceSdk.sendMessageEcho(text: String)
sendChangeLanguage()
会話中に言語を動的に変更します。
klleonOndeviceSdk.sendChangeLanguage(language: String)
例:
// 英語に変更
klleonOndeviceSdk.sendChangeLanguage("en")
sendStopSpeech()
アバターの現在の発話を即座に中断します。
klleonOndeviceSdk.sendStopSpeech()
Wakeword API
STT認識結果から登録されたwakewordを検出してコールバックを渡します。Wakewordがマッチすると、該当STT結果は通常の会話入力(STT_RESULT)から除外されます。
Wakewordマッチングは基本的に無効状態です。enterStandby() 呼び出し時に自動で有効化され、exitStandby() 呼び出し時に自動で無効化されます。registerWakewords() でwakewordを登録しても、standbyモードに入ってからマッチングが動作します。
play(language) または sendChangeLanguage(language) で設定した言語がSTT認識言語としても適用されます。Wakewordマッチングは該当言語のSTT認識結果で動作するため、各言語のSTTが認識できるwakewordを登録する必要があります。
例:
- 韓国語STT →
"영어","일본어","니혼고"など韓国語発音のwakeword - 日本語STT →
"韓国語","英語","コリアン"など日本語認識のwakeword - 英語STT →
"Korean","Japanese"など英語のwakeword
registerWakewords()
Wakewordを登録します。既存のwakewordを全体置換します。登録だけではマッチングは動作せず、enterStandby() 進入時に有効化されます。
fun registerWakewords(wakewords: Map<String, String>)
パラメータ:
| パラメータ | 型 | 説明 |
|---|---|---|
wakewords | Map<String, String> | wakeword → タグマップ。Wakewordが検出されるとタグ値がコールバックで渡されます |
例:
// 言語切り替え用wakeword登録
klleonOndeviceSdk.registerWakewords(mapOf(
"니혼고" to "ja_jp", "일본어" to "ja_jp",
"잉글리쉬" to "en_us", "영어" to "en_us",
"한국어" to "ko_kr", "코리안" to "ko_kr",
))
clearWakewords()
登録されたwakewordを全初期化します。初期化後はwakewordマッチングが動作せず、すべてのSTT結果が STT_RESULT として渡されます。
klleonOndeviceSdk.clearWakewords()
wakewordDetected
Wakewordマッチング結果を発行する SharedFlow です。
val wakewordDetected: SharedFlow<WakewordResult>
WakewordResult:
| フィールド | 型 | 説明 |
|---|---|---|
wakeword | String | マッチしたwakeword原文(例: "니혼고") |
tag | String | 登録時に指定したタグ(例: "ja_jp") |
fullText | String | STTが認識した全テキスト |
例:
// Wakeword検出時に言語切り替え
LaunchedEffect(Unit) {
klleonOndeviceSdk.wakewordDetected.collect { result ->
// result.wakeword = "니혼고", result.tag = "ja_jp"
klleonOndeviceSdk.sendChangeLanguage(result.tag)
}
}
SDKはwakewordが何を意味するかには関与しません。タグ値はアプリが自由に定義でき、言語コード以外にも "mode_quiet"、"stop" など任意の文字列を使用できます。
待機画面(Standby) API
enterStandby()
待機画面モードに進入します。パイプライン全体を整理(キューのクリア、オーディオバッファの破棄、タイミング初期化)した後、ビデオデコーディングとオーディオ再生を一時停止します。リソースは維持されます。
klleonOndeviceSdk.enterStandby()
exitStandby()
待機画面モードを解除します。ビデオデコーディングとオーディオ再生を再開します。
klleonOndeviceSdk.exitStandby()
isStandby()
待機画面モード状態であるかを確認します。
val isStandby: Boolean = klleonOndeviceSdk.isStandby()
setIdleTimeout(timeoutMs)
idle timeoutを有効化します。アバター発話終了(TTS_END)後、指定時間無活動の場合に自動で enterStandby() を呼び出します。STANDBY_ENTER イベントが sdkState に発行された後、待機画面に進入します。
// デフォルト値60秒
klleonOndeviceSdk.setIdleTimeout()
// カスタムtimeout(30秒)
klleonOndeviceSdk.setIdleTimeout(30_000L)
play() 呼び出しの前後いずれの時点でも呼び出し可能です。呼び出さなければ自動待機画面機能は無効状態です。
disableIdleTimeout()
idle timeoutを無効化します。有効化されたタイマーがあればキャンセルされます。
klleonOndeviceSdk.disableIdleTimeout()
isResponding: StateFlow<Boolean>
アバターが応答準備中または発話中であれば true。PREPARING_RESPONSE 受信時に true、TTS_END または ERROR 受信時に false に遷移します。
// 現在の値を確認
if (klleonOndeviceSdk.isResponding.value) {
// アバター応答中
}
// Flowで購読
klleonOndeviceSdk.isResponding.collect { responding ->
// UI更新
}
音声認識API
startVoiceRecognition()
音声認識を開始します。マイク録音を開始し、WebSocketでSTART_VOICEシグナルを送信します。無音が検出されると自動的に録音を終了し、END_VOICEシグナルを送信します。
fun startVoiceRecognition(
config: SilenceDetectionConfig = SilenceDetectionConfig.default()
): Boolean
パラメータ:
config: 無音検出設定(オプション、デフォルト:SilenceDetectionConfig.default())
戻り値: 成功可否 (Boolean)
例:
// デフォルト設定で音声認識を開始
val success = klleonOndeviceSdk.startVoiceRecognition()
// カスタム設定で開始
val customConfig = SilenceDetectionConfig.default().copy(
silenceTimeoutMs = 2000L // 無音検出時間2秒
)
val success = klleonOndeviceSdk.startVoiceRecognition(customConfig)
stopVoiceRecognition()
音声認識を停止します。
klleonOndeviceSdk.stopVoiceRecognition()
isVoiceRecognizing()
音声認識中であるかを確認します。
val isRecognizing: Boolean = klleonOndeviceSdk.isVoiceRecognizing()
voiceRecognitionMode
音声認識モードを設定します。play() 呼び出し前に設定する必要があります。
klleonOndeviceSdk.voiceRecognitionMode = VoiceRecognitionMode.ALWAYS_ON
モード:
| モード | 説明 |
|---|---|
DISCRETE | 単発モード(デフォルト)。手動で開始/終了 |
ALWAYS_ON | 常時リスニング。play()後に自動開始、セッション維持 |
startAlwaysOnListening()
ALWAYS_ONリスニングを手動で開始します。
val success: Boolean = klleonOndeviceSdk.startAlwaysOnListening()
isAutoListening()
ALWAYS_ON自動リスニング中であるかを確認します。
val isListening: Boolean = klleonOndeviceSdk.isAutoListening()
オーディオ入力ユーティリティ
hasRecordAudioPermission()
RECORD_AUDIO権限があるかを確認します。
val hasPermission: Boolean = klleonOndeviceSdk.hasRecordAudioPermission()
hasUsbMicrophone()
USBマイクが接続されているかを確認します。
val hasUsb: Boolean = klleonOndeviceSdk.hasUsbMicrophone()
状態管理
sdkState
SDK状態の更新をJSON文字列として発行するSharedFlowです。
klleonOndeviceSdk.sdkState: SharedFlow<String>
使用法:
klleonOndeviceSdk.sdkState.collect { state ->
val messageToAdd = try {
val json = JSONObject(state)
json.getString("message")
} catch (t: Throwable) {
state.toString()
}
// 状態更新の処理
updateUI(messageToAdd)
}
状態フォーマット (JSON):
{
"message": "",
"chat_type": "ACTIVATE_VOICE",
"time": "2025-09-03T05:42:08.394975295",
"id": "99dd3ab3-53c4-4418-bee4-b1fbaea272aa"
}
主なchat_type値:
| chat_type | 説明 |
|---|---|
WSS_OPEN | WebSocket接続成功 |
WSS_FAILURE | WebSocket接続失敗 |
WSS_CLOSING | WebSocket接続終了中 |
WSS_CLOSED | WebSocket接続終了済み |
WSS_RETRY_OVER | 最大リトライ超過 |
WSS_NOT_CONNECTED | 未接続状態 |
ACTIVATE_VOICE | 音声入力受信準備完了 |
TEXT | サーバーからのテキスト応答受信 |
RESPONSE_IS_ENDED | サーバー応答ストリーム終了 |
TTS_START | TTS音声再生開始 |
TTS_END | TTS音声再生完了(発話終了検出に使用) |
SHOW_AVATAR | アバター表示準備完了 |
USER_SPEECH_STARTED | ユーザー発話開始検出 |
USER_SPEECH_STOPPED | ユーザー発話終了検出 |
PREPARING_RESPONSE | サーバー応答準備中 |
STT_RESULT | 音声認識最終結果 |
STT_PARTIAL | 音声認識中間結果 |
STT_ERROR | 音声認識エラー |
STT_STATUS | 音声認識状態変化通知(準備中/再接続中/準備完了) |
WORKER_DISCONNECTED | ソケット接続終了 |
SPEECH_START | アバター発話開始 |
SPEECH_END | アバター発話終了 |
STOP_RESPONSE_MESSAGE | 現在のアバター発話中断 |
STT_STATUS詳細
音声認識セッションの一時的な状態変化を通知します。トークンベース認証を使用するSTTプロバイダー(Azureなど)で発生します。
| 状態 | message値 | 意味 | 発生タイミング |
|---|---|---|---|
Preparing | 音声認識準備中 | トークン待機中のため認識開始が遅延 | トークン未受信状態で音声認識開始時 |
Recovering | 音声認識再接続中 | 認証失敗によりトークン再発行待機中 | 認識中に認証トークン期限切れ時 |
Ready | 音声認識準備完了 | 復旧完了、音声認識再開 | トークン再発行後に認識再開時 |
STT_STATUS は一時的な状態通知です。音声認識準備中 または 音声認識再接続中 受信時にユーザーにトーストなどで案内し、音声認識準備完了 受信時に自然に解除してください。
recorderState
レコーダー状態をリアルタイムで購読できるStateFlowです。
klleonOndeviceSdk.recorderState: StateFlow<OboeRecorderState>
状態値:
| 状態 | 説明 |
|---|---|
Idle | 初期状態 |
Starting | 開始中 |
Recording(deviceId, deviceName, deviceType) | 録音中 |
Stopping | 停止中 |
Error(message) | エラー状態 |
SilenceDetectionConfig
音声認識時の無音検出動作を設定します。
import io.klleon.ondevice.audio.oboe.SilenceDetectionConfig
フィールド:
| フィールド | 型 | デフォルト値 | 説明 |
|---|---|---|---|
silenceThreshold | Float | 0.02 | 無音判定レベル閾値 |
speechThreshold | Float | 0.05 | 音声判定レベル閾値 |
speechTimeoutMs | Long | 5000 | 音声入力待機時間 (ms) |
silenceTimeoutMs | Long | 2000 | 音声後の無音検出時間 (ms) |
maxRecordingTimeMs | Long | 60000 | 最大録音時間 (ms, 0=無制限) |
preBufferMs | Int | 300 | 音声開始前のオーディオ保存 (ms) |
preBufferDelayMs | Long | 300 | プリバッファフラッシュ遅延 (ms) |
プリセット:
| プリセット | 特徴 |
|---|---|
SilenceDetectionConfig.default() | デフォルト設定 |
SilenceDetectionConfig.fast() | 高速応答 (speechTimeout 3秒, silenceTimeout 1.5秒) |
SilenceDetectionConfig.longSpeech() | 長い発話 (speechTimeout 7秒, silenceTimeout 3秒, maxRecording 120秒) |
SilenceDetectionConfig.noisyEnvironment() | 騒音環境 (閾値上方修正: silence 0.05, speech 0.10) |
例:
// プリセット使用
klleonOndeviceSdk.startVoiceRecognition(SilenceDetectionConfig.fast())
// カスタム設定
val config = SilenceDetectionConfig.default().copy(
speechTimeoutMs = 3000L,
maxRecordingTimeMs = 120_000L
)
klleonOndeviceSdk.startVoiceRecognition(config)
プロパティ
klleonSdkView
現在のレンダリングビュー参照です。
var klleonSdkView: KlleonSdkView?
Companion Object
| プロパティ | 型 | 説明 |
|---|---|---|
VERSION | String | SDKバージョン |
playing | Boolean | SDK再生状態 |
sendVoice | Boolean | 音声送信状態 |
インスタンスプロパティ
| プロパティ | 型 | 説明 |
|---|---|---|
isStopping | Boolean | SDKが現在終了中であるか(finish() 進行中であれば true) |
エラー処理
すべてのSDKメソッドはtry-catchブロックで囲む必要があります:
try {
klleonOndeviceSdk.sendMessage(message)
} catch (e: Exception) {
Log.e("KlleonSDK", "操作失敗", e)
// 適切にエラー処理
}
ライフサイクル管理
play() と finish() は suspend 関数です。Activityライフサイクルではコルーチンでラップして呼び出します。
class ChatActivity : ComponentActivity() {
private val sdk = SdkConfig.sdk
override fun onDestroy() {
super.onDestroy()
// finish()はsuspendのためコルーチンで実行
CoroutineScope(Dispatchers.Default).launch {
sdk.finish() // SDK停止(バッファは再利用のために維持)
}
ResourceManager.deinit() // アプリ完全終了時にのみ呼び出し
}
}
高速再進入 (finish → play)
finish() 後すぐに play() を呼び出すと、リソース競合が発生する可能性があります。
awaitFinish() を使用して、前回の終了が完了した後に進めてください:
// キャラクター選択画面で新しいアバター開始時
CoroutineScope(Dispatchers.Default).launch {
sdk.awaitFinish() // 前回のfinish()が進行中であれば完了を待機
ResourceManager.init(context, mp4, npz, style, avatarId,
onSuccess = { /* ChatActivity開始 → play() */ },
onError = { /* エラー処理 */ }
)
}