这适用于我在 MacBook Pro(2011 型号)上设置输入音量。这有点时髦,我必须尝试设置主通道音量,然后设置每个独立的立体声通道音量,直到找到一个有效的音量。查看我的代码中的注释,我怀疑判断代码是否正常工作的最佳方法是找到有效的 get/set-property 组合,然后执行诸如 get/set(其他操作)/get 之类的操作来验证您的代码是否正常工作设置器正在工作。
哦,我当然会指出,我不会像我在这里所做的那样,依赖于在 getProperty 调用中保持相同的地址值。它似乎有效,但当您通过引用函数传递结构值时,依赖相同的结构值绝对是不好的做法。这当然是示例代码,所以请原谅我的懒惰。 ;)
//
// main.c
// testInputVolumeSetter
//
#include <CoreFoundation/CoreFoundation.h>
#include <CoreAudio/CoreAudio.h>
OSStatus setDefaultInputDeviceVolume( Float32 toVolume );
int main(int argc, const char * argv[]) {
OSStatus err;
// Load the Sound system preference, select a default
// input device, set its volume to max. Now set
// breakpoints at each of these lines. As you step over
// them you'll see the input volume change in the Sound
// preference panel.
//
// On my MacBook Pro setting the channel[ 1 ] volume
// on the default microphone input device seems to do
// the trick. channel[ 0 ] reports that it works but
// seems to have no effect and the master channel is
// unsettable.
//
// I do not know how to tell which one will work so
// probably the best thing to do is write your code
// to call getProperty after you call setProperty to
// determine which channel(s) work.
err = setDefaultInputDeviceVolume( 0.0 );
err = setDefaultInputDeviceVolume( 0.5 );
err = setDefaultInputDeviceVolume( 1.0 );
}
// 0.0 == no volume, 1.0 == max volume
OSStatus setDefaultInputDeviceVolume( Float32 toVolume ) {
AudioObjectPropertyAddress address;
AudioDeviceID deviceID;
OSStatus err;
UInt32 size;
UInt32 channels[ 2 ];
Float32 volume;
// get the default input device id
address.mSelector = kAudioHardwarePropertyDefaultInputDevice;
address.mScope = kAudioObjectPropertyScopeGlobal;
address.mElement = kAudioObjectPropertyElementMaster;
size = sizeof(deviceID);
err = AudioObjectGetPropertyData( kAudioObjectSystemObject, &address, 0, nil, &size, &deviceID );
// get the input device stereo channels
if ( ! err ) {
address.mSelector = kAudioDevicePropertyPreferredChannelsForStereo;
address.mScope = kAudioDevicePropertyScopeInput;
address.mElement = kAudioObjectPropertyElementWildcard;
size = sizeof(channels);
err = AudioObjectGetPropertyData( deviceID, &address, 0, nil, &size, &channels );
}
// run some tests to see what channels might respond to volume changes
if ( ! err ) {
Boolean hasProperty;
address.mSelector = kAudioDevicePropertyVolumeScalar;
address.mScope = kAudioDevicePropertyScopeInput;
// On my MacBook Pro using the default microphone input:
address.mElement = kAudioObjectPropertyElementMaster;
// returns false, no VolumeScalar property for the master channel
hasProperty = AudioObjectHasProperty( deviceID, &address );
address.mElement = channels[ 0 ];
// returns true, channel 0 has a VolumeScalar property
hasProperty = AudioObjectHasProperty( deviceID, &address );
address.mElement = channels[ 1 ];
// returns true, channel 1 has a VolumeScalar property
hasProperty = AudioObjectHasProperty( deviceID, &address );
}
// try to get the input volume
if ( ! err ) {
address.mSelector = kAudioDevicePropertyVolumeScalar;
address.mScope = kAudioDevicePropertyScopeInput;
size = sizeof(volume);
address.mElement = kAudioObjectPropertyElementMaster;
// returns an error which we expect since it reported not having the property
err = AudioObjectGetPropertyData( deviceID, &address, 0, nil, &size, &volume );
size = sizeof(volume);
address.mElement = channels[ 0 ];
// returns noErr, but says the volume is always zero (weird)
err = AudioObjectGetPropertyData( deviceID, &address, 0, nil, &size, &volume );
size = sizeof(volume);
address.mElement = channels[ 1 ];
// returns noErr, but returns the correct volume!
err = AudioObjectGetPropertyData( deviceID, &address, 0, nil, &size, &volume );
}
// try to set the input volume
if ( ! err ) {
address.mSelector = kAudioDevicePropertyVolumeScalar;
address.mScope = kAudioDevicePropertyScopeInput;
size = sizeof(volume);
if ( toVolume < 0.0 ) volume = 0.0;
else if ( toVolume > 1.0 ) volume = 1.0;
else volume = toVolume;
address.mElement = kAudioObjectPropertyElementMaster;
// returns an error which we expect since it reported not having the property
err = AudioObjectSetPropertyData( deviceID, &address, 0, nil, size, &volume );
address.mElement = channels[ 0 ];
// returns noErr, but doesn't affect my input gain
err = AudioObjectSetPropertyData( deviceID, &address, 0, nil, size, &volume );
address.mElement = channels[ 1 ];
// success! correctly sets the input device volume.
err = AudioObjectSetPropertyData( deviceID, &address, 0, nil, size, &volume );
}
return err;
}
编辑回答你的问题,“我是怎么解决这个问题的?”
在过去五年左右的时间里,我花了很多时间使用苹果的音频代码,并且在涉及到在哪里以及如何寻找解决方案时,我已经形成了一些直觉/流程。我和我的商业伙伴共同为第一代 iPhone 和其他一些设备编写了最初的 iHeartRadio 应用程序,我在该项目中的职责之一是音频部分,特别是为 iOS 编写 AAC Shoutcast 流解码器/播放器。当时没有任何文档或开源示例,因此涉及大量的反复试验,我学到了很多东西。
无论如何,当我读到你的问题并看到赏金时,我认为这只是唾手可得的成果(即你没有 RTFM ;-)。我写了几行代码来设置音量属性,当这不起作用时,我真的很感兴趣。
从流程角度来看,您可能会发现这很有用:
一旦我知道这不是一个简单的答案,我就开始思考how来解决问题。我知道声音系统首选项可以让你设置输入增益,所以我开始用 otool 对其进行反汇编,看看 Apple 是否使用旧的或新的音频工具箱例程(碰巧是新的):
尝试使用:
otool -tV /System/Library/PreferencePanes/Sound.prefPane/Contents/MacOS/Sound | bbedit
然后搜索Audio
查看调用了哪些方法(如果您没有 bbedit(我认为每个 Mac 开发人员都应该使用 bbedit),请将其转储到文件中并在其他文本编辑器中打开)。
我最熟悉的是较旧的、已弃用的 Audio Toolbox 例程(在这个行业已经过时了三年),所以我查看了 Apple 的一些技术说明。他们有一个演示如何获取默认输入设备并使用最新的 CoreAudio 方法设置其音量,但正如您无疑看到的那样,他们的代码无法正常工作(至少在我的 MBP 上)。
一旦我到达这一点,我就回到了经过验证的方法:开始谷歌搜索可能涉及的关键字(例如AudioObjectSetPropertyData
, kAudioDevicePropertyVolumeScalar
等)寻找示例用法。
关于 CoreAudio 和使用 Apple Toolbox,我发现的一件有趣的事情是,有一个lot大量的开源代码可供人们尝试各种事物(大量的 Pastebin 和 GoogleCode 项目等)。如果您愿意深入研究一堆这样的代码,您通常会直接找到答案或得到一些非常好的想法。
在我的搜索中,我发现最相关的内容是 Apple 技术说明,展示了如何获取默认输入设备并使用新的工具箱例程设置主输入增益(即使它在我的硬件上不起作用),并且我找到了一些代码显示了在输出设备上按通道设置增益。由于输入设备可以是多通道的,我认为这是下一个要尝试的合乎逻辑的事情。
你的问题非常好,因为至少现在苹果还没有正确的文档来说明如何按照你的要求进行操作。这也很愚蠢,因为两个通道都报告它们设置了音量,但显然只有其中一个通道设置了音量(输入麦克风是单声道源,所以这并不奇怪,但我认为有一个无操作通道,并且没有关于它的文档) Apple 上的一个错误)。
当你开始接触苹果的尖端技术时,这种情况经常发生。你可以用他们的工具箱做一些令人惊奇的事情,它让我曾经开发过的所有其他操作系统都大吃一惊,但不需要太长时间就能超越他们的文档,特别是如果你试图做任何适度复杂的事情。
例如,如果您决定编写内核驱动程序,您会发现 IOKit 上的文档严重不足。最终,你必须上网并挖掘源代码,无论是其他人的项目还是 OS X 源代码,或者两者兼而有之,很快你就会得出结论,就像我所知道的那样,源代码确实是获得答案的最佳位置(尽管 StackOverflow非常棒)。
感谢您的积分,祝您的项目顺利:)