Концепция
Итак, надеюсь, есть лучший способ справиться с этим, но это концепция:
Раскрутите новый поток, чтобы посмотреть атрибут громкости, найденный в AudioToolbox
. Затем пусть это вызовет какой-нибудь обратный вызов.
#import "AppDelegate.h"
#define kVolumeKey @"currentvolumeforvolumemonitorkey"
@implementation AppDelegate
@synthesize window = _window;
/* Credit to CocoaDev Starts Now */
/* http://www.cocoadev.com/index.pl?SoundVolume */
+(AudioDeviceID)defaultOutputDeviceID
{
AudioDeviceID outputDeviceID = kAudioObjectUnknown;
// get output device device
UInt32 propertySize = 0;
OSStatus status = noErr;
AudioObjectPropertyAddress propertyAOPA;
propertyAOPA.mScope = kAudioObjectPropertyScopeGlobal;
propertyAOPA.mElement = kAudioObjectPropertyElementMaster;
propertyAOPA.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
if (!AudioHardwareServiceHasProperty(kAudioObjectSystemObject, &propertyAOPA))
{
NSLog(@"Cannot find default output device!");
return outputDeviceID;
}
propertySize = sizeof(AudioDeviceID);
status = AudioHardwareServiceGetPropertyData(kAudioObjectSystemObject, &propertyAOPA, 0, NULL, &propertySize, &outputDeviceID);
if(status)
{
NSLog(@"Cannot find default output device!");
}
return outputDeviceID;
}
+(float)volume
{
Float32 outputVolume;
UInt32 propertySize = 0;
OSStatus status = noErr;
AudioObjectPropertyAddress propertyAOPA;
propertyAOPA.mElement = kAudioObjectPropertyElementMaster;
propertyAOPA.mSelector = kAudioHardwareServiceDeviceProperty_VirtualMasterVolume;
propertyAOPA.mScope = kAudioDevicePropertyScopeOutput;
AudioDeviceID outputDeviceID = [AppDelegate defaultOutputDeviceID];
if (outputDeviceID == kAudioObjectUnknown)
{
NSLog(@"Unknown device");
return 0.0;
}
if (!AudioHardwareServiceHasProperty(outputDeviceID, &propertyAOPA))
{
NSLog(@"No volume returned for device 0x%0x", outputDeviceID);
return 0.0;
}
propertySize = sizeof(Float32);
status = AudioHardwareServiceGetPropertyData(outputDeviceID, &propertyAOPA, 0, NULL, &propertySize, &outputVolume);
if (status)
{
NSLog(@"No volume returned for device 0x%0x", outputDeviceID);
return 0.0;
}
if (outputVolume < 0.0 || outputVolume > 1.0) return 0.0;
return outputVolume;
}
/* Thanks CocoaDev! */
- (void)dealloc
{
[super dealloc];
}
- (void)volumeDidChangeToLevel: (CGFloat)level
{
NSLog(@"LEVEL: %f", level);
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),
^{
[[NSUserDefaults standardUserDefaults] setFloat: [[self class] volume] forKey: kVolumeKey];
[[NSUserDefaults standardUserDefaults] synchronize];
for(CGFloat volLevel = [[self class] volume];; volLevel = [[self class] volume])
{
if (volLevel != [[NSUserDefaults standardUserDefaults] floatForKey: kVolumeKey])
{
[[NSUserDefaults standardUserDefaults] setFloat: [[self class] volume] forKey: kVolumeKey];
[[NSUserDefaults standardUserDefaults] synchronize];
dispatch_async(dispatch_get_main_queue(),
^{
[self volumeDidChangeToLevel: volLevel];
});
}
}
});
}
@end
Если вам подходит такой подход, возможно, вы захотите создать объект с обратным вызовом делегата, блоком или чем-то еще.
Протест
Это решение требует одного фонового потока для постоянного отслеживания изменений . Это должно быть довольно сдержанно, потому что это такая простая проверка, но стоит упомянуть.