title: How to get audio volume level, and volume changed notifications on iOS?
body: <p>I'm writing a very simple application that plays a sound when pressing a button. Since that button does not make a lot of sense when the device is set to silence I want to disable it when the device's audio volume is zero. (And subsequently reenable it when the volume is cranked up again.)</p>
  
  <p>I am seeking a working (and AppStore safe) way to <em>detect the current volume setting</em> and get a notification/callback when the volume level changes. I <em>do not want to alter the volume</em> setting.</p>
  
  <p>All this is implemented in my <code>ViewController</code> where said button is used. I've tested this with an iPhone 4 running iOS 4.0.1 and 4.0.2 as well as an iPhone 3G running 4.0.1. Built with iOS SDK 4.0.2 with llvm 1.5. (Using gcc or llvm-gcc doesn't improve anything.) There are no issues during build implementing either way, neither errors nor warnings. Static analyzer is happy as well.</p>
  
  <p>Here is what I've tried so far, all without any success.</p>
  
  <p>Following Apple's audio services documentation I should register an <code>AudioSessionAddPropertyListener</code> for <code>kAudioSessionProperty_CurrentHardwareOutputVolume</code> which should work like this:</p>
  
  <pre><code>// Registering for Volume Change notifications
  AudioSessionInitialize(NULL, NULL, NULL, NULL);
  returnvalue = AudioSessionAddPropertyListener (
  
  kAudioSessionProperty_CurrentHardwareOutputVolume ,
        audioVolumeChangeListenerCallback,
        self
  );
  </code></pre>
  
  <p><code>returnvalue</code> is <code>0</code>, which means that registering the callback worked.</p>
  
  <p>Sadly, I never get a callback to my function <code>audioVolumeChangeListenerCallback</code> when I press the volume buttons on my device, the headset clicker or flip the ringer-silent switch.</p>
  
  <p>When using the exact same code for registering for <code>kAudioSessionProperty_AudioRouteChange</code> (which is used as an analogous sample project in WWDC videos, Developer documentation and on numerous sites on the interwebs) I actually <em>do</em> get a callback when changing the audio route (by plugging in/out a headset or docking the device).</p>
  
  <p>A user named <a href="https://stackoverflow.com/users/377600/doug">Doug</a> opened a thread titled <a href="https://stackoverflow.com/questions/3129073/iphone-volume-changed-event-for-volume-already-max">iPhone volume changed event for volume already max</a> where he claimed that he is sucessfully using this way (unless the volume would not actually change because it is already set to maximum).
  Still, it doesn't work for me.</p>
  
  <p>Another way I have tried is to register at <code>NSNotificationCenter</code> like this.</p>
  
  <pre><code>// sharedAVSystemController 
  AudioSessionInitialize(NULL, NULL, NULL, NULL);
  NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
  [notificationCenter addObserver:self
                                           selector:@selector(volumeChanged:) 
                                               name:@"AVSystemController_SystemVolumeDidChangeNotification" 
                                             object:nil];
  </code></pre>
  
  <p>This should notify my method <code>volumeChanged</code> of any <code>SystemVolume</code> changes but it doesn't actually do so.</p>
  
  <p>Since common belief tells me that if one is working too hard to achieve something with Cocoa one is doing something fundamentally wrong I'm expecting to miss something here. It's hard to believe that there is <em>no simple way</em> to <em>get</em> the current volume level, yet I haven't been able to find one using Apple's documentation, sample code, Google, Apple Developer Forums or by watching WWDC 2010 videos.</p>