提问人:Чайка 提问时间:10/18/2023 最后编辑:Чайка 更新时间:10/23/2023 访问量:91
如何在 CoreAudio 中从多个设备输出音频?
How do I output audio from multiple devices in CoreAudio?
问:
Audio Midi Setup
允许从多个设备输出单个声源,但是有没有办法做到这一点?CoreAudio
这可以通过将相同的附加到两个来完成吗?我考虑过这样做,但它抛出了一个堆栈跟踪并给了我一个错误。playerNode
AVAudioEngine
import Cocoa
import CoreAudio
@main
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet var window: NSWindow!
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Get the default output device
var defaultOutputDeviceID = AudioDeviceID(0)
var defaultOutputDeviceIDSize = UInt32(MemoryLayout<AudioDeviceID>.size)
var property: AudioObjectPropertyAddress = AudioObjectPropertyAddress(mSelector:kAudioHardwarePropertyDefaultOutputDevice, mScope: kAudioDevicePropertyScopeOutput, mElement: kAudioObjectPropertyElementMain)
var getDefaultOutputDeviceIDStatus = AudioObjectGetPropertyData(AudioObjectID(kAudioObjectSystemObject), &property, 0, nil, &defaultOutputDeviceIDSize, &defaultOutputDeviceID)
// Get the number of output devices
var outputDeviceCount = UInt32(0)
var outputDeviceCountSize = UInt32(MemoryLayout<UInt32>.size)
property.mSelector = kAudioHardwarePropertyDevices
var getOutputDeviceCountStatus = AudioObjectGetPropertyData(AudioObjectID(kAudioObjectSystemObject), &property, 0, nil, &outputDeviceCountSize, &outputDeviceCount)
// Get the IDs of all output devices
var outputDeviceIDs = [AudioDeviceID](repeating: 0, count: Int(outputDeviceCount))
var outputDeviceIDsSize = UInt32(MemoryLayout<AudioDeviceID>.size * Int(outputDeviceCount))
property.mSelector = kAudioHardwarePropertyDevices
var getOutputDeviceIDsStatus = AudioObjectGetPropertyData(AudioObjectID(kAudioObjectSystemObject), &property, 0, nil, &outputDeviceIDsSize, &outputDeviceIDs)
// Set the output device IDs to the first two devices
var outputDeviceIDsToSet = [outputDeviceIDs[0], outputDeviceIDs[1]]
var outputDeviceIDsToSetSize = UInt32(MemoryLayout<AudioDeviceID>.size * outputDeviceIDsToSet.count)
property.mSelector = kAudioAggregateDevicePropertyComposition
var setOutputDeviceIDsStatus = AudioObjectSetPropertyData(defaultOutputDeviceID, &property, 0, nil, outputDeviceIDsToSetSize, &outputDeviceIDsToSet) }
}
}
}
答:
0赞
Rainy sidewalks
10/18/2023
#1
这解决了你的问题吗
import CoreAudio
// Create an array of output device IDs to include in the aggregate device
let outputDeviceIDs: [AudioDeviceID] = [deviceID1, deviceID2, deviceID3] // Replace with the actual device IDs
// Create an aggregate device
var aggregateDeviceID = AudioDeviceID(0)
var aggregateDeviceIDSize = UInt32(MemoryLayout<AudioDeviceID>.size)
var createAggregateDeviceStatus = withUnsafeMutablePointer(to: &aggregateDeviceID) { deviceIDPtr in
AudioObjectCreateAggregateDevice(kAudioObjectSystemObject, outputDeviceIDs.count, outputDeviceIDs, deviceIDPtr)
}
// Set the aggregate device as the default output device
var setDefaultOutputDeviceStatus = AudioObjectSetPropertyData(AudioObjectID(kAudioObjectSystemObject), &AudioObjectPropertyAddress(kAudioHardwarePropertyDefaultOutputDevice), 0, nil, aggregateDeviceIDSize, &aggregateDeviceID)
评论
0赞
Чайка
10/18/2023
Xcode
说对不起,但真的有效吗?Cannot pass immutable value as inout argument: function call returns immutable value
Argument passed to call that takes no arguments
0赞
Rainy sidewalks
10/18/2023
立即尝试编辑
0赞
Чайка
10/18/2023
对不起,Sonoma 上的 Xcode 15 中也有同样的错误
0赞
Rainy sidewalks
10/18/2023
请分享代码,这样会很有帮助。
0赞
Чайка
10/18/2023
AudioObjectCreateAggregateDevice
找不到同样的错误。
2赞
Чайка
10/23/2023
#2
在准备、结构、
public Struct DeviceID {
let deviceID: AudioObjectID
let UID: String
}
并由它们组成。Dictionary<String, DeviceID>
代码是
func makeAggregate (devices devs: Array<DeviceID>) -> AudioDeviceID {
let deviceList = devs.map {
[
kAudioSubDeviceUIDKey: $0.UID,
kAudioSubDeviceDriftCompensationKey : $0.UID == "com.rogueamoeba.Loopback:32B21BC2-536C-43A0-8A7B-8354B85AD4C7" ? 1 : 0
]
}
let description: Dictionary<String, Any> = [
kAudioAggregateDeviceNameKey: "testDevice",
kAudioAggregateDeviceUIDKey: UUID().uuidString,
kAudioAggregateDeviceSubDeviceListKey: deviceList,
kAudioAggregateDeviceMasterSubDeviceKey: devs.first?.UID as Any,
kAudioAggregateDeviceClockDeviceKey: devs.first?.UID as Any,
kAudioAggregateDeviceIsPrivateKey: 1,
kAudioAggregateDeviceIsStackedKey: 1
]
var aggregateDeviceID: AudioDeviceID = 0
let status: OSStatus = AudioHardwareCreateAggregateDevice(description as CFDictionary, &aggregateDeviceID)
print(status)
return aggregateDeviceID
}
func applicationDidFinishLaunching(_ aNotification: Notification) {
let devices: AudioDevices = AudioDevices()
var audioFile: AVAudioFile
print(devices.outputDevices)
let deviceToBind: Array<DeviceID> = [devices.outputDevices["Loopback Audio"]!, devices.outputDevices["BoomAudio"]!]
audioDeviceId = makeAggregate(devices: deviceToBind)
print("new device \(audioDeviceId)")
do {
let fileURL: URL = Bundle.main.url(forResource: "1-03 RTRT", withExtension: "mp3")!
audioFile = try AVAudioFile(forReading: fileURL)
engine.attach(player)
engine.connect(player, to: engine.mainMixerNode, format: nil)
player.scheduleFile(audioFile, at: nil)
try engine.outputNode.auAudioUnit.setDeviceID(audioDeviceId)
try engine.start()
player.play()
} catch let error {
print(error.localizedDescription)
}
}
func applicationWillTerminate(_ aNotification: Notification) {
let destroyStatus: OSStatus = AudioHardwareDestroyAggregateDevice(audioDeviceId)
print("destroy done \(destroyStatus)")
}
评论