Files
HaishinKit.swift/HaishinKit/Sources/Mixer/AudioMixerSettings.swift
2026-01-06 02:13:42 +09:00

79 lines
3.0 KiB
Swift

import AVFoundation
import Foundation
/// Constraints on the audio mixier settings.
public struct AudioMixerSettings: Codable, Sendable {
/// The default value.
public static let `default` = AudioMixerSettings()
/// Maximum sampleRate supported by the system
public static let maximumSampleRate: Float64 = 48000.0
#if os(macOS)
static let commonFormat: AVAudioCommonFormat = .pcmFormatFloat32
#else
static let commonFormat: AVAudioCommonFormat = .pcmFormatInt16
#endif
/// Specifies the sampleRate of audio output. A value of 0 will be the same as the main track source.
public let sampleRate: Float64
/// Specifies the channels of audio output. A value of 0 will be the same as the main track source.
/// - Warning: If you are using IOStreamRecorder, please set it to 1 or 2. Otherwise, the audio will not be saved in local recordings.
public let channels: UInt32
/// Specifies the muted that indicates whether the audio output is muted.
public var isMuted: Bool
/// Specifies the main track number.
public var mainTrack: UInt8
/// Specifies the track settings.
public var tracks: [UInt8: AudioMixerTrackSettings]
/// Specifies the maximum number of channels supported by the system
/// - Description: The maximum number of channels to be used when the number of channels is 0 (not set). More than 2 channels are not supported by the service. It is defined to prevent audio issues since recording does not support more than 2 channels.
public var maximumNumberOfChannels: UInt32 = 2
/// Creates a new instance of a settings.
public init(
sampleRate: Float64 = 0,
channels: UInt32 = 0,
isMuted: Bool = false,
mainTrack: UInt8 = 0,
tracks: [UInt8: AudioMixerTrackSettings] = .init()
) {
self.sampleRate = sampleRate
self.channels = channels
self.isMuted = isMuted
self.mainTrack = mainTrack
self.tracks = tracks
}
func invalidateOutputFormat(_ oldValue: Self) -> Bool {
return !(sampleRate == oldValue.sampleRate &&
channels == oldValue.channels)
}
func makeOutputFormat(_ formatDescription: CMFormatDescription?) -> AVAudioFormat? {
guard let format = AVAudioUtil.makeAudioFormat(formatDescription) else {
return nil
}
let sampleRate = min(sampleRate == 0 ? format.sampleRate : sampleRate, Self.maximumSampleRate)
let channelCount = channels == 0 ? min(format.channelCount, maximumNumberOfChannels) : channels
if let channelLayout = AVAudioUtil.makeChannelLayout(channelCount) {
return .init(
commonFormat: Self.commonFormat,
sampleRate: sampleRate,
interleaved: format.isInterleaved,
channelLayout: channelLayout
)
}
return .init(
commonFormat: Self.commonFormat,
sampleRate: sampleRate,
channels: min(channelCount, 2),
interleaved: format.isInterleaved
)
}
}