メインコンテンツまでスキップ

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
)

パラメータ:

パラメータ必須説明
contextContextO現在のコンテキスト
mp4FileNameStringOアバターMP4ファイル名(assets内)
npzFileNameStringOアバターNPZファイル名(assets内)
styleFileNameStringXスタイルファイル名(デフォルト: "")
avatarIdStringXアバターID。同一アバター再進入時にバッファを再利用して即座に onSuccess を返します
onSuccess() -> UnitOリソース準備完了コールバック
onError(Throwable) -> UnitOエラーコールバック

例:

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となります。

呼び出し規則

  1. init() — アバター選択完了時に呼び出し。アバター変更時に以前のバッファを自動解放します。
  2. play()init()onSuccess コールバックが来た時のみ呼び出し可能
  3. deinit() — アプリ完全終了時に呼び出し。finish() はバッファを維持して同一アバター再進入を最適化します。

SDKメソッド

play()

AIアバタービデオ再生を開始します。suspend 関数のため、コルーチン内で呼び出す必要があります。

suspend fun play(
context: Context,
klleonSdkViewInstance: KlleonSdkView?,
sdkKey: String,
avatarId: String,
language: String
)

パラメータ:

パラメータ必須説明
contextContextO現在のコンテキスト
klleonSdkViewInstanceKlleonSdkView?Oレンダリングビュー
sdkKeyStringOSDK認証キー
avatarIdStringOAIアバターID
languageStringO言語コード (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)から除外されます。

Standby連動ポリシー

Wakewordマッチングは基本的に無効状態です。enterStandby() 呼び出し時に自動で有効化され、exitStandby() 呼び出し時に自動で無効化されます。registerWakewords() でwakewordを登録しても、standbyモードに入ってからマッチングが動作します。

STT言語とwakeword

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>)

パラメータ:

パラメータ説明
wakewordsMap<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:

フィールド説明
wakewordStringマッチしたwakeword原文(例: "니혼고"
tagString登録時に指定したタグ(例: "ja_jp"
fullTextStringSTTが認識した全テキスト

例:

// 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>

アバターが応答準備中または発話中であれば truePREPARING_RESPONSE 受信時に trueTTS_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_OPENWebSocket接続成功
WSS_FAILUREWebSocket接続失敗
WSS_CLOSINGWebSocket接続終了中
WSS_CLOSEDWebSocket接続終了済み
WSS_RETRY_OVER最大リトライ超過
WSS_NOT_CONNECTED未接続状態
ACTIVATE_VOICE音声入力受信準備完了
TEXTサーバーからのテキスト応答受信
RESPONSE_IS_ENDEDサーバー応答ストリーム終了
TTS_STARTTTS音声再生開始
TTS_ENDTTS音声再生完了(発話終了検出に使用)
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

フィールド:

フィールドデフォルト値説明
silenceThresholdFloat0.02無音判定レベル閾値
speechThresholdFloat0.05音声判定レベル閾値
speechTimeoutMsLong5000音声入力待機時間 (ms)
silenceTimeoutMsLong2000音声後の無音検出時間 (ms)
maxRecordingTimeMsLong60000最大録音時間 (ms, 0=無制限)
preBufferMsInt300音声開始前のオーディオ保存 (ms)
preBufferDelayMsLong300プリバッファフラッシュ遅延 (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

プロパティ説明
VERSIONStringSDKバージョン
playingBooleanSDK再生状態
sendVoiceBoolean音声送信状態

インスタンスプロパティ

プロパティ説明
isStoppingBooleanSDKが現在終了中であるか(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 = { /* エラー処理 */ }
)
}