文章目录
引言
每隔一段时间就会有人问,怎样获取音量,怎样切换声卡,这里写个方法总结吧。
偏好设置中的声音,在 Cocoa 中主要使用 CoreAudio 和 AudioToolbox 来控制,在使用下面方法后,不妨通读这个框架来加深了解。
常用方法
- AudioHardwareGetProperty
- AudioObjectGetPropertyData
- AudioHardwareSetProperty
一、声卡、声音输入输出
1、获取当前声卡ID
- (void)test7{
AudioDeviceID inID = kAudioDeviceUnknown;
AudioDeviceID outID = kAudioDeviceUnknown;
UInt32 propertySize0 = sizeof(inID);
UInt32 propertySize1 = sizeof(outID);
AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propertySize0, &inID);
AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice , &propertySize1, &outID);
NSLog(@"outID : %d",outID);
// NSLog(@"inID : %d",inID);
}
2、根据 UID 获取声卡 id
#define KVirtualAudioUID "AudioDevice_UID"
- (AudioDeviceID)getAudioIDWithUID:(NSString *)UID{
CFStringRef virtualDeviceAudioUID = (__bridge CFStringRef)UID;
CFStringRef *inDeviceAudioUID = &virtualDeviceAudioUID;
AudioDeviceID virtualAudioDeviceID = kAudioDeviceUnknown;
AudioObjectPropertyAddress proprtyAddress = {};
proprtyAddress.mSelector = kAudioHardwarePropertyTranslateUIDToDevice;
proprtyAddress.mScope = kAudioObjectPropertyScopeGlobal;
proprtyAddress.mElement = kAudioObjectPropertyElementMaster;
UInt32 inSize = sizeof(inDeviceAudioUID);
uint32 outSize = sizeof(virtualAudioDeviceID);
OSStatus ret = AudioObjectGetPropertyData(kAudioObjectSystemObject,
&proprtyAddress,
inSize,
inDeviceAudioUID,
&outSize,
&virtualAudioDeviceID);
NSLog(@"ret : %d",ret);
NSLog(@"virtualAudioDeviceID : %d",virtualAudioDeviceID);
// NSLog(@"virtualDeviceAudioUID : %@",(__bridge NSString *)virtualDeviceAudioUID);
if (virtualAudioDeviceID == kAudioDeviceUnknown) {
NSLog(@"没有发现声卡");
return kAudioDeviceUnknown;
}
return virtualAudioDeviceID;
}
3、根据 ID 获取声卡名字
+ (NSString *)deviceNameForID:(AudioDeviceID)deviceID {
UInt32 propertySize = 256;
char deviceName[256];
AudioDeviceGetProperty(deviceID, 0, false, kAudioDevicePropertyDeviceName, &propertySize, deviceName);
NSString *deviceNameForID = [NSString stringWithCString:deviceName encoding:NSUTF8StringEncoding];
return deviceNameForID;
}
4、根据 声卡名字 获取 ID
+ (AudioDeviceID)deviceIDForName:(NSString *)requestedDeviceName {
AudioDeviceID deviceIDForName = kAudioDeviceUnknown;
NSArray *availableOutputDeviceIDs = [self availableOutputDeviceIDs];
for(NSNumber *deviceIDNumber in availableOutputDeviceIDs) {
UInt32 deviceID = [deviceIDNumber unsignedIntValue];
NSString *deviceName = [self deviceNameForID:deviceID];
if ([requestedDeviceName isEqualToString:deviceName]) {
deviceIDForName = deviceID;
break;
}
}
return deviceIDForName;
}
5、获取当前所有有效的输出设备ID
+ (NSArray *)availableOutputDeviceIDs {
UInt32 propertySize;
AudioDeviceID devices[64];
int devicesCount = 0;
AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propertySize, NULL);
AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propertySize, devices);
devicesCount = (propertySize / sizeof(AudioDeviceID));
NSMutableArray *availableOutputDeviceIDs = [[NSMutableArray alloc] initWithCapacity:devicesCount];
for(int i = 0; i < devicesCount; ++i) {
if ([self isOutputDevice:devices[i]]) {
NSNumber *outputDeviceID = [NSNumber numberWithUnsignedInt:devices[i]];
[availableOutputDeviceIDs addObject:outputDeviceID];
}
}
return [NSArray arrayWithArray:availableOutputDeviceIDs];
}
+ (BOOL)isOutputDevice:(AudioDeviceID)deviceID {
UInt32 propertySize = 256;
AudioDeviceGetPropertyInfo(deviceID, 0, false, kAudioDevicePropertyStreams, &propertySize, NULL);
BOOL isOutputDevice = (propertySize > 0);
return isOutputDevice;
}
6、切换输出声卡
#pragma mark -- 切换输出声卡
+ (void)setOutputDeviceByID:(AudioDeviceID)newDeviceID {
UInt32 propertySize = sizeof(UInt32);
AudioHardwareSetProperty(kAudioHardwarePropertyDefaultOutputDevice, propertySize, &newDeviceID);
}
7、切换输入声卡
#pragma mark -- 切换输入声卡
+ (void)setInputDeviceByID:(AudioDeviceID)newDeviceID {
UInt32 propertySize = sizeof(UInt32);
AudioHardwareSetProperty(kAudioHardwarePropertyDefaultInputDevice, propertySize, &newDeviceID);
}
8、显示/隐藏声卡
在系统偏好设置中 显示/隐藏声卡
- (void)shouldHide:(BOOL)shouldHide audioID:(AudioDeviceID)audioID{
AudioDeviceID virtualAudioDeviceID = audioID;
int32_t hidden = 0;
if (shouldHide) {
hidden = 1;
}
AudioObjectPropertyAddress proprtyAddress = {};
proprtyAddress.mSelector = 'hide';
proprtyAddress.mScope = kAudioObjectPropertyScopeGlobal;
proprtyAddress.mElement = kAudioObjectPropertyElementMaster;
int32_t hidden_value = hidden;
CFNumberRef number = CFNumberCreate(NULL, kCFNumberSInt32Type, &hidden_value);
AudioObjectSetPropertyData(virtualAudioDeviceID, &proprtyAddress, 0, NULL, sizeof(CFNumberRef), &number);
CFRelease(number);
}
二、音量
1、设置音量
+ (void)setSystemVolume:(float)theVolume
{
float newValue = theVolume;
AudioObjectPropertyAddress theAddress;
AudioDeviceID defaultDevID;
OSStatus theError = noErr;
UInt32 muted;
Boolean canSetVol = YES, muteValue;
Boolean hasMute = YES, canMute = YES;
defaultDevID = obtainDefaultOutputDevice();
if (defaultDevID == kAudioObjectUnknown) { //device not found: return without trying to set
NSLog(@"Device unknown");
return;
}
//check if the new value is in the correct range - normalize it if not
newValue = theVolume > 1.0 ? 1.0 : (theVolume < 0.0 ? 0.0 : theVolume);
if (newValue != theVolume) {
NSLog(@"Tentative volume (%5.2f) was out of range; reset to %5.2f", theVolume, newValue);
}
theAddress.mElement = kAudioObjectPropertyElementMaster;
theAddress.mScope = kAudioDevicePropertyScopeOutput;
//set the selector to mute or not by checking if under threshold and check if a mute command is available
if ( (muteValue = (newValue < THRESHOLD)) )
{
theAddress.mSelector = kAudioDevicePropertyMute;
hasMute = AudioObjectHasProperty(defaultDevID, &theAddress);
if (hasMute)
{
theError = AudioObjectIsPropertySettable(defaultDevID, &theAddress, &canMute);
if (theError != noErr || !canMute)
{
canMute = NO;
NSLog(@"Should mute device 0x%0x but did not success",defaultDevID);
}
}
else canMute = NO;
}
else
{
theAddress.mSelector = kAudioHardwareServiceDeviceProperty_VirtualMasterVolume;
}
// **** now manage the volume following the what we found ****
//be sure the device has a volume command
if (! AudioObjectHasProperty(defaultDevID, &theAddress))
{
NSLog(@"The device 0x%0x does not have a volume to set", defaultDevID);
return;
}
//be sure the device can set the volume
theError = AudioObjectIsPropertySettable(defaultDevID, &theAddress, &canSetVol);
if ( theError!=noErr || !canSetVol )
{
NSLog(@"The volume of device 0x%0x cannot be set", defaultDevID);
return;
}
//if under the threshold then mute it, only if possible - done/exit
if (muteValue && hasMute && canMute)
{
muted = 1;
theError = AudioObjectSetPropertyData(defaultDevID, &theAddress, 0, NULL, sizeof(muted), &muted);
if (theError != noErr)
{
NSLog(@"The device 0x%0x was not muted",defaultDevID);
return;
}
}
else //else set it
{
theError = AudioObjectSetPropertyData(defaultDevID, &theAddress, 0, NULL, sizeof(newValue), &newValue);
if (theError != noErr)
{
NSLog(@"The device 0x%0x was unable to set volume", defaultDevID);
}
//if device is able to handle muting, maybe it was muted, so unlock it
if (hasMute && canMute)
{
theAddress.mSelector = kAudioDevicePropertyMute;
muted = 0;
theError = AudioObjectSetPropertyData(defaultDevID, &theAddress, 0, NULL, sizeof(muted), &muted);
}
}
if (theError != noErr) {
NSLog(@"Unable to set volume for device 0x%0x", defaultDevID);
}
}
2、设置静音
+ (void)applyMute:(Boolean)m
{
AudioDeviceID defaultDevID = kAudioObjectUnknown;
AudioObjectPropertyAddress theAddress;
Boolean hasMute, canMute = YES;
OSStatus theError = noErr;
UInt32 muted = 0;
defaultDevID = obtainDefaultOutputDevice();
if (defaultDevID == kAudioObjectUnknown) { //device not found
NSLog(@"Device unknown");
return;
}
theAddress.mElement = kAudioObjectPropertyElementMaster;
theAddress.mScope = kAudioDevicePropertyScopeOutput;
theAddress.mSelector = kAudioDevicePropertyMute;
muted = m ? 1 : 0;
hasMute = AudioObjectHasProperty(defaultDevID, &theAddress);
if (hasMute)
{
theError = AudioObjectIsPropertySettable(defaultDevID, &theAddress, &canMute);
if (theError == noErr && canMute)
{
theError = AudioObjectSetPropertyData(defaultDevID, &theAddress, 0, NULL, sizeof(muted), &muted);
if (theError != noErr) NSLog(@"Cannot change mute status of device 0x%0x", defaultDevID);
}
}
}
3、判断是否静音
+ (Boolean)isMuted
{
AudioDeviceID defaultDevID = kAudioObjectUnknown;
AudioObjectPropertyAddress theAddress;
Boolean hasMute, canMute = YES;
OSStatus theError = noErr;
UInt32 muted = 0;
UInt32 mutedSize = 4;
defaultDevID = obtainDefaultOutputDevice();
if (defaultDevID == kAudioObjectUnknown) { //device not found
NSLog(@"Device unknown");
return false; // works, but not the best return code for this
}
theAddress.mElement = kAudioObjectPropertyElementMaster;
theAddress.mScope = kAudioDevicePropertyScopeOutput;
theAddress.mSelector = kAudioDevicePropertyMute;
hasMute = AudioObjectHasProperty(defaultDevID, &theAddress);
if (hasMute)
{
theError = AudioObjectIsPropertySettable(defaultDevID, &theAddress, &canMute);
if (theError == noErr && canMute)
{
theError = AudioObjectGetPropertyData(defaultDevID, &theAddress, 0, NULL, &mutedSize, &muted);
if (muted) {
return true;
}
}
}
return false;
}