Tous les produits
Search
Centre de documentation

Alibaba Cloud Model Studio:Référence API du SDK Android HappyOyster

Dernière mise à jour :Oct 11, 2026

Le point d'entrée du SDK Android HappyOyster est l'objet singleton HappyOyster. À l'exception de initialize, updateToken, attachVideo et sendCommand, toutes les méthodes métier sont des fonctions suspend qui lèvent SDKError en cas d'échec. Couvre les trois modes aventure / réalisation / acting, la configuration requise du modèle et aspectRatio.

Si la coroutine appelante est annulée, le SDK annule la requête HTTP en cours de cet appel, le cas échéant, et propage CancellationException inchangé plutôt que de le convertir en SDKError. L'annulation ne fait pas revenir en arrière une requête que le serveur a déjà acceptée.

Pour le flux d'intégration, l'installation et les bonnes pratiques, voir Guide d'intégration du SDK Android Happy Oyster.

Terminologie de base

Terme

Signification

token

Clé API de la passerelle Bailian : injectée en tant que jeton Bearer par votre application via updateToken(token). Le SDK ne conserve que la dernière clé ; il ne la persiste ni ne la rafraîchit. Lorsque la clé change, vous devez l'injecter à nouveau. La passerelle exige que toutes les requêtes SDK, y compris startTravel, utilisent ce Bearer. Lorsque la clé Bearer est expirée ou invalide, le SDK lève SDKError(101002) ; dans ce cas, vous devez obtenir et injecter à nouveau la clé Bearer (updateToken), plutôt que d'échanger contre un nouveau ticket. Recommandation de sécurité : le Bearer côté client doit utiliser un jeton à courte durée de vie émis par votre serveur, plutôt que d'intégrer une clé API à longue durée de vie dans l'application ou de la valider dans un dépôt de code.

ticket

Identifiant d'expérience à usage unique : échangé par votre serveur via la plateforme ouverte et livré au client, utilisé uniquement pour un seul startTravel. Il devient invalide une fois l'expérience terminée (normalement ou anormalement) et ne peut pas être réutilisé. Les erreurs d'identification au niveau du ticket sont identifiées par des codes serveur à six chiffres (par ex., 401010 = ticket invalide/expiré, 401011 = ticket déjà utilisé), que le SDK transmet tels quels.

Exigences environnementales

Élément

Exigence

minSdk

24 (Android 7.0) et versions ultérieures

compileSdk

36

Langage

Kotlin (APIs de coroutine suspend)

ABI

arm64-v8a / armeabi-v7a (le moteur de communication en temps réel inclut des bibliothèques natives)

Réseau

Accès Internet public requis

Concepts de base

Concept

Description

Monde

Un monde IA, contenant des personnages et des scènes. Créé et géré par votre serveur.

Travel

Une expérience temps réel unique. Cycle de vie de base : init → pending → running → completed (l'échec correspond à failed). En mode Réalisation et Acting, si l'expérience prend en charge la pause, running peut passer à paused via pauseTravel, puis revenir à running via resumeTravel (la Réalisation peut également utiliser rewindTravel, après quoi le serveur reprend automatiquement l'expérience) ; running ⇄ paused peut s'enchaîner plusieurs fois.

Mode

adventure (interaction appareil/commande), directing (narration pilotée par texte), ou acting (Acting : narration pilotée par texte dont le format d'image de lecture est fixé par le serveur lors de la création du monde). Le SDK expose uniformément ces trois valeurs.

Vidéo en temps réel

Établie et maintenue automatiquement par le SDK après le succès de startTravel ; vous n'avez pas besoin de connecter/déconnecter manuellement. Elle est libérée automatiquement lors de endTravel.

Vue d'ensemble

Méthodes HappyOyster

Méthode

Description

initialize(context, config)

Initialise le SDK. La réinitialisation à l'état inactif est prise en charge ; la réinitialisation pendant qu'un Travel est en cours de démarrage, actif ou en cours de fin est rejetée avec 103004.

updateToken(token)

Injecte/met à jour la clé API de la passerelle Bailian (jeton Bearer).

startTravel(ticket)

Démarre une expérience avec un identifiant à usage unique et établit automatiquement la connexion vidéo en temps réel.

pauseTravel()

Met en pause l'expérience de manière asynchrone (réalisation et Acting, et uniquement si l'expérience prend en charge la pause) ; après acceptation, la pause effective est déterminée par onStatusChanged(Paused).

resumeTravel()

Reprend une expérience en pause (réalisation et Acting) ; inclut une temporisation de nouvelle tentative 3× en interne.

rewindTravel(rewindToSec)

Rembobine au nombre de secondes spécifié (réalisation uniquement, état paused). La valeur en secondes doit être un multiple de 4. Acting ne prend pas en charge le rembobinage.

sendInstruct(content)

Envoie une instruction textuelle pour piloter la narration (réalisation et Acting, running ou paused).

sendCommand(command)

Envoie des commandes de contrôle de direction/vue/action (mode aventure, running uniquement ; thread principal). Non disponible pour Acting.

attachVideo()

Retourne une SurfaceView pour la lecture ; ajoutez-la à votre mise en page pour le rendu (thread principal).

endTravel()

Met fin à l'expérience, déconnectant automatiquement la connexion en temps réel et libérant toutes les ressources de session.

VERSION

Chaîne de version du SDK (SemVer), constante au moment de la compilation.

Événements

Événement

Description

onStatusChanged(status)

Changement d'état de l'expérience (y compris le cycle de vie vidéo en temps réel) ; les valeurs sont définies dans TravelStatusValue.

onError(error)

Rappel lorsqu'un flux automatique interne échoue ; une erreur fatale met également fin à l'expérience en cours.

Types de données clés

Type

Description

SDKConfig

Configuration d'initialisation du SDK (apiHost et model sont obligatoires, ainsi que logLevel, logcatEnabled, logHandler et callbackTimeoutMs).

TravelStatusValue

État de l'expérience : Init / Pending / Running / Paused / Failed / Completed.

ModeValue

Mode d'expérience : adventure / directing / acting.

CreationModelValue

Modèle de création de monde : Simple (par défaut, piloté par instructions) / ScriptList (script structuré, sendInstruct non pris en charge).

StartTravelData

Retourné par startTravel ; contient des métadonnées telles que mode, version, creationModel, aspectRatio et maxExperienceTimeSec.

AdventureCommand

Paramètre pour sendCommand ; contient les trois champs translation / rotation / interaction.

SDKError

Erreur SDK ; contient code: Int et raw: Any? facultatif.

HappyOyster.initialize

Initialise le SDK ; appelez-le avant toute autre API (de préférence dans Application.onCreate). config est obligatoire et doit contenir le apiHost Bailian de votre compte ainsi qu'un model parmi happyoyster-1.0-directing / happyoyster-1.0-acting / happyoyster-1.0-adventure (correspondant à l'entrée Open API). Le SDK construit les URL de requête comme suit :

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

model n'a pas de valeur par défaut : l'omettre lors de la construction de SDKConfig constitue une erreur de compilation. Passer une valeur vide fait que initialize lève de manière synchrone SDKError(100002) ; aucun runtime n'est créé ni remplacé et aucune requête réseau n'est effectuée. Le SDK ne conserve que le contexte de l'application, pas une Activity. La réinitialisation n'est prise en charge que lorsque le runtime précédent est inactif. Pour changer de modèle, réinitialisez avec le nouveau model pendant l'inactivité ; si un Travel démarre, est actif ou se termine, attendez d'abord endTravel().

Remarque

Avis de conformité régionale :
  • Pour garantir la conformité aux exigences légales et relatives aux données applicables, si vos utilisateurs cibles incluent des utilisateurs américains, vous devez configurer un API Host de région américaine lors de l'initialisation du SDK pour les services fournis à ces utilisateurs.
  • Les développeurs sont responsables de la configuration correcte et assument la responsabilité correspondante en vertu de la loi applicable en cas de non-respect de cette exigence.

Signature

fun initialize(context: Context, config: SDKConfig)

Paramètres

Champ

Type

Obligatoire

Description

context

Context

Oui

Il est recommandé de passer applicationContext.

config

SDKConfig

Oui

Configuration du SDK ; doit contenir les paramètres obligatoires sans valeur par défaut apiHost et model.

Retourne

Aucune valeur de retour.

Erreurs

code

Description

100002

model est vide. L'initialisation échoue de manière synchrone avec SDKError.raw défini sur SDKConfig.model must not be blank ; aucun runtime n'est créé ou remplacé et aucune requête réseau n'est effectuée.

103004

Réinitialisation rejetée car un Travel est en cours de démarrage, actif ou en cours de fin. Attendre endTravel() et réessayer.

HappyOyster.updateToken

Injecte/met à jour la clé API de la passerelle Bailian. Thread-safe et appelable après initialize ; le SDK utilise le dernier jeton pour startTravel et les requêtes ultérieures de contrôle d'expérience. Le ticket est un identifiant d'expérience à usage unique et ne doit pas être confondu avec le jeton Bearer.

Signature

fun updateToken(token: String)

Paramètres

Champ

Type

Obligatoire

Description

token

String

Oui

La clé API de la passerelle Bailian, utilisée comme jeton Bearer.

Retourne

Aucune valeur de retour.

Erreurs

code

Description

100001

Le SDK n'a pas été initialisé.

HappyOyster.startTravel

Démarre une expérience avec un ticket à usage unique. En cas de succès, le SDK établit automatiquement la connexion vidéo en temps réel et lance l'interrogation interne de l'état, l'état étant exposé via onStatusChanged.

  • ticket est un identifiant à usage unique et est considéré comme consommé dès que l'appel est effectué.
  • Un seul Travel simultané est autorisé par application à tout moment ; appeler à nouveau alors qu'une expérience est en cours lève SDKError(103004), avec SDKError.raw ne contenant qu'un résumé expurgé du ticket actuellement actif pour le diagnostic, jamais le ticket complet.
  • Passer facultativement maxExperienceTimeSec pour plafonner la durée maximale de cette expérience (exploration de monde / mode aventure uniquement) ; voir Paramètres.

StartTravelData.creationModel (CreationModelValue, par défaut CreationModelValue.Simple) : indique le modèle de création du monde, c'est-à-dire la manière dont le contenu du script est géré. simple (par défaut) est un monde ordinaire piloté par instructions ; les mondes d'exploration de monde sont également normalisés à cette valeur. scriptlist est un monde ScriptList structuré — son contenu de script n'est pas accessible via ce SDK. En mode ScriptList (creationModel == CreationModelValue.ScriptList), l'appel à sendInstruct est rejeté et lève SDKError(103002). Ce champ a pour valeur par défaut simple.

StartTravelData.aspectRatio (String?) : le rapport d'aspect de lecture attribué par le serveur à cette session, sous forme de chaîne width:height. Non-null uniquement pour Acting—"9:16" (portrait, valeur par défaut côté serveur à la création) ou "16:9" (paysage) ; null pour les modes exploration de monde et réalisation, et null lorsque le serveur ne signale pas la valeur. Le SDK conserve les valeurs inconnues telles quelles (il ne les réduit pas à null), de sorte que les hôtes doivent traiter toute valeur non reconnue comme null et revenir à leur propre orientation par défaut ; le SDK lui-même n'utilise pas ce champ.

La valeur est fournie avec la valeur de retour de startTravel() : dimensionnez le conteneur de lecture à partir de celle-ci après le retour de startTravel() et avant d'appeler attachVideo() et d'ajouter la vue retournée à votre mise en page — le SDK ne commence à lier le flux distant pour le rendu que lorsque l'hôte attache la vue, donc décider de l'orientation à ce moment précède toujours la première image rendue (cependant, il n'est pas garanti que cela se produise avant que le SDK ne rejoigne la salle temps réel). La vue distante est liée avec un mode de rendu clip-to-fill, de sorte qu'un conteneur dont l'orientation ne correspond pas à cette valeur recadre l'image au lieu d'ajouter des bandes noires.

Signature

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

Paramètres

Champ

Type

Obligatoire

Description

ticket

String

Oui

L'identifiant d'expérience à usage unique, fourni par votre serveur.

maxExperienceTimeSec

Int?

Non

Durée maximale de cette expérience en secondes ; le monde termine la session automatiquement une fois cette durée atteinte. S'applique uniquement au mode exploration de monde (aventure) ; ignoré en mode réalisation (réalisation temps réel) et Acting. Les valeurs autorisées sont configurées côté serveur, actuellement 60 / 90 / 120 ; passer null (ou utiliser la surcharge sans ce paramètre) applique la valeur par défaut du serveur (actuellement 60). Passer une valeur non prise en charge entraîne un rejet par le serveur startTravel avec 400000, levant SDKError(400000) sans qu'aucun Travel actif ne soit créé. Le SDK ne valide pas la valeur localement — l'ensemble autorisé fait autorité sur le serveur.

Retourne

Renvoie StartTravelData, contenant les métadonnées de l'expérience (mode, version, creationModel, aspectRatio, etc.). Inspectez les métadonnées renvoyées avant de décider comment interagir (par ex., travel.mode, travel.creationModel, travel.version) ; pour le mode Acting, dimensionnez également le conteneur de lecture à partir de travel.aspectRatio.

Erreurs

code

Description

401010

ticket invalide ou expiré

401011

ticket déjà utilisé

400000

Paramètre invalide (par ex. maxExperienceTimeSec n'est pas dans l'ensemble autorisé par le serveur) ; ce startTravel ne parvient pas à démarrer

403002

Monde non prêt

500001

Allocation de ressources / échec du service interne

103004

Un Travel est déjà en cours de démarrage, actif ou en cours de fin, ou startTravel est appelé simultanément (un seul Travel est autorisé à la fois ; SDKError.raw ne contient qu'un résumé expurgé du ticket actif)

HappyOyster.pauseTravel / HappyOyster.resumeTravel

Mettre en pause / reprendre l'expérience. Le SDK ne gère qu'un seul Travel à la fois ; encryptedTravelId est obtenu en interne par le SDK et n'a pas besoin d'être passé par l'appelant.

Préconditions :

  • pauseTravel : appelable uniquement en réalisation ou Acting et lorsque l'état est running.
  • resumeTravel : appelable uniquement en réalisation ou Acting et lorsque l'état est paused.

Toutes les expériences ne prennent pas en charge la pause / la reprise : l'expérience doit rapporter l'identifiant de version requis par son mode (StartTravelData.version—storyV2 pour directing, actingV2 pour Acting ; comparé en ignorant les espaces environnants et la casse des lettres), sinon pauseTravel et resumeTravel renvoient tous deux 103002. Le mode Acting prend en charge la pause / la reprise mais ne prend pas en charge rewindTravel.

La pause est asynchrone (important) : pauseTravel est une opération « lourde » — un appel réussi (retour de la méthode) signifie seulement que la pause a été acceptée ; à ce moment-là, l'expérience n'est pas encore réellement en pause. La pause n'est effective que lorsque le rappel onStatusChanged signale paused. Par conséquent, pilotez la machine à états de l'hôte et le contrôle des appels depuis ce rappel : entre « l'appel à pauseTravel » et « la réception du rappel paused », vous pouvez marquer l'état local comme pausing ; ce n'est qu'après avoir reçu paused que vous devez autoriser le lancement de resumeTravel ou rewindTravel. Ne considérez pas le retour de pauseTravel comme une mise en pause effective.

Gestion de la connexion en temps réel : après une pause effective, le SDK déconnecte la connexion en temps réel ; lors de la reprise, le SDK rejoint automatiquement et restaure l'image en utilisant l'identifiant fourni lors du même startTravel, sans intervention de l'hôte requise.

Barrière ordonnée de démantèlement de pause : après l'émission de Paused, le démantèlement de la salle temps réel côté serveur peut encore subir un léger délai. Le SDK établit une fenêtre de stabilisation de 3 secondes à partir de la confirmation de la pause. Si resumeTravel ou rewindTravel est appelé dans cette fenêtre, l'appel de suspension attend d'abord de manière non bloquante le temps restant, puis envoie la requête API de réouverture de la salle. Aucun délai n'est ajouté si 3 secondes se sont déjà écoulées naturellement. Cela empêche un démantèlement tardif de la pause de fermer la salle nouvellement ouverte et de faire apparaître 105001.

Nouvelle tentative d'API de reprise : resumeTravel effectue en interne jusqu'à 3 tentatives en cas d'échec (backoff de 1 s / 2 s / 3 s) pour gérer une indisponibilité temporaire du service après une pause ; ce n'est que si les 3 tentatives échouent que l'erreur est propagée vers le haut.

Remarque⚠️ Remarque : Il est recommandé que l'hôte attende jusqu'à 3 s après le retour réussi de resumeTravel avant de lancer à nouveau pauseTravel, afin d'éviter des basculements trop fréquents. Il s'agit d'une recommandation de temporisation d'appel côté hôte et elle n'est pas imposée par le SDK lui-même. Voir Guide d'intégration du SDK Android Happy Oyster pour plus de détails.

Signature

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

Paramètres

Aucun paramètre.

Retourne

Retourne TravelStateData (contient encryptedTravelId, status).

Erreurs

code

Description

103001

Aucune expérience active

103002

État non autorisé, ou cette expérience ne prend pas en charge la pause / reprise

103003

Appelé en mode aventure ; seuls les modes réalisation et Acting prennent en charge la pause / reprise

HappyOyster.rewindTravel

Rembobine au nombre de secondes spécifié. encryptedTravelId est obtenu en interne par le SDK.

Prérequis : appelable uniquement en mode directing et lorsque l'état est paused (le rembobinage n'est pas autorisé à l'état running). Toutes les expériences directing ne prennent pas en charge le rembobinage, et celles non prises en charge renvoient 103002. Après un rembobinage réussi, l'expérience reprend automatiquement et le SDK reconnecte automatiquement le RTC, sans intervention de l'hôte requise.

Le mode Acting n'a aucune capacité de rembobinage : l'appeler en mode Acting est rejeté localement par le SDK avec 103003, et aucune requête n'est émise. En mode Acting, les hôtes doivent masquer le point d'entrée du rembobinage plutôt que de simplement désactiver le bouton.

Signature

suspend fun rewindTravel(rewindToSec: Double): RewindTravelData

Paramètres

Champ

Type

Obligatoire

Description

rewindToSec

Double

Oui

Le nombre cible de secondes pour le rembobinage, qui doit être un multiple de 4 (par ex., 4, 8, 12). Une valeur non multiple de 4 est arrondie par le serveur au multiple inférieur de 4 le plus proche (par ex., passer 7 donne 4).

Retourne

Retourne RewindTravelData (contient encryptedTravelId, status, resumedAtSec), où resumedAtSec est le nombre de secondes auquel le serveur a effectivement rembobiné (déjà arrondi à l'entier inférieur vers un multiple de 4).

Erreurs

code

Description

103001

Aucune expérience active

103002

L'état n'est pas paused, ou cette expérience ne prend pas en charge le rembobinage

103003

Appelé en mode aventure ou Acting ; seul le mode réalisation prend en charge le rembobinage

HappyOyster.sendInstruct

Envoie une instruction textuelle pour piloter la narration. Valide en mode directing ou Acting et lorsque l'état de l'expérience est running ou paused. encryptedTravelId est obtenu en interne par le SDK.

Comportement à l'état paused : le SDK ne reprend pas automatiquement lorsqu'il est en pause ; l'instruction est envoyée directement. C'est à l'hôte de décider s'il doit appeler resumeTravel avant d'envoyer l'instruction.

Signature

suspend fun sendInstruct(content: String): SendInstructData

Paramètres

Champ

Type

Obligatoire

Description

content

String

Oui

Le contenu de l'instruction textuelle à envoyer.

Retourne

Retourne SendInstructData (contient encryptedTravelId, content, accepted).

Erreurs

code

Description

103001

Aucune expérience active (startTravel n'a jamais été appelé, ou elle est terminée)

103003

Le mode actuel n'est ni réalisation ni Acting (appelé en mode aventure)

103002

L'état de l'expérience n'est ni running ni paused (par ex., encore en phase init/pending) ; ou le monde actuel est en mode ScriptList (StartTravelData.creationModel == CreationModelValue.ScriptList) — l'envoi d'instructions n'est pas autorisé en mode ScriptList, où les scripts sont gérés par l'API de la plateforme Bailian

403004

Blocage de modération de contenu

404000

Le Travel n'existe pas

HappyOyster.sendCommand

Envoie des commandes de contrôle de direction/vue/action. Valide uniquement en mode aventure et lorsque running.

  • Appeler sur le thread principal ; un appel hors thread principal lève synchrone IllegalStateException.
  • L'absence d'expérience active signale 103001.
  • Un appel en dehors du mode aventure (réalisation / Acting) signale 103003.
  • Un état non autorisé signale 103002.
  • La liaison montante est établie via un flux audio silencieux (le SDK n'enregistre ni ne téléverse d'audio réel) ; RECORD_AUDIO n'est pas une condition stricte pour le DataChannel, mais le déclarer et l'accorder est recommandé pour la compatibilité entre appareils (voir Guide d'intégration du SDK Android Happy Oyster § Installation · Permissions). 105004 signifie que le canal temps réel n'est pas prêt ou qu'un envoi a échoué (par exemple, une interruption de connexion DataChannel ou une anomalie du canal temps réel) ; cela n'est pas déclenché directement par une permission manquante.

Limitation intégrée de 42 ms (24 fps, la dernière valeur l'emporte) : sendCommand limite en interne les écritures DataChannel par intervalles de 42 ms (environ 24 fps). La validation de l'état s'exécute de manière synchrone et immédiate, levant immédiatement une exception en cas d'appel illégal ; l'écriture DataChannel réelle est limitée de manière asynchrone. Si au moins 42 ms se sont écoulées depuis l'envoi précédent, la commande est envoyée immédiatement (y compris pour le premier appel). Sinon, la commande en attente est remplacée par la dernière valeur et envoyée une seule fois à la fin de la fenêtre de 42 ms en cours. Plusieurs appels dans une même fenêtre produisent donc une seule écriture sur le réseau contenant la dernière valeur. L'hôte peut appeler sendCommand à la fréquence d'images du jeu sans implémenter son propre limiteur de débit.

Échecs d'envoi pendant la limitation : le vidage limité est asynchrone, et un échec d'envoi ne peut pas être levé à l'appelant — l'erreur est exposée via le callback onError (non fatal, 105004). Les commandes en attente sont abandonnées lorsque la session se termine (elles ne seront pas envoyées après la fin de la session).

Champs et valeurs de AdventureCommand :

Champ

Sémantique

Valeurs

translation

Mouvement : avant/gauche/arrière/droite/diagonale/inactif

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

rotation

Vue : haut/bas/gauche/droite/diagonale/none

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

interaction

Interaction : saut/attaque/accroupissement/sprint/none

Jump / Attack / Squat / Sprint / None

Les trois champs sont des groupes de commandes mutuellement exclusifs et indépendants. Le déplacement/la vue en diagonale utilise une valeur combinée unique (par exemple, avant+gauche est W_A, et non W et A simultanés dans le même champ). Chaque appel doit porter l'état actuel complet.

Bonnes pratiques : actions ponctuelles contre actions maintenues

Utiliser l'intervalle de 42 ms comme modèle mental :

  • Action ponctuelle (par exemple, appuyer pour sauter/attaquer ou faire un pas) : appeler une seule fois. Le SDK l'envoie dans l'intervalle le plus proche ; aucun appel répété ni commande None de suivi n'est requis.

    // Jump once
    HappyOyster.sendCommand(AdventureCommand("None", "None", "Jump"))
    
  • Action maintenue (par exemple, continuer à se déplacer ou à tourner) : appeler à chaque frame tant que maintenu. Le SDK émet environ une commande toutes les 42 ms. Au relâchement, envoyer explicitement une commande contenant None pour réinitialiser l'état. Le SDK ne génère jamais de commande de réinitialisation automatiquement.

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

Signature

fun sendCommand(command: AdventureCommand)

Paramètres

Champ

Type

Obligatoire

Description

command

AdventureCommand

Oui

Un objet de commande contenant les trois champs translation, rotation, interaction.

Retourne

Aucune valeur de retour (synchrone). La validation de l'état s'exécute de manière synchrone et immédiate ; l'écriture DataChannel est limitée de manière asynchrone.

Erreurs

code

Description

103001

Aucune expérience active

103002

État non autorisé

103003

Appelé en dehors du mode aventure (réalisation / Acting)

105004 (via onError)

Échec d'envoi différé par limitation de débit (non fatal, rappel asynchrone)

HappyOyster.attachVideo

Retourne une SurfaceView pour la lecture, que vous ajoutez à votre mise en page ; le SDK effectue en interne la liaison de rendu avec le flux distant.

  • Appeler sur le thread principal ; un appel hors thread principal lève synchrone IllegalStateException.
  • Le SDK ne détient qu'une référence faible à la Vue retournée et libère la liaison de rendu lorsque l'expérience se termine ; vous devez retirer la Vue de la mise en page vous-même.
  • Pour les expériences Acting, dimensionnez le conteneur de lecture à partir de StartTravelData.aspectRatio avant d'ajouter la vue retournée à votre mise en page : le rendu est lié avec un mode clip-to-fill, de sorte qu'une orientation inadaptée recadre l'image (voir startTravel).

Signature

fun attachVideo(): SurfaceView

Paramètres

Aucun paramètre.

Retourne

Retourne une SurfaceView ; ajoutez-la à votre mise en page pour lire la vidéo en temps réel.

Erreurs

code

Description

100001

SDK non initialisé

HappyOyster.endTravel

Met fin à l'expérience. encryptedTravelId est obtenu en interne par le SDK. Après un appel réussi (ou une sortie anormale), le SDK déconnecte automatiquement la connexion en temps réel, arrête l'interrogation interne et libère toutes les ressources de session, et le ticket actuel est invalidé en même temps.

Signature

suspend fun endTravel(): EndTravelData

Paramètres

Aucun paramètre.

Retourne

Retourne EndTravelData (contient encryptedTravelId, status, endedAt, durationSec).

Erreurs

code

Description

100001

SDK non initialisé

103001

Aucune expérience active

HappyOyster.VERSION

Retourne la chaîne de version du SDK (SemVer), telle que "x.y.z". Cette valeur est une constante au moment de la compilation injectée par la propriété Gradle VERSION_NAME ; elle peut être lue en toute sécurité sans appeler initialize au préalable.

Signature

val VERSION: String

Retourne

La chaîne de version du SDK, telle que "x.y.z".

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

Écoute des événements

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

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

Les événements du SDK constituent un canal de push proactif vers vous, utilisé pour signaler des situations non déclenchées par vos propres appels explicites (par ex., des problèmes dans la connexion en temps réel ou l'interrogation d'état que le SDK maintient automatiquement).

Événement

Description

onStatusChanged

Changement d'état de l'expérience (y compris le cycle de vie vidéo en temps réel) ; les valeurs sont définies dans TravelStatusValue.

onError

Rappel lorsqu'un flux automatique interne échoue ; une erreur fatale met également fin à l'expérience en cours (voir la section des codes d'erreur).

Remarque⚠️ Remarque : addListener / removeListener doivent être appelés après initialize ; les appeler avant l'initialisation lève SDKError(100001). Il est recommandé d'enregistrer les écouteurs immédiatement après le retour réussi de HappyOyster.initialize(...).

Modèles de données

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

Codes d'erreur

Les erreurs sont identifiées par un code numérique. Le SDK transmet les codes d'erreur métier que l'appelant peut gérer (couramment 4xxxxx / 5xxxxx) ; les codes d'erreur locaux du SDK sont 1xxxxx.

Codes d'erreur métier (courants)

code

Signification

Traitement suggéré

400000

Paramètre invalide (enum invalide, etc.)

Vérifier les paramètres de la requête ou la version du SDK

401010

ticket invalide ou expiré

Demander à votre serveur de réémettre un identifiant

401011

ticket déjà utilisé

L'identifiant est à usage unique ; le réémettre

403001

Le monde n'existe pas, a été supprimé ou n'appartient pas au développeur actuel (y compris un monde déjà supprimé dans l'identifiant startTravel)

Resélectionner un Monde valide

403002

Monde non prêt

Attendre que le monde soit prêt avant de commencer

403004

Violation de contenu d'entrée (modération de contenu) ; s'applique aux instructions textuelles de sendInstruct

Modifier le contenu saisi et réessayer

403007

Spécification de service non activée pour ce compte

Ne pas réessayer en tant que capacité pleine ; changer pour une spécification activée ou demander l'activation

403008

Configuration de capacité temporairement indisponible

Réessayer plus tard

404000

La ressource Travel n'existe pas ou l'ID n'appartient pas au compte actuel

Redémarrer le Travel

409000

La requête est en conflit avec l'état actuel de la ressource

Vérifier l'état du Travel

429001

Limite de concurrence SKU atteinte

Réessayer après la fin d'une session existante (ne pas confondre avec 500001)

429002

Aucune capacité disponible actuellement

Réessayer plus tard

500001

Allocation de ressources d'inférence / échec du service interne

Réessayer plus tard

500000

Erreur système interne

Réessayer plus tard / signaler

Codes d'erreur locaux côté client

code

Signification

Fatal ?

Traitement suggéré

100001

Appelé avant l'initialisation du SDK

Appel rejeté

initialize d'abord

100002

model était vide lors de l'initialisation du SDK ; levé de manière synchrone avec SDKError.raw défini sur SDKConfig.model must not be blank ; aucun runtime n'est créé ou remplacé et aucune requête réseau n'est effectuée

Échec de l'initialisation

Passer un nom de modèle complet et une version non vides, puis appeler initialize à nouveau ; consulter la documentation officielle du modèle Bailian HappyOyster pour les valeurs disponibles

101001

Clé API de la passerelle Bailian non injectée

Non

Réessayer après updateToken

101002

Clé API Bearer de la passerelle Bailian expirée ou rejetée. Remarque : il s'agit de la clé Bearer de la passerelle, et non du ticket à usage unique ; les erreurs d'identification au niveau du ticket sont identifiées par des codes serveur à six chiffres (par ex., 401010/401011)

Non

Obtenir à nouveau la clé Bearer et updateToken ; inutile d'échanger contre un nouveau ticket

103001

Aucune expérience active actuellement

Appel rejeté

startTravel d'abord

103002

L'état actuel ne permet pas cette opération (incluant : incompatibilité d'état ; l'expérience ne prend pas en charge la pause / la reprise / le rembobinage pour pauseTravel/resumeTravel/rewindTravel (son version n'est pas l'identifiant v2 requis par son mode) ; état non paused pour rewindTravel ; creationModel == ScriptList pour sendInstruct)

Appel rejeté

Vérifier l'état et le mode de l'expérience ; sendInstruct n'est pas disponible en mode ScriptList (creationModel == CreationModelValue.ScriptList), où le contenu du script n'est pas géré via ce SDK

103003

Incompatibilité de mode : sendCommand appelé en mode directing ou Acting, ou pauseTravel / resumeTravel / rewindTravel / sendInstruct appelé en mode adventure, ou rewindTravel appelé en mode Acting

Appel rejeté

Vérifier si le mode actuel correspond à l'exigence de l'interface

103004

Un appel startTravel simultané, ou une réinitialisation alors qu'un Travel est en cours de démarrage, actif ou en cours de fin (un seul Travel est autorisé à la fois ; SDKError.raw pour un démarrage simultané ne contient qu'un résumé expurgé du ticket)

Appel rejeté

Attendre endTravel() avant de réessayer

105001

Échec de la connexion en temps réel

Oui

Terminer et redémarrer

105002

Expiration du délai de jonction en temps réel

Oui

Terminer et redémarrer

105003

Délai d'attente dépassé pour la première image vidéo

Oui

Terminer et redémarrer

105004

Canal en temps réel non prêt / échec de l'envoi

Non

Confirmez que le canal en temps réel est prêt et réessayez sendCommand après running ; si un appareil spécifique dysfonctionne, essayez de déclarer et d'accorder RECORD_AUDIO (voir Guide d'intégration du SDK Android Happy Oyster § Installation · Permissions)

105005

Un appel de signalisation HTTP de la passerelle SDK n'a pas répondu dans les callbackTimeoutMs (par défaut 30s) ; les délais d'attente de jonction RTC et de première image utilisent respectivement 105002 et 105003

Non

Une nouvelle tentative est recommandée, ou augmenter callbackTimeoutMs

105006

Fin automatique en l'absence de flux : la première image n'est jamais arrivée, ou le flux a été interrompu pendant l'exécution et n'a pas récupéré avant le délai d'attente. Le SDK met fin proactivement à l'expérience en cours

Oui

Terminer et redémarrer

106001

Erreur réseau locale

Non

Réessayable

106002

Échec de l'analyse de la réponse

Non

Levé à l'appelant lorsqu'il est déclenché par un appel explicite ; lors de l'interrogation d'état interne, seul onError est émis et l'expérience n'est pas terminée

106003

Le service en amont a renvoyé une réponse d'erreur non reconnaissable ; le SDK a conservé les informations d'origine dans SDKError.raw (y compris les rejets de passerelle edge tels que AccessDenied)

Non

Réessayable ; si le problème persiste, vérifiez la disponibilité du service ainsi que raw. Si raw contient AccessDenied (le plus souvent lors de la première requête après l'initialisation), il s'agit d'un problème de configuration de la passerelle ; vérifiez dans l'ordre : ① si le nom et la version de model sont corrects, toujours disponibles, publiés et autorisés ; ② l'orthographe de apiHost ; ③ si apiHost, model et la clé injectée via updateToken correspondent au compte et à la région requis ; ④ si votre compte a été ajouté à la liste d'autorisation de l'application

108001

SDK désactivé à distance (arrêt complet ou version trop ancienne) ; la raison se trouve dans SDKError.raw (String)

Oui (lorsque le SDK détecte un résultat de désactivation, il met automatiquement fin à l'expérience en cours ; vous pouvez redémarrer après récupération)

Informer l'utilisateur en fonction de la raison dans raw ; guider une mise à niveau lorsque la version est trop ancienne

Remarque« Fatal ? » fait spécifiquement référence à si cela déclenche l'arrêt automatique de l'expérience en cours par le SDK. Les erreurs de validation synchrones telles que 100001/100002/103xxx rejettent/lèvent uniquement pour cet appel (100002 fait directement échouer l'initialisation) et ne mettent pas fin à une expérience.

Erreurs fatales vs non fatales :

  • Erreurs fatales : le SDK termine automatiquement l'expérience en cours (déconnecte la connexion temps réel, libère les ressources, appelle endTravel) et la signale via onError ; l'hôte doit nettoyer l'état de l'expérience actuelle et autoriser un redémarrage. Il existe quatre catégories : ① l'interrogation interne de statut lit un état d'expérience failed (par exemple, échec d'inférence 500001) ; ② erreur fatale de connexion temps réel (105001/105002/105003) ; ③ fin automatique en l'absence de flux (105006 : la première image n'est jamais arrivée, ou le flux a été interrompu pendant l'exécution et n'a pas récupéré avant le délai d'attente, et le SDK y met fin proactivement) ; ④ SDK désactivé à distance (108001).
  • Erreurs non fatales : elles ne terminent pas l'expérience et sont uniquement signalées via onError ; vous pouvez appeler updateToken à nouveau ou attendre que le service ou le canal temps réel se rétablisse avant de continuer. Un seul échec de requête de l'interrogation interne de statut elle-même (réseau 106001, analyse 106002, anomalie en amont 106003, erreur métier 5xxxxx) entre dans cette catégorie — l'interrogation se poursuit au cycle suivant, et ce n'est que lorsqu'elle lit un statut failed qu'elle termine l'expérience ; l'échec d'authentification 101001 et l'échec d'envoi asynchrone avec limitation sendCommand 105004 sont également non fatals. Remarque : le SDK n'envoie jamais de charge utile keepalive de sa propre initiative sur le canal temps réel, donc 105004 ne peut pas apparaître lorsque la session est inactive — cela ne peut être déclenché que par votre propre appel à sendCommand.