Advertise here




Advertise here

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Hardware Volume Change Listener Callback

AptoTechAptoTech Posts: 29Registered Users
edited January 2012 in iPhone SDK Development
Hi everyone,

I am trying to code a callback function that fires two separate methods depending on if the system volume increases or decreases. I have found some example code that detects a change in the audio route (see below), and am trying to convert this to respond to the kAudioSessionProperty_CurrentHardwareOutputVolume (which returns a Float32 from 0.0 to 1.0) property. I am, however, struggling with it as it is written in plain C, which I know little about (I learnt Objective-C as my first language). I would be highly grateful if anyone would help me write this callback.
#import "MainViewController.h"
#import <Foundation/Foundation.h>

void audioRouteChangeListenerCallback (
   void                      *inUserData,
   AudioSessionPropertyID    inPropertyID,
   UInt32                    inPropertyValueSize,
   const void                *inPropertyValue
) {
	
	// ensure that this callback was invoked for a route change
	if (inPropertyID != kAudioSessionProperty_AudioRouteChange) return;

	// This callback, being outside the implementation block, needs a reference to the
	//		MainViewController object, which it receives in the inUserData parameter.
	//		You provide this reference when registering this callback (see the call to 
	//		AudioSessionAddPropertyListener).
	MainViewController *controller = (MainViewController *) inUserData;
	
	// if application sound is not playing, there's nothing to do, so return.
	if (controller.appSoundPlayer.playing == 0 ) {

		NSLog (@"Audio route change while application audio is stopped.");
		return;
		
	} else {

		// Determines the reason for the route change, to ensure that it is not
		//		because of a category change.
		CFDictionaryRef	routeChangeDictionary = inPropertyValue;
		
		CFNumberRef routeChangeReasonRef =
						CFDictionaryGetValue (
							routeChangeDictionary,
							CFSTR (kAudioSession_AudioRouteChangeKey_Reason)
						);

		SInt32 routeChangeReason;
		
		CFNumberGetValue (
			routeChangeReasonRef,
			kCFNumberSInt32Type,
			&routeChangeReason
		);
		
		// "Old device unavailable" indicates that a headset was unplugged, or that the
		//	device was removed from a dock connector that supports audio output. This is
		//	the recommended test for when to pause audio.
		if (routeChangeReason == kAudioSessionRouteChangeReason_OldDeviceUnavailable) {

			[controller.appSoundPlayer pause];
			NSLog (@"Output device removed, so application audio was paused.");

			UIAlertView *routeChangeAlertView = 
					[[UIAlertView alloc]	initWithTitle: NSLocalizedString (@"Playback Paused", @"Title for audio hardware route-changed alert view")
												  message: NSLocalizedString (@"Audio output was changed", @"Explanation for route-changed alert view")
												 delegate: controller
										cancelButtonTitle: NSLocalizedString (@"StopPlaybackAfterRouteChange", @"Stop button title")
										otherButtonTitles: NSLocalizedString (@"ResumePlaybackAfterRouteChange", @"Play button title"), nil];
			[routeChangeAlertView show];
			// release takes place in alertView:clickedButtonAtIndex: method
		
		} else {

			NSLog (@"A route change occurred that does not require pausing of application audio.");
		}
	}
}

@implementation MainViewController

-(void)viewDidLoad {
        [super viewDidLoad];
	[[AVAudioSession sharedInstance] setDelegate: self];
	[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryAmbient error: nil];
	AudioSessionAddPropertyListener (
		kAudioSessionProperty_AudioRouteChange,
		audioRouteChangeListenerCallback,
		self
	);
	NSError *activationError = nil;
	[[AVAudioSession sharedInstance] setActive: YES error: &activationError];
}

Thanks :)
Post edited by AptoTech on
[SIGPIC][/SIGPIC]<br />
<a href="http://www.aptotech.com" target="_blank">AptoTech.com</a> - <b>Our website!</b><br />
<a href="http://www.twitter.com/aptotech" target="_blank">Twitter Feed</a> - <b>Follow us on Twitter!</b><br />
<a href="http://www.y

Replies

  • AptoTechAptoTech Posts: 29Registered Users
    edited July 2010
    Im getting somewhere... kinda...

    I have managed to get a value for kAudioSessionProperty_CurrentHardwareOutputVolume, just not the right value. Here is my current code:
    void volumeListenerCallback (
                                 void *inUserData, 
                                 AudioSessionPropertyID inPropertyID, 
                                 Float32 volume){
        
        if (inPropertyID != kAudioSessionProperty_CurrentHardwareOutputVolume) return;
        
    	volume = kAudioSessionProperty_CurrentHardwareOutputVolume;
        NSLog(@"%f", volume);
    }
    
    - (void)viewDidLoad {
    	[super viewDidLoad];
    	
    	[[AVAudioSession sharedInstance] setDelegate: self];
    	[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: nil];
    	AudioSessionAddPropertyListener (
                                         kAudioSessionProperty_CurrentHardwareOutputVolume,
                                         volumeListenerCallback,
    									 self
    									 );
    }
    

    Xcode annoyingly throws up a warning at the volumeListenerCallback line:
    incompatible pointer types passing void
    
    and the output of the NSLog is 1667788672.000000 no matter how high or low the volume actually is. If anyone can help correct this code to fire a different method if the volume is increased or decreased I would be, as I said before, hugely grateful. Plain C is something I know very little about, and as such I am struggling to do this simple thing.

    Thank you in advance to anyone who offers help.
    [SIGPIC][/SIGPIC]<br />
    <a href="http://www.aptotech.com" target="_blank">AptoTech.com</a> - <b>Our website!</b><br />
    <a href="http://www.twitter.com/aptotech" target="_blank">Twitter Feed</a> - <b>Follow us on Twitter!</b><br />
    <a href="http://www.y
  • fhsjaagshsfhsjaagshs Posts: 93Registered Users
    edited December 2011
    If you're writing an audio player use an MPVolumeView.

    1. Make a UIView in interface builder
    2. Change the class to MPVolumeView

    Done!!!
    <b><b>My apps</b></b><br />
    <a href="http://itunes.apple.com/us/app/rest-counter/id464985741?ls=1&mt=8" target="_blank">Rest Counter - Count bars of rest in orchestra with ease!!!</a><br />
    <a href="http://itunes.apple.com/us/app/swiftload/id4697629
  • bagusflyerbagusflyer Posts: 29Registered Users
    edited January 2012
    AptoTech wrote: »
    Hi everyone,

    I am trying to code a callback function that fires two separate methods depending on if the system volume increases or decreases. I have found some example code that detects a change in the audio route (see below), and am trying to convert this to respond to the kAudioSessionProperty_CurrentHardwareOutputVolume (which returns a Float32 from 0.0 to 1.0) property. I am, however, struggling with it as it is written in plain C, which I know little about (I learnt Objective-C as my first language). I would be highly grateful if anyone would help me write this callback.
    #import "MainViewController.h"
    #import <Foundation/Foundation.h>
    
    void audioRouteChangeListenerCallback (
       void                      *inUserData,
       AudioSessionPropertyID    inPropertyID,
       UInt32                    inPropertyValueSize,
       const void                *inPropertyValue
    ) {
    	
    	// ensure that this callback was invoked for a route change
    	if (inPropertyID != kAudioSessionProperty_AudioRouteChange) return;
    
    	// This callback, being outside the implementation block, needs a reference to the
    	//		MainViewController object, which it receives in the inUserData parameter.
    	//		You provide this reference when registering this callback (see the call to 
    	//		AudioSessionAddPropertyListener).
    	MainViewController *controller = (MainViewController *) inUserData;
    	
    	// if application sound is not playing, there's nothing to do, so return.
    	if (controller.appSoundPlayer.playing == 0 ) {
    
    		NSLog (@"Audio route change while application audio is stopped.");
    		return;
    		
    	} else {
    
    		// Determines the reason for the route change, to ensure that it is not
    		//		because of a category change.
    		CFDictionaryRef	routeChangeDictionary = inPropertyValue;
    		
    		CFNumberRef routeChangeReasonRef =
    						CFDictionaryGetValue (
    							routeChangeDictionary,
    							CFSTR (kAudioSession_AudioRouteChangeKey_Reason)
    						);
    
    		SInt32 routeChangeReason;
    		
    		CFNumberGetValue (
    			routeChangeReasonRef,
    			kCFNumberSInt32Type,
    			&routeChangeReason
    		);
    		
    		// "Old device unavailable" indicates that a headset was unplugged, or that the
    		//	device was removed from a dock connector that supports audio output. This is
    		//	the recommended test for when to pause audio.
    		if (routeChangeReason == kAudioSessionRouteChangeReason_OldDeviceUnavailable) {
    
    			[controller.appSoundPlayer pause];
    			NSLog (@"Output device removed, so application audio was paused.");
    
    			UIAlertView *routeChangeAlertView = 
    					[[UIAlertView alloc]	initWithTitle: NSLocalizedString (@"Playback Paused", @"Title for audio hardware route-changed alert view")
    												  message: NSLocalizedString (@"Audio output was changed", @"Explanation for route-changed alert view")
    												 delegate: controller
    										cancelButtonTitle: NSLocalizedString (@"StopPlaybackAfterRouteChange", @"Stop button title")
    										otherButtonTitles: NSLocalizedString (@"ResumePlaybackAfterRouteChange", @"Play button title"), nil];
    			[routeChangeAlertView show];
    			// release takes place in alertView:clickedButtonAtIndex: method
    		
    		} else {
    
    			NSLog (@"A route change occurred that does not require pausing of application audio.");
    		}
    	}
    }
    
    @implementation MainViewController
    
    -(void)viewDidLoad {
            [super viewDidLoad];
    	[[AVAudioSession sharedInstance] setDelegate: self];
    	[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryAmbient error: nil];
    	AudioSessionAddPropertyListener (
    		kAudioSessionProperty_AudioRouteChange,
    		audioRouteChangeListenerCallback,
    		self
    	);
    	NSError *activationError = nil;
    	[[AVAudioSession sharedInstance] setActive: YES error: &activationError];
    }
    

    Thanks :)

    Did you get the callback when you press the volume button? I tried the code but it doesn't work.
Sign In or Register to comment.