我想迅速列出所有可用的音频设备,以提供输入和输出的选择。我的应用程序应该在音频通道上侦听,然后“写入”另一个通道。我不希望系统默认!
let devices = AVCaptureDevice.devices(for: .audio)
print(devices.count)
for device in devices {
print(device.localizedName)
}
该代码列出了0个设备。但我至少希望内部输出。
一些指向CoreAudio,AudioToolbox和AVFoundation的链接会很好地说明音频源的选择。
答案 0 :(得分:1)
当我将其粘贴到Xcode Playground中时,您发布的代码对于音频 input 设备非常合适。
但是请注意,AVCaptureDevice
API不会列出音频输出设备,因为它们不是捕获设备,而是回放设备。如果设备同时支持输入和输出,则您仍可以在输出上下文中使用设备的uniqueID
,例如与AVPlayer
的{{1}}一起使用。
(还要注意,如果您希望代码也能在iOS上运行,自iOS 11起,audioOutputDeviceUniqueID
被标记为已弃用,而应改为AVCaptureDevice.DiscoverySession
。)
关于您对Core Audio和AudioToolbox的其他信息的要求,this SO question对此有一些非常全面的答案。该问题要求输入设备,但答案提供了足够的上下文,使您也可以了解输出端的处理方式。甚至还有一些(日期)Swift code的答案。就个人而言,我不得不说从Swift调用Core Audio API通常比获得更多的痛苦。因此,虽然有些不安全,但如果您的项目允许,将这些代码的部分包装到Objective-C或普通C并通过Swift桥接标头公开,可能会更快。
答案 1 :(得分:1)
下面是一些Swift 5代码,将枚举所有音频设备。
您可以将uid
与AVAudioPlayer的currentDevice属性一起使用,以输出到特定设备。
import Cocoa
import AVFoundation
class AudioDevice {
var audioDeviceID:AudioDeviceID
init(deviceID:AudioDeviceID) {
self.audioDeviceID = deviceID
}
var hasOutput: Bool {
get {
var address:AudioObjectPropertyAddress = AudioObjectPropertyAddress(
mSelector:AudioObjectPropertySelector(kAudioDevicePropertyStreamConfiguration),
mScope:AudioObjectPropertyScope(kAudioDevicePropertyScopeOutput),
mElement:0)
var propsize:UInt32 = UInt32(MemoryLayout<CFString?>.size);
var result:OSStatus = AudioObjectGetPropertyDataSize(self.audioDeviceID, &address, 0, nil, &propsize);
if (result != 0) {
return false;
}
let bufferList = UnsafeMutablePointer<AudioBufferList>.allocate(capacity:Int(propsize))
result = AudioObjectGetPropertyData(self.audioDeviceID, &address, 0, nil, &propsize, bufferList);
if (result != 0) {
return false
}
let buffers = UnsafeMutableAudioBufferListPointer(bufferList)
for bufferNum in 0..<buffers.count {
if buffers[bufferNum].mNumberChannels > 0 {
return true
}
}
return false
}
}
var uid:String? {
get {
var address:AudioObjectPropertyAddress = AudioObjectPropertyAddress(
mSelector:AudioObjectPropertySelector(kAudioDevicePropertyDeviceUID),
mScope:AudioObjectPropertyScope(kAudioObjectPropertyScopeGlobal),
mElement:AudioObjectPropertyElement(kAudioObjectPropertyElementMaster))
var name:CFString? = nil
var propsize:UInt32 = UInt32(MemoryLayout<CFString?>.size)
let result:OSStatus = AudioObjectGetPropertyData(self.audioDeviceID, &address, 0, nil, &propsize, &name)
if (result != 0) {
return nil
}
return name as String?
}
}
var name:String? {
get {
var address:AudioObjectPropertyAddress = AudioObjectPropertyAddress(
mSelector:AudioObjectPropertySelector(kAudioDevicePropertyDeviceNameCFString),
mScope:AudioObjectPropertyScope(kAudioObjectPropertyScopeGlobal),
mElement:AudioObjectPropertyElement(kAudioObjectPropertyElementMaster))
var name:CFString? = nil
var propsize:UInt32 = UInt32(MemoryLayout<CFString?>.size)
let result:OSStatus = AudioObjectGetPropertyData(self.audioDeviceID, &address, 0, nil, &propsize, &name)
if (result != 0) {
return nil
}
return name as String?
}
}
}
class AudioDeviceFinder {
static func findDevices() {
var propsize:UInt32 = 0
var address:AudioObjectPropertyAddress = AudioObjectPropertyAddress(
mSelector:AudioObjectPropertySelector(kAudioHardwarePropertyDevices),
mScope:AudioObjectPropertyScope(kAudioObjectPropertyScopeGlobal),
mElement:AudioObjectPropertyElement(kAudioObjectPropertyElementMaster))
var result:OSStatus = AudioObjectGetPropertyDataSize(AudioObjectID(kAudioObjectSystemObject), &address, UInt32(MemoryLayout<AudioObjectPropertyAddress>.size), nil, &propsize)
if (result != 0) {
print("Error \(result) from AudioObjectGetPropertyDataSize")
return
}
let numDevices = Int(propsize / UInt32(MemoryLayout<AudioDeviceID>.size))
var devids = [AudioDeviceID]()
for _ in 0..<numDevices {
devids.append(AudioDeviceID())
}
result = AudioObjectGetPropertyData(AudioObjectID(kAudioObjectSystemObject), &address, 0, nil, &propsize, &devids);
if (result != 0) {
print("Error \(result) from AudioObjectGetPropertyData")
return
}
for i in 0..<numDevices {
let audioDevice = AudioDevice(deviceID:devids[i])
if (audioDevice.hasOutput) {
if let name = audioDevice.name,
let uid = audioDevice.uid {
print("Found device \"\(name)\", uid=\(uid)")
}
}
}
}
}
答案 2 :(得分:1)
可以列出输入和输出设备。这是stevex's answer的简化。
对于输出设备:
if (audioDevice.hasOutput) {
if let name = audioDevice.name,
let uid = audioDevice.uid {
print("Found device \"\(name)\", uid=\(uid)")
}
}
对于输入设备:
if (!audioDevice.hasOutput) {
if let name = audioDevice.name,
let uid = audioDevice.uid {
print("Found device \"\(name)\", uid=\(uid)")
}
}
(请注意{{1}之前的!
。)
答案 3 :(得分:-1)
在macOS 10.12和更高版本中使用macos-audio-devices。这是一个node.js应用程序。该文档说,macOS 10.13或更早的版本需要下载the Swift runtime support libraries。