Callum.Voice
0.0.2
dotnet add package Callum.Voice --version 0.0.2
NuGet\Install-Package Callum.Voice -Version 0.0.2
<PackageReference Include="Callum.Voice" Version="0.0.2" />
<PackageVersion Include="Callum.Voice" Version="0.0.2" />
<PackageReference Include="Callum.Voice" />
paket add Callum.Voice --version 0.0.2
#r "nuget: Callum.Voice, 0.0.2"
#:package Callum.Voice@0.0.2
#addin nuget:?package=Callum.Voice&version=0.0.2
#tool nuget:?package=Callum.Voice&version=0.0.2
Callum.Voice — Real-Time Voice Chat Library
A .NET library for cross-platform real-time voice communication over a Go server (phonil-opus).
All microphone capture, audio playback, WebSocket connection, multi-peer audio mixing, speaking detection, and room management logic is implemented in this library.
Table of Contents
- Architecture
- File Structure
- Communication Protocol
- Supported Platforms
- API Reference
- VoiceConfig
- Events
- Important Notes
Architecture
┌──────────────────────────────────────────────────────────┐
│ Callum.Voice │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌──────────┐ │
│ │ VoiceClient │────▶│ IAudioEngine │────▶│ Platform │ │
│ │ │◀────│ (interface) │◀────│ Audio │ │
│ │ • WebSocket │ │ │ │ Engine │ │
│ │ • Room Mgmt │ │ • Capture │ │ │ │
│ │ • Peer Track│ │ • Playback │ │ • WASAPI │ │
│ │ • Speaking │ │ • Volume │ │ • AVAudio│ │
│ │ • Reconnect │ │ • Power Mgmt │ │ • AudioR.│ │
│ └─────────────┘ └──────────────┘ └──────────┘ │
│ │ ▲ │
│ │ WebSocket (PCM 16-bit mono) │ │
│ ▼ │ │
│ ┌─────────────┐ │ │
│ │ Go Server │────── PCM Audio ────────────┘ │
│ │ (phonil-opus)│ │
│ └─────────────┘ │
└──────────────────────────────────────────────────────────┘
Layers
| Layer | Responsibility |
|---|---|
| VoiceClient | Network logic (WebSocket), room management, peer tracking, speaking detection, auto-reconnect |
| IAudioEngine | Abstract interface for audio capture and playback — each platform has its own implementation |
| AudioEngine (Platform) | Platform-specific implementation: Android (AudioRecord/AudioTrack), iOS (AVAudioEngine), Windows (WASAPI) |
File Structure
Callum.Voice/
├── VoiceClient.cs # Core logic: WebSocket, room, mixing, speaking detection
├── VoiceConfig.cs # Connection settings (server, API key, sample rate)
├── VoiceClientState.cs # Connection states (Disconnected → Connected → InRoom)
├── IAudioEngine.cs # Abstract audio engine interface
├── Platforms/
│ ├── Android/
│ │ ├── AudioEngine.cs # Capture/playback with AudioRecord/AudioTrack + Ring Buffer
│ │ └── VoiceForegroundService.cs # Android foreground service
│ ├── iOS/
│ │ └── AudioEngine.cs # Capture/playback with AVAudioEngine + AVAudioPlayerNode
│ ├── MacCatalyst/
│ │ └── (uses the iOS engine)
│ └── Windows/
│ └── AudioEngine.cs # Capture/playback with WASAPI (COM Interop)
└── Callum.Voice.csproj
Communication Protocol
WebSocket Connection
ws(s)://{server}/ws?room=__lobby__&peer={peerId}&api_key={apiKey}
Text Message (JSON) — Join Room
{
"type": "join",
"room": "room-id",
"peer": "user-123",
"sampleRate": 48000
}
Binary Message (Audio) — Packet Format
[1B RoomLen][RoomID][1B PeerLen][PeerID][PCM Audio Data]
- PCM Format: 16-bit signed integer, mono, 48 kHz
- Each packet contains the room ID, sender ID, and raw audio data
Supported Platforms
1. .NET MAUI
Status: Fully supported — Production ready
The library is distributed as a standalone NuGet package (Callum.Voice) with no MAUI dependency. It only uses native platform APIs.
Target Frameworks:
<TargetFrameworks>net10.0-android;net10.0-ios;net10.0-maccatalyst;net10.0-windows10.0.19041.0</TargetFrameworks>
Dependencies:
- Android:
Xamarin.AndroidX.Core(forContextCompatandNotificationCompat) - iOS/MacCatalyst/Windows: No additional dependencies
Minimum supported versions: | Platform | Minimum Version | |----------|----------------| | Android | API 23 (6.0) | | iOS | 15.0 | | MacCatalyst | 15.0 | | Windows | 10.0.17763.0 |
NuGet Installation
dotnet add package Callum.Voice
MAUI Example — Main Page
using Callum.Voice;
public partial class VoicePage : ContentPage
{
private VoiceClient? _client;
public VoicePage()
{
InitializeComponent();
}
protected async override void OnAppearing()
{
base.OnAppearing();
// 1. Create audio engine (auto-selects platform implementation)
var audio = new AudioEngine(sampleRate: 48_000);
// 2. Create client
var config = new VoiceConfig
{
Server = "callem.cloudfort.ir",
ApiKey = "vc_live_YOUR_API_KEY",
PeerId = $"user-{Guid.NewGuid():N}",
AutoReconnect = true,
};
_client = new VoiceClient(config, audio);
// 3. Register events
_client.Connected += () =>
MainThread.BeginInvokeOnMainThread(() =>
lblStatus.Text = "Connected");
_client.PeerJoined += peerId =>
MainThread.BeginInvokeOnMainThread(() =>
lblPeers.Text += $"\n{peerId}");
_client.PeerSpeaking += peerId =>
MainThread.BeginInvokeOnMainThread(() =>
lblSpeaking.Text = $"{peerId} is speaking...");
_client.Error += ex =>
MainThread.BeginInvokeOnMainThread(() =>
lblStatus.Text = $"Error: {ex.Message}");
// 4. Connect and join room
await _client.ConnectAsync();
await _client.JoinRoomAsync("general");
// 5. Enable microphone
await _client.EnableMicAsync();
}
private async void OnToggleMic(object sender, EventArgs e)
{
bool isOn = await _client!.ToggleMicAsync();
btnMic.Text = isOn ? "🎤 Mute" : "🎤 Unmute";
}
protected override void OnDisappearing()
{
_client?.Dispose();
base.OnDisappearing();
}
}
2. WPF (Windows)
Status: Fully supported — No changes needed
The library has no MAUI dependency and can be used directly in WPF projects.
WPF Example
using System.Windows;
using Callum.Voice;
namespace MyWpfApp;
public partial class MainWindow : Window
{
private VoiceClient? _client;
public MainWindow()
{
InitializeComponent();
}
private async void BtnConnect_Click(object sender, RoutedEventArgs e)
{
var audio = new AudioEngine(sampleRate: 48_000);
var config = new VoiceConfig
{
Server = "callem.cloudfort.ir",
ApiKey = "vc_live_YOUR_API_KEY",
PeerId = $"wpf-user-{Guid.NewGuid():N}",
};
_client = new VoiceClient(config, audio);
_client.Connected += () =>
Dispatcher.Invoke(() => txtStatus.Text = "Connected");
_client.PeerSpeaking += peerId =>
Dispatcher.Invoke(() => txtSpeaking.Text = $"{peerId} speaking");
await _client.ConnectAsync();
await _client.JoinRoomAsync("general");
await _client.EnableMicAsync();
}
private async void BtnToggleMic_Click(object sender, RoutedEventArgs e)
{
bool isOn = await _client!.ToggleMicAsync();
btnMic.Content = isOn ? "Mute" : "Unmute";
}
protected override void OnClosed(EventArgs e)
{
_client?.Dispose();
base.OnClosed(e);
}
}
Note: The Windows
AudioEngineuses WASAPI COM Interop and is fully standalone.
Custom IAudioEngine for WPF
using Callum.Voice;
using NAudio.Wave; // NuGet: NAudio
public class WpfAudioEngine : IAudioEngine
{
private WaveInEvent? _waveIn;
private WaveOutEvent? _waveOut;
// ... NAudio implementation
public int SampleRate => 48_000;
public event Action<short[]>? AudioCaptured;
public event Action<string>? ErrorOccurred;
public void StartCapture()
{
_waveIn = new WaveInEvent { WaveFormat = new WaveFormat(48000, 16, 1) };
_waveIn.DataAvailable += (s, e) =>
{
var samples = new short[e.BytesRecorded / 2];
Buffer.BlockCopy(e.Buffer, 0, samples, 0, e.BytesRecorded);
AudioCaptured?.Invoke(samples);
};
_waveIn.StartRecording();
}
public void StopCapture() => _waveIn?.StopRecording();
public void StartPlayback() { /* ... */ }
public void StopPlayback() { /* ... */ }
public void EnqueuePeerAudio(string peerId, short[] samples) { /* ... */ }
public void RemovePeer(string peerId) { /* ... */ }
public void ClearPeers() { /* ... */ }
public void SetPlaybackVolume(float volume) { /* ... */ }
public void KeepScreenAwake() { /* no-op on WPF */ }
public void ReleaseScreenAwake() { /* no-op on WPF */ }
public Task<bool> RequestMicrophonePermission() => Task.FromResult(true);
public void Dispose() { StopCapture(); StopPlayback(); }
}
3. ASP.NET Core MVC
Status: Server-side only — No mic/speaker access
ASP.NET Core is a server-side framework and does not have direct access to microphones or speakers. However, it can:
- Act as a relay server for audio routing
- Serve the JavaScript SDK (
voice-chat-sdk.js) to browsers - Use
VoiceClientfor server-side room connections (e.g., recording or monitoring)
ASP.NET Core Example — Serving SDK to Browser
// Controllers/VoiceController.cs
using Microsoft.AspNetCore.Mvc;
namespace MyWebApp.Controllers;
public class VoiceController : Controller
{
public IActionResult Chat()
{
// HTML page with JavaScript SDK
return View();
}
}
<!DOCTYPE html>
<html>
<head>
<title>Voice Chat</title>
<script src="~/js/voice-chat-sdk.js"></script>
</head>
<body>
<h1>Voice Chat Room</h1>
<button onclick="join()">Join</button>
<button onclick="toggleMic()">Toggle Mic</button>
<script>
const client = new VoiceChatSDK({
server: 'callem.cloudfort.ir',
apiKey: 'vc_live_YOUR_API_KEY',
peerId: 'web-user-@ViewBag.UserId',
});
client.on('connected', () => client.joinRoom('general'));
client.on('peer-speaking', (id) => console.log(`${id} speaking`));
client.connect();
async function join() {
await client.joinRoom('general');
await client.enableMic();
}
async function toggleMic() { await client.toggleMic(); }
</script>
</body>
</html>
ASP.NET Core Example — Server-Side VoiceClient (Monitoring/Recording)
// Services/VoiceMonitor.cs
using Callum.Voice;
public class VoiceMonitorService : BackgroundService
{
private VoiceClient? _client;
protected override async Task ExecuteAsync(CancellationToken ct)
{
// Server without mic — for listening/monitoring only
var audio = new HeadlessAudioEngine(); // No-audio implementation
var config = new VoiceConfig
{
Server = "callem.cloudfort.ir",
ApiKey = "vc_live_YOUR_API_KEY",
PeerId = "server-monitor-01",
};
_client = new VoiceClient(config, audio);
_client.PeerSpeaking += peerId =>
Console.WriteLine($"[Monitor] {peerId} is speaking");
await _client.ConnectAsync(ct);
await _client.JoinRoomAsync("general");
}
}
// HeadlessAudioEngine implementation (no audio hardware)
public class HeadlessAudioEngine : IAudioEngine
{
public int SampleRate => 48_000;
public event Action<short[]>? AudioCaptured;
public event Action<string>? ErrorOccurred;
public Task<bool> RequestMicrophonePermission() => Task.FromResult(true);
public void StartCapture() { }
public void StopCapture() { }
public void StartPlayback() { }
public void StopPlayback() { }
public void EnqueuePeerAudio(string peerId, short[] samples)
{
// Receive audio but don't play it (monitoring only)
}
public void RemovePeer(string peerId) { }
public void ClearPeers() { }
public void SetPlaybackVolume(float volume) { }
public void KeepScreenAwake() { }
public void ReleaseScreenAwake() { }
public void Dispose() { }
}
4. Blazor WebAssembly
Status: Usable — Web Audio API via JS Interop
Blazor WASM runs in the browser, so it must use voice-chat-sdk.js (JavaScript SDK) via IJSRuntime.
Blazor WASM Example
@page "/voice"
@inject IJSRuntime JS
@implements IAsyncDisposable
<h3>Voice Chat</h3>
<p>Status: @_status</p>
<p>Speaking: @_speaking</p>
<button @onclick="JoinRoom">Join</button>
<button @onclick="ToggleMic">Toggle Mic</button>
@code {
private string _status = "Disconnected";
private string _speaking = "";
private IJSObjectReference? _jsModule;
protected async override Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
_jsModule = await JS.InvokeAsync<IJSObjectReference>(
"import", "./js/voice-interop.js");
}
}
public async Task JoinRoom()
{
if (_jsModule is not null)
await _jsModule.InvokeVoidAsync("joinVoiceRoom", "general");
}
public async Task ToggleMic()
{
if (_jsModule is not null)
await _jsModule.InvokeVoidAsync("toggleMic");
}
public async ValueTask DisposeAsync()
{
if (_jsModule is not null)
await _jsModule.DisposeAsync();
}
}
// wwwroot/js/voice-interop.js
import VoiceChatSDK from './voice-chat-sdk.js';
const client = new VoiceChatSDK({
server: 'callem.cloudfort.ir',
apiKey: 'vc_live_YOUR_API_KEY',
peerId: 'blazor-user-' + Date.now(),
});
client.on('connected', () => {
DotNet.invokeMethodAsync('MyBlazorApp', 'OnVoiceStatus', 'Connected');
});
client.on('peer-speaking', (id) => {
DotNet.invokeMethodAsync('MyBlazorApp', 'OnPeerSpeaking', id);
});
client.connect();
export function joinVoiceRoom(roomId) {
client.joinRoom(roomId).then(() => client.enableMic());
}
export function toggleMic() {
client.toggleMic();
}
5. Avalonia UI
Status: Usable — Similar to WPF
Avalonia is a cross-platform UI framework. To use Callum.Voice:
- Windows: Use the Windows
AudioEngine(WASAPI) - Linux/macOS: Implement a custom
IAudioEnginewith PulseAudio/CoreAudio
Avalonia Example
// MainWindowViewModel.cs
using Callum.Voice;
public class MainWindowViewModel : ViewModelBase
{
private VoiceClient? _client;
private string _status = "Disconnected";
public string Status
{
get => _status;
set => this.RaiseAndSetIfChanged(ref _status, value);
}
public async Task ConnectAsync()
{
var audio = new AudioEngine(sampleRate: 48_000); // Windows WASAPI
var config = new VoiceConfig
{
Server = "callem.cloudfort.ir",
ApiKey = "vc_live_YOUR_API_KEY",
PeerId = $"avalonia-{Guid.NewGuid():N}",
};
_client = new VoiceClient(config, audio);
_client.Connected += () => Status = "Connected";
_client.PeerSpeaking += id => Status = $"{id} speaking";
await _client.ConnectAsync();
await _client.JoinRoomAsync("general");
await _client.EnableMicAsync();
}
}
6. Console App (.NET)
Status: Usable — Headless (no playback/capture)
For command-line tools, bots, or background services:
Console Example — Monitoring Bot
using Callum.Voice;
var audio = new HeadlessAudioEngine();
var config = new VoiceConfig
{
Server = "callem.cloudfort.ir",
ApiKey = "vc_live_YOUR_API_KEY",
PeerId = $"bot-{Guid.NewGuid():N}",
};
using var client = new VoiceClient(config, audio);
client.Connected += () => Console.WriteLine("[+] Connected");
client.PeerJoined += id => Console.WriteLine($"[+] Peer joined: {id}");
client.PeerSpeaking += id => Console.WriteLine($"[!] {id} is speaking");
client.PeerLeft += id => Console.WriteLine($"[-] Peer left: {id}");
client.Disconnected += () => Console.WriteLine("[-] Disconnected");
await client.ConnectAsync();
await client.JoinRoomAsync("general");
Console.WriteLine("Monitoring room... Press Enter to exit.");
Console.ReadLine();
7. Unity
Status: Supported — Requires custom IAudioEngine implementation
The library ships a netstandard2.1 build that can be consumed by Unity (2021.2+). Since Unity has its own audio system, you need to implement IAudioEngine using Unity APIs (Microphone, AudioClip, OnAudioFilterRead).
Setup
- Install the NuGet package via NuGetForUnity or copy the DLLs manually:
dotnet add package Callum.Voice - Create a
UnityAudioEngineclass (see below) - Use
VoiceClientas you would on any other platform
Unity Example — UnityAudioEngine
using Callum.Voice;
using System.Collections.Concurrent;
using UnityEngine;
public class UnityAudioEngine : IAudioEngine
{
private AudioClip? _micClip;
private int _sampleRate = 48000;
private float _volume = 1f;
// Peer playback
private readonly ConcurrentDictionary<string, ConcurrentQueue<short>> _peerBuffers = new();
private float[] _mixBuffer = new float[480]; // 10ms at 48kHz
public int SampleRate => _sampleRate;
public event Action<short[]>? AudioCaptured;
public event Action<string>? ErrorOccurred;
public Task<bool> RequestMicrophonePermission()
{
// Unity handles mic permission via Application.RequestUserAuthorization
return Task.FromResult(true);
}
public void StartCapture()
{
_sampleRate = AudioSettings.outputSampleRate;
var mic = Microphone.devices.Length > 0 ? Microphone.devices[0] : null;
_micClip = Microphone.Start(mic, true, 1, _sampleRate);
}
public void StopCapture()
{
if (_micClip != null)
{
Microphone.End(null);
_micClip = null;
}
}
public void StartPlayback() { }
public void StopPlayback()
{
_peerBuffers.Clear();
}
public void EnqueuePeerAudio(string peerId, short[] samples)
{
var queue = _peerBuffers.GetOrAdd(peerId, _ => new ConcurrentQueue<short>());
foreach (var s in samples) queue.Enqueue(s);
}
public void RemovePeer(string peerId)
{
_peerBuffers.TryRemove(peerId, out _);
}
public void ClearPeers() => _peerBuffers.Clear();
public void SetPlaybackVolume(float volume) => _volume = volume;
public void KeepScreenAwake() => Screen.sleepTimeout = SleepTimeout.NeverSleep;
public void ReleaseScreenAwake() => Screen.sleepTimeout = SleepTimeout.SystemSetting;
/// <summary>
/// Called by Unity on the audio thread.
/// Reads mic data and mixes peer audio into the output.
/// Attach this component to a GameObject with an AudioSource.
/// </summary>
public void OnAudioFilterRead(float[] data, int channels)
{
// 1) Capture mic samples and fire event
if (_micClip != null)
{
var pos = Microphone.GetPosition(null);
if (pos > 0)
{
var micData = new float[pos];
_micClip.GetData(micData, 0);
var pcm = new short[micData.Length];
for (int i = 0; i < micData.Length; i++)
pcm[i] = (short)(Mathf.Clamp(micData[i], -1f, 1f) * 32767f);
AudioCaptured?.Invoke(pcm);
}
}
// 2) Mix peer audio into output
for (int i = 0; i < data.Length; i++) data[i] = 0f;
foreach (var kvp in _peerBuffers)
{
for (int i = 0; i < data.Length; i += channels)
{
if (kvp.Value.TryDequeue(out short sample))
{
float f = (sample / 32768f) * _volume;
for (int c = 0; c < channels; c++)
data[i + c] += f;
}
}
}
}
public void Dispose()
{
StopCapture();
StopPlayback();
}
}
Unity Example — Usage in a MonoBehaviour
using Callum.Voice;
using UnityEngine;
public class VoiceChatManager : MonoBehaviour
{
private VoiceClient? _client;
private UnityAudioEngine? _audio;
async void Start()
{
_audio = new UnityAudioEngine();
var config = new VoiceConfig
{
Server = "callem.cloudfort.ir",
ApiKey = "vc_live_YOUR_API_KEY",
PeerId = $"unity-{System.Guid.NewGuid():N}",
AutoReconnect = true,
};
_client = new VoiceClient(config, _audio);
_client.Connected += () => Debug.Log("[Voice] Connected");
_client.PeerJoined += id => Debug.Log($"[Voice] Peer joined: {id}");
_client.PeerSpeaking += id => Debug.Log($"[Voice] {id} speaking");
_client.Error += ex => Debug.LogError($"[Voice] Error: {ex.Message}");
await _client.ConnectAsync();
await _client.JoinRoomAsync("general");
await _client.EnableMicAsync();
}
void OnAudioFilterRead(float[] data, int channels)
{
_audio?.OnAudioFilterRead(data, channels);
}
void OnDestroy()
{
_client?.Dispose();
}
}
Note: Attach
VoiceChatManagerto a GameObject in your scene. TheOnAudioFilterReadcallback is used by Unity to process audio on the audio thread — it must be on a MonoBehaviour.
API Reference
VoiceClient
| Method | Return Type | Description |
|---|---|---|
ConnectAsync(ct) |
Task |
Connect to server |
Disconnect() |
void |
Disconnect from server |
JoinRoomAsync(roomId) |
Task |
Join a room |
LeaveRoomAsync() |
Task |
Leave current room |
EnableMicAsync() |
Task |
Enable microphone (requests permission) |
DisableMic() |
void |
Disable microphone |
ToggleMicAsync() |
Task<bool> |
Toggle microphone state |
EnableSpeaker() |
void |
Enable speaker (Android) |
DisableSpeaker() |
void |
Disable speaker |
ToggleSpeaker() |
bool |
Toggle speaker state |
IsPeerSpeaking(peerId) |
bool |
Check if peer is speaking |
IsPeerSpeaking(peerId, out level) |
bool |
Also returns RMS level |
Dispose() |
void |
Release resources |
Properties
| Property | Type | Description |
|---|---|---|
State |
VoiceClientState |
Current connection state |
IsConnected |
bool |
Whether connected to server |
IsInRoom |
bool |
Whether in a room |
IsMicEnabled |
bool |
Whether microphone is enabled |
CurrentRoom |
string? |
Current room ID |
Peers |
IReadOnlyCollection<string> |
List of peers in room |
VoiceConfig
| Property | Type | Default | Description |
|---|---|---|---|
Server |
string |
— | Server address (e.g., callem.cloudfort.ir) |
ApiKey |
string |
— | API key (vc_live_...) |
PeerId |
string |
— | Unique peer identifier |
UseTls |
bool? |
null |
Use WSS (null = auto-detect) |
SampleRate |
int |
48000 |
Audio sample rate (Hz) |
AutoReconnect |
bool |
true |
Auto reconnect on disconnect |
MaxReconnectAttempts |
int |
5 |
Maximum reconnect attempts |
ReconnectDelay |
TimeSpan |
2s |
Delay between attempts |
EchoCancellation |
bool |
true |
Echo cancellation |
NoiseSuppression |
bool |
true |
Noise suppression |
AutoGainControl |
bool |
true |
Automatic gain control |
Events
| Event | Type | Description |
|---|---|---|
Connected |
Action |
Connection established |
Disconnected |
Action |
Connection lost |
Reconnecting |
Action<int> |
Reconnection attempt (with attempt number) |
AuthFailed |
Action<string> |
Authentication failed |
RoomJoined |
Action<string> |
Joined a room |
RoomLeft |
Action<string> |
Left a room |
PeerJoined |
Action<string> |
New peer joined |
PeerLeft |
Action<string> |
Peer left |
PeerSpeaking |
Action<string> |
Peer started speaking |
PeerStopped |
Action<string> |
Peer stopped speaking |
MicEnabled |
Action |
Microphone enabled |
MicDisabled |
Action |
Microphone disabled |
Error |
Action<Exception> |
Error occurred |
StateChanged |
Action<VoiceClientState> |
Connection state changed |
Important Notes
Platform Support Summary
| Platform | Capture/Playback | VoiceClient | Custom IAudioEngine Needed |
|---|---|---|---|
| MAUI Android | ✅ Ready | ✅ Ready | ❌ No |
| MAUI iOS | ✅ Ready | ✅ Ready | ❌ No |
| MAUI Windows | ✅ Ready | ✅ Ready | ❌ No |
| WPF | ✅ Ready | ✅ Ready | ❌ No (WASAPI built-in) |
| Avalonia | ✅ Ready | ✅ Ready | ⚠️ For Linux/macOS |
| ASP.NET Core | ❌ Server-side | ✅ Ready | ✅ HeadlessAudioEngine |
| Blazor WASM | ✅ Browser | ✅ Via JS Interop | ✅ JavaScript SDK |
| Console | ❌ No hardware | ✅ Ready | ✅ HeadlessAudioEngine |
| Unity | ✅ Via Unity Audio | ✅ Ready | ✅ UnityAudioEngine (provided) |
Required Permissions
| Platform | Permission |
|---|---|
| Android | RECORD_AUDIO (runtime) |
| iOS | NSMicrophoneUsageDescription (Info.plist) |
| Windows | Microphone (via OS settings) |
Audio Format
- PCM 16-bit signed integer
- Mono (single channel)
- 48,000 Hz sample rate (default)
- Bitrate: ~768 kbps (48000 × 16 × 1)
Server
The Go server (phonil-opus) is available at callem.cloudfort.ir.
For self-hosting, refer to the server's README-SDK.md.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-android36.0 is compatible. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 is compatible. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- System.Text.Json (>= 9.0.3)
-
net10.0-android36.0
- Xamarin.AndroidX.Core (>= 1.15.0.2)
-
net10.0-ios26.0
- No dependencies.
-
net10.0-maccatalyst26.0
- No dependencies.
-
net10.0-windows10.0.19041
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.