Ce guide explique comment intégrer le SDK ARTC dans votre projet iOS pour créer une application audio et vidéo en temps réel, adaptée à des cas d'utilisation tels que la diffusion en direct interactive et les appels vidéo.
Concepts clés
Avant de commencer, examinez les concepts clés suivants :
SDK ARTC : SDK d'Alibaba Cloud pour les interactions audio et vidéo en temps réel.
GRTN : Global Realtime Transport Network d'Alibaba Cloud, fournissant des services de communication audio et vidéo sécurisés, fiables, de haute qualité et à ultra-faible latence.
channel : Salle virtuelle destinée aux interactions audio et vidéo en temps réel.
host : Rôle permettant à un utilisateur de publier des flux audio et vidéo dans un channel et de s'abonner aux flux publiés par d'autres hosts.
viewer : Rôle permettant à un utilisateur de s'abonner aux flux audio et vidéo dans un channel, sans pouvoir publier de flux.
-
Appelez
setChannelProfilepour définir le scénario du channel, puis appelez joinChannel pour rejoindre un channel :Dans un scénario d'appel vidéo, tous les utilisateurs ont le rôle host et peuvent publier et s'abonner aux flux.
Dans un scénario de diffusion interactive, vous devez appeler
setClientRolepour définir le rôle de l'utilisateur. Définissez le rôle sur host pour les utilisateurs qui vont publier un flux. Si un utilisateur doit uniquement s'abonner à un flux, définissez son rôle sur viewer.
-
Après avoir rejoint un channel, le rôle de l'utilisateur détermine s'il peut publier ou s'abonner aux flux :
Tous les utilisateurs d'un channel peuvent s'abonner à ses flux audio et vidéo.
Un host peut publier des flux audio et vidéo dans le channel.
Si un viewer doit publier un flux, il doit appeler la méthode
setClientRolepour changer son rôle en host.
Exemple de projet
Le SDK ARTC fournit un exemple de projet open source pour les applications audio et vidéo en temps réel.
Prérequis
Avant d'exécuter l'exemple de projet, assurez-vous que votre environnement de développement répond aux exigences suivantes :
Outil de développement : Xcode 14.0 ou version ultérieure. Utilisez si possible la dernière version stable.
Configuration recommandée : CocoaPods 1.9.3 ou version ultérieure.
Appareil de test : Un appareil iOS physique exécutant iOS 9.0 ou version ultérieure.
Utilisez un appareil physique pour les tests. Les simulateurs peuvent ne pas prendre en charge certaines fonctionnalités.
Réseau : Une connexion réseau stable est requise.
Configuration de l'application : Obtenez l'AppID et l'AppKey de votre application ApsaraVideo Real-time Communication. Pour plus d'informations, consultez la rubrique Créer une application.
Créer un projet (facultatif)
Cette section décrit comment créer un nouveau projet et ajouter les autorisations nécessaires pour l'interaction audio et vidéo. Vous pouvez ignorer cette section si vous disposez déjà d'un projet.
Ouvrez Xcode, accédez à File > New > Project, et sélectionnez le modèle App. Sur l'écran suivant, définissez Interface sur Storyboard et Language sur Swift.

Configurez les paramètres de votre projet, y compris
Bundle Identifier,SigningetMinimum Deployments.
Configurer votre projet
Étape 3 : Créer une interface utilisateur
Créez une interface utilisateur adaptée à votre scénario d'interaction en temps réel. Pour cet exemple d'appel vidéo multipersonne, créez un ScrollView. Lorsqu'un utilisateur rejoint l'appel, ajoutez une vue vidéo à ce conteneur. Lorsqu'un utilisateur quitte l'appel, supprimez sa vue vidéo et actualisez la mise en page.
Implémentation
Cette section explique comment utiliser le SDK ARTC pour créer une application audio et vidéo en temps réel de base. Copiez l'exemple de code pour effectuer un test rapide, puis suivez les étapes pour comprendre les appels d'API principaux.
Le diagramme suivant illustre le flux de travail de base pour un appel audio et vidéo en temps réel :
Exemple de code pour un scénario d'appel vidéo
Pour plus de détails sur l'exemple de code complet, consultez la rubrique Exécuter le projet de démonstration ARTC pour iOS.
1. Demander des autorisations
Bien que le SDK vérifie les autorisations nécessaires au démarrage d'un appel, nous vous recommandons de vérifier les autorisations d'accès à la caméra et au microphone avant d'initier un appel afin de garantir une expérience utilisateur fluide.
func checkMicrophonePermission(completion: @escaping (Bool) -> Void) {
let status = AVCaptureDevice.authorizationStatus(for: .audio)
switch status {
case .notDetermined:
AVCaptureDevice.requestAccess(for: .audio) { granted in
completion(granted)
}
case .authorized:
completion(true)
default:
completion(false)
}
}
func checkCameraPermission(completion: @escaping (Bool) -> Void) {
let status = AVCaptureDevice.authorizationStatus(for: .video)
switch status {
case .notDetermined:
AVCaptureDevice.requestAccess(for: .video) { granted in
completion(granted)
}
case .authorized:
completion(true)
default:
completion(false)
}
}
// Usage example
checkMicrophonePermission { granted in
if granted {
print("Microphone access granted.")
} else {
print("Microphone access denied.")
}
}
checkCameraPermission { granted in
if granted {
print("Camera access granted.")
} else {
print("Camera access denied.")
}
}
2. Obtenir un jeton d'authentification
La connexion à un channel ARTC nécessite un jeton d'authentification pour vérifier l'identité de l'utilisateur. Pour plus de détails sur la génération du jeton, consultez la rubrique Authentification par jeton. Un jeton peut être généré à l'aide d'une méthode à paramètre unique ou d'une méthode à plusieurs paramètres. La méthode utilisée détermine l'API joinChannel que vous devez appeler.
Pour les environnements de production :
Étant donné que la génération d'un jeton nécessite votre AppKey, le coder en dur côté client présente un risque de sécurité. Dans un environnement de production, nous vous recommandons vivement de générer le jeton sur votre serveur et de l'envoyer au client.
Pour le développement et le débogage :
Lors du développement, si votre serveur métier ne dispose pas encore de la logique de génération de jetons, vous pouvez utiliser temporairement la logique de génération de jetons d'APIExample pour créer un jeton temporaire. Le code de référence est le suivant :
class ARTCTokenHelper: NSObject {
/**
* RTC AppId
*/
public static let AppId = "<RTC AppId>"
/**
* RTC AppKey
*/
public static let AppKey = "<RTC AppKey>"
/**
* Generate a multi-parameter token for joining a channel based on channelId, userId, and timestamp.
*/
public func generateAuthInfoToken(appId: String = ARTCTokenHelper.AppId, appKey: String = ARTCTokenHelper.AppKey, channelId: String, userId: String, timestamp: Int64) -> String {
let stringBuilder = appId + appKey + channelId + userId + "\(timestamp)"
let token = ARTCTokenHelper.GetSHA256(stringBuilder)
return token
}
/**
* Generate a single-parameter token for joining a channel based on channelId, userId, and nonce.
*/
public func generateJoinToken(appId: String = ARTCTokenHelper.AppId, appKey: String = ARTCTokenHelper.AppKey, channelId: String, userId: String, timestamp: Int64, nonce: String = "") -> String {
let token = self.generateAuthInfoToken(appId: appId, appKey: appKey, channelId: channelId, userId: userId, timestamp: timestamp)
let tokenJson: [String: Any] = [
"appid": appId,
"channelid": channelId,
"userid": userId,
"nonce": nonce,
"timestamp": timestamp,
"token": token
]
if let jsonData = try? JSONSerialization.data(withJSONObject: tokenJson, options: []),
let base64Token = jsonData.base64EncodedString() as String? {
return base64Token
}
return ""
}
/**
* Sign a string using SHA256.
* String signing (SHA256)
*/
private static func GetSHA256(_ input: String) -> String {
// Convert input string to data.
let data = Data(input.utf8)
// Create a buffer to store the hash result.
var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
// Calculate the SHA-256 hash.
data.withUnsafeBytes {
_ = CC_SHA256($0.baseAddress, CC_LONG(data.count), &hash)
}
// Convert the hash to a hexadecimal string.
return hash.map { String(format: "%02hhx", $0) }.joined()
}
}
3. Importer le module SDK ARTC
// Import the ARTC module.
import AliVCSDK_ARTC
4. Créer et initialiser le moteur
-
Créer le moteur RTC
Appelez la méthode sharedInstance pour créer une instance d'
AliRtcEngine.private var rtcEngine: AliRtcEngine? = nil // Create the engine and set the delegate. let engine = AliRtcEngine.sharedInstance(self, extras:nil) ... self.rtcEngine = engine -
Initialiser le moteur
-
Appelez
setChannelProfilepour définir le canal surAliRTCInteractiveLive(mode interactif).Selon vos besoins métier, vous pouvez opter pour le mode interactif, adapté aux scénarios de divertissement en direct, ou pour le mode communication, idéal pour les diffusions un-à-un ou un-à-plusieurs. Le choix du mode approprié garantit une expérience utilisateur fluide et une utilisation efficace des ressources réseau.
Mode
Publication
Abonnement
Description
Mode interactif
Limité par le rôle. Seuls les utilisateurs ayant le rôle d'hôte peuvent publier des flux.
Les participants peuvent changer de rôle de manière flexible tout au long de la session.
Aucune restriction de rôle. Tous les participants sont autorisés à s'abonner aux flux.
En mode interactif, les événements tels que l'arrivée ou le départ d'un hôte dans le canal, ou le début de la publication d'un flux, sont notifiés aux spectateurs en temps réel. Inversement, les activités des spectateurs ne sont pas notifiées aux hôtes, ce qui assure une diffusion ininterrompue.
Dans ce mode, les hôtes gèrent l'interaction, tandis que les spectateurs se contentent de consommer le contenu. Si vos besoins métier sont susceptibles d'évoluer, envisagez d'utiliser le mode interactif par défaut. Sa flexibilité vous permet de vous adapter à différentes exigences d'interaction en ajustant les rôles des utilisateurs.
Mode communication
Aucune restriction de rôle. Tous les participants sont autorisés à publier des flux.
Aucune restriction de rôle. Tous les participants sont autorisés à s'abonner aux flux.
En mode communication, les participants sont conscients de la présence des autres.
Bien que ce mode ne différencie pas les rôles des utilisateurs, il est fonctionnellement équivalent au rôle d'hôte en mode interactif. L'objectif est de simplifier les opérations, permettant aux utilisateurs d'obtenir la fonctionnalité souhaitée avec moins d'appels API.
-
Appelez
setClientRolepour définir le rôle de l'utilisateur surAliRTCSdkInteractive(hôte) ouAliRTCSdkLive(spectateur). Par défaut, le rôle d'hôte publie et s'abonne aux flux, tandis que le rôle de spectateur ne fait que s'abonner, la prévisualisation locale et la publication étant désactivées.Remarque : Lorsqu'un utilisateur passe du rôle d'hôte à celui de spectateur, le système arrête la publication des flux audio et vidéo locaux, mais les abonnements existants ne sont pas affectés. Lorsqu'un utilisateur passe du rôle de spectateur à celui d'hôte, le système commence à publier les flux audio et vidéo locaux, sans affecter les abonnements existants.
// Set the channel profile to Interactive Mode. Use AliRtcInteractivelive for all RTC scenarios. engine.setChannelProfile(AliRtcChannelProfile.interactivelive) // Set the client role. Use AliRtcClientRoleInteractive for users who need to both publish and subscribe. Use AliRtcClientRolelive for users who only subscribe. engine.setClientRole(AliRtcClientRole.roleInteractive)
-
-
Implémenter les rappels courants
Si le SDK rencontre un problème lors de son exécution, il tente d'abord de se rétablir automatiquement grâce à ses mécanismes internes de nouvelle tentative. Pour les erreurs qu'il ne peut pas résoudre seul, le SDK notifie votre application via des interfaces de rappel prédéfinies.
Voici les principaux rappels pour les problèmes que le SDK ne peut pas gérer, auxquels votre application doit écouter et répondre :
Cause de l'exception
Rappel et paramètres
Solution
Description
Échec de l'authentification
Le paramètre result dans onJoinChannelResult renvoie AliRtcErrJoinBadToken.
L'application doit vérifier si le jeton est correct.
Lorsqu'un utilisateur appelle une API, si l'authentification échoue, le rappel de l'API renvoie une erreur d'échec d'authentification.
Expiration imminente du jeton
onAuthInfoWillExpire
Récupérez un nouveau jeton et appelez refreshAuthInfo pour mettre à jour les informations.
Une erreur d'expiration de jeton peut survenir lors de l'appel d'une API ou pendant l'exécution. L'erreur est signalée via les rappels d'API ou un rappel d'erreur distinct.
Jeton expiré
onAuthInfoExpired
L'application doit rejoindre à nouveau le canal.
Une erreur d'expiration de jeton peut survenir lors de l'appel d'une API ou pendant l'exécution. L'erreur est signalée via les rappels d'API ou un rappel d'erreur distinct.
Problème de connexion réseau
Le rappel onConnectionStatusChange renvoie AliRtcConnectionStatusFailed.
L'application doit rejoindre à nouveau le canal.
Le SDK peut se rétablir automatiquement après de brèves déconnexions réseau. Si la durée de déconnexion dépasse un seuil, un délai d'attente se produit. L'application doit vérifier l'état du réseau et guider l'utilisateur pour qu'il rejoigne à nouveau le canal.
Expulsion du canal
onBye
AliRtcOnByeUserReplaced : Vérifiez si un autre utilisateur a rejoint avec le même userId.
AliRtcOnByeBeKickedOut : L'utilisateur a été expulsé du canal et doit le rejoindre à nouveau.
AliRtcOnByeChannelTerminated : Le canal a été terminé et l'utilisateur doit le rejoindre à nouveau.
Le service RTC permet à un administrateur de supprimer des participants.
Exception de l'appareil local
onLocalDeviceException
Vérifiez les permissions de l'application et le bon fonctionnement du matériel.
Lorsqu'une exception de l'appareil local survient et que le SDK ne peut pas la résoudre, il en informe l'application via un rappel. L'application doit alors intervenir pour vérifier l'état de l'appareil.
extension VideoCallMainVC: AliRtcEngineDelegate { func onJoinChannelResult(_ result: Int32, channel: String, elapsed: Int32) { "onJoinChannelResult1 result: \(result)".printLog() } func onJoinChannelResult(_ result: Int32, channel: String, userId: String, elapsed: Int32) { "onJoinChannelResult2 result: \(result)".printLog() } func onRemoteUser(onLineNotify uid: String, elapsed: Int32) { // A remote user comes online. "onRemoteUserOlineNotify uid: \(uid)".printLog() } func onRemoteUserOffLineNotify(_ uid: String, offlineReason reason: AliRtcUserOfflineReason) { // A remote user goes offline. "onRemoteUserOffLineNotify uid: \(uid) reason: \(reason)".printLog() } func onRemoteTrackAvailableNotify(_ uid: String, audioTrack: AliRtcAudioTrack, videoTrack: AliRtcVideoTrack) { "onRemoteTrackAvailableNotify uid: \(uid) audioTrack: \(audioTrack) videoTrack: \(videoTrack)".printLog() } func onAuthInfoWillExpire() { "onAuthInfoWillExpire".printLog() /* TODO: Must handle. The token is about to expire. Your app needs to get a new token for the current channel and user, then call refreshAuthInfo. */ } func onAuthInfoExpired() { "onAuthInfoExpired".printLog() /* TODO: Must handle. Notify the user that the token has expired, then leave the channel and destroy the engine. */ } func onBye(_ code: Int32) { "onBye code: \(code)".printLog() /* TODO: Must handle. This callback is triggered if another device logs in with the same UserID, kicking the current device out of the channel. */ } func onLocalDeviceException(_ deviceType: AliRtcLocalDeviceType, exceptionType: AliRtcLocalDeviceExceptionType, message msg: String?) { "onLocalDeviceException deviceType: \(deviceType) exceptionType: \(exceptionType)".printLog() /* TODO: Must handle. We recommend notifying the user of a device error. This callback is triggered when the SDK's internal recovery strategies have failed.*/ } func onConnectionStatusChange(_ status: AliRtcConnectionStatus, reason: AliRtcConnectionStatusChangeReason) { "onConnectionStatusChange status: \(status) reason: \(reason)".printLog() if status == .failed { /* TODO: Must handle. We recommend notifying the user. This callback is triggered when the SDK's internal recovery strategies have failed. */ } else { /* TODO: Optional. You can add business logic here, typically for analytics or UI updates. */ } } }
5. Définir les propriétés audio et vidéo
-
Définir les propriétés audio
Appelez
setAudioProfilepour définir le mode d'encodage audio et le scénario.// Set the audio profile. The default is high-quality mode (AliRtcEngineHighQualityMode) and music scenario (AliRtcSceneMusicMode). engine.setAudioProfile(AliRtcAudioProfile.engineHighQualityMode, audio_scene: AliRtcAudioScenario.sceneMusicMode) -
Définir les propriétés vidéo
Définissez les propriétés du flux vidéo publié, telles que la résolution, le débit binaire et la fréquence d'images.
// Set the video encoder configuration. let config = AliRtcVideoEncoderConfiguration() config.dimensions = CGSize(width: 720, height: 1280) config.frameRate = 20 config.bitrate = 1200 config.keyFrameInterval = 2000 config.orientationMode = AliRtcVideoEncoderOrientationMode.adaptive engine.setVideoEncoderConfiguration(config) engine.setCapturePipelineScaleMode(.post)
6. Définir les propriétés de publication et d'abonnement
Configurez la publication des flux audio/vidéo et définissez l'abonnement par défaut à tous les flux des utilisateurs :
Appelez
publishLocalAudioStreampour publier un flux audio.Appelez
publishLocalVideoStreampour publier un flux vidéo. Pour un appel audio uniquement, vous pouvez définir cette valeur sur false.
// By default, the SDK publishes the audio stream. Calling publishLocalAudioStream(true) is optional.
engine.publishLocalVideoStream(true)
// By default, the SDK publishes the video stream. For a video call, calling publishLocalVideoStream(true) is optional.
// To stop publishing video for a voice-only call, call publishLocalVideoStream(false).
engine.publishLocalAudioStream(true)
// Set the default to subscribe to all remote audio and video streams.
engine.setDefaultSubscribeAllRemoteAudioStreams(true)
engine.subscribeAllRemoteAudioStreams(true)
engine.setDefaultSubscribeAllRemoteVideoStreams(true)
engine.subscribeAllRemoteVideoStreams(true)
Par défaut, le SDK publie automatiquement les flux audio et vidéo locaux et s'abonne aux flux audio et vidéo de tous les autres utilisateurs du canal. Vous pouvez appeler les méthodes ci-dessus pour remplacer ce comportement par défaut.
7. Démarrer la prévisualisation locale
Appelez
setLocalViewConfigpour configurer la vue de rendu locale et les propriétés d'affichage vidéo locales.Appelez la méthode
startPreviewpour démarrer la prévisualisation vidéo locale.
let videoView = self.createVideoView(uid: self.userId)
let canvas = AliVideoCanvas()
canvas.view = videoView.canvasView
canvas.renderMode = .auto
canvas.mirrorMode = .onlyFrontCameraPreviewEnabled
canvas.rotationMode = ._0
self.rtcEngine?.setLocalViewConfig(canvas, for: AliRtcVideoTrack.camera)
self.rtcEngine?.startPreview()
8. Rejoindre un canal
Appelez joinChannel pour rejoindre le canal. Si le jeton a été généré à l'aide de la méthode à paramètre unique, appelez l'opération [joinChannel[3/3]](t2309850.xdita#7ab2c22015zro). Le résultat est renvoyé dans le rappel onJoinChannelResult. Une valeur result de 0 indique une jonction réussie. Une valeur non nulle peut indiquer un jeton invalide.
let ret = self.rtcEngine?.joinChannel(joinToken, channelId: nil, userId: nil, name: nil) { [weak self] errCode, channelId, userId, elapsed in
if errCode == 0 {
// success
}
else {
// failed
}
let resultMsg = "\(msg) \n CallbackErrorCode: \(errCode)"
resultMsg.printLog()
UIAlertController.showAlertWithMainThread(msg: resultMsg, vc: self!)
}
let resultMsg = "\(msg) \n ReturnErrorCode: \(ret ?? 0)"
resultMsg.printLog()
if ret != 0 {
UIAlertController.showAlertWithMainThread(msg: resultMsg, vc: self)
}
Après avoir rejoint le canal, le SDK publiera et s'abonnera aux flux selon les paramètres définis avant la jonction.
Le SDK publie et s'abonne automatiquement par défaut afin de réduire le nombre d'appels API que le client doit effectuer.
9. Définir la vue distante
Lorsqu'un utilisateur distant commence ou arrête de publier un flux, le rappel onRemoteTrackAvailableNotify est déclenché. Dans ce rappel, vous pouvez configurer ou supprimer la vue de l'utilisateur distant. Exemple de code :
func onRemoteTrackAvailableNotify(_ uid: String, audioTrack: AliRtcAudioTrack, videoTrack: AliRtcVideoTrack) {
"onRemoteTrackAvailableNotify uid: \(uid) audioTrack: \(audioTrack) videoTrack: \(videoTrack)".printLog()
// Stream status of a remote user.
if audioTrack != .no {
let videoView = self.videoViewList.first { $0.uidLabel.text == uid }
if videoView == nil {
_ = self.createVideoView(uid: uid)
}
}
if videoTrack != .no {
var videoView = self.videoViewList.first { $0.uidLabel.text == uid }
if videoView == nil {
videoView = self.createVideoView(uid: uid)
}
let canvas = AliVideoCanvas()
canvas.view = videoView!.canvasView
canvas.renderMode = .auto
canvas.mirrorMode = .onlyFrontCameraPreviewEnabled
canvas.rotationMode = ._0
self.rtcEngine?.setRemoteViewConfig(canvas, uid: uid, for: AliRtcVideoTrack.camera)
}
else {
self.rtcEngine?.setRemoteViewConfig(nil, uid: uid, for: AliRtcVideoTrack.camera)
}
if audioTrack == .no && videoTrack == .no {
self.removeVideoView(uid: uid)
self.rtcEngine?.setRemoteViewConfig(nil, uid: uid, for: AliRtcVideoTrack.camera)
}
}
10. Quitter le canal et détruire le moteur
Lorsque la session se termine, quittez le canal et détruisez le moteur pour libérer les ressources :
Appelez
stopPreviewpour arrêter la prévisualisation vidéo.Appelez
leaveChannelpour quitter le canal.Appelez
destroypour détruire le moteur et libérer les ressources associées.
self.rtcEngine?.stopPreview()
self.rtcEngine?.leaveChannel()
AliRtcEngine.destroy()
self.rtcEngine = nil
11. Démonstration de l'effet

