すべてのプロダクト
Search
ドキュメントセンター

Alibaba Cloud Model Studio:HappyOyster Android SDK API リファレンス

最終更新日:Sep 23, 2026

HappyOyster Android SDK のエントリーポイントはシングルトンオブジェクト HappyOyster です。initialize、updateToken、attachVideo、sendCommand を除き、すべてのビジネスメソッドはサスペンド関数であり、失敗時に SDKError をスローします。アドベンチャー/演出/演技の3つのモード、必要なモデル設定、および aspectRatio に対応しています。

呼び出し元のコルーチンがキャンセルされた場合、SDKはその呼び出しに関連する進行中のHTTPリクエスト(存在する場合)をキャンセルし、それをSDKErrorに変換することなくCancellationExceptionとしてそのまま伝播させます。キャンセル操作を行っても、サーバーがすでに受け入れたリクエストがロールバックされることはありません。

統合フロー、インストール、ベストプラクティスについては、Happy Oyster Android SDK 統合ガイドを参照してください。

主要用語

用語

意味

token

Bailian ゲートウェイ API Key:アプリによって updateToken(token) を介して Bearer トークンとして注入されます。SDK は最新のキーのみを保持し、永続化や更新は行いません。Key が変更された場合は、再度注入してください。ゲートウェイは、startTravel を含むすべての SDK リクエストに対してこの Bearer の使用を要求します。Bearer Key が期限切れまたは無効な場合、SDK は SDKError(101002) をスローします。その場合は、新しいチケットと交換するのではなく、Bearer Key を再取得して注入(updateToken)してください。セキュリティに関する推奨事項:クライアント側の Bearer には、長期間有効な API Key をアプリにバンドルしたりコードリポジトリにコミットしたりするのではなく、サーバーで発行された 短命トークン を使用してください。

ticket

ワンタイム体験用認証情報:オープンプラットフォーム経由でサーバーによって交換され、クライアントに渡されます。単一のstartTravelにのみ使用されます。体験が終了すると(正常または異常にかかわらず)無効になり、再利用することはできません。チケットレベルの認証エラーは、6桁のサーバーコード(例:401010 = チケット無効/期限切れ、401011 = チケット使用済み)によって識別され、SDKはこれをそのまま通過させます。

環境要件

項目

要件

minSdk

24 (Android 7.0) 以上

compileSdk

36

言語

Kotlin(コルーチン suspend API)

ABI

arm64-v8a / armeabi-v7a(リアルタイム通信エンジンにはネイティブライブラリが含まれます)

ネットワーク

パブリックインターネットアクセスが必要

主要概念

概念

説明

World

キャラクターやシーンを含む AI ワールドです。サーバーによって作成・管理されます。

Travel

単一のリアルタイム体験です。基本的なライフサイクルは init → pending → running → completed です(失敗時は failed)。演出モードおよび演技モードにおいて、体験が一時停止をサポートしている場合、running は pauseTravel を通じて paused に入り、その後 resumeTravel を通じて running に戻ることができます(演出モードでは追加で rewindTravel も使用可能で、その後サーバーが体験を自動的に再開します)。running ⇄ paused は複数回ループ可能です。

モード

adventure(デバイス/コマンドによるインタラクション)、directing(テキスト駆動のナラティブ)、またはacting(Acting:ワールド作成時にサーバーによって再生アスペクト比が固定されるテキスト駆動のナラティブ)です。SDKはこれら3つの値を統一的に公開します。

リアルタイムビデオ

startTravel が成功した後、SDKによって 自動的に 確立・維持されます。手動での接続や切断は不要です。endTravel 時に自動的に解放されます。

概要

HappyOyster メソッド

メソッド

説明

initialize(context, config)

SDK を初期化します。アイドル状態での再初期化はサポートされています。Travel が開始中、アクティブ、または終了中の再初期化は 103004 で拒否されます。

updateToken(token)

Bailian ゲートウェイ API キー(Bearer トークン)を注入または更新します。

startTravel(ticket)

ワンタイムクレデンシャルを使用して体験を開始し、リアルタイム動画接続を自動的に確立します。

pauseTravel()

体験を非同期に一時停止します(ディレクティングおよびアクティング、かつ体験が一時停止をサポートする場合のみ)。受理後、実際の一時停止は onStatusChanged(Paused) によって決定されます。

resumeTravel()

一時停止中の体験を再開します(ディレクティングおよびアクティング)。内部的に 3 回のリトライバックオフを含みます。

rewindTravel(rewindToSec)

指定された秒数まで巻き戻します(ディレクティングのみ、状態は paused)。秒数の値は 4 の倍数である必要があります。アクティングは巻き戻しをサポートしません。

sendInstruct(content)

ナラティブを進行させるためのテキスト指示を送信します(ディレクティングおよびアクティング、running または paused)。

sendCommand(command)

方向/視点/アクション制御コマンドを送信します(アドベンチャーモード、running のみ、メインスレッド)。アクティングでは使用できません。

attachVideo()

再生用の SurfaceView を返します。これをレイアウトに追加してレンダリングしてください(メインスレッド)。

endTravel()

体験を終了し、リアルタイム接続を自動的に切断してすべてのセッションリソースを解放します。

VERSION

SDK バージョン文字列(SemVer)、コンパイル時定数です。

イベント

イベント

説明

onStatusChanged(status)

体験ステータスの変更(リアルタイム動画のライフサイクルを含む)。値は TravelStatusValue で定義されています。

onError(error)

内部自動フローが失敗した際のコールバックです。致命的なエラーの場合は現在の体験も終了します。

主要データ型

タイプ

説明

SDKConfig

SDK 初期化設定です(apiHost と model は必須で、さらに logLevel、logcatEnabled、logHandler、および callbackTimeoutMs があります)。

TravelStatusValue

体験ステータス:Init / Pending / Running / Paused / Failed / Completed。

ModeValue

体験モード:adventure / directing / acting。

CreationModelValue

ワールド作成モデル:Simple(デフォルト、指示駆動)/ ScriptList(構造化スクリプト、sendInstruct はサポートされません)。

StartTravelData

startTravel によって返されます。mode、version、creationModel、aspectRatio、maxExperienceTimeSec などのメタデータを含みます。

AdventureCommand

sendCommand のパラメータです。translation / rotation / interaction の3つのフィールドを含みます。

SDKError

SDK エラー。code: Int とオプションの raw: Any? を含みます。

HappyOyster.initialize

SDKを初期化します。他のどのAPIよりも前に呼び出してください(できればApplication.onCreate内で行います)。configは必須であり、アカウントのBailian apiHostと、happyoyster-1.0-directing / happyoyster-1.0-acting / happyoyster-1.0-adventureのいずれかのmodel(Open APIのエントリーポイントと一致するもの)を含める必要があります。SDKは以下のようにリクエストURLを構築します。

https://{apiHost}/api/v2/apps/{model}/openapi/v1/{endpoint}

modelにはデフォルト値がありません。SDKConfigの構築時にこれを省略するとコンパイルエラーになります。空の値を渡すと、initializeが同期的にSDKError(100002)をスローします。ランタイムの作成や置換は行われず、ネットワークリクエストも送信されません。SDKはActivityではなくアプリケーションコンテキストのみを保持します。再初期化は、前のランタイムがアイドル状態の場合にのみサポートされます。モデルを切り替えるには、アイドル中に新しいmodelで再初期化してください。Travelが開始中、アクティブ、または終了中の場合は、まずendTravel()を待機してください。

注記

地域のコンプライアンスに関するお知らせ:
  • 適用される法令およびデータ要件への準拠をサポートするため、対象ユーザーに米国ユーザーが含まれる場合、それらのユーザーに提供されるサービスについては、SDK 初期化時に米国リージョンの API Host を設定する必要があります。
  • 開発者は正しい設定を行う責任があり、この要件に従わなかった場合は適用される法律に基づき相応の責任を負います。

シグネチャ

fun initialize(context: Context, config: SDKConfig)

パラメータ

フィールド

タイプ

必須

説明

context

Context

はい

applicationContext を渡すことを推奨します。

config

SDKConfig

はい

SDK 設定。必須かつデフォルト値のない apiHost および model を含む必要があります。

を返します

戻り値はありません。

エラー

code

説明

100002

model が空白です。SDKError.raw が SDKConfig.model must not be blank に設定された状態で同期的に初期化が失敗します。ランタイムは作成も置換もされず、ネットワークリクエストも行われません。

103004

Travel が開始中、アクティブ、または終了中のため再初期化が拒否されました。endTravel() の完了を待ってから再試行してください。

HappyOyster.updateToken

BailianゲートウェイAPI Keyを注入または更新します。スレッドセーフであり、initializeの後に呼び出し可能です。SDKはstartTravelおよびその後の体験制御リクエストに最新のトークンを使用します。ticketはワンタイムの体験用認証情報であり、Bearerトークンと混同しないでください。

シグネチャ

fun updateToken(token: String)

パラメータ

フィールド

タイプ

必須

説明

token

String

はい

Bailian ゲートウェイ API キー、Bearer トークンとして使用されます。

を返します

戻り値はありません。

エラー

code

説明

100001

SDK が初期化されていません。

HappyOyster.startTravel

1回限りの ticket を使用して体験を開始します。成功すると、SDK は 自動的にリアルタイムビデオ接続を確立し、内部ステータスポーリングを開始 し、ステータスは onStatusChanged を通じて通知されます。

  • ticket はワンタイムクレデンシャルであり、呼び出しが行われた時点で消費済みとみなされます。
  • アプリごとに同時に実行できるTravelは、いかなる時点でも1つだけです。体験の進行中に再度呼び出すとSDKError(103004)がスローされ、SDKError.rawには診断用に現在アクティブなチケットの要約のみが含まれ、完全なチケット情報は含まれません。
  • オプションで maxExperienceTimeSec を渡して、この体験の最大時間を制限できます(ワールド探索/アドベンチャーモードのみ)。パラメータを参照してください。

StartTravelData.creationModel(CreationModelValue、デフォルトはCreationModelValue.Simple):ワールドの作成モデル、つまりスクリプトコンテンツの管理方法を示します。simple(デフォルト)は通常のinstruct駆動型ワールドです。ワールド探索型のワールドもこの値に正規化されます。scriptlistは構造化されたScriptListワールドであり、そのスクリプトコンテンツはこのSDKを通じてアクセスされません。ScriptListモード(creationModel == CreationModelValue.ScriptList)でsendInstructを呼び出すと拒否され、SDKError(103002)がスローされます。このフィールドのデフォルト値はsimpleです。

StartTravelData.aspectRatio(String?):サーバーがこのセッションに割り当てた再生アスペクト比をwidth:height文字列として示します。nullでないのはActingのみであり、"9:16"(縦向き、作成時のサーバー側のデフォルト)または"16:9"(横向き)となります。ワールド探索およびdirectingモードではnullとなり、サーバーが値を報告しない場合もnullとなります。SDKは未知の値をそのまま保持し(nullに統合することはありません)、ホスト側は認識できない値をnullと同様に扱い、独自のデフォルトの向きにフォールバックする必要があります。SDK自体はこのフィールドを使用しません。

この値は startTravel() の戻り値とともに提供されます。startTravel() が返った後、かつ **** attachVideo() を呼び出して返されたビューをレイアウトに追加する前に、この値に基づいて再生コンテナのサイズを設定してください。SDK はホストがビューをアタッチして初めてリモートストリームのレンダリング用バインドを開始するため、その時点で向きを決定しても最初のレンダリングフレームより前に行われます(ただし、SDK がリアルタイムルームに参加する前に完了することは 保証されません)。リモートビューは clip-to-fill レンダーモードでバインドされるため、この値と向きの異なるコンテナを使用すると、レターボックスになる代わりに 画像がトリミングされます。

シグネチャ

suspend fun startTravel(ticket: String): StartTravelData
suspend fun startTravel(ticket: String, maxExperienceTimeSec: Int?): StartTravelData

パラメータ

フィールド

タイプ

必須

説明

ticket

String

はい

サーバーから発行されるワンタイム体験クレデンシャルです。

maxExperienceTimeSec

Int?

いいえ

このエクスペリエンスの最大持続時間(秒単位)。この時間に達すると、ワールドはセッションを自動的に終了します。ワールド探索(アドベンチャー)モードにのみ適用されます。演出(リアルタイム演出)モードおよび演技モードでは無視されます。許可される値はサーバー側で設定されており、現在は 60 / 90 / 120 です。null を渡す(またはこのパラメーターのないオーバーロードを使用する)と、サーバーのデフォルト値(現在は 60)が適用されます。サポートされていない値を渡すと、サーバーによって拒否 startTravel され、400000 が返されて SDKError(400000) がスローされ、アクティブな Travel は作成されません。SDK は値をローカルで検証しません。許可される値のセットはサーバー側が権威を持ちます。

を返します

StartTravelDataを返します。これには体験のメタデータ(mode、version、creationModel、aspectRatioなど)が含まれます。インタラクション方法(例:travel.mode、travel.creationModel、travel.version)を決定する前に、返されたメタデータを確認してください。Actingの場合は、travel.aspectRatioに基づいて再生コンテナのサイズも設定してください。

エラー

code

説明

401010

ticket が無効または期限切れです

401011

ticket はすでに使用されています

400000

無効なパラメータ(例:maxExperienceTimeSec がサーバー許可セット内にない)。この startTravel は開始に失敗します

403002

World が準備完了状態ではありません

500001

リソース割り当て/内部サービス障害

103004

Travel がすでに開始中、アクティブ、または終了中であるか、あるいは startTravel が並行して呼び出されました(一度に許可される Travel は1つだけです。SDKError.raw にはアクティブなチケットの要約のみが含まれます)。

HappyOyster.pauseTravel / HappyOyster.resumeTravel

体験を一時停止または再開します。SDK は一度に1つの Travel のみを管理します。encryptedTravelId は SDK 内部で取得されるため、呼び出し元が渡す必要はありません。

前提条件:

  • pauseTravel:ディレクティングまたはアクティング かつ状態が running の場合のみ呼び出し可能です。
  • resumeTravel:ディレクティングまたはアクティング かつ状態が paused の場合のみ呼び出し可能です。

すべての体験が一時停止/再開をサポートしているわけではありません。体験は、そのモードが必要とするバージョン識別子(StartTravelData.version—directingの場合はstoryV2、Actingの場合はactingV2。周囲の空白文字や大文字小文字を無視して比較されます)を報告する必要があります。そうでない場合、pauseTravelとresumeTravelの両方が103002を返します。Actingは一時停止/再開をサポートしますが、rewindTravelはサポートしていません。

一時停止は非同期です(重要):pauseTravel は「重い」操作であり、呼び出しの成功(メソッドの復帰)は 一時停止が受理された ことのみを意味し、その時点ではエクスペリエンスは 実際にはまだ一時停止されていません。一時停止が実際に有効になるのは、onStatusChanged コールバックが paused を報告したときだけです。 したがって、ホストの状態遷移や呼び出しの制御はそのコールバックから行ってください。「pauseTravel の呼び出し」と「paused コールバックの受信」の間は、ローカル状態を pausing としてマークできます。paused を受信した後でのみ、resumeTravel または rewindTravel の開始を許可してください。pauseTravel の戻り値をすでに一時停止済みとして扱わないでください。

リアルタイム接続の処理:実際に一時停止した後、SDKはリアルタイム接続を切断します。再開時、SDKは自動的に再接続し、同じstartTravel時に渡された認証情報を使用して映像を復元します。ホスト側の介入は不要です。

順序付けられた一時停止解体バリア:Pausedが発行された後でも、サーバー側のリアルタイムルームの解体にはわずかな遅延が生じる可能性があります。SDKは一時停止の確認から3秒の確定ウィンドウを設定します。このウィンドウ内でresumeTravelまたはrewindTravelが呼び出された場合、サスペンド中の呼び出しはまず残りの時間をノンブロッキングで待機し、その後ルーム再オープンのAPIリクエストを送信します。すでに3秒が自然に経過している場合は、遅延は追加されません。これにより、遅れた一時停止解体によって新しくオープンされたルームが閉じられ、105001が表面化することを防ぎます。

resume API retry:resumeTravel は、一時停止後の一時的なサービス利用不可に対処するため、失敗時に最大 3 回内部でリトライします(バックオフ 1 s / 2 s / 3 s)。3 回の試行すべてが失敗した場合にのみ、エラーが上位に伝播されます。

注記⚠️ 注意:頻繁な切り替えを避けるため、resumeTravelが正常にリターンした後、最大3秒待機してからpauseTravelを再度開始することを推奨します。これはホスト側の呼び出しクールダウンに関する推奨事項であり、SDK自体によって強制されるものではありません。詳細については、Happy Oyster Android SDK統合ガイドを参照してください。

シグネチャ

suspend fun pauseTravel(): TravelStateData
suspend fun resumeTravel(): TravelStateData

パラメータ

パラメータはありません。

を返します

TravelStateData(encryptedTravelId、status を含む)を返します。

エラー

code

説明

103001

アクティブな体験がありません

103002

状態が許可されていないか、この体験は一時停止/再開をサポートしていません

103003

アドベンチャーモードで呼び出されました。一時停止/再開をサポートするのはディレクティングとアクティングのみです

HappyOyster.rewindTravel

指定された秒数まで巻き戻します。encryptedTravelId は SDK 内部で取得されます。

前提条件:directingモードかつ状態がpausedの場合にのみ呼び出し可能です(running状態では巻き戻しは許可されていません)。すべてのdirecting体験が巻き戻しをサポートしているわけではなく、サポートされていない場合は103002が返されます。巻き戻しが成功した後、体験は自動的に再開され、SDKも自動的にRTCに再接続するため、ホスト側の介入は不要です。

Actingには巻き戻し機能が一切ありません:Actingでこれを呼び出すと、SDKによってローカルで拒否され、103003が返されます。リクエストは発行されません。Actingでは、ホスト側でボタンを単に無効化するのではなく、巻き戻しのエントリーポイントを非表示にするべきです。

シグネチャ

suspend fun rewindTravel(rewindToSec: Double): RewindTravelData

パラメータ

フィールド

タイプ

必須

説明

rewindToSec

Double

はい

巻き戻す目標秒数です。4 の倍数 である必要があります(例:4、8、12)。4 の倍数でない値は、サーバーによって最も近い小さい 4 の倍数に切り捨てられます(例:7 を渡すと 4 になります)。

を返します

RewindTravelData(encryptedTravelId、status、resumedAtSec を含む)を返します。ここで resumedAtSec はサーバーが実際に巻き戻した秒数です(すでに 4 の倍数に切り捨てられています)。

エラー

code

説明

103001

アクティブな体験がありません

103002

状態が paused ではないか、この体験は巻き戻しをサポートしていません

103003

アドベンチャーまたはアクティングモードで呼び出されました。巻き戻しをサポートするのはディレクティングモードのみです

HappyOyster.sendInstruct

ナラティブを推進するためのテキスト指示を送信します。directing or Acting であり、体験ステータスが running または paused の場合に有効です。encryptedTravelId は SDK 内部で取得されます。

一時停止状態での動作:SDKは一時停止中に自動的には再開しません。instructは直接送信されます。instructを送信する前にresumeTravelを先に呼び出すかどうかは、ホスト側の判断に委ねられます。

シグネチャ

suspend fun sendInstruct(content: String): SendInstructData

パラメータ

フィールド

タイプ

必須

説明

content

String

はい

送信するテキスト指示の内容。

を返します

SendInstructData(encryptedTravelId、content、accepted を含む)を返します。

エラー

code

説明

103001

アクティブな体験がありません(startTravel が一度も呼び出されていないか、すでに終了しています)

103003

現在のモードはディレクティングでもアクティングでもありません(アドベンチャーモードで呼び出されました)

103002

体験の状態がrunningでもpausedでもない場合(例:まだinit/pendingフェーズにある)、または現在のワールドがScriptListモード(StartTravelData.creationModel == CreationModelValue.ScriptList)である場合。ScriptListモードではinstructの送信は許可されていません。このモードではスクリプトはBailianプラットフォームAPIによって管理されます。

403004

コンテンツモデレーションによるブロック

404000

Travel が存在しません

HappyOyster.sendCommand

方向/視点/アクション制御コマンドを送信します。アドベンチャーモード かつ running の場合のみ有効です。

  • メインスレッドで呼び出してください。メインスレッド外での呼び出しは同期的に IllegalStateException をスローします。
  • アクティブな体験がない場合は 103001 が報告されます。
  • アドベンチャーモード外(ディレクティング/アクティング)で呼び出すと 103003 が報告されます。
  • 許可されていない状態の場合は 103002 が報告されます。
  • アップリンクはサイレントオーディオストリームを介して確立されます(SDKは実際の音声を録音またはアップロードしません)。DataChannelにとってRECORD_AUDIOは厳密な前提条件ではありませんが、クロスデバイスの互換性のためにこれを宣言して許可することが推奨されます(Happy Oyster Android SDK統合ガイド § インストール・権限 を参照)。105004は、リアルタイムチャネルの準備ができていない、または送信に失敗したことを意味します(例:DataChannel接続の中断やリアルタイムチャネルの異常)。これは権限の欠如によって直接引き起こされるものではありません。

組み込みの 42 ms スロットリング(24 fps、最新優先):sendCommand は内部で DataChannel への書き込みを 42 ms 間隔(約 24 fps)でスロットリングします。状態検証は 同期的かつ即座に 実行され、不正な呼び出しの場合は直ちに例外をスローしますが、実際の DataChannel 書き込みは非同期にスロットリングされます。前回の送信から少なくとも 42 ms が経過している場合、コマンドは即座にディスパッチされます(初回呼び出しを含む)。それ以外の場合、保留中のコマンドは最新の値に置き換えられ、現在の 42 ms ウィンドウの終了時に一度だけディスパッチされます。したがって、1つのウィンドウ内での複数回の呼び出しは、最後の値を含む1回のネットワーク書き込みとなります。ホストは独自のレートリミッターを実装することなく、ゲームのフレームレートで sendCommand を呼び出すことができます。

スロットリング中の送信失敗:スロットリングされたフラッシュ処理は非同期であるため、送信失敗を呼び出し元にスローすることはできません。エラーはonErrorコールバックを通じて通知されます(非致命的、105004)。保留中のコマンドはセッション終了時に破棄されます(セッション終了後に送信されることはありません)。

AdventureCommand のフィールドと値:

フィールド

セマンティクス

値

translation

移動:前/左/後/右/斜め/待機

W / A / S / D / W_A / W_D / S_A / S_D / None

rotation

視点:上/下/左/右/斜め/none

Mouse_Up / Mouse_Down / Mouse_Left / Mouse_Right / Mouse_Up_Left / Mouse_Up_Right / Mouse_Down_Left / Mouse_Down_Right / None

interaction

インタラクション:ジャンプ/攻撃/しゃがむ/ダッシュ/none

Jump / Attack / Squat / Sprint / None

これら3つのフィールドは、互いに排他的な独立したコマンドグループです。斜め移動や視線移動には単一の組み合わせ値を使用します(例えば、前+左は同じフィールド内でWとAを同時に指定するのではなく、W_Aとなります)。各呼び出しでは、現在の完全な状態を渡す必要があります。

ベストプラクティス:単発アクションと継続アクション

42 ms の間隔をメンタルモデルとして使用してください。

  • One-shot action(例:ジャンプ/攻撃のタップ、または1歩歩く):call once。SDK は最も近い間隔でそれを送信します。繰り返しの呼び出しや後続の None コマンドは不要です。

    // Jump once
    HappyOyster.sendCommand(AdventureCommand("None", "None", "Jump"))
    
  • 長押しアクション(例:移動や回転の継続):長押し中は毎フレーム呼び出してください。SDKは約42ミリ秒ごとに1つのコマンドを発行します。リリース時には、状態をリセットするためにNoneを含むコマンドを明示的に1回送信してください。SDKが自動的にリセットコマンドを生成することはありません。

    // While held: call from the host's frame loop
    HappyOyster.sendCommand(AdventureCommand("W", "None", "None"))
    // On release: explicitly reset once
    HappyOyster.sendCommand(AdventureCommand("None", "None", "None"))
    

シグネチャ

fun sendCommand(command: AdventureCommand)

パラメータ

フィールド

タイプ

必須

説明

command

AdventureCommand

はい

translation、rotation、interaction の3つのフィールドを含むコマンドオブジェクトです。

を返します

戻り値なし(同期)。状態検証は同期的かつ即座に実行されます。DataChannel への書き込みは非同期にスロットリングされます。

エラー

code

説明

103001

アクティブな体験がありません

103002

許可されていない状態

103003

アドベンチャーモード外(ディレクティング/アクティング)で呼び出されました

105004(onError 経由)

スロットリングによるフラッシュ送信失敗(非致命的、非同期コールバック)

HappyOyster.attachVideo

再生用の SurfaceView を返します。これをレイアウトに追加してください。SDK は内部でリモートストリームとのレンダリングバインディングを完了します。

  • メインスレッドで呼び出してください。メインスレッド外での呼び出しは同期的に IllegalStateException をスローします。
  • SDK は返された View への弱参照のみを保持し、体験終了時にレンダリングバインディングを解放します。View をレイアウトから削除するのは開発者の責任です。
  • Acting体験の場合、返されたビューをレイアウトに追加する前に、StartTravelData.aspectRatioに基づいて再生コンテナのサイズを設定してください。レンダリングはclip-to-fillモードにバインドされているため、向きが一致しないと画像がトリミングされます(startTravelを参照)。

シグネチャ

fun attachVideo(): SurfaceView

パラメータ

パラメータはありません。

を返します

SurfaceView を返します。これをレイアウトに追加してリアルタイム動画を再生してください。

エラー

code

説明

100001

SDK が初期化されていません

HappyOyster.endTravel

体験を終了します。encryptedTravelIdはSDK内部で取得されます。呼び出しが成功した後(または異常終了後)、SDKは自動的にリアルタイム接続を切断し、内部ポーリングを停止し、すべてのセッションリソースを解放します。同時に、現在のticketも無効化されます。

シグネチャ

suspend fun endTravel(): EndTravelData

パラメータ

パラメータはありません。

を返します

EndTravelData(encryptedTravelId、status、endedAt、durationSec を含む)を返します。

エラー

code

説明

100001

SDK が初期化されていません

103001

アクティブな体験がありません

HappyOyster.VERSION

SDK バージョン文字列(SemVer)を返します(例:"x.y.z")。この値は VERSION_NAME Gradle プロパティによって注入されるコンパイル時定数であり、initialize を先に呼び出さなくても安全に読み取ることができます。

シグネチャ

val VERSION: String

を返します

SDK バージョン文字列(例:"x.y.z")。

Log.d("MyApp", "SDK version: ${HappyOyster.VERSION}")

イベントリスニング

interface HappyOysterListener {
    fun onStatusChanged(status: TravelStatusValue) {}
    fun onError(error: SDKError) {}
}

fun addListener(listener: HappyOysterListener)
fun removeListener(listener: HappyOysterListener)

SDK イベントは、あなたへの proactive push channel であり、あなた自身の明示的な呼び出しによってトリガーされない状況(例:SDK が自動的に維持するリアルタイム接続やステータスポーリングの問題)を報告するために使用されます。

イベント

説明

onStatusChanged

体験ステータスの変更(リアルタイム動画のライフサイクルを含む)。値は TravelStatusValue で定義されています。

onError

内部自動フローが失敗した際のコールバックです。致命的なエラーの場合は現在の体験も終了します(エラーコードセクションを参照)。

注記⚠️ 注意:addListener / removeListenerはinitializeの後に呼び出す必要があります。初期化前にこれらを呼び出すとSDKError(100001)がスローされます。リスナーの登録は、HappyOyster.initialize(...)が正常にリターンした直後に行うことを推奨します。

データモデル

// Configuration
data class SDKConfig(
    // Required: your account's Bailian API Host (e.g., llm-xxxx.ap-southeast-1.maas.aliyuncs.com), copied from the API Key page in the Bailian console;
    // must belong to the same account/region as the injected API Key, otherwise the gateway returns AccessDenied.
    val apiHost: String,
    // Required with no default: the complete HappyOyster model name and version (e.g., happyoyster-1.0);
    // refer to the official Bailian HappyOyster model documentation for available values.
    val model: String,
    // Minimum level for the built-in Logcat sink (does not affect logHandler); defaults to INFO, which
    // includes the lifecycle anchors (initialize, Travel start/status/end, RTC connect/first-frame) needed
    // to reconstruct a session timeline. Drop to WARN for errors-only, or raise to DEBUG/VERBOSE to diagnose.
    val logLevel: LogLevel = LogLevel.INFO,
    // Timeout for RTC join (timeout triggers 105002), first-frame wait (timeout triggers 105003), and SDK gateway HTTP signaling calls (timeout triggers 105005);
    // the two RTC phases are serial, so the worst-case wait is 2×callbackTimeoutMs (60s).
    val callbackTimeoutMs: Long = SDKConfig.DEFAULT_CALLBACK_TIMEOUT_MS, // 30_000ms
    // Whether the SDK writes its own logs to Android Logcat (tag HappyOysterSDK); defaults to false (silent).
    val logcatEnabled: Boolean = false,
    // Host log callback; receives the full stream of SDK LogRecords, unaffected by logLevel; defaults to null.
    val logHandler: HappyOysterLogHandler? = null,
) {
    companion object {
        /** Default callback timeout (milliseconds). Public constant, usable for comparison or display. */
        const val DEFAULT_CALLBACK_TIMEOUT_MS: Long = 30_000
    }
}

enum class LogLevel { VERBOSE, DEBUG, INFO, WARN, ERROR, NONE }

// Host log sink; injected via SDKConfig.logHandler; full firehose, unaffected by logLevel.
fun interface HappyOysterLogHandler {
    fun onLog(record: LogRecord)
}

// SDK structured log record; delivered to HappyOysterLogHandler; contains no sensitive values (Bearer /
// ticket / RTC token, RTC identity fields, and media URLs are all redacted). travelId (encryptedTravelId)
// is kept in full so it can be correlated with server-side session logs.
data class LogRecord(
    val level: LogLevel,
    val tag: String,        // fixed as "HappyOysterSDK"
    val message: String,    // readable log line (includes event name and details)
    val throwable: Throwable?,
    val timestampMs: Long,  // epoch milliseconds at emission time
)

// Status and mode (unknown values are preserved to allow service extension)
@JvmInline value class TravelStatusValue(val rawValue: String) {
    companion object {
        val Init = TravelStatusValue("init")
        val Pending = TravelStatusValue("pending")
        val Running = TravelStatusValue("running")
        val Paused = TravelStatusValue("paused")
        val Failed = TravelStatusValue("failed")
        val Completed = TravelStatusValue("completed")
    }
}
@JvmInline value class ModeValue(val rawValue: String) {
    companion object {
        val Adventure = ModeValue("adventure")
        val Directing = ModeValue("directing")
        val Acting = ModeValue("acting")
    }
}
@JvmInline value class CreationModelValue(val rawValue: String) {
    companion object {
        val Simple = CreationModelValue("simple")         // default; prompt/instruct-driven, world-exploration worlds normalize to this
        val ScriptList = CreationModelValue("scriptlist") // structured ScriptList world; sendInstruct not supported (throws 103002)
    }
}

// startTravel return
data class StartTravelData(
    val encryptedTravelId: String, // identifier for subsequent control interfaces
    val encryptedWorldId: String,
    val mode: ModeValue,           // adventure / directing / acting
    val creationModel: CreationModelValue = CreationModelValue.Simple, // world creation model; Simple (default) is instruct-driven, ScriptList does not support sendInstruct
    val playUrl: String?,
    val firstFrame: String?,       // first-frame image address, may be produced asynchronously
    val bgmUrl: String?,
    val version: String,           // world version identifier; Acting is actingV2
    val aspectRatio: String? = null, // Acting only: 9:16 / 16:9; other modes null. Use to set player orientation
    val maxExperienceTimeSec: Int? = null, // server-reported max experience time (seconds); non-null only for adventure; null for directing / acting
)

// Control interface parameters and returns
data class AdventureCommand(
    val translation: String, // movement: forward/left/back/right/diagonal (W_A, …)/idle
    val rotation: String,    // view: up/down/left/right/diagonal (Mouse_Up_Left, …)/none
    val interaction: String, // interaction: jump/attack/squat/sprint/none
)
data class TravelStateData(val encryptedTravelId: String, val status: TravelStatusValue)
data class RewindTravelData(val encryptedTravelId: String, val status: TravelStatusValue, val resumedAtSec: Double)
data class EndTravelData(val encryptedTravelId: String, val status: TravelStatusValue, val endedAt: String, val durationSec: Int)
data class SendInstructData(val encryptedTravelId: String, val content: String, val accepted: Boolean)

// Error (identified by code; the original information is in raw)
// Note: SDKError is not a data class (no copy()/destructuring), it is a plain class.
class SDKError(val code: Int, val raw: Any? = null) : Exception("Happy Oyster SDK error: $code")

エラーコード

エラーは数値の code によって識別されます。SDK は呼び出し元が処理可能なビジネスエラーコード(一般的に 4xxxxx / 5xxxxx)をパススルーします。ローカル SDK エラーコードは 1xxxxx です。

ビジネスエラーコード(共通)

code

意味

推奨対応

400000

無効なパラメータ(無効な列挙型など)

リクエストパラメータまたは SDK バージョンを確認してください

401010

ticket が無効または期限切れです

サーバーにクレデンシャルの再発行を依頼してください

401011

ticket はすでに使用されています

クレデンシャルは使い捨てです。再発行してください。

403001

ワールドが存在しない、削除済み、または現在の開発者に属していません(startTravel クレデンシャル内で既に削除されているワールドも含む)

有効な World を再選択してください

403002

World が準備完了状態ではありません

開始前に World の準備が整うまでお待ちください

403004

入力コンテンツ違反(コンテンツモデレーション)。sendInstruct のテキスト指示に適用されます

入力内容を変更して再試行してください

403007

このアカウントではサービス仕様が有効化されていません

容量不足として再試行しないでください。有効な仕様に切り替えるか、有効化をリクエストしてください

403008

キャパシティ設定が一時的に利用できません

後で再試行

404000

Travel リソースが存在しないか、ID が現在のアカウントに属していません

Travel を再起動

409000

リクエストが現在のリソース状態と競合しています

Travel の状態を確認してください

429001

SKU 同時実行制限に達しました

既存のセッション終了後に再試行してください(500001 と混同しないでください)

429002

現在利用可能なキャパシティがありません

後で再試行

500001

推論リソース割り当て/内部サービス障害

後で再試行

500000

内部システムエラー

後で再試行/報告

クライアント側ローカルエラーコード

code

意味

致命的?

推奨対応

100001

SDK の初期化前に呼び出されました

呼び出し拒否

最初に initialize を実行してください

100002

SDK 初期化時に model が空白でした。SDKError.raw が SDKConfig.model must not be blank に設定された状態で同期的にスローされます。ランタイムは作成も置換もされず、ネットワークリクエストも行われません。

初期化失敗

空でない完全なモデル名とバージョンを渡し、再度 initialize を呼び出してください。利用可能な値については Bailian HappyOyster モデルの公式ドキュメントを参照してください

101001

Bailian ゲートウェイ API Key が注入されていません

いいえ

updateToken の後に再試行してください

101002

BailianゲートウェイのBearer API Keyの有効期限切れ、または拒否されました。注意:これはゲートウェイのBearer Keyであり、ワンタイムチケットではありません。チケットレベルの認証エラーは、6桁のサーバーコード(例:401010/401011)によって識別されます。

いいえ

Bearer キーを再取得して updateToken を実行してください。新しいチケットへの交換は不要です

103001

現在アクティブな体験はありません

呼び出し拒否

最初に startTravel を実行してください

103002

現在の状態ではこの操作は許可されていません(以下の状況を含みます:状態の不一致、体験が pauseTravel/resumeTravel/rewindTravel の一時停止/再開/巻き戻しをサポートしていない(その version がモードに必要な v2 識別子ではない)、rewindTravel に対する状態が paused ではない、sendInstruct に対する creationModel == ScriptList)。

呼び出し拒否

体験の状態とモードを確認してください。ScriptList モード(creationModel == CreationModelValue.ScriptList)では sendInstruct は使用できません。このモードではスクリプトの内容はこのSDKを通じて管理されません。

103003

モードの不一致:sendCommandがdirectingまたはActingで呼び出されたか、あるいはpauseTravel / resumeTravel / rewindTravel / sendInstructがadventureで呼び出されたか、またはrewindTravelがActingで呼び出されました。

呼び出し拒否

現在のモードがインターフェースの要件に合致しているか確認してください

103004

並行した startTravel の呼び出し、または Travel の開始中、アクティブ中、終了中の再初期化です(一度に許可される Travel は1つだけです。並行開始時の SDKError.raw には、編集済みのチケット要約のみが含まれます)。

呼び出し拒否

再試行前に endTravel() の完了を待ってください

105001

リアルタイム接続に失敗しました

はい

終了して再起動

105002

リアルタイム参加がタイムアウトしました

はい

終了して再起動

105003

ビデオの最初のフレーム待機中にタイムアウトしました

はい

終了して再起動

105004

リアルタイムチャンネルの準備未完了/送信失敗

いいえ

リアルタイムチャネルの準備ができていることを確認し、running の後に sendCommand を再試行してください。特定のデバイスで問題が発生する場合は、RECORD_AUDIO を宣言して付与してみてください(Happy Oyster Android SDK統合ガイド § インストール · 権限 を参照)。

105005

SDK ゲートウェイ HTTP シグナリング呼び出しが callbackTimeoutMs(デフォルト 30 秒)以内に返ってきませんでした。RTC 参加および初回フレームのタイムアウトには、それぞれ 105002 および 105003 が使用されます

いいえ

再試行を推奨します。または callbackTimeoutMs を増やしてください

105006

ストリームなしによる自動終了:最初のフレームが届かなかったか、実行中にストリームが中断され、タイムアウト前に回復しませんでした。SDK は現在の体験を能動的に終了します

はい

終了して再起動

106001

ローカルネットワークエラー

いいえ

リトライ可能

106002

レスポンスの解析に失敗しました

いいえ

明示的な呼び出しによってトリガーされた場合は呼び出し元にスローされます。内部ステータスポーリング時は onError のみが送出され、体験は終了しません

106003

アップストリームサービスが認識できないエラーレスポンスを返しました。SDK は元の情報を SDKError.raw に保持しています(AccessDenied などのゲートウェイエッジ拒否を含みます)。

いいえ

再試行可能です。問題が継続する場合は、raw とともにサービスの可用性を確認してください。raw に AccessDenied が含まれる場合(初期化後の最初のリクエストで最も頻繁に発生します)、これはゲートウェイ設定の問題です。以下の順序で確認してください:① model の名前とバージョンが正しく、現在も利用可能で、公開されており、認可されているか;② apiHost のスペル;③ apiHost、model、および updateToken を介して注入された Key が、必要なアカウントとリージョンと一致しているか;④ お使いのアカウントがアプリの許可リストに追加されているか。

108001

SDK がリモートで無効化されています(完全停止またはバージョン过低)。理由は SDKError.raw(String)に含まれます

はい(SDK が無効化結果を検出すると、進行中の体験を自動的に終了します。復旧後に再起動可能です)

raw の理由に基づいてユーザーに通知してください。バージョンが低い場合はアップグレードを案内してください

注記「Fatal?」は、具体的にはそれがSDKに現在の体験を自動終了させるかどうかを指します。100001/100002/103xxxのような同期検証エラーは、その呼び出しに対してのみ拒否またはスローを行い(100002は初期化を直接失敗させます)、体験を終了させることはありません。

致命的エラーと非致命的エラー:

  • 致命的エラー:SDK は現在のエクスペリエンスを自動的に終了し(リアルタイム接続の切断、リソースの解放、endTravel の呼び出し)、onError を通じて通知します。ホストは現在のエクスペリエンス状態をクリーンアップし、再起動を可能にする必要があります。カテゴリは次の4つです:① 内部ステータスポーリングがエクスペリエンスステータスとして failed を読み取った場合(例:500001 推論失敗);② リアルタイム接続の致命的エラー(105001/105002/105003);③ ストリームなしによる自動終了(105006:最初のフレームが到達しない、または実行中にストリームが中断され、タイムアウト前に回復せず、SDK が能動的に終了させる場合);④ SDK がリモートで無効化された場合(108001)。
  • 非致命的エラー:エクスペリエンスを終了させず、onError を通じてのみ通知されます。updateToken を再実行するか、サービス/リアルタイムチャネルの復旧を待ってから続行することができます。内部ステータスポーリング自体の単一リクエスト失敗(ネットワーク 106001、パース 106002、上流異常 106003、ビジネスエラー 5xxxxx)もこのカテゴリに含まれます。ポーリングは次のサイクルで継続され、ステータスが failed と読み取られた場合にのみエクスペリエンスが終了します。認証失敗 101001 や非同期の sendCommand スロットリングフラッシュ送信失敗 105004 も同様に非致命的です。注:SDK はリアルタイムチャネル経由で独自のキープアライブペイロードを送信しないため、セッションがアイドル状態の間は 105004 が発生することはありません。これはユーザー自身の sendCommand 呼び出しによってのみトリガーされます。