I need the user to control the device's media volume. I've seen many solutions using volume view or AVAudioPlayer, but I want to use the device volume buttons to set the app volume, like many apps have.
Thanks!
To use this functionality you need to set the audio session to playback. This is done with something like this:
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
dumped in appdelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(volumeChanged:)
name:#"AVSystemController_SystemVolumeDidChangeNotification"
object:nil];
}
- (void)volumeChanged:(NSNotification *)notification
{
float volume =
[[[notification userInfo]
objectForKey:#"AVSystemController_AudioVolumeNotificationParameter"]
floatValue];
// Do stuff with volume
}
Related
I created a MPMoviePlayerViewController which plays a live video. However, if I play the video twice meaning opening the player, clicking done, and playing the stream again. The result is only a black screen with no controls of the MPMoviePlayerViewController. And I need to stop the simulator cause I think the application is crashing. Here's how I did it
- (void) playUrl:(NSURL *)movieInfo
{
NSURL *streamUrl = movieInfo;
MPMoviePlayerViewController *mpvc = [[MPMoviePlayerViewController alloc] initWithContentURL:streamUrl];
[[mpvc view] setFrame:self.view.bounds];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(movieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];
mpvc.moviePlayer.movieSourceType = MPMovieSourceTypeStreaming;
[mpvc.moviePlayer setControlStyle:MPMovieControlStyleFullscreen];
[mpvc.moviePlayer setShouldAutoplay:YES];
[mpvc.moviePlayer setFullscreen:NO animated:YES];
[mpvc setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[mpvc.moviePlayer setScalingMode:MPMovieScalingModeNone];
[mpvc.moviePlayer setUseApplicationAudioSession:NO];
[self presentMoviePlayerViewControllerAnimated:mpvc];
}
- (void) movieFinishedCallback:(NSNotification*) aNotification
{
MPMoviePlayerController *player = [aNotification object];
[player stop];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:player];
[player.view removeFromSuperview];
NSLog(#"stopped?");
}
I see that in your movieFinishedCallback: implementation, you remove the MPMoviePlayerController view, but in your playUrl: implementation, you are only setting the view's frame, presumably after you have already added the view in viewDidLoad.
One obvious change which is worth trying, is update you code to use the AVPictureInPictureController or AVPlayerViewController class from the AVKit framework, or the WKWebView class from WebKit. According to the MPMoviePlayerViewController docs, it is deprecated as of iOS 9:
The MPMoviePlayerViewController class is formally deprecated in iOS 9. (The MPMoviePlayerController class is also formally deprecated.) To play video content in iOS 9 and later, instead use the AVPictureInPictureController or AVPlayerViewController class from the AVKit framework, or the WKWebView class from WebKit.
Try moving the line where you add the view to the hierarchy, to the playUrl: method. Generally, it is good practice to have countering implementations in opposing methods for your event counterparts. For instance, implement a method to build and add a view when an event starts, and have a corresponding method where you tear down and remove the same view when the same event ends. But, I say 'generally' because there are always exceptions, and you may have very compelling reasons for not doing so. So, in this case, the opposing calls are presentMoviePlayerViewControllerAnimated: and dismissMoviePlayerViewControllerAnimated:, available from the UIViewController category.
After changing the view access to using dot-notation, to be consistent with your callback implementation, here is what your new playUrl: implemntation would look like, assuming you're adding the view to self.view:
- (void) playUrl:(NSURL *)movieInfo
{
NSURL *streamUrl = movieInfo;
MPMoviePlayerViewController *mpvc = [[MPMoviePlayerViewController alloc] initWithContentURL:streamUrl];
[mpvc.view setFrame:self.view.bounds];
[self.view addSubview:mpvc.view];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(movieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:nil];
mpvc.moviePlayer.movieSourceType = MPMovieSourceTypeStreaming;
[mpvc.moviePlayer setControlStyle:MPMovieControlStyleFullscreen];
[mpvc.moviePlayer setShouldAutoplay:YES];
[mpvc.moviePlayer setFullscreen:NO animated:YES];
[mpvc setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[mpvc.moviePlayer setScalingMode:MPMovieScalingModeNone];
[mpvc.moviePlayer setUseApplicationAudioSession:NO];
[self presentMoviePlayerViewControllerAnimated:mpvc];
}
Another option is to simply not remove the player's view in your callback method. If that is not the culprit, then the next thing I would investigate is check if you are sending messages to nil objects. Also, see what happens when you take out all the implementation from movieFinishedCallback:, except for getting and stopping the player.
I hope that helps!
Fixed the issue by removing the [player.view removeFromSuperview] line
I'm trying to create an application that plays a sound in one view controller (background music) and mutes it in the other view controllers. I have the part of the code figured out for playing background music but I can't get the application to mute it in another window? How do you I fix this? Thank you so much! :)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSString *music = [[NSBundle mainBundle]pathForResource:#"Waltz" ofType:#"wav"];
audioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:music] error: NULL];
audioPlayer.delegate = self;
audioPlayer.numberOfLoops = -1;
[audioPlayer play];`
You can also use notifications to pause/restart the music. That way, a view controller that doesn't know anything about the music player could simply:
[[NSNotificationCenter defaultCenter] postNotificationName:#"STOP_MUSIC" object:nil];
I'm developing kind of a plugin for iTunes.
A lot of user have requested, that they would like to start the plugin if they start iTunes, which of course makes sense. However, I'm not sure how to do this.
I thought about a helper app, which is probably the only way.
The only thing that bothers me is how to get the notification.
Of course I could consistently check if iTunes is running, but I'm not sure if that's the right way to do it.
I would rather add my app as an observer of that process.
Is that possible?
If not, how does Activity Monitor do it?
SOLUTION
Thanks to Daij-Djan! I got it working like this:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
selector:#selector(iTunesLaunched:)
name:NSWorkspaceDidLaunchApplicationNotification
object:nil];
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
selector:#selector(iTunesTerminated:)
name:NSWorkspaceDidTerminateApplicationNotification
object:nil];
}
-(void) iTunesLaunched:(NSNotification *)notification {
NSRunningApplication *runApp = [[notification userInfo] valueForKey:#"NSWorkspaceApplicationKey"];
if ([runApp.bundleIdentifier isEqualToString:#"com.apple.iTunes"])
NSLog(#"start");
}
-(void) iTunesTerminated:(NSNotification *)notification {
NSRunningApplication *runApp = [[notification userInfo] valueForKey:#"NSWorkspaceApplicationKey"];
if ([runApp.bundleIdentifier isEqualToString:#"com.apple.iTunes"])
NSLog(#"terminate");
}
register for NSWorkspace notifications:
NSWorkspaceDidLaunchApplicationNotification
NSWorkspaceDidTerminateApplicationNotification
see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSWorkspace_Class/Reference/Reference.html
there is also the possibility to KVO the runningApplications property
btw cocoatech has a nice NTRunningAppManager class that does just that
I'm uisng this code to display a movie:
MPMoviePlayerViewController *mp = [[MPMoviePlayerViewController alloc]
initWithContentURL:movieURL];
mp.moviePlayer.movieSourceType = MPMovieSourceTypeUnknown;
[self presentMoviePlayerViewControllerAnimated:mp]; [mp.moviePlayer play];
The code is working fine. However when the application goes to the background while playing a movie, when the app comes back in the foreground the movieplayer is not displayed. (I see the view of the controller that called presentMoviePlayerViewControllerAnimated:mp
Is it possible when entering the foregound to resume the movie that was playing before the app went to the background?
Have you set the UIBackgroundmode to audio and also there has been problem with playing the video after app enters foreground .Refer this Tutorial on MPMoviePlayerViewController Also you can try using MPMoviePlayerViewController which has options for implementing various notifications .
you can implement notification techniques to handle it. Add a notification in the class where movie player is playing and associate with it a selector. When app goes to background then in the delegate method
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
UIApplication *app = [UIApplication sharedApplication];
UIBackgroundTaskIdentifier bgTask = 0;
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
}];
}
write this code.Actually when app goes background it pauses the MPMoviePlayerController so when it is coming to foreground you post the notification which call the method in class where movie controller is implemented and play it again in this method.
-(void)playIntroAnimationAgain
{
[[NSNotificationCenter defaultCenter]removeObserver:self name:NOTIFICATION_PlayAgain_Player object:nil];
[self.moviePlayerController play];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playIntroAnimationAgain)name:NOTIFICATION_PlayAgain_Player object:nil];
}
It solved my problem.
I want to check something every time there is a new session in an iOS application.
Neither -(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ nor -(void)applicationDidBecomeActive:(UIApplication *)application{ are achieving what I want here.
What do you recommend to achieve what I want? I want to keep multitasking...
You can add your object as an observer for the UIApplicationWillEnterForegroundNotification notfication (or related notifications) in order for it to perform some check whenever the app enters the foreground. Using this code, you can associate the notification with a block:
[[NSNotificationCenter defaultCenter]
addObserverForName:UIApplicationWillEnterForegroundNotification
object:nil
queue:nil
usingBlock:^(NSNotification *notification) {
// Whatever check is needed
}];
You are not restricted to doing all that work in your app delegate.