Setting the file. One moment.
Skill 126 · Zoom Meeting SDK Windows
Subchapter 126.11
examples/captions-transcription.mdMarkdown18 KBView on GitHub
The Meeting SDK provides two related caption features through IClosedCaptionController:
Both features support multi-language translation when enabled.
IMeetingService
└── GetMeetingClosedCaptionController() → IClosedCaptionController
├── SetEvent(IClosedCaptionControllerEvent*)
├── EnableCaptions(bool)
├── StartLiveTranscription()
├── SetMeetingSpokenLanguage(int)
├── SetTranslationLanguage(int)
└── SendClosedCaption(const zchar_t*)#include <meeting_service_interface.h>
#include <meeting_service_components/meeting_closedcaption_interface.h>// ClosedCaptionControllerEventListener.h
#pragma once
#include <meeting_service_components/meeting_closedcaption_interface.h>
#include <functional>
class ClosedCaptionControllerEventListener
: public ZOOMSDK::IClosedCaptionControllerEvent {
public:
using TranscriptionCallback = std::function<void(const std::wstring&, unsigned int)>;
using CaptionCallback = std::function<void(const std::wstring&, unsigned int)>;
ClosedCaptionControllerEventListener(
TranscriptionCallback onTranscription = nullptr,
CaptionCallback onCaption = nullptr
);
virtual ~ClosedCaptionControllerEventListener() = default;
// Called when assigned to send closed captions
virtual void onAssignedToSendCC(bool bAssigned) override;
// Called when manual closed caption is received
virtual void onClosedCaptionMsgReceived(
const zchar_t* ccMsg,
unsigned int sender_id,
time_t time
) override;
// Called when live transcription status changes
virtual void onLiveTranscriptionStatus(
ZOOMSDK::SDKLiveTranscriptionStatus status
) override;
// Called when original (untranslated) message is received
virtual void onOriginalLanguageMsgReceived(
ZOOMSDK::ILiveTranscriptionMessageInfo* messageInfo
) override;
// Called when translated transcription message is received
virtual void onLiveTranscriptionMsgInfoReceived(
ZOOMSDK::ILiveTranscriptionMessageInfo* messageInfo
) override;
// Called when translation error occurs
virtual void onLiveTranscriptionMsgError(
ZOOMSDK::ILiveTranscriptionLanguage* spokenLanguage,
ZOOMSDK::ILiveTranscriptionLanguage* transcriptLanguage
) override;
// Host receives this when someone requests transcription
virtual void onRequestForLiveTranscriptReceived(
unsigned int requester_id,
bool bAnonymous
) override;
// Called when request status changes
virtual void onRequestLiveTranscriptionStatusChange(bool bEnabled) override;
// Called when caption enable status changes
virtual void onCaptionStatusChanged(bool bEnabled) override;
// Called when someone requests to start captions
virtual void onStartCaptionsRequestReceived(
ZOOMSDK::ICCRequestHandler* handler
) override;
// Called when caption request is approved
virtual void onStartCaptionsRequestApproved() override;
// Called when manual caption status changes
virtual void onManualCaptionStatusChanged(bool bEnabled) override;
// Called when spoken language changes
virtual void onSpokenLanguageChanged(
ZOOMSDK::ILiveTranscriptionLanguage* spokenLanguage
) override;
private:
TranscriptionCallback m_onTranscription;
CaptionCallback m_onCaption;
std::string wstringToUtf8(const std::wstring& wstr);
};// ClosedCaptionControllerEventListener.cpp
#include "ClosedCaptionControllerEventListener.h"
#include <iostream>
using namespace ZOOMSDK;
ClosedCaptionControllerEventListener::ClosedCaptionControllerEventListener(
TranscriptionCallback onTranscription,
CaptionCallback onCaption
) : m_onTranscription(onTranscription), m_onCaption(onCaption) {}
void ClosedCaptionControllerEventListener::onAssignedToSendCC(bool bAssigned) {
std::cout << "Assigned to send CC: " <<
// Global variables
IClosedCaptionController* g_captionController = nullptr;
ClosedCaptionControllerEventListener* g_captionListener = nullptr;
void initializeCaptions(IMeetingService* meetingService) {
// Get the caption controller
g_captionController = meetingService->GetMeetingClosedCaptionController();
if (!g_captionController) {
std::cerr << "Failed to get caption controller" << std::endl;
return;
}
// Create and set event listener
g_captionListener = new ClosedCaptionControllerEventListener(
// Transcription callback
[](const std::wstring& text, unsigned int speakerId) {
// Process transcription text
std::wcout << L"Speaker " << speakerId << L": " << text << std::endl;
},
// Caption callback
[](const std::wstring& text, unsigned int senderId) {
// Process manual caption
std::wcout << L"Caption: " << text << std::endl;
}
);
SDKError err = g_captionController->SetEvent(g_captionListener);
if (err != SDKERR_SUCCESS) {
std::cerr << "Failed to set caption listener: " << err << std::endl;
return;
}
std::cout << "Caption controller initialized" << std::endl;
}void checkTranscriptionFeatures() {
if (!g_captionController) return;
std::cout << "=== Transcription Features ===" << std::endl;
std::cout << "Captions enabled: "
<< g_captionController->IsCaptionsEnabled() << std::endl;
std::cout << "Live transcription feature: "
<< g_captionController->IsLiveTranscriptionFeatureEnabled() << std::endl;
std::cout << "Manual caption enabled: "
<< g_captionController->IsMeetingManualCaptionEnabled() << std::endl;
std::cout << "Multi-language transcription: "
<< g_captionController->IsMultiLanguageTranscriptionEnabled() << std::endl;
std::cout << "Receive spoken language: "
<< g_captionController->IsReceiveSpokenLanguageContentEnabled() << std::endl;
std::cout << "Request to start enabled: "
<< g_captionController->IsRequestToStartLiveTranscriptionEnabled() << std::endl;
std::cout << "Text translation enabled: "
<< g_captionController->IsTextLiveTranslationEnabled() << std::endl;
}void startLiveTranscription() {
if (!g_captionController) return;
SDKError err;
// Start live transcription service
err = g_captionController->StartLiveTranscription();
if (err != SDKERR_SUCCESS) {
std::cerr << "Failed to start transcription: " << err << std::endl;
// May need host permission
}
// Set spoken language (0 = English)
// Use GetAvailableSpokenLanguageList() to get all options
err = g_captionController->SetMeetingSpokenLanguage(0);
if (err != SDKERR_SUCCESS) {
std::cerr << "Failed to set spoken language: " << err << std::endl;
}
// Set translation language (1 = Chinese, -1 = disable translation)
err = g_captionController->SetTranslationLanguage(1);
if (err != SDKERR_SUCCESS) {
std::cerr << "Failed to set translation language: " << err << std::endl;
}
// Enable receiving original spoken language content
err = g_captionController->EnableReceiveSpokenLanguageContent(true);
if (err != SDKERR_SUCCESS) {
std::cerr << "Failed to enable spoken language content: " << err << std::endl;
}
std::cout << "Live transcription started" << std::endl;
}void stopLiveTranscription() {
if (!g_captionController) return;
SDKError err = g_captionController->StopLiveTranscription();
if (err == SDKERR_SUCCESS) {
std::cout << "Live transcription stopped" << std::endl;
}
}void enableManualCaptions() {
if (!g_captionController) return;
SDKError err;
// Enable captions feature
err = g_captionController->EnableCaptions(true);
if (err != SDKERR_SUCCESS) {
std::cerr << "Failed to enable captions: " << err << std::endl;
}
// Enable manual caption mode
err = g_captionController->EnableMeetingManualCaption(true);
if (err != SDKERR_SUCCESS) {
std::cerr << "Failed to enable manual captions: " << err << std::endl;
}
std::cout << "Manual captions enabled" << std::endl;
}void assignCaptionPrivilege(unsigned int userId, bool assign) {
if (!g_captionController) return;
// Host assigns someone to type captions
// userId = 0 means current user
SDKError err = g_captionController->AssignCCPrivilege(userId, assign);
if (err == SDKERR_SUCCESS) {
std::cout << "Caption privilege "
<< (assign ? "assigned to" : "removed from")
<< " user " << userId << std::endl;
} else {
std::cerr << "Failed to assign caption privilege: " << err << std::endl;
}
}void sendManualCaption(const wchar_t* captionText) {
if (!g_captionController) return;
// Only works if you have been assigned CC privilege
SDKError err = g_captionController->SendClosedCaption(captionText);
if (err == SDKERR_SUCCESS) {
std::cout << "Caption sent" << std::endl;
} else if (err == SDKERR_NO_PERMISSION) {
std::cerr << "No permission to send captions" << std::endl;
}
}void onInMeeting(IMeetingService* meetingService) {
initializeCaptions(meetingService);
// Check available features
checkTranscriptionFeatures();
// Start live transcription with translation
startLiveTranscription();
}
// For host: enable manual captions
void onIsHost() {
enableManualCaptions();
assignCaptionPrivilege(0, true); // Assign to self
}Common language IDs for SetMeetingSpokenLanguage() and SetTranslationLanguage():
| ID | Language |
|---|---|
| 0 | English |
| 1 | Chinese (Simplified) |
| 2 | Japanese |
| 3 | German |
| 4 | French |
| 5 | Russian |
| 6 | Portuguese |
| 7 | Spanish |
| 8 | Korean |
| -1 | Disable translation |
Use GetAvailableSpokenLanguageList() and GetAvailableTranslationLanguageList() to get the full list of supported languages for the meeting.
enum SDKLiveTranscriptionOperationType {
SDK_LiveTranscription_OperationType_None = 0,
SDK_LiveTranscription_OperationType_Add, // New text added
SDK_LiveTranscription_OperationType_Update, // Text updated
SDK_LiveTranscription_OperationType_Delete, // Text deleted
SDK_LiveTranscription_OperationType_Complete, // Sentence complete
SDK_LiveTranscription_OperationType_NotSupported
};Important: Only process SDK_LiveTranscription_OperationType_Complete for final transcription text. Other types represent partial/streaming results.
enum SDKLiveTranscriptionStatus {
SDK_LiveTranscription_Status_Stop = 0, // Not running
SDK_LiveTranscription_Status_Start = 1, // Running
SDK_LiveTranscription_Status_User_Sub = 2, // User subscribed
SDK_LiveTranscription_Status_Connecting = 10 // Connecting
};SDKError err = g_captionController->StartLiveTranscription();
switch (err) {
case SDKERR_SUCCESS:
std::cout << "Transcription started" << std::endl;
break;
case SDKERR_NO_PERMISSION:
std::cerr << "No permission (need host or feature disabled)" << std::endl;
break;
case SDKERR_WRONG_USAGE:
std::cerr << "Feature not available in this meeting" << std::endl;
break;
case SDKERR_SERVICE_FAILED:
std::cerr << "Service failed to start" << std::endl;
break;
default:
std::cerr << "Error: " << err << std::endl;
}GetMessageOperationType() == Complete to avoid streaming updateszchar_t* (wide string) - convert to UTF-8 for display