Skip to content

Latest commit

 

History

History
233 lines (208 loc) · 19.3 KB

File metadata and controls

233 lines (208 loc) · 19.3 KB

ARCHITECTURE.md — APIExample

Application Lifecycle

The app and its extensions default to iOS 12. SDK-conditional build settings raise the minimum to iOS 15 when using iOS 27 SDKs, and the Podfile applies the same minimum to Pods. Use a toolchain supporting iOS 12 deployment for packages intended for iOS 12 devices. On iOS 12, AppDelegate creates the window and loads the initial controller from Main.storyboard. On iOS 13 and later, Info.plist declares a single application scene: UIKit loads Main.storyboard and assigns its window to SceneDelegate. Scene declarations and window APIs are guarded by iOS availability checks; the window helper retains its iOS 12 fallback. Do not rebuild the root controller on scene activation or end RTC sessions merely because the scene enters the background. Use a build toolchain that supports the deployment target; adopting the scene lifecycle does not require raising the minimum iOS version.

ViewController owns a LogFloatingButton defined in Common/LogViewController.swift. It is attached to the navigation container after appearance so it remains available in example pages on both iOS 12 and later. Its safe-area placement and share sheet use its own view/window hierarchy; do not use Floaty.global, which creates a window without a scene.

Case Index

Case Path Key APIs Description
JoinChannelVideo Examples/Basic/JoinChannelVideo/JoinChannelVideo.swift joinChannel(), setupLocalVideo(), setupRemoteVideo() Basic video call — join channel and render local/remote video
JoinChannelVideo(Token) Examples/Basic/JoinChannelVideo(Token)/JoinChannelVideoToken.swift joinChannel(byToken:), setupLocalVideo(), setupRemoteVideo() Video call with token authentication
JoinChannelVideo(Recorder) Examples/Basic/JoinChannelVideo(Recorder)/JoinChannelVideoRecorder.swift createMediaRecorder(), joinChannel(), setupLocalVideo() Local and remote stream recording
JoinChannelAudio Examples/Basic/JoinChannelAudio/JoinChannelAudio.swift joinChannel(), setAudioProfile(), enableAudioVolumeIndication(), adjustRecordingSignalVolume() Basic audio call with relay, scenario, volume and in-ear monitoring controls; participant area adapts to available height
LiveStreaming Examples/Advanced/LiveStreaming/LiveStreaming.swift setClientRole(), setVideoScenario(), preloadChannel(), enableCameraCenterStage() Interactive live streaming with role switching and camera features
RTMPStreaming Examples/Advanced/RTMPStreaming/RTMPStreaming.swift startRtmpStreamWithoutTranscoding(), startRtmpStream(withTranscoding:), updateRtmpTranscoding(), stopRtmpStream() Push stream to CDN with optional transcoding
VideoMetadata Examples/Advanced/VideoMetadata/VideoMetadata.swift setMediaMetadataDataSource(), setMediaMetadataDelegate() Send and receive metadata attached to video stream
VoiceChanger Examples/Advanced/VoiceChanger/VoiceChanger.swift setVoiceBeautifierPreset(), setAudioEffectPreset(), setVoiceConversionPreset(), setAINSMode() Voice beautifier, effects, conversion presets, and AI noise suppression
CustomPcmAudioSource Examples/Advanced/CustomPcmAudioSource/CustomPcmAudioSource.swift createCustomAudioTrack(), enableCustomAudioLocalPlayback(), pushExternalAudioFrameRawData() Push custom PCM audio frames as external audio source
CustomAudioRender Examples/Advanced/CustomAudioRender/CustomAudioRender.swift enableExternalAudioSink(), pullPlaybackAudioFrameRawData() Pull audio frames for custom rendering
CustomAudioSource Examples/Advanced/CustomAudioSource/CustomAudioSource.swift createCustomAudioTrack() Push custom audio via mixable audio track
CustomVideoSourcePush Examples/Advanced/CustomVideoSourcePush/CustomVideoSourcePush.swift setExternalVideoSource(), pushExternalVideoFrame() Push external video frames as custom video source
CustomVideoSourcePushMulti Examples/Advanced/CustomVideoSourcePushMulti/CustomVideoSourcePushMulti.swift createCustomVideoTrack(), createCustomEncodedVideoTrack(), pushExternalEncodedVideoFrame() Multi-track custom video source with encoded frame push
CustomVideoRender Examples/Advanced/CustomVideoRender/CustomVideoRender.swift setVideoFrameDelegate() Custom rendering of remote video frames via delegate
RawAudioData Examples/Advanced/RawAudioData/RawAudioData.swift setAudioFrameDelegate(), sendAudioMetadata() Capture raw audio PCM data via delegate
RawVideoData Examples/Advanced/RawVideoData/RawVideoData.swift setVideoFrameDelegate() Capture raw video frames via delegate
RawMediaData Examples/Advanced/RawMediaData/RawMediaData.swift setVideoFrameDelegate(), setAudioFrameDelegate(), setRecordingAudioFrameParametersWithSampleRate(), startAudioRecording() Capture both raw audio and video data simultaneously
PictureInPicture Examples/Advanced/PictureInPicture/ AVPictureInPictureController, joinChannel(), setVideoFrameDelegate() Picture-in-Picture using AVKit (iOS 15+)
SimpleFilter Examples/Advanced/SimpleFilter/SimpleFilter.swift enableExtension(), setExtensionPropertyWithVendor() Apply audio/video filter via Agora Extension API
QuickSwitchChannel Examples/Advanced/QuickSwitchChannel/QuickSwitchChannel.swift joinChannel(), leaveChannel() Quickly switch between channels as audience
JoinMultiChannel Examples/Advanced/JoinMultiChannel/JoinMultiChannel.swift joinChannelEx(), takeSnapshotEx() Join multiple channels simultaneously via ex connection
StreamEncryption Examples/Advanced/StreamEncryption/StreamEncryption.swift enableEncryption() Built-in and custom stream encryption
AudioMixing Examples/Advanced/AudioMixing/AudioMixing.swift startAudioMixing(), stopAudioMixing(), adjustAudioMixingVolume(), setEffectsVolume() Mix local audio file with microphone input
PrecallTest Examples/Advanced/PrecallTest/PrecallTest.swift startEchoTest(), stopEchoTest(), startLastmileProbeTest(), stopLastmileProbeTest() Pre-call echo test and last-mile network probe
MediaPlayer Examples/Advanced/MediaPlayer/MediaPlayer.swift createMediaPlayer(), updateChannelEx() Play media files and publish to channel via media player
ScreenShare Examples/Advanced/ScreenShare/ScreenShare.swift startScreenCapture(), updateScreenCapture(), stopScreenCapture(), setScreenCaptureScenario() Screen capture and sharing via ReplayKit extension
LocalCompositeGraph Examples/Advanced/LocalCompositeGraph/LocalCompositeGraph.swift startLocalVideoTranscoder(), startCameraCapture(), startScreenCapture(), enableVirtualBackground() Composite multiple video sources locally before publishing
VideoProcess Examples/Advanced/VideoProcess/VideoProcess.swift setBeautyEffectOptions(), enableVirtualBackground(), enableExtension() Built-in beauty, virtual background, and video enhancement
AgoraBeauty Examples/Advanced/AgoraBeauty/AgoraBeauty.swift createVideoEffectObject(), setVideoEffectStringParam(), enableVirtualBackground() Agora beauty extension with virtual background
RhythmPlayer (hidden) Examples/Advanced/RhythmPlayer/RhythmPlayer.swift startRhythmPlayer(), stopRhythmPlayer() Source retained for reference; hidden from the menu because the Rhythm Player APIs are deprecated since RTC SDK 4.6.0
CreateDataStream Examples/Advanced/CreateDataStream/CreateDataStream.swift createDataStream(), sendStreamMessage() Create and send data stream messages between users
MediaChannelRelay Examples/Advanced/MediaChannelRelay/MediaChannelRelay.swift startOrUpdateChannelMediaRelay(), stopChannelMediaRelay(), pauseAllChannelMediaRelay(), resumeAllChannelMediaRelay() Relay media stream to multiple destination channels
SpatialAudio Examples/Advanced/SpatialAudio/SpatialAudio.swift createMediaPlayer(), updateChannel() 3D spatial audio with media player integration
ContentInspect Examples/Advanced/ContentInspect/ContentInspect.swift enableContentInspect(), switchCamera() Moderate content in video stream
MutliCamera Examples/Advanced/MutliCamera/MutliCamera.swift enableMultiCamera(), startCameraCapture(), stopCameraCapture() Capture from front and back cameras simultaneously (iOS 13+)
KtvCopyrightMusic Examples/Advanced/KtvCopyrightMusic/KtvCopyrightMusic.swift — Links to KTV copyright music documentation
ThirdBeautify Examples/Advanced/ThirdBeautify/ThirdBeautify.swift enableExtension() Third-party beauty SDK integration (FaceUnity / SenseTime)
ARKit Examples/Advanced/ARKit/ARKit.swift setVideoFrameDelegate(), enableInstantMediaRendering(), startMediaRenderingTracing() Push ARKit face tracking frames as custom video source
AudioRouterPlayer Examples/Advanced/AudioRouterPlayer/AudioRouterPlayer.swift setEnableSpeakerphone() Control audio output routing with third-party player
AudioWaveform Examples/Advanced/AudioWaveform/AudioWaveform.swift setAudioProfile(), enableAudioVolumeIndication() Visualize audio waveform from volume callbacks
TransparentRender Examples/Advanced/TransparentRender/TransparentRender.swift createMediaPlayer(), setExternalVideoSource(), pushExternalVideoFrame() Render video with transparent background
RtePlayer Examples/Advanced/RtePlayer/RtePlayer.swift AgoraRte, AgoraRtePlayer, AgoraRteCanvas URL-based stream playback via RTE Player API
Simulcast Examples/Advanced/Simulcast/Simulcast.swift setSimulcastConfig(), setRemoteVideoStream() Publish multiple video quality layers simultaneously
Multipath Examples/Advanced/Multipath/Multipath.swift updateChannel() Multi-path network transmission configuration

Directory Layout

APIExample/
├── Podfile                                  # CocoaPods dependencies (AgoraRtcEngine_iOS, Floaty, AGEVideoLayout, etc.)
├── SimpleFilter/                            # Optional C++ audio/video extension module
├── Agora-ScreenShare-Extension/             # ReplayKit broadcast extension for screen sharing
├── FULib/                                   # Optional FaceUnity beauty SDK resources
├── SenseLib/                                # Optional SenseTime beauty SDK resources
├── libs/                                    # Local SDK frameworks (when not using CocoaPods)
└── APIExample/
    ├── AppDelegate.swift
    ├── SceneDelegate.swift                  # Window owned by the application scene
    ├── ViewController.swift                 # Root menu controller — MenuItem registration lives here
    ├── Info.plist
    ├── APIExample.entitlements
    ├── APIExample-Bridging-Header.h
    │
    ├── Common/
    │   ├── KeyCenter.swift                  # App ID and Certificate
    │   ├── GlobalSettings.swift             # Shared runtime config (resolution, fps, orientation, role)
    │   ├── BaseViewController.swift         # Base class all Main VCs must extend
    │   ├── EntryViewController.swift        # Generic Entry VC for storyboard == "Main" cases
    │   ├── LogViewController.swift          # Log viewer
    │   ├── AlertManager.swift
    │   ├── AgoraExtension.swift
    │   ├── PickerView.swift
    │   ├── StatisticsInfo.swift
    │   ├── UITypeAlias.swift
    │   ├── VideoView.swift / .xib           # Reusable video rendering view
    │   ├── Settings/                        # Settings UI components
    │   ├── Utils/                           # LogUtils, Util (privatization config)
    │   ├── NetworkManager/                  # Token request helper
    │   ├── ExternalAudio/                   # External audio source helpers
    │   ├── ExternalVideo/                   # External video source helpers
    │   ├── CustomEncryption/                # Custom stream encryption helpers
    │   └── ARKit/                           # ARKit integration helpers
    │
    ├── Examples/
    │   ├── Basic/
    │   │   ├── JoinChannelVideo/            # "Join a channel (Video)"
    │   │   ├── JoinChannelVideo(Token)/     # "Join a channel (Token)"
    │   │   ├── JoinChannelVideo(Recorder)/  # "Local or remote recording"
    │   │   └── JoinChannelAudio/            # "Join a channel (Audio)"
    │   └── Advanced/
    │       ├── LiveStreaming/               # "Live Streaming" — setClientRole
    │       ├── RTMPStreaming/               # "RTMP Streaming" — push to CDN
    │       ├── VideoMetadata/               # "Media Metadata" — send/receive metadata
    │       ├── VoiceChanger/                # "Voice Effects" — voice beautifier/effects
    │       ├── CustomPcmAudioSource/        # "Custom Audio Source (PCM)" — push PCM audio
    │       ├── CustomAudioRender/           # "Custom Audio Render" — pull audio rendering
    │       ├── CustomAudioSource/           # (legacy custom audio source)
    │       ├── CustomVideoSourcePush/       # "Custom Video Source" — push external video
    │       ├── CustomVideoSourcePushMulti/  # "Multiple Video Sources" — multi-track push
    │       ├── CustomVideoRender/           # "Custom Video Render"
    │       ├── RawAudioData/                # "Raw Audio Data"
    │       ├── RawVideoData/                # "Raw Video Data"
    │       ├── RawMediaData/                # (legacy raw media data)
    │       ├── PictureInPicture/            # "Picture In Picture"
    │       ├── SimpleFilter/                # "Simple Filter Extension"
    │       ├── QuickSwitchChannel/          # "Quick Switch Channel"
    │       ├── JoinMultiChannel/            # "Join Multiple Channels"
    │       ├── StreamEncryption/            # "Stream Encryption"
    │       ├── AudioMixing/                 # "Audio Mixing"
    │       ├── PrecallTest/                 # "Pre-call Test"
    │       ├── MediaPlayer/                 # "Media Player"
    │       ├── ScreenShare/                 # "Screen Share"
    │       ├── LocalCompositeGraph/         # "Local Composite Graph"
    │       ├── VideoProcess/                # "Video Process"
    │       ├── AgoraBeauty/                 # "Beauty 2.0"
    │       ├── RhythmPlayer/                # Hidden — APIs deprecated since RTC SDK 4.6.0
    │       ├── CreateDataStream/            # "Send Data Stream"
    │       ├── MediaChannelRelay/           # "Media Channel Relay"
    │       ├── SpatialAudio/                # "Spatial Audio"
    │       ├── ContentInspect/              # "Content Inspect"
    │       ├── MutliCamera/                 # "Multi Camera"
    │       ├── KtvCopyrightMusic/           # "KTV Copyright Music"
    │       ├── ThirdBeautify/               # "Third-party Beauty" — third-party beauty SDK
    │       ├── ARKit/                       # "ARKit"
    │       ├── AudioRouterPlayer/           # "Audio Router (Third-party Player)"
    │       ├── AudioWaveform/               # "Audio Waveform"
    │       ├── TransparentRender/           # "Transparent Rendering"
    │       ├── RtePlayer/                   # "URL Streaming (RTE Player)"
    │       ├── Simulcast/                   # "Simulcast"
    │       ├── Multipath/                   # "Multipath"
    │       └── VideoChat/                   # (disabled) Group Video Chat
    │
    ├── Resources/                           # Audio/video sample files, beauty resources
    ├── Assets.xcassets/
    ├── Base.lproj/                          # Main.storyboard, LaunchScreen.storyboard
    └── zh-Hans.lproj/                       # Chinese localization

Case Registration Mechanism

Registration is manual via the menus array in ViewController.swift. No reflection or annotation scanning.

MenuItem struct:

struct MenuItem {
    var name: String        // display name in the list
    var entry: String       // storyboard ID of the entry VC (default: "EntryViewController")
    var storyboard: String  // storyboard file name (default: "Main")
    var controller: String  // storyboard ID of the main VC
    var note: String        // optional description
}

Two navigation paths exist depending on storyboard:

  1. storyboard == "Main" — uses the shared Main.storyboard. The generic EntryViewController is instantiated, and nextVCIdentifier is set to controller to load the Main VC.
  2. storyboard != "Main" — each example has its own .storyboard file. The VC with identifier entry (default "EntryViewController") is instantiated directly from that storyboard.

Most examples use path 2 (their own storyboard).

A registered case connects the MenuItem, its Swift controller(s), and its storyboard. New source files must belong to the Xcode target's Sources build phase, and storyboards, localized files, and media assets must belong to Resources. Follow upsert-case for the complete change procedure and update the Case Index when the case changes.

Entry/Main ViewController Pattern

Every example is split into two view controller roles:

Entry (<ExampleName>Entry : UIViewController)

  • Collects user configuration before entering the example
  • Passes configuration to Main via a configs dictionary

Main (<ExampleName>Main : BaseViewController)

  • Owns the AgoraRtcEngineKit lifecycle for the duration of the example
  • Implements AgoraRtcEngineDelegate
  • Receives configuration exclusively through configs

AgoraRtcEngineKit Lifecycle

viewDidLoad    → AgoraRtcEngineKit.sharedEngine(withAppId:delegate:)
               → engine.setVideoEncoderConfiguration / setChannelProfile
               → engine.joinChannel() (after permission granted)
                      ↓
                 [AgoraRtcEngineDelegate callbacks — may be on background thread]
                      ↓
willMove(toParent:) when parent == nil
               → engine.leaveChannel()
               → AgoraRtcEngineKit.destroy()

For navigation-based cases, cleanup runs when the controller is removed from its parent. Temporary disappearance alone must not destroy the engine; follow the guarded cleanup in the upsert and review skills.

Token Flow

Use the guarded permission → Token → join implementation in upsert-case. Snapshot channel, UID, request generation and engine identity before asynchronous work. Recheck them on main before each continuation; leave/destroy invalidates pending requests and destroy clears engine ownership. Weak capture alone does not protect a still-alive controller whose RTC session has ended.

A nil/empty Token is allowed only when no App Certificate is configured. Reject a missing required Token and check the SDK join return code without logging credentials.