// Marshaling — shared "walk a native array of owned-struct entries, convert to Swift value // types, free the native list" pattern. Identical shape for vc_device_list / vc_channel_list // / vc_user_list / vc_stream_summary_list / vc_account_list (all core-allocated, caller-freed // per voicecat.h). The matching vc_free_*_list call happens INSIDE each function here, // immediately after the conversion, so callers never need to remember to free anything // themselves. This is the Swift analog of the C# client's Marshaling.cs. import VoiceCatC import Foundation /// Internal marshaling helpers — convert core-allocated C arrays to Swift arrays and /// immediately free the native list. Not part of the public API. internal enum Marshaling { /// Convert a nullable `const char*` to a Swift `String` (empty if NULL). @inline(__always) static func string(_ ptr: UnsafePointer?) -> String { guard let ptr else { return "" } return String(cString: ptr) } static func devices(_ list: inout vc_device_list) -> [Device] { guard let items = list.items else { vc_free_device_list(&list); return [] } var result: [Device] = [] result.reserveCapacity(list.count) for i in 0.. [Channel] { guard let items = list.items else { vc_free_channel_list(&list); return [] } var result: [Channel] = [] result.reserveCapacity(list.count) for i in 0.. [User] { guard let items = list.items else { vc_free_user_list(&list); return [] } var result: [User] = [] result.reserveCapacity(list.count) for i in 0.. [StreamSummary] { guard let items = list.items else { vc_free_stream_summary_list(&list); return [] } var result: [StreamSummary] = [] result.reserveCapacity(list.count) for i in 0.. [Account] { guard let items = list.items else { vc_free_account_list(&list); return [] } var result: [Account] = [] result.reserveCapacity(list.count) for i in 0.. RemoteStreamState { RemoteStreamState(gain: s.gain, muted: s.muted != 0, noiseReduction: s.noise_reduction != 0) } static func audioConfig(_ c: vc_audio_config) -> AudioConfig { AudioConfig(codec: c.codec, stereo: c.mode != 0, sampleRate: c.sample_rate, bitrateBps: c.bitrate_bps, frameMs: c.frame_ms, application: c.application, fec: c.fec != 0, expectedPacketLoss: c.expected_packet_loss, dtx: c.dtx != 0, complexity: c.complexity, dred: c.dred != 0) } static func permissions(_ p: vc_permissions) -> Permissions { Permissions(canCreateTempChannel: p.can_create_temp_channel != 0, canKick: p.can_kick != 0, canBan: p.can_ban != 0, canMoveUsers: p.can_move_users != 0, canAdminAccounts: p.can_admin_accounts != 0, isAdmin: p.is_admin != 0) } }