Zoom Video SDK - Développement Windows
Conseils d'experts pour développer avec le Zoom Video SDK sur Windows. Ce SDK permet des applications vidéo personnalisées, la capture/injection de médias bruts, l'enregistrement cloud, la diffusion en direct et la transcription en temps réel sur les plateformes Windows.
Documentation officielle : https://developers.zoom.us/docs/video-sdk/windows/ Référence API : https://marketplacefront.zoom.us/sdk/custom/windows/ Dépôt d'exemples : https://github.com/zoom/videosdk-windows-rawdata-sample
Liens rapides
Nouveau sur Video SDK ? Suivez ce parcours :
- Modèle d'architecture SDK - Modèle universel en 3 étapes pour TOUTE fonctionnalité
- Modèle de jointure de session - Code fonctionnel complet pour rejoindre une session
- Boucle de messages Windows - CRITIQUE : Corrigez les callbacks qui ne se déclenchent pas
- Rendu vidéo - Afficher la vidéo avec Canvas API
Référence :
- Hiérarchie Singleton - Carte de navigation SDK sur 5 niveaux
- Référence API - Méthodes, codes d'erreur, règles de timing
- Méthodes Delegate - Les 80+ méthodes de callback
- Exemples d'applications - Guide des exemples officiels
- windows.md - Document de vue d'ensemble secondaire (style pointeur)
- SKILL.md - Navigation complète de la documentation
Vous avez des problèmes ?
- Les callbacks ne se déclenchent pas → Boucle de messages Windows
- Erreurs de compilation → Guide des erreurs de compilation
- L'abonnement vidéo échoue → Rendu vidéo (s'abonner dans
onUserVideoStatusChanged) - Diagnostics rapides → Problèmes courants
Créer une interface utilisateur personnalisée ?
- Canvas vs Raw Data - Choisissez votre approche de rendu
- Capture vidéo brute - Traitement des trames YUV420
Vue d'ensemble du SDK
Le Zoom Video SDK pour Windows est une bibliothèque C++ qui fournit :
- Gestion de session : Rejoindre/quitter les sessions du SDK vidéo
- Accès aux données brutes : Capturer les trames audio/vidéo brutes (YUV420, PCM)
- Injection de données brutes : Envoyer de l'audio/vidéo personnalisé dans les sessions
- Partage d'écran : Partager les écrans ou injecter des sources de partage personnalisées
- Enregistrement cloud : Enregistrer les sessions sur le cloud Zoom
- Diffusion en direct : Diffuser vers des points de terminaison RTMP (YouTube, etc.)
- Chat et commandes : Messagerie en session et canaux de commande
- Transcription en direct : Conversion parole-texte en temps réel
- Sous-sessions : Support des salles de réunion
- Tableau blanc : Fonctionnalités collaboratives de tableau blanc
- Annotations : Annotations de partage d'écran
- Intégration C# : Wrapper C++/CLI pour les applications .NET
Prérequis
Configuration requise du système
- OS : Windows 10 (1903 ou version ultérieure) ou Windows 11
- Architecture : x64 (recommandé), x86 ou ARM64
- Visual Studio : 2019 ou 2022 (Community, Professional ou Enterprise)
- Windows SDK : 10.0.19041.0 ou version ultérieure
- .NET Framework : 4.8 ou version ultérieure (pour les applications C#)
Charges de travail Visual Studio
Installez ces charges de travail via Visual Studio Installer :
-
Développement de bureau avec C++
- Compilateur MSVC v142 ou v143
- SDK Windows 10/11
- Outils CMake C++ (optionnel)
-
Développement de bureau .NET (pour les applications C#)
- Pack de ciblage .NET Framework 4.8
- Support C++/CLI
Démarrage rapide
Application C++
#include <windows.h>
#include "zoom_video_sdk_api.h"
#include "zoom_video_sdk_interface.h"
#include "zoom_video_sdk_delegate_interface.h"
USING_ZOOM_VIDEO_SDK_NAMESPACE
// 1. Créer l'objet SDK
IZoomVideoSDK* video_sdk_obj = CreateZoomVideoSDKObj();
// 2. Initialiser
ZoomVideoSDKInitParams init_params;
init_params.domain = L"https://zoom.us";
init_params.enableLog = true;
init_params.logFilePrefix = L"zoom_win_video";
init_params.videoRawDataMemoryMode = ZoomVideoSDKRawDataMemoryModeHeap;
init_params.shareRawDataMemoryMode = ZoomVideoSDKRawDataMemoryModeHeap;
init_params.audioRawDataMemoryMode = ZoomVideoSDKRawDataMemoryModeHeap;
ZoomVideoSDKErrors err = video_sdk_obj->initialize(init_params);
// 3. Ajouter l'écouteur d'événements
video_sdk_obj->addListener(myDelegate);
// 4. Rejoindre la session (IMPORTANT : définir audioOption.connect = false)
ZoomVideoSDKSessionContext session_context;
session_context.sessionName = L"my-session";
session_context.userName = L"Windows User";
session_context.token = L"your-jwt-token";
session_context.videoOption.localVideoOn = false;
session_context.audioOption.connect = false; // Connecter l'audio après la jointure
session_context.audioOption.mute = true;
IZoomVideoSDKSession* session = video_sdk_obj->joinSession(session_context);
// 5. CRITIQUE : Ajouter la pompe de messages Windows pour que les callbacks fonctionnent
bool running = true;
while (running) {
// Traiter les messages Windows (obligatoire pour les callbacks du SDK)
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Logique de votre application ici
Sleep(10);
}
Application C
using ZoomVideoSDK;
var sdkManager = new ZoomSDKManager();
sdkManager.Initialize();
sdkManager.JoinSession("my-session", "jwt-token", "User Name", "");
Fonctionnalités clés
| Fonctionnalité | Description |
|---|---|
| Gestion de session | Rejoindre, quitter et gérer les sessions vidéo |
| Vidéo brute (YUV I420) | Capturer et injecter des trames vidéo brutes |
| Audio brut (PCM) | Capturer et injecter des données audio brutes |
| Partage d'écran | Partager les écrans ou le contenu personnalisé |
| Enregistrement cloud | Enregistrer les sessions sur le cloud Zoom |
| Diffusion en direct | Diffuser vers les points de terminaison RTMP |
| Chat | Envoyer/recevoir des messages de chat |
| Canal de commande | Messagerie de commande personnalisée |
| Transcription en direct | Conversion parole-texte en temps réel |
| Support C# | Intégration complète .NET Framework |
Exemples d'applications
Dépôt officiel : https://github.com/zoom/videosdk-windows-rawdata-sample
| Exemple | Description |
|---|---|
| VSDK_SkeletonDemo | Jointure de session minimale - commencez ici |
| VSDK_getRawVideo | Capturer les trames vidéo YUV420 |
| VSDK_getRawAudio | Capturer l'audio PCM |
| VSDK_sendRawVideo | Injecter une vidéo personnalisée (caméra virtuelle) |
| VSDK_sendRawAudio | Injecter un audio personnalisé (microphone virtuel) |
| VSDK_CloudRecording | Contrôle de l'enregistrement cloud |
| VSDK_CommandChannel | Messagerie de commande personnalisée |
| VSDK_TranscriptionAndTranslation | Légendes en direct |
Voir le guide complet : Référence des exemples d'applications
Points critiques à éviter et bonnes pratiques
⚠️ CRITIQUE : Pompe de messages Windows obligatoire
Le problème n°1 qui provoque la suspension des jointures de session sans callbacks :
Toutes les applications Windows utilisant le SDK Zoom DOIVENT traiter les messages Windows. Le SDK utilise les messages Windows pour livrer les callbacks comme onSessionJoin(), onError(), etc.
Problème : Sans pompe de messages, joinSession() semble réussir mais les callbacks ne se déclenchent jamais.
Solution : Ajoutez ceci à votre boucle principale :
while (running) {
// OBLIGATOIRE : Traiter les messages Windows
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Logique de votre application
Sleep(10);
}
S'applique à :
- Applications console (pas de pompe de messages automatique)
- Boucles principales personnalisées
- Applications qui n'utilisent pas WinMain/WndProc standard
Les applications GUI utilisant WinMain avec boucle de messages standard ont déjà ceci.
Stratégie de connexion audio
Bonne pratique : Définir audioOption.connect = false lors de la jointure, puis connecter l'audio dans le callback onSessionJoin().
// Lors de la jointure
session_context.audioOption.connect = false; // Ne pas connecter encore
session_context.audioOption.mute = true;
// Dans le callback onSessionJoin()
void onSessionJoin() override {
IZoomVideoSDKAudioHelper* audioHelper = video_sdk_obj->getAudioHelper();
if (audioHelper) {
audioHelper->startAudio(); // Connecter maintenant
}
}
Pourquoi : Ce modèle est utilisé dans tous les exemples officiels de Zoom. Il sépare la jointure de session de l'initialisation de l'audio pour une meilleure fiabilité et gestion d'erreurs.
Tous les callbacks Delegate doivent être implémentés
L'interface IZoomVideoSDKDelegate a plus de 70 méthodes virtuelles pures. TOUS doivent être implémentés, même s'ils sont vides :
// Obligatoire même si vous ne les utilisez pas
void onProxyDetectComplete() override {}
void onUserWhiteboardShareStatusChanged(IZoomVideoSDKUser*, IZoomVideoSDKWhiteboardHelper*) override {}
// ... etc
Conseil : Vérifiez le zoom_video_sdk_delegate_interface.h de la version du SDK pour la liste complète. L'interface change entre les versions du SDK.
Mode mémoire pour les données brutes
Utilisez toujours le mode heap pour la mémoire des données brutes :
init_params.videoRawDataMemoryMode = ZoomVideoSDKRawDataMemoryModeHeap;
init_params.shareRawDataMemoryMode = ZoomVideoSDKRawDataMemoryModeHeap;
init_params.audioRawDataMemoryMode = ZoomVideoSDKRawDataMemoryModeHeap;
Le mode stack peut causer des problèmes avec les grandes trames vidéo.
Sécurité des threads
Les callbacks du SDK s'exécutent sur les threads du SDK, pas sur votre thread principal :
- Ne pas effectuer d'opérations lourdes dans les callbacks
- Ne pas appeler
cleanup()depuis les callbacks - Utiliser des files d'attente thread-safe pour passer les données au thread UI
- Utiliser des mutexes lors de l'accès à l'état partagé
Consulter d'abord les exemples officiels
Lorsque le comportement du SDK est inattendu, toujours vérifier les exemples officiels avant le dépannage :
Exemples locaux :
C:\tempsdk\Zoom_VideoSDK_Windows_RawDataDemos\VSDK_SkeletonDemo\(le plus simple)C:\tempsdk\sdksamples\zoom-video-sdk-windows-2.4.12\Sample-Libs\x64\demo\
Les exemples officiels montrent les modèles corrects pour :
- Implémentation de la pompe de messages ✓
- Stratégie de connexion audio ✓
- Gestion d'erreurs ✓
- Gestion de la mémoire ✓
Rendu vidéo - Deux approches
Le SDK Zoom fournit deux façons différentes de rendre la vidéo. Choisissez en fonction de vos besoins.
🎯 Canvas API (recommandée pour la plupart des cas)
Idéale pour : Applications standard, qualité vidéo optimale, facilité de mise en œuvre
Le SDK rend la vidéo directement à votre HWND. Aucune conversion YUV nécessaire.
// S'abonner à la vidéo d'un utilisateur avec Canvas API
IZoomVideoSDKCanvas* canvas = user->GetVideoCanvas();
if (canvas) {
ZoomVideoSDKErrors ret = canvas->subscribeWithView(
hwnd, // Votre handle de fenêtre
ZoomVideoSDKVideoAspect_PanAndScan, // Adapter à la fenêtre, peut recadrer
ZoomVideoSDKResolution_Auto // Laisser le SDK choisir la meilleure résolution
);
if (ret == ZoomVideoSDKErrors_Success) {
// Le SDK rend maintenant directement à votre fenêtre !
}
}
// Vous désabonner quand vous avez fini
canvas->unSubscribeWithView(hwnd);
Avantages :
- ✅ Meilleure qualité - Le SDK utilise un rendu optimisé, accéléré matériellement
- ✅ Aucun artefact - Qualité vidéo professionnelle
- ✅ Code simple - 3 lignes pour s'abonner
- ✅ Meilleures performances - Pas de conversion YUV gourmande en CPU
- ✅ Mise à l'échelle automatique - Le SDK gère le redimensionnement de la fenêtre
- ✅ Rapport d'aspect - Gestion du rapport d'aspect intégrée
Exemple de l'exemple officiel .NET :
// Aperçu de votre vidéo
IZoomVideoSDKCanvas* canvas = myself->GetVideoCanvas();
canvas->subscribeWithView(selfVideoHwnd, aspect, resolution);
// Vidéo de l'utilisateur distant
IZoomVideoSDKCanvas* remoteCanvas = remoteUser->GetVideoCanvas();
remoteCanvas->subscribeWithView(remoteVideoHwnd, aspect, resolution);
Options d'aspect vidéo :
ZoomVideoSDKVideoAspect_Original- Letterbox/pillarbox, pas de recadrageZoomVideoSDKVideoAspect_FullFilled- Remplir la fenêtre, peut recadrer les bordsZoomVideoSDKVideoAspect_PanAndScan- Recadrage intelligent pour remplir la fenêtreZoomVideoSDKVideoAspect_LetterBox- Afficher la vidéo complète avec barres noires
Options de résolution :
ZoomVideoSDKResolution_90PZoomVideoSDKResolution_180PZoomVideoSDKResolution_360P- Bon équilibreZoomVideoSDKResolution_720P- Qualité HDZoomVideoSDKResolution_1080PZoomVideoSDKResolution_Auto- Laisser le SDK décider (recommandé)
🔧 Raw Data Pipe (Cas d'usage avancés)
Idéale pour : Traitement vidéo personnalisé, effets, enregistrement, vision par ordinateur
Vous recevez les trames YUV420 brutes et gérez le rendu vous-même.
// 1. Créer un delegate pour recevoir les trames
class VideoRenderer : public IZoomVideoSDKRawDataPipeDelegate {
public:
void onRawDataFrameReceived(YUVRawDataI420* data) override {
int width = data->GetStreamWidth();
int height = data->GetStreamHeight();
char* yBuffer = data->GetYBuffer();
char* uBuffer = data->GetUBuffer();
char* vBuffer = data->GetVBuffer();
// Convertir YUV420 en RGB et rendre
ConvertYUVToRGB(yBuffer, uBuffer, vBuffer, width, height);
RenderToWindow(rgbBuffer, width, height);
}
void onRawDataStatusChanged(RawDataStatus status) override {
// Gérer vidéo on/off
}
};
// 2. S'abonner aux données brutes
IZoomVideoSDKRawDataPipe* pipe = user->GetVideoPipe();
VideoRenderer* renderer = new VideoRenderer();
pipe->subscribe(ZoomVideoSDKResolution_720P, renderer);
Conversion YUV420 vers RGB (ITU-R BT.601) :
void ConvertYUV420ToRGB(char* yBuffer, char* uBuffer, char* vBuffer,
int width, int height) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int yIndex = y * width + x;
int uvIndex = (y / 2) * (width / 2) + (x / 2);
int Y = (unsigned char)yBuffer[yIndex];
int U = (unsigned char)uBuffer[uvIndex];
int V = (unsigned char)vBuffer[uvIndex];
// Conversion YUV vers RGB
int C = Y - 16;
int D = U - 128;
int E = V - 128;
int R = (298 * C + 409 * E + 128) >> 8;
int G = (298 * C - 100 * D - 208 * E + 128) >> 8;
int B = (298 * C + 516 * D + 128) >> 8;
// Limiter à [0, 255]
R = (R < 0) ? 0 : (R > 255) ? 255 : R;
G = (G < 0) ? 0 : (G > 255) ? 255 : G;
B = (B < 0) ? 0 : (B > 255) ? 255 : B;
// Stocker RGB (format BGR pour Windows)
rgbBuffer[yIndex * 3 + 0] = (unsigned char)B;
rgbBuffer[yIndex * 3 + 1] = (unsigned char)G;
rgbBuffer[yIndex * 3 + 2] = (unsigned char)R;
}
}
}
Rendre avec GDI :
void RenderToWindow(unsigned char* rgbBuffer, int width, int height) {
HDC hdc = GetDC(hwnd);
BITMAPINFO bmi = {};
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = width;
bmi.bmiHeader.biHeight = -height; // Négatif pour top-down
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 24; // RGB 24-bit
bmi.bmiHeader.biCompression = BI_RGB;
RECT rect;
GetClientRect(hwnd, &rect);
StretchDIBits(hdc,
0, 0, rect.right, rect.bottom, // Destination
0, 0, width, height, // Source
rgbBuffer, &bmi,
DIB_RGB_COLORS, SRCCOPY);
ReleaseDC(hwnd, hdc);
}
Inconvénients :
- ⚠️ Gourmand en CPU - La conversion YUV peut causer des pertes de trames
- ⚠️ Artefacts - Le rendu manuel peut montrer des déchirures/artefacts
- ⚠️ Complexe - Plus de code à maintenir
- ⚠️ Performance - Plus lent que Canvas API
Utiliser Raw Data quand :
- Ajouter des filtres/effets vidéo
- Enregistrer dans des formats personnalisés
- Traitement de vision par ordinateur
- Composition personnalisée
- Diffuser vers des sorties non-standard
Votre vidéo vs Utilisateurs distants
Votre vidéo (votre propre caméra) :
Option A : Canvas API
IZoomVideoSDKSession* session = sdk->getSessionInfo();
IZoomVideoSDKUser* myself = session->getMyself();
IZoomVideoSDKCanvas* canvas = myself->GetVideoCanvas();
canvas->subscribeWithView(selfVideoHwnd, aspect, resolution);
Option B : Aperçu vidéo (pour vous seul)
IZoomVideoSDKVideoHelper* videoHelper = sdk->getVideoHelper();
videoHelper->startVideo(); // Démarrer la transmission
// Pour le rendu d'aperçu
videoHelper->startVideoCanvasPreview(selfVideoHwnd, aspect, resolution);
Utilisateurs distants (autres participants) :
Canvas API (recommandée) :
// Dans le callback onUserJoin
void onUserJoin(IZoomVideoSDKUserHelper*, IVideoSDKVector<IZoomVideoSDKUser*>* userList) {
for (int i = 0; i < userList->GetCount(); i++) {
IZoomVideoSDKUser* user = userList->GetItem(i);
IZoomVideoSDKCanvas* canvas = user->GetVideoCanvas();
canvas->subscribeWithView(userVideoHwnd, aspect, resolution);
}
}
Modèle d'abonnement piloté par les événements
⚠️ CRITIQUE : L'abonnement vidéo doit être piloté par les événements et manuel.
Événements clés :
onSessionJoin- S'abonner à votre vidéoonUserJoin- S'abonner aux nouveaux utilisateurs distantsonUserVideoStatusChanged- Se réabonner quand la vidéo s'allume/éteintonUserLeave- Se désabonner et nettoyer
Modèle complet :
class MainFrame : public IZoomVideoSDKDelegate {
private:
std::map<IZoomVideoSDKUser*, IZoomVideoSDKCanvas*> subscribedUsers_;
HWND videoWindow_;
public:
void onSessionJoin() override {
// Démarrer votre vidéo
IZoomVideoSDKVideoHelper* videoHelper = sdk->getVideoHelper();
videoHelper->startVideo();
// S'abonner à votre vidéo
IZoomVideoSDKUser* myself = sdk->getSessionInfo()->getMyself();
SubscribeToUser(myself);
}
void onUserJoin(IZoomVideoSDKUserHelper*,
IVideoSDKVector<IZoomVideoSDKUser*>* userList) override {
// Obtenir l'utilisateur actuel pour l'exclure
IZoomVideoSDKUser* myself = sdk->getSessionInfo()->getMyself();
for (int i = 0; i < userList->GetCount(); i++) {
IZoomVideoSDKUser* user = userList->GetItem(i);
// IMPORTANT : S'abonner UNIQUEMENT aux utilisateurs DISTANTS !
if (user != myself) {
SubscribeToUser(user);
}
}
}
void onUserVideoStatusChanged(IZoomVideoSDKVideoHelper*,
IVideoSDKVector<IZoomVideoSDKUser*>* userList) override {
IZoomVideoSDKUser* myself = sdk->getSessionInfo()->getMyself();
for (int i = 0; i < userList->GetCount(); i++) {
IZoomVideoSDKUser* user = userList->GetItem(i);
if (user != myself) {
// Se réabonner quand le statut vidéo change
SubscribeToUser(user);
}
}
}
void onUserLeave(IZoomVideoSDKUserHelper*,
IVideoSDKVector<IZoomVideoSDKUser*>* userList) override {
for (int i = 0; i < userList->GetCount(); i++) {
IZoomVideoSDKUser* user = userList->GetItem(i);
UnsubscribeFromUser(user);
}
}
void onSessionLeave() override {
// Nettoyer tous les abonnements
for (auto& pair : subscribedUsers_) {
IZoomVideoSDKCanvas* canvas = pair.second;
if (canvas) {
canvas->unSubscribeWithView(videoWindow_);
}
}
subscribedUsers_.clear();
}
private:
void SubscribeToUser(IZoomVideoSDKUser* user) {
if (!user || subscribedUsers_.find(user) != subscribedUsers_.end())
return;
IZoomVideoSDKCanvas* canvas = user->GetVideoCanvas();
if (canvas) {
ZoomVideoSDKErrors ret = canvas->subscribeWithView(
videoWindow_,
ZoomVideoSDKVideoAspect_PanAndScan,
ZoomVideoSDKResolution_Auto
);
if (ret == ZoomVideoSDKErrors_Success) {
subscribedUsers_[user] = canvas;
}
}
}
void UnsubscribeFromUser(IZoomVideoSDKUser* user) {
auto it = subscribedUsers_.find(user);
if (it != subscribedUsers_.end()) {
IZoomVideoSDKCanvas* canvas = it->second;
if (canvas) {
canvas->unSubscribeWithView(videoWindow_);
}
subscribedUsers_.erase(it);
}
}
};
Points clés :
- ✅ S'abonner en réponse aux événements (onUserJoin, onUserVideoStatusChanged)
- ✅ Toujours exclure l'utilisateur actuel des abonnements distants
- ✅ Se désabonner sur onUserLeave
- ✅ Nettoyer tous les abonnements sur onSessionLeave
- ✅ Suivre les abonnements dans une carte pour la gestion du cycle de vie
⚠️ Abonnement au partage d'écran (DIFFÉRENT de la vidéo !)
CRITIQUE : L'abonnement au partage d'écran utilise IZoomVideoSDKShareAction du callback, PAS user->GetShareCanvas() !
// INCORRECT - Cela ne fonctionnera pas pour les partages d'écran distants !
user->GetShareCanvas()->subscribeWithView(hwnd, ...);
// CORRECT - Utiliser IZoomVideoSDKShareAction du callback onUserShareStatusChanged
void onUserShareStatusChanged(IZoomVideoSDKShareHelper* pShareHelper,
IZoomVideoSDKUser* pUser,
IZoomVideoSDKShareAction* pShareAction) {
if (!pShareAction) return;
ZoomVideoSDKShareStatus status = pShareAction->getShareStatus();
if (status == ZoomVideoSDKShareStatus_Start ||
status == ZoomVideoSDKShareStatus_Resume) {
// S'abonner au partage avec Canvas API
IZoomVideoSDKCanvas* shareCanvas = pShareAction->getShareCanvas();
if (shareCanvas) {
shareCanvas->subscribeWithView(shareWindow_,
ZoomVideoSDKVideoAspect_Original);
}
}
else if (status == ZoomVideoSDKShareStatus_Stop) {
// Se désabonner quand le partage s'arrête
IZoomVideoSDKCanvas* shareCanvas = pShareAction->getShareCanvas();
if (shareCanvas) {
shareCanvas->unSubscribeWithView(shareWindow_);
}
}
}
Pourquoi le partage est-il différent de la vidéo ?
- Vidéo : Chaque utilisateur a un flux vidéo → utiliser
user->GetVideoCanvas() - Partage : Un utilisateur peut avoir plusieurs actions de partage (partage multi) → utiliser
IZoomVideoSDKShareAction*du callback - L'objet
IZoomVideoSDKShareActionreprésente un flux de partage spécifique et contient le statut de partage, le type et les interfaces de rendu
Voir aussi : Exemple d'abonnement au partage d'écran
Disposition vidéo multi-utilisateur
Pour plusieurs participants, vous avez besoin d'un HWND par utilisateur :
// Créer des fenêtres/panneaux séparés pour chaque utilisateur
HWND selfVideoWindow = CreateWindow(...); // Votre vidéo
HWND user1Window = CreateWindow(...); // Vidéo de l'utilisateur 1
HWND user2Window = CreateWindow(...); // Vidéo de l'utilisateur 2
// S'abonner chaque utilisateur à sa propre fenêtre
myself->GetVideoCanvas()->subscribeWithView(selfVideoWindow, ...);
user1->GetVideoCanvas()->subscribeWithView(user1Window, ...);
user2->GetVideoCanvas()->subscribeWithView(user2Window, ...);
Stratégies de disposition :
- Grille (2x2, 3x3)
- Vue galerie (défilement)
- Orateur actif (grand) + vignettes
- Image dans l'image
Problèmes vidéo courants
| Problème | Cause | Solution |
|---|---|---|
| Vidéo qui ne s'affiche pas | N'appelant pas startVideo() |
Appeler videoHelper->startVideo() dans onSessionJoin |
| Artefacts/déchirures | Utiliser Raw Data Pipe | Basculer vers Canvas API |
| Mauvaises performances | Conversion YUV sur le thread UI | Utiliser Canvas API ou déplacer la conversion vers un thread de travail |
| Vidéo figée | Ne pas traiter les messages Windows | Ajouter pompe de messages à la boucle principale |
| Ne pas se voir | S'abonner au mauvais utilisateur | Utiliser session->getMyself() pour votre vidéo |
| Se voir dans la liste distante | Ne pas exclure soi-même | Vérifier if (user != myself) avant de s'abonner |
Bibliothèque de documentation complète
Cette skill inclut des guides complets organisés par catégorie :
Concepts fondamentaux (Commencez ici !)
- Modèle d'architecture SDK - Modèle universel en 3 étapes pour TOUTE fonctionnalité
- Hiérarchie Singleton - Guide de navigation sur 5 niveaux
- Canvas vs Raw Data - Choisissez votre approche de rendu
Exemples complets
- Modèle de jointure de session - Authentification JWT + jointure de session avec code complet
- Rendu vidéo - Affichage vidéo Canvas API
- Abonnement au partage d'écran - Afficher les partages d'écran distants (DIFFÉRENT de la vidéo !)
- Capture vidéo brute - Capture de trames YUV420
- Capture audio brute - Capture d'audio PCM
- Envoyer vidéo brute - Caméra virtuelle (injecter vidéo personnalisée)
- Envoyer audio brut - Microphone virtuel (injecter audio personnalisé)
- Enregistrement cloud - Contrôle d'enregistrement cloud
- Canal de commande - Messagerie de commande personnalisée
- Transcription - Transcription/légendes en direct
Intégration du framework UI
- Win32 natif - Utilisation directe du SDK avec Canvas API (meilleure performance)
- WinForms (.NET) - Wrapper C++/CLI + Raw Data Pipe
- WPF (.NET) - Wrapper C++/CLI + conversion BitmapSource
- Directives de qualité production - Checklist et problèmes courants
Modèles de wrapper C++/CLI (Wrapper de TOUTE bibliothèque native)
- Guide complet - 8 modèles pour interopérabilité natif→.NET
- Modèle 1 : Structure de base - Configuration du projet, disposition de la classe
- *[Modèle 2 : Pointeurs void](examples/dotnet-winforms/README.md#pattern-2-opaque-void-pointers)** - Masquer les types natifs
- Modèle 3 : Callbacks gcroot - Événements natif→géré
- Modèle 4 : IDisposable - Modèle de nettoyage
- Modèle 5 : Chaînes - Conversion String^ ↔ wstring/string
- Modèle 6 : Tableaux - pin_ptr, Marshal::Copy
- Modèle 7 : Threading - Dispatch du thread UI
- Modèle 8 : LockBits - Manipulation d'image rapide
- Erreurs courantes - Dépannage
Dépannage
- Boucle de messages Windows - CRITIQUE : Pourquoi les callbacks ne se déclenchent pas
- Erreurs de compilation - Corrections des dépendances d'en-tête SDK
- Problèmes courants - Diagnostics rapides & codes d'erreur
Références
- Référence API - Hiérarchie API sur 5 niveaux, méthodes, codes d'erreur
- Méthodes Delegate - Tous les 80+ méthodes de callback
- SKILL.md - Guide de navigation complet
Problèmes les plus critiques (Basés sur le débogage réel)
-
Les callbacks ne se déclenchent pas → Boucle de messages Windows manquante (99% des problèmes)
-
L'abonnement vidéo retourne l'erreur 2 → S'abonner trop tôt
- Voir : Rendu vidéo - S'abonner dans
onUserVideoStatusChanged
- Voir : Rendu vidéo - S'abonner dans
-
Erreurs de classe abstraite → Implémentations de méthode virtuelle manquantes
- Voir : Méthodes Delegate
Point clé
Une fois que vous apprenez le modèle en 3 étapes, vous pouvez implémenter TOUTE fonctionnalité :
- Obtenir singleton → 2. Implémenter delegate → 3. S'abonner & utiliser
Voir : Modèle d'architecture SDK
Ressources
- Docs officielles : https://developers.zoom.us/docs/video-sdk/windows/
- Référence API : https://marketplacefront.zoom.us/sdk/custom/windows/
- Forum dev : https://devforum.zoom.us/
- Exemples GitHub : https://github.com/zoom/videosdk-windows-rawdata-sample
- Exemple fonctionnel :
C:\tempsdk\zoom-video-sdk-windows-sample\(implémentation complète)
Besoin d'aide ? Commencez avec SKILL.md pour une navigation complète.
Fusionné à partir de video-sdk/windows/SKILL.md
Zoom Video SDK Windows - Index de documentation complète
Parcours de démarrage rapide
Si vous êtes nouveau au SDK, suivez cet ordre :
-
Vue d'ensemble → windows.md
-
Lire le modèle d'architecture → concepts/sdk-architecture-pattern.md
- Formule universelle : Singleton → Delegate → S'abonner
- Une fois que vous comprenez cela, vous pouvez implémenter n'importe quelle fonctionnalité
-
Corriger les erreurs de compilation → troubleshooting/build-errors.md
- Dépendances des en-têtes SDK
- Ordre d'inclusion obligatoire
-
Implémenter la jointure de session → examples/session-join-pattern.md
- Code complet fonctionnel JWT + jointure de session
-
Corriger les problèmes de callback → troubleshooting/windows-message-loop.md
- CRITIQUE : Pourquoi les callbacks ne se déclenchent pas sans boucle de messages Windows
-
Implémenter la vidéo → examples/video-rendering.md
- Canvas API (rendu SDK) vs Raw Data Pipe
-
Dépanner tout problème → troubleshooting/common-issues.md
- Checklist de diagnostic rapide
- Tableaux des codes d'erreur
Structure de la documentation
video-sdk/windows/
├── SKILL.md # Vue d'ensemble principale de la skill
├── SKILL.md # Ce fichier - guide de navigation
├── windows.md # Document de vue d'ensemble secondaire (style pointeur)
│
├── concepts/ # Modèles architecturaux fondamentaux
│ ├── sdk-architecture-pattern.md # Formule universelle pour TOUTE fonctionnalité
│ ├── singleton-hierarchy.md # Guide de navigation sur 5 niveaux
│ └── canvas-vs-raw-data.md # Choix entre rendu SDK vs auto-rendu
│
├── examples/ # Code fonctionnel complet
│ ├── session-join-pattern.md # Authentification JWT + jointure de session
│ ├── video-rendering.md # Affichage vidéo Canvas API
│ ├── screen-share-subscription.md # Afficher les partages d'écran distants
│ ├── raw-video-capture.md # Capture de trames brutes YUV420
│ ├── raw-audio-capture.md # Capture d'audio brut PCM
│ ├── send-raw-video.md # Caméra virtuelle (injecter vidéo)
│ ├── send-raw-audio.md # Microphone virtuel (injecter audio)
│ ├── cloud-recording.md # Contrôle d'enregistrement cloud
│ ├── command-channel.md # Messagerie de commande personnalisée
│ ├── transcription.md # Transcription/légendes en direct
│ └── dotnet-winforms/ # Intégration du framework UI
│ └── README.md # Modèles Win32, WinForms, WPF
│ # Modèles de wrapper C++/CLI
│ # Directives de qualité production
│
├── troubleshooting/ # Guides de résolution de problèmes
│ ├── windows-message-loop.md # CRITIQUE - Pourquoi les callbacks échouent
│ ├── build-errors.md # Corrections des dépendances d'en-tête
│ └── common-issues.md # Flux de diagnostic rapide
│
└── references/ # Documentation de référence
├── windows-reference.md # Hiérarchie API, méthodes, codes d'erreur
├── delegate-methods.md # Tous les 80+ méthodes de callback
└── samples.md # Guide des exemples officiels
Par cas d'usage
Je veux construire une application vidéo
- Modèle d'architecture SDK - Comprendre le modèle
- Modèle de jointure de session - Rejoindre les sessions
- Rendu vidéo - Afficher la vidéo
- Boucle de messages Windows - Corriger les problèmes de callback
J'obtiens des erreurs de compilation
- Guide des erreurs de compilation - Dépendances des en-têtes SDK
- Méthodes Delegate - Erreurs de classe abstraite
- Problèmes courants - Erreurs de liaison
J'obtiens des erreurs à l'exécution
- Boucle de messages Windows - Les callbacks ne se déclenchent pas
- Problèmes courants - Tableaux des codes d'erreur
Je veux afficher les partages d'écran
- Abonnement au partage d'écran - DIFFÉRENT de la vidéo !
- Modèle d'architecture SDK - Modèle piloté par les événements
- Rendu vidéo - Comparer avec l'abonnement vidéo
Je veux capturer audio/vidéo brute
- Canvas vs Raw Data - Choisissez votre approche
- Capture vidéo brute - Capture de trames YUV420
- Capture audio brute - Capture d'audio PCM
- Modèle d'architecture SDK - Modèle d'abonnement
Je veux envoyer une vidéo/audio personnalisée (caméra/microphone virtuel)
- Envoyer vidéo brute - Injecter des trames vidéo personnalisées
- Envoyer audio brut - Injecter de l'audio personnalisé
- Modèle d'architecture SDK - Modèle de source externe
Je veux enregistrer des sessions
- Enregistrement cloud - Démarrer/arrêter l'enregistrement cloud
- Référence API - Méthodes d'aide d'enregistrement
Je veux utiliser la transcription en direct
- Transcription - Activer les légendes en direct
- Méthodes Delegate - Callbacks de transcription
Je veux la messagerie personnalisée entre participants
- Canal de commande - Envoyer des commandes personnalisées
- Référence API - Méthodes du canal de commande
Je veux construire une application Win32 native
- Intégration Win32 - SDK direct + Canvas API
- Rendu vidéo - Modèles Canvas API
- Directives production - Bonnes pratiques
Je veux construire une application WinForms (.NET)
- Intégration WinForms - Wrapper C++/CLI + Raw Data
- Modèles C++/CLI - gcroot, Finalizer, LockBits
- Directives production - IDisposable, sécurité des threads
Je veux construire une application WPF (.NET)
- Intégration WPF - C++/CLI + BitmapSource
- Conversion Bitmap - Freeze(), Dispatcher
- Directives production - Optimisation des performances
Je veux utiliser C# / .NET Framework (général)
- Vue d'ensemble intégration .NET - Guide complet de wrapper C++/CLI
- Capture vidéo brute - Modèles de conversion YUV→RGB
- Modèle de jointure de session - Flux d'initialisation du SDK
Je veux wrapper TOUTE bibliothèque C++ native pour .NET
- Modèles de wrapper C++/CLI - Guide complet en 8 modèles
- Modèle 1 : Structure de base - Configuration du projet + disposition de la classe
- Modèle 3 : Callbacks gcroot - Événements natif→géré
- Modèle 4 : IDisposable - Modèle de nettoyage
- Erreurs courantes - Dépannage
Je veux implémenter une fonctionnalité spécifique
- Modèle d'architecture SDK - COMMENCEZ ICI !
- Hiérarchie Singleton - Naviguer vers la fonctionnalité
- Référence API - Signatures de méthodes
Documents les plus critiques
1. Modèle d'architecture SDK (DOCUMENT MAÎTRE)
concepts/sdk-architecture-pattern.md
Le modèle universel en 3 étapes :
- Obtenir singleton (SDK, helpers, session, utilisateurs)
- Implémenter delegate (callbacks d'événements)
- S'abonner et utiliser
2. Boucle de messages Windows (PROBLÈME PLUS COURANT)
troubleshooting/windows-message-loop.md
99% des problèmes « les callbacks ne se déclenchent pas » sont causés par une boucle de messages Windows manquante.
3. Hiérarchie Singleton (CARTE DE NAVIGATION)
concepts/singleton-hierarchy.md
Navigation profonde sur 5 niveaux montrant comment accéder à chaque fonctionnalité.
Apprentissages clés
Découvertes critiques :
-
La boucle de messages Windows est OBLIGATOIRE
- Le SDK utilise la pompe de messages Windows pour les callbacks
- Sans elle, les callbacks sont mis en file d'attente mais ne se déclenchent jamais
- Voir : Guide de boucle de messages Windows
-
S'abonner dans onUserVideoStatusChanged, PAS dans onUserJoin
- La vidéo peut ne pas être prête quand l'utilisateur rejoint
- Attendre le callback de changement de statut vidéo
- Voir : Rendu vidéo
-
Deux voies de rendu
- Canvas API : Le SDK rend vers votre HWND (recommandée)
- Raw Data Pipe : Vous recevez des trames YUV (avancée)
- Voir : Canvas vs Raw Data
-
Les helpers contrôlent UNIQUEMENT vos propres flux
videoHelper->startVideo()démarre votre caméra- Pour voir les autres, s'abonner à leur Canvas/Pipe
- Voir : Hiérarchie Singleton
-
L'intégration du framework UI diffère selon la plateforme
- Win32 : SDK direct, Canvas API (SDK rend vers HWND) - meilleures performances
- WinForms : Wrapper C++/CLI, Raw Data Pipe, YUV→Bitmap, InvokeRequired
- WPF : Même wrapper + Bitmap→BitmapSource, Dispatcher, Freeze()
- Voir : Intégration du framework UI
-
Modèles de wrapper C++/CLI (pour TOUTE bibliothèque native → .NET)
- Pointeurs
void*- masquer les types natifs des en-têtes gérés gcroot<T^>- empêcher le GC de collecter les références gérées dans le code natif- Finalizer + Destructeur -
~Class()et!Class()pour le nettoyage IDisposable pin_ptr+Marshal::Copy- conversion tableau/bufferLockBits- 100x plus rapide que SetPixel pour la manipulation d'image- Marshaling de threads - InvokeRequired (WinForms) / Dispatcher (WPF)
- Voir : Guide de wrapper C++/CLI
- Pointeurs
-
Timing de connexion audio
- Définir
audioOption.connect = falselors de la jointure - Appeler
startAudio()dans le callbackonSessionJoin - Voir : Directives production
- Définir
Référence rapide
« Mon code ne compile pas »
→ Guide des erreurs de compilation
« Les callbacks ne se déclenchent jamais »
« L'abonnement vidéo retourne l'erreur 2 »
→ Rendu vidéo - S'abonner dans onUserVideoStatusChanged
« Erreur de classe abstraite »
« Comment implémenter [fonctionnalité] ? »
« Comment naviguer vers [contrôleur] ? »
« Que signifie le code d'erreur ? »
Version du document
Basé sur Zoom Video SDK pour Windows v2.x
Bon codage !
Rappelez-vous : Le Modèle d'architecture SDK est votre clé pour déverrouiller le SDK entier. Lisez-le en premier !
Opérations
- RUNBOOK.md - Checklist de contrôle préalable et débogage en 5 minutes.