54

I'm building an audio player for a non-native sound format. The application's hierarchy is based on the iPod.app. It has a number of UITableView's and one UIView (TrackView) that uses an MPVolumeView to allow the user to change the volume onscreen. Until the first time TrackView becomes visible changing the volume using the hardware buttons displays the system volume overlay as expected (and desired). When TrackView is visible these overlays don't appear since the MPVolumeView updates when changing the volume with the hardware buttons (also desired).

Here's the problem: once you back out of TrackView the system volume overlay does not appear when using the hardware volume buttons. I have tried programmatically allocing, creating and adding the MPVolumeView in TrackViewController viewWillAppear: and then removing, releasing and nil-ing the same MPVolumeView in TrackViewController viewWillDisappear:.

This does not happen in the iPod.app. Once backing out of the view that contains an MPVolumeView the system volume overlays display when using the hardware volume buttons.

What am I missing?


Update 2: This appears to be a bug in MPVolumeView that was introduced sometime after iOS 3.2 and fixed in 4.2.


Update: I made a simple reduction from the default window-based application project that exhibits the same behavior. Once an MPVolumeView becomes visible the system volume overlays are never seen in the application again.

VolumeAppDelegate.h:

#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>

@interface VolumeAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    IBOutlet UIView *volumeView;
    IBOutlet MPVolumeView *mpVolumeView;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

-(IBAction)toggleVolumeView:(id)sender;

@end

VolumeAppDelegate.m:

#import "VolumeAppDelegate.h"

@implementation VolumeAppDelegate

@synthesize window;

-(IBAction)toggleVolumeView:(id)sender{

    if (mpVolumeView == nil){
        mpVolumeView = [[MPVolumeView alloc] initWithFrame:volumeView.bounds];
        [volumeView addSubview:mpVolumeView];
    }
    else{
        [mpVolumeView removeFromSuperview];
        [mpVolumeView release];
        mpVolumeView = nil;
    }
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    

    [self.window makeKeyAndVisible];
    mpVolumeView = nil;
    return YES;
}

- (void)dealloc {
    [window release];
    [super dealloc];
}

@end

You'll need to add the MediaPlayer framework to your project in Xcode and open up MainWindow.xib in Interface builder to add the UIView and UIButton IBOutlets and hookup the IBAction to the UIButton.

Shaun Inman
  • 1,968
  • 1
  • 19
  • 28
  • This appears to be a problem on iPod touches running iOS 4.1. The same application running on my iPad with iOS 3.2 doesn't exhibit this problem. I'm updating one of my iPod touches to iOS 4.2 now to see if the problem has been fixed. (In any case I'm still looking for a solution since iPod.app on 4.1 doesn't exhibit this behavior.) – Shaun Inman Nov 28 '10 at 14:48
  • The problem appears to be fixed in iOS 4.2 but if anyone has a solution for earlier versions, I'm still interested. – Shaun Inman Nov 28 '10 at 15:02
  • I'm experiencing a similar problem on 4.2.1, My MPVolumeView is not always visible but shown and hidden in response to a tap on the screen. When my equivalent of your Track view is first loaded the volume view is not visible and the system volume overlay is shown in response to volume button changes. Once the MPVolumeView is shown the volume overlay no longer appears (regardless of whether MPVolumeView is subsequently hidden) until the view is removed from view and added again. – prendio2 Jan 04 '11 at 14:29

2 Answers2

1

This is sadly an issue with the private framework in the earlier versions of iOS.

I understand your wish to make a solution for this, but it would cause your code to manipulate the private framework, making your app unable to pass approval.

Fortunately, the version span that had this error is short, and the number of devices in circulation with these version are growing thinner by the minute.

Nils Munch
  • 8,805
  • 11
  • 51
  • 103
0

You can increase and decrease device volume by programmatically like:

- (void)setVolume:(float)Level
{

   OSStatus errorMsg = AudioQueueSetParameter(audioQueue, kAudioQueueParam_Volume, Level);

   if (errorMsg) {
      NSLog(@"%d", errorMsg);
   }

}
Nazik
  • 8,696
  • 27
  • 77
  • 123
Bipin Patel
  • 228
  • 1
  • 5