# Live Transcription Complete working code for real-time speech-to-text transcription. **Official Sample**: `VSDK_TranscriptionAndTranslation` in [videosdk-windows-rawdata-sample](https://github.com/zoom/videosdk-windows-rawdata-sample) --- ## Overview Live transcription provides real-time captions of speech. Features: - Automatic speech recognition - Multiple language support - Speaker identification - Translation (optional) ``` ┌─────────────────────────────────────────────────────────────────┐ │ TRANSCRIPTION FLOW │ ├─────────────────────────────────────────────────────────────────┤ │ 1. Enable transcription → startLiveTranscription() │ │ 2. Receive captions → onLiveTranscriptionMsgInfoReceived() │ │ 3. Display/process text │ └─────────────────────────────────────────────────────────────────┘ ``` --- ## Prerequisites - Live transcription must be enabled for the session - Valid Zoom account with transcription feature --- ## Complete Working Code ### TranscriptionManager.h ```cpp #pragma once #include #include #include #include #include "zoom_video_sdk_interface.h" USING_ZOOM_VIDEO_SDK_NAMESPACE struct TranscriptionMessage { std::wstring speakerName; std::wstring text; bool isFinal; unsigned long long timestamp; }; class TranscriptionManager { public: TranscriptionManager(IZoomVideoSDK* sdk); // Control bool StartTranscription(); bool StopTranscription(); bool IsTranscribing() const { return m_isTranscribing; } // Language settings bool SetSpokenLanguage(ILiveTranscriptionLanguage* language); bool SetTranslationLanguage(ILiveTranscriptionLanguage* language); std::vector GetAvailableLanguages(); // Callbacks from delegate void OnStatusChanged(ZoomVideoSDKLiveTranscriptionStatus status); void OnMessageReceived(ILiveTranscriptionMessageInfo* info); void OnOriginalLanguageReceived(ILiveTranscriptionMessageInfo* info); void OnError(ILiveTranscriptionLanguage* spoken, ILiveTranscriptionLanguage* transcript); // Set message handler using MessageCallback = std::function; void SetMessageHandler(MessageCallback callback) { m_callback = callback; } private: IZoomVideoSDK* m_sdk; IZoomVideoSDKLiveTranscriptionHelper* m_helper; bool m_isTranscribing; MessageCallback m_callback; }; ``` ### TranscriptionManager.cpp ```cpp #include "TranscriptionManager.h" #include TranscriptionManager::TranscriptionManager(IZoomVideoSDK* sdk) : m_sdk(sdk) , m_helper(nullptr) , m_isTranscribing(false) { } bool TranscriptionManager::StartTranscription() { m_helper = m_sdk->getLiveTranscriptionHelper(); if (!m_helper) { std::cout << "Transcription helper not available" << std::endl; return false; } // Check if transcription is available if (!m_helper->canStartLiveTranscription()) { std::cout << "Cannot start transcription" << std::endl; return false; } ZoomVideoSDKErrors err = m_helper->startLiveTranscription(); if (err == ZoomVideoSDKErrors_Success) { std::cout << "Transcription started" << std::endl; return true; } std::cout << "Start transcription failed: " << err << std::endl; return false; } bool TranscriptionManager::StopTranscription() { if (!m_helper) return false; ZoomVideoSDKErrors err = m_helper->stopLiveTranscription(); if (err == ZoomVideoSDKErrors_Success) { std::cout << "Transcription stopped" << std::endl; m_isTranscribing = false; return true; } return false; } std::vector TranscriptionManager::GetAvailableLanguages() { std::vector languages; if (!m_helper) { m_helper = m_sdk->getLiveTranscriptionHelper(); } if (m_helper) { IVideoSDKVector* langList = m_helper->getAvailableSpokenLanguages(); if (langList) { for (int i = 0; i < langList->GetCount(); i++) { languages.push_back(langList->GetItem(i)); } } } return languages; } bool TranscriptionManager::SetSpokenLanguage(ILiveTranscriptionLanguage* language) { if (!m_helper || !language) return false; ZoomVideoSDKErrors err = m_helper->setSpokenLanguage(language); if (err == ZoomVideoSDKErrors_Success) { std::wcout << L"Spoken language set to: " << language->getLTTLanguageName() << std::endl; return true; } return false; } bool TranscriptionManager::SetTranslationLanguage(ILiveTranscriptionLanguage* language) { if (!m_helper || !language) return false; ZoomVideoSDKErrors err = m_helper->setTranslationLanguage(language); if (err == ZoomVideoSDKErrors_Success) { std::wcout << L"Translation language set to: " << language->getLTTLanguageName() << std::endl; return true; } return false; } void TranscriptionManager::OnStatusChanged(ZoomVideoSDKLiveTranscriptionStatus status) { switch (status) { case ZoomVideoSDKLiveTranscription_Status_Start: std::cout << "Transcription started" << std::endl; m_isTranscribing = true; break; case ZoomVideoSDKLiveTranscription_Status_Stop: std::cout << "Transcription stopped" << std::endl; m_isTranscribing = false; break; case ZoomVideoSDKLiveTranscription_Status_Connecting: std::cout << "Transcription connecting..." << std::endl; break; default: std::cout << "Transcription status: " << status << std::endl; } } void TranscriptionManager::OnMessageReceived(ILiveTranscriptionMessageInfo* info) { if (!info) return; TranscriptionMessage msg; // Get speaker IZoomVideoSDKUser* speaker = info->getSpeaker(); if (speaker) { msg.speakerName = speaker->getUserName(); } // Get text const zchar_t* text = info->getMessageContent(); if (text) { msg.text = text; } // Get metadata msg.isFinal = (info->getMessageType() == ZoomVideoSDKLiveTranscriptionOperationType_Complete); msg.timestamp = info->getTimeStamp(); // Display std::wcout << L"[" << msg.speakerName << L"] " << msg.text; if (msg.isFinal) { std::wcout << L" (final)"; } std::wcout << std::endl; // Call user handler if (m_callback) { m_callback(msg); } } void TranscriptionManager::OnOriginalLanguageReceived(ILiveTranscriptionMessageInfo* info) { // Original language message (before translation) if (!info) return; const zchar_t* text = info->getMessageContent(); if (text) { std::wcout << L"[Original] " << text << std::endl; } } void TranscriptionManager::OnError(ILiveTranscriptionLanguage* spoken, ILiveTranscriptionLanguage* transcript) { std::cout << "Transcription error" << std::endl; if (spoken) { std::wcout << L"Spoken language: " << spoken->getLTTLanguageName() << std::endl; } if (transcript) { std::wcout << L"Transcript language: " << transcript->getLTTLanguageName() << std::endl; } } ``` ### Using in Delegate ```cpp class MyDelegate : public IZoomVideoSDKDelegate { private: TranscriptionManager* m_transcription; public: MyDelegate(IZoomVideoSDK* sdk) { m_transcription = new TranscriptionManager(sdk); // Set message handler m_transcription->SetMessageHandler([](const TranscriptionMessage& msg) { // Process transcription (e.g., save to file, analyze) if (msg.isFinal) { SaveTranscript(msg.speakerName, msg.text); } }); } void onSessionJoin() override { // Start transcription m_transcription->StartTranscription(); } void onLiveTranscriptionStatus(ZoomVideoSDKLiveTranscriptionStatus status) override { m_transcription->OnStatusChanged(status); } void onLiveTranscriptionMsgInfoReceived(ILiveTranscriptionMessageInfo* info) override { m_transcription->OnMessageReceived(info); } void onOriginalLanguageMsgReceived(ILiveTranscriptionMessageInfo* info) override { m_transcription->OnOriginalLanguageReceived(info); } void onLiveTranscriptionMsgError(ILiveTranscriptionLanguage* spoken, ILiveTranscriptionLanguage* transcript) override { m_transcription->OnError(spoken, transcript); } // ... other callbacks }; ``` --- ## Message Types | Type | Description | |------|-------------| | `ZoomVideoSDKLiveTranscriptionOperationType_N` | Interim result (may change) | | `ZoomVideoSDKLiveTranscriptionOperationType_Complete` | Final result | | `ZoomVideoSDKLiveTranscriptionOperationType_Update` | Updated previous result | **Note**: Interim results allow real-time display but may be revised. --- ## ILiveTranscriptionMessageInfo Methods | Method | Returns | Description | |--------|---------|-------------| | `getMessageContent()` | `const zchar_t*` | Transcribed text | | `getSpeaker()` | `IZoomVideoSDKUser*` | Speaker user object | | `getTimeStamp()` | `unsigned long long` | Message timestamp | | `getMessageType()` | `ZoomVideoSDKLiveTranscriptionOperationType` | Interim/final | | `getMessageID()` | `const zchar_t*` | Unique message ID | --- ## Language Support ### List Available Languages ```cpp auto languages = transcriptionManager->GetAvailableLanguages(); for (auto lang : languages) { std::wcout << lang->getLTTLanguageID() << L": " << lang->getLTTLanguageName() << std::endl; } ``` ### Common Language Codes | Code | Language | |------|----------| | `en` | English | | `es` | Spanish | | `fr` | French | | `de` | German | | `zh` | Chinese | | `ja` | Japanese | --- ## Common Issues ### Transcription Not Available **Cause**: Feature not enabled for session **Fix**: Check `canStartLiveTranscription()` first: ```cpp if (helper->canStartLiveTranscription()) { helper->startLiveTranscription(); } ``` ### No Messages Received **Cause**: No one is speaking or audio not connected **Fix**: Ensure audio is connected: ```cpp void onSessionJoin() override { sdk->getAudioHelper()->startAudio(); // Connect audio first transcription->StartTranscription(); } ``` ### Wrong Language **Cause**: Spoken language not set correctly **Fix**: Set spoken language: ```cpp auto languages = manager->GetAvailableLanguages(); for (auto lang : languages) { if (wcscmp(lang->getLTTLanguageID(), L"en") == 0) { manager->SetSpokenLanguage(lang); break; } } ``` --- ## Related Documentation - [Raw Audio Capture](raw-audio-capture.md) - Alternative audio processing - [Session Join Pattern](session-join-pattern.md) - Session setup - [Delegate Methods](../references/delegate-methods.md) - Transcription callbacks - [API Reference](../references/windows-reference.md) - Method signatures