Summary
In a webinar, IZoomSDKShareSourceHelper::setExternalShareSource(share, share_audio)
returns SDKERR_UNKNOWN(13) while the exact same code returns SUCCESS(0) in
a regular meeting. Share-video registration works in both; only the share-audio
side is rejected in webinar. I have ruled out every account/permission/timing
hypothesis I can think of and am out of ideas — looking for guidance on whether
this is intentional or a bug, and what the supported path is for injecting
computer-sound audio into a webinar via the raw data API.
Environment
- Zoom Meeting SDK for Windows: 7.0.2.34512
- OS: Windows 11 Pro 26200
- App type: General App (User-managed), Development credentials
- Selected Zoom products: Meetings + Webinars
- Embed > Meeting SDK enabled
- “Are you developing a programmatic join use case?” = ON
- S2S OAuth scopes:
user:read:zak:adminmeeting:read:local_recording_token:adminwebinar:read:local_recording_token:admin
- Account: Pro (with webinar add-on)
- Account-level recording: Local + Cloud both ON
- Webinar-level “Allow local recording”: ON
- Webinar is owned by the same user the bot joins as (ZAK
userId=me)
What I am trying to do
A headless C++ bot that streams a pre-recorded MP4 into a Zoom session via the
raw data API, with four channels:
IZoomSDKVideoSource— camera tileIZoomSDKVirtualAudioMicEvent— mic (speaker voice)IZoomSDKShareSource— share video (slides)IZoomSDKShareAudioSource— share audio (BGM, full-bandwidth music)
Problem: meeting works, webinar does not
Meeting (meetingId 3021611089) — works:
MySelf: role=USERROLE_HOST(1) isHost=true
HasRawdataLicense() (initial) -> false
CanStartRawRecording() -> WRONG_USAGE
EnableShareComputerSound(true) -> SUCCESS(0)
setExternalShareSource(share, share_audio) -> SUCCESS(0) ✅
[ShareSource] onStartSend ✅
[ShareAudioSource] onStartSendAudio ✅
sendShareAudio(...) -> SUCCESS for every chunk
Note that CanStartRawRecording returns WRONG_USAGE here too, yet
setExternalShareSource works — so the “raw recording” gate by itself
does not seem to be what controls share-audio registration in meeting mode.
Webinar (webinarId 84790922291) — fails:
MySelf: role=USERROLE_HOST(1) isHost=true
HasRawdataLicense() (initial) -> false
CanStartRawRecording() -> WRONG_USAGE
EnableShareComputerSound(true) -> SUCCESS(0)
setExternalShareSource(share, share_audio) -> UNKNOWN(13) ❌
[ShareSource] onStartSend ✅ (share video alive)
[ShareAudioSource] onStartSendAudio ❌ (never fires)
Things I have already ruled out
- Role: Tested with
isHost=true, USERROLE_HOST. Same result with COHOST. - Permissions / settings:
- Account Cloud + Local recording: ON
- Webinar Local recording: ON
- “Webinars” selected in app’s “Select where to use your app” panel
- “Programmatic join use case” toggle: ON
- Manual sanity check: From the Zoom desktop client, the SAME user account
in the SAME webinar can manually do “Share screen → Share computer sound”
successfully. So the account license and webinar settings are sufficient.
It is specifically the SDK raw-data injection that fails. - Timing / async-init race: Tested with a 15-second sleep between
MEETING_STATUS_INMEETING and the setExternalShareSource call. No effect. - Mic stream collision: Disabled mic source entirely (no
setExternalAudioSource, noJoinVoip, no Mute/UnMute dance). Same
UNKNOWN(13). - EnableShareComputerSound(true) before the helper call: in place
(returns SUCCESS). No effect on the subsequent UNKNOWN(13).
Things I have additionally tried per Zoom’s “Use raw data” doc
Per the Zoom Meeting SDK docs section “Receive local recording permission
through an OAuth app”, I implemented the app_privilege_token flow:
- Added scopes
meeting:read:local_recording_token:adminand
webinar:read:local_recording_token:adminto my S2S app. - Fetched the token via
GET /v2/webinars/{id}/jointoken/local_recording.
Response:{"token":"<9-char string>","expire_in":120}— successfully returned. - Passed it as
JoinParam.withoutloginuserJoin.app_privilege_tokenalongside
userZAK.
Observed effect:
[SDK] onRecordingStatus: Recording_Start(0)fires automatically shortly
after MEETING_STATUS_INMEETING — so the SDK considers raw recording started.CanStartRawRecording()and (forced)StartRawRecording()both still
returnWRONG_USAGE(2)— presumably “already started”.- Despite raw recording being active,
setExternalShareSource(share, share_audio)
still returnsUNKNOWN(13). - No “Recording consent” dialog appears for the other webinar participants,
which the docs say should happen whenStartRawRecordingsucceeds. So it
looks like the SDK-side state says “recording started” but the server-side
may not be in sync.
Workaround that partially works
setExternalShareSource(share, nullptr) + setSharePureAudioSource(share_audio)
in webinar:
- Both calls return
SUCCESS(0) [ShareAudioSource] onStartSendAudiofiressendShareAudiosucceeds, audio actually reaches participants
BUT: as soon as setSharePureAudioSource is called, the share-video session is
killed ([ShareSource] onStartSend immediately followed by onStopSend). So
share-video and share-audio appear to be mutually exclusive when using
setSharePureAudioSource. Same exclusion observed on Linux SDK 7.0.2.5001.
Questions
- Is
IZoomSDKShareSourceHelper::setExternalShareSource(share, share_audio)
officially supported in webinar mode? The header (rawdata_share_source_helper_interface.h)
doesn’t gate it, but the published docs only mention the single-argument
form. If unsupported, can the header please be annotated to make this clear? - If supported: what additional configuration enables it? My ruled-out list
above covers everything I could find — is there another flag, marketplace
feature add-on, or webinar setting I’m missing? - The fact that
onRecordingStatus(Recording_Start)fires but no consent
dialog appears for participants seems like a bug or a real signal that
the server hasn’t actually opened the raw-data pipeline. Is there a way to
verify server-side raw recording state from the SDK? setSharePureAudioSourceworks in webinar but kills share-video. Is the
share-video / pure-audio exclusion an intentional SDK design, and is there
any way to dynamically toggle between them at runtime (e.g., share-video
for slide segments, pure-audio for BGM segments) without breaking the
session?
Attached
Encrypted SDK logs available — happy to share via DM. Timestamps:
- Failing webinar call:
2026-05-18T07:39:13 JST - Successful pure-audio webinar call:
2026-05-18T06:45:03 JST - Successful meeting call (reference):
2026-05-18T05:52:58 JST
Account ID and SDK app credentials available via DM if useful.
Thanks in advance for any insight.