This is an iOS implementation of the Audio Safety feature for real-time voice moderation, matching the Android reference implementation.
- ✅ Rolling audio buffer (300 seconds default) for local and remote users
- ✅ 8-seat audio view displaying joined users
- ✅ Tap-to-report functionality for any user
- ✅ WAV file generation with complete audio evidence
- ✅ User registration system for selective monitoring
- ✅ Thread-safe audio processing
- ✅ Debounce protection for report actions
- iOS 13.0+
- Xcode 14.0+
- CocoaPods
- Agora App ID
git clone https://github.com/AgoraIO-Solutions/AudioSafety.git
cd AudioSafetypod installCopy the example credentials file and add your Agora App ID:
cp KeyStore.swift.example KeyStore.swiftThen open KeyStore.swift and replace the placeholder values:
struct KeyStore {
static let appId: String = "YOUR_AGORA_APP_ID" // Get from https://console.agora.io/
static let token: String? = nil // Optional: Add token for production
static let channelName: String = "test-channel" // Change as needed
}KeyStore.swift is in .gitignore - never commit your credentials!
open AudioSafety.xcworkspace.xcworkspace file, not the .xcodeproj file, when using CocoaPods.
- Select your target device or simulator
- Press
Cmd + Rto build and run
- Join Channel: App automatically joins the channel specified in
KeyStore.channelName - View Users: Up to 8 users displayed in seat views
- Blue seats = Local user (you)
- Green seats = Remote users
- Report User: Tap any seat to generate audio evidence
- Audio Files: WAV files saved to app's temporary directory
AudioSafety/
├── AudioSafety.swift # Main view controller with 8-seat UI
├── AudioSafetyManager.swift # Audio buffer manager
├── AppDelegate.swift # App lifecycle
├── SceneDelegate.swift # Scene management
├── Info.plist # App configuration
├── Podfile # CocoaPods dependencies
├── KeyStore.swift.example # Template for credentials (commit this)
├── KeyStore.swift # Your actual credentials (DO NOT COMMIT)
├── .gitignore # Protects credentials
└── README.md # This file
-
Recording State:
startRecording()when joining channelstopRecording()when leaving channel
-
User Registration:
- Local user automatically registered on join
- Remote users registered when they join
- Users unregistered when they leave
-
Audio Capture:
- Local audio via
onRecordAudioFrame - Remote audio via
onPlaybackAudioFrame(beforeMixing:) - 48kHz, Mono, 16-bit PCM format
- Local audio via
-
Buffer Storage:
- Circular buffer (300 seconds = 5 minutes)
- Rolling overwrites oldest data when full
- Separate buffer per user
-
Report Generation:
- Tap any seat to report that user
- Creates WAV file with audio evidence
- Non-destructive read (can report multiple times)
- Sample Rate: 48,000 Hz
- Channels: 1 (Mono)
- Bit Depth: 16-bit
- Format: PCM, Little Endian
- Output: WAV files
The app requires the following permissions (configured in Info.plist):
- Microphone: For capturing local audio
- Camera (optional): If you add video features later
- Join channel on simulator
- Audio recording will work but you won't hear remote users
- Useful for UI testing
- Requires physical iOS device
- Join same channel from multiple devices to test remote user features
- Can test with Android app for cross-platform verification
- Device A: Join channel "AudioSafetyDemo"
- Device B: Join same channel
- Tap on remote user seat to generate report
- Check console logs for WAV file paths
# Update CocoaPods
sudo gem install cocoapods
pod repo update
pod install- Clean build folder:
Cmd + Shift + K - Delete DerivedData:
rm -rf ~/Library/Developer/Xcode/DerivedData - Re-install pods:
pod deintegrate && pod install
- Check microphone permissions in Settings
- Verify App ID is correct
- Check console logs for detailed errors
- Replace App ID: Use your production Agora App ID
- Add Token Authentication: Implement token generation for security
- Upload Audio Files: Send WAV files to your moderation service
- Error Handling: Add robust error handling and retry logic
- Analytics: Track report events for monitoring
- User Privacy: Ensure compliance with privacy regulations
- Storage Management: Clean up old WAV files periodically
private func reportUser(uid: UInt) {
// ... existing code ...
manager.recordBuffer(uid: uid) { fileUrl in
if let url = fileUrl {
// Upload to your moderation service
self.uploadToModerationService(fileUrl: url, reportedUid: uid)
}
}
}
private func uploadToModerationService(fileUrl: URL, reportedUid: UInt) {
// Implement your upload logic here
// Example: POST to https://your-api.com/moderation/upload
}This implementation follows the Android reference to AudioSafety: https://github.com/AgoraIO/API-Examples/tree/dev/CSD-75694/Android/APIExample-Audio/app/src/main/java/io/agora/api/example/examples/advanced/audiosafety
- User Registration: Only monitored users consume memory
- Recording State: Explicit start/stop control
- Thread Safety: All buffer operations on dedicated queue
- Format Validation: Ensures correct audio format
- Debounce Protection: Prevents spam reporting
This is a demo implementation. Check with Agora and your organization for licensing requirements.