macOS example project using Swift + Cocoa. Demonstrates Agora RTC SDK features through a collection of self-contained examples organized by complexity.
- Language: Swift
- UI Framework: Cocoa (AppKit)
- Architecture: Single-window application with example selection
- State: Instance variables + delegate callbacks
macOS/
├── APIExample/
│ ├── Examples/
│ │ ├── Basic/
│ │ │ └── <ExampleName>/
│ │ │ ├── <ExampleName>.swift
│ │ │ └── SKILL.md # Per-example agent guide (present or forthcoming)
│ │ └── Advanced/
│ │ └── <ExampleName>/
│ │ ├── <ExampleName>.swift
│ │ └── SKILL.md # Per-example agent guide (present or forthcoming)
│ ├── Common/ # Shared utilities (KeyCenter, GlobalSettings, LogUtils, Util)
│ ├── Resources/
│ ├── Base.lproj/ # Base storyboards
│ ├── zh-Hans.lproj/ # Simplified Chinese project localization
│ ├── AppDelegate.swift
│ └── ViewController.swift # Main window controller
├── SimpleFilter/ # Specialized filter example
├── APIExample.xcodeproj/ # Xcode project
├── APIExample.xcworkspace/ # Xcode workspace
├── libs/ # SDK libraries
├── Pods/ # CocoaPods dependencies
├── .agents/skills/query-cases/ # Read-only case and registration discovery
├── .agents/skills/upsert-case/ # Add or modify a case
├── .agents/skills/review-case/ # Review lifecycle, threading, and conventions
├── AGENTS.md # Agent guide
└── ARCHITECTURE.md # This file
Each example lives in its own folder under APIExample/Examples/Basic/ or APIExample/Examples/Advanced/ and consists of:
- A Swift file containing the example implementation
- A per-example storyboard, typically at
Base.lproj/<ExampleName>.storyboard
Each example is a self-contained class that:
- Manages its own Agora engine lifecycle
- Implements
AgoraRtcEngineDelegate - Receives configuration via initialization or property injection
- Owns all UI elements for that example
All examples are registered in APIExample/ViewController.swift via a menu or list structure. The example name must match the folder name.
- Example folder names: PascalCase (e.g.,
JoinChannelVideo) - Example class:
<ExampleName>(e.g.,JoinChannelVideo)
All examples share utilities from APIExample/Common/:
KeyCenter— App ID and optional CertificateGlobalSettings— Shared runtime configurationLogUtils— SDK log pathUtil— Privatization configuration
| Case | Path | Key APIs | Description |
|---|---|---|---|
| JoinChannelAudio | Examples/Basic/JoinChannelAudio/ |
createAgoraRtcEngine(), setAudioScenario(), joinChannel(), leaveChannel(), destroy() |
Basic audio call — select an audio scenario, join a channel, and manage the audio stream |
| JoinChannelVideo | Examples/Basic/JoinChannelVideo/ |
createAgoraRtcEngine(), joinChannel(), setupLocalVideo(), setupRemoteVideo(), leaveChannel(), destroy() |
Basic video call — join channel and render local/remote video |
| JoinChannelVideo(Token) | Examples/Basic/JoinChannelVideo(Token)/ |
createAgoraRtcEngine(), joinChannel() with token, setupLocalVideo(), setupRemoteVideo() |
Video call with token authentication |
| JoinChannelVideo(Recorder) | Examples/Basic/JoinChannelVideo(Recorder)/ |
createAgoraRtcEngine(), joinChannel(), startAudioRecording(), stopAudioRecording() |
Video call with local audio recording |
| AgoraBeauty | Examples/Advanced/AgoraBeauty/ |
createVideoEffectObject(), setVideoEffectStringParam(), enableVirtualBackground() |
Beauty filter and enhancement effects |
| AudioMixing | Examples/Advanced/AudioMixing/ |
setAudioScenario(), startAudioMixing(), stopAudioMixing(), pauseAudioMixing(), resumeAudioMixing() |
Audio scenario selection, file mixing, and playback control |
| ChannelMediaRelay | Examples/Advanced/ChannelMediaRelay/ |
startChannelMediaRelay(), updateChannelMediaRelay(), stopChannelMediaRelay() |
Relay media streams across multiple channels |
| ContentInspect | Examples/Advanced/ContentInspect/ |
enableContentInspect(), disableContentInspect() |
Content inspection and moderation |
| CreateDataStream | Examples/Advanced/CreateDataStream/ |
createDataStream(), sendStreamMessage() |
Custom data stream creation and messaging |
| CustomAudioRender | Examples/Advanced/CustomAudioRender/ |
setExternalAudioSink(), pullAudioFrame() |
Custom audio rendering pipeline |
| CustomAudioSource | Examples/Advanced/CustomAudioSource/ |
setExternalAudioSource(), pushAudioFrame() |
Custom audio source capture |
| CustomVideoRender | Examples/Advanced/CustomVideoRender/ |
setExternalVideoSink(), pullVideoFrame() |
Custom video rendering pipeline |
| CustomVideoSourceMediaIO | Examples/Advanced/CustomVideoSourceMediaIO/ |
setExternalVideoSource(), pushVideoFrame() with MediaIO |
Custom video source with media I/O |
| CustomVideoSourcePush | Examples/Advanced/CustomVideoSourcePush/ |
setExternalVideoSource(), pushVideoFrame() |
Custom video source push |
| CustomVideoSourcePushMulti | Examples/Advanced/CustomVideoSourcePushMulti/ |
setExternalVideoSource(), pushVideoFrame() with multiple sources |
Multiple custom video sources |
| JoinMultiChannel | Examples/Advanced/JoinMultiChannel/ |
createRtcChannel(), joinChannel() on multiple channels |
Join and manage multiple channels simultaneously |
| LiveStreaming | Examples/Advanced/LiveStreaming/ |
setClientRole(), addVideoWatermark() with WatermarkConfig, startRtmpStreamWithTranscoding(), stopRtmpStream() |
Live streaming with watermark configuration and RTMP transcoding |
| LocalVideoTranscoding | Examples/Advanced/LocalVideoTranscoding/ |
getScreenCaptureSources(), startLocalVideoTranscoder(), updateLocalTranscoderConfiguration(), stopLocalVideoTranscoder() |
Local video transcoding and composition |
| MediaPlayer | Examples/Advanced/MediaPlayer/ |
createMediaPlayer(), open(), play(), pause(), stop() |
Media file playback and control |
| MultiCameraSourece | Examples/Advanced/MultiCameraSourece/ |
enumerateDevices(), setDevice() with multiple cameras |
Multiple camera source selection |
| Multipath | Examples/Advanced/Multipath/ |
enableMultipath(), setMultipathConfig() |
Multipath redundancy for reliability |
| PrecallTest | Examples/Advanced/PrecallTest/ |
startEchoTest(), stopEchoTest(), startNetworkTest(), stopNetworkTest() |
Pre-call network and device testing |
| QuickSwitchChannel | Examples/Advanced/QuickSwitchChannel/ |
switchChannel() |
Quick channel switching without reconnection |
| RawAudioData | Examples/Advanced/RawAudioData/ |
setAudioFrameDelegate(), onMixedAudioFrame() |
Raw audio frame access and processing |
| RawMediaData | Examples/Advanced/RawMediaData/ |
setVideoFrameDelegate(), setAudioFrameDelegate() |
Raw audio and video frame access |
| RawVideoData | Examples/Advanced/RawVideoData/ |
setVideoFrameDelegate(), onCapturedVideoFrame(), onRemoteVideoFrame() |
Raw video frame capture and processing |
| RtePlayer | Examples/Advanced/RtePlayer/ |
createMediaPlayer(), open() with RTE protocol |
RTE protocol media playback |
| RTMPStreaming | Examples/Advanced/RTMPStreaming/ |
startRtmpStreamWithTranscoding(), updateRtmpTranscodingConfig(), stopRtmpStream() |
RTMP streaming with live transcoding |
| ScreenShare | Examples/Advanced/ScreenShare/ |
startScreenCapture(), updateScreenCaptureParameters(), stopScreenCapture() |
Screen sharing and capture |
| SimpleFilter | Examples/Advanced/SimpleFilter/ |
enableExtension(), setExtensionPropertyWithVendor(), onEventWithContext() |
Simple audio and video filter extensions with context-aware event callbacks |
| Simulcast | Examples/Advanced/Simulcast/ |
setSimulcastConfig(), enableSimulcast() |
Simulcast streaming with multiple bitrates |
| SpatialAudio | Examples/Advanced/SpatialAudio/ |
getLocalSpatialAudioEngine(), updateSelfPosition(), updateRemotePosition() |
3D spatial audio positioning |
| StreamEncryption | Examples/Advanced/StreamEncryption/ |
enableEncryption(), setEncryptionConfig() |
Stream encryption and security |
| VideoProcess | Examples/Advanced/VideoProcess/ |
setVideoEncoderConfiguration(), setBeautyEffectOptions() |
Video processing and enhancement |
| VoiceChanger | Examples/Advanced/VoiceChanger/ |
setVoiceBeautifierPreset(), setAudioEffectPreset() |
Voice effects and voice changer |
The main case controller creates its engine using
AgoraRtcEngineKit.sharedEngine(with:delegate:) and AgoraRtcEngineConfig. After media
configuration and permission checks, it joins with
joinChannel(byToken:channelId:uid:mediaOptions:).
The host calls viewWillBeRemovedFromSplitView() when switching cases. Cleanup invalidates
pending Token/join requests, stops case-owned media, calls leaveChannel(nil) and
AgoraRtcEngineKit.destroy(), then clears the engine reference. SDK delegate callbacks may
arrive on background threads; AppKit updates go to the main queue.
See upsert-case and review-case for implementation and verification steps.
KeyCenter supplies AppId and optional Certificate. The basic case uses
NetworkManager.shared.generateToken(channelName:uid:success:) to obtain a Token for the
same channel and UID passed to joinChannel(byToken:channelId:uid:mediaOptions:). A case may
also expose explicit Token input. There is no KeyCenter.Token API.
When Certificate is absent, the helper returns nil for projects that do not require Token
authentication. When authentication is required, handle a failed request explicitly, and
refresh expiring tokens using renewToken(_:). Before using an asynchronous response,
confirm the request still belongs to the active case and engine. Production tokens should
be generated on a server.