I created a very simple music player using MPMusicPlayerController that is working fine except the stop button (see picture below). When the music is playing and stop button is pressed, the app doesn't play anymore. I tried to terminate it when in background but the app doesn't work. I just can use the app again after press play on center control (picture two).
And my code
#import "ViewController.h"
#import <MediaPlayer/MediaPlayer.h>
#interface ViewController ()
{
MPMusicPlayerController *playerController;
MPMediaQuery *query;
}
#end
#implementation ViewController
#synthesize musicTitleLabel;
- (void)viewDidLoad {
[super viewDidLoad];
playerController = [[MPMusicPlayerController alloc] init];
}
- (IBAction)playPressed:(id)sender {
query = [MPMediaQuery songsQuery];
MPMediaItem *item = [[query collections] objectAtIndex:0];
[playerController setNowPlayingItem:item];
[playerController play];
NSString *titleString = [item valueForProperty:MPMediaItemPropertyTitle];
musicTitleLabel.text = [NSString stringWithFormat:#"%#",titleString];
}
- (IBAction)pausePressed:(id)sender {
[playerController pause];
}
- (IBAction)stopPressed:(id)sender {
[playerController stop];
}
How can I fix that problem? What's the function o the Stop Method?
try this:
MPMusicPlayerController *player = [MPMusicPlayerController systemMusicPlayer];
Playing media items with the systemMusicPlayer will replace the user's current Music state.
Related
I currently have a SettingsViewController which handles starting/stopping music and adjusting the musics volume.
Is it possible to make the music stay on after unwinding the SettingsViewController? And after turning on the music and switching ViewControllers, can I re-open the SettingsViewController and turn off the music as well? Please let me know the limitations.
Here is the code for my SettingsViewController.h
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#interface SettingsViewController : UIViewController <AVAudioPlayerDelegate>
{
AVAudioPlayer *audioPlayer;
IBOutlet UISwitch *Switch;
IBOutlet UISlider *Slider;
}
-(IBAction)Switch:(UISwitch *)sender;
-(IBAction)Slider:(UISlider *)sender;
#end
And here is the code for my SettingsViewController.m
#import "SettingsViewController.h"
#interface SettingsViewController ()
#end
#implementation SettingsViewController
-(IBAction)Switch:(UISwitch *)sender{
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
if(sender.tag == 0){
if(sender.on){
[standardDefaults setObject:#"On" forKey:#"keyName"];
//choosing and setting the music file
NSString *music = [[NSBundle mainBundle]pathForResource:#"bgmusic1" ofType:#"mp3"];
audioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:music] error:NULL];
audioPlayer.delegate = self;
audioPlayer.numberOfLoops= -1; //sets the music to loop infinitely
[audioPlayer play]; //plays the music
} else if (sender.on == 0){
[standardDefaults setObject:#"Off" forKey:#"keyName"];
[audioPlayer stop]; //stops the music
}
}
[standardDefaults synchronize];
}
-(IBAction)Slider:(UISlider *)sender{
audioPlayer.volume = sender.value / 100.0; //will adjust the volume of the music according the slider value
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
Let me know what needs to be modified!
Do that in your AppDelegate.
To access it from anywhere, import it's .h file in your ViewControllers .m file and access it with
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
Make the audioplayer to a property in your AppDelegate.h to allow public access (for e.g. your other viewControllers)
#interface AppDelegate: NSAppDelegate
{
IBOutlet UISwitch *Switch;
IBOutlet UISlider *Slider;
}
#property AVAudioPlayer *audioPlayer; // <------
-(IBAction)Switch:(UISwitch *)sender;
-(IBAction)Slider:(UISlider *)sender;
#end
Then adjust each call of your audioplayer in the m file to adopt the change in your h file.
//Instead of [audioplayer doSomething] write...
[self.audioplayer doSomething];
// in modern objective-c you can use also
[_audioplayer doSomething];
To call your audioplayer from other ViewControllers then implement the first mentioned code and call your player like so
[appDelegate.audioplayer doSomething]
Because your audioPlayer will be release when its parent SettingsViewController released.
So you should add it to global and you can make it with Singleton Pattern.
Create BackgroundPlayer.h
#interface BackgroundPlayer: NSObject {
AVAudioPlayer *audioPlayer;
}
+ (id)sharedManager;
#end
and BackgroundPlayer.m
#implementation BackgroundPlayer
static BackgroundPlayer* sharedInstance = nil;
+ (BackgroundPlayer*) sharedInstance {
if (sharedInstance == nil) {
sharedInstance = [[super allocWithZone:NULL] init];
}
return sharedInstance;
}
- (id)init
{
self = [super init];
return self;
}
-(void)playAudio:(NSString *) audioPath
{
audioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:audioPath] error:NULL];
audioPlayer.delegate = self;
audioPlayer.numberOfLoops= -1; //sets the music to loop infinitely
[audioPlayer play]; //plays the music
}
-(void)setVolum:(float) volum {
if (audioPlayer) {
audioPlayer.volume = sender.value / 100.0;
}
}
Then you just call
NSString *music = [[NSBundle mainBundle]pathForResource:#"bgmusic1" ofType:#"mp3"];
[[BackgroundPlayersharedInstance] playAudio:music];
I'am trying to add remote control events to a music player app, but can't get it working.
Some facts:
I'm using [MPMusicPlayerController applicationMusicPlayer];
I added Audio, AirPlay and Picture in Picture background modes;
The example is playing audio;
It does not receive remote notifications from the lock screen and control center;
I've made an example project which can be downloaded here:
example project
The main source:
#import "ViewController.h"
#import <MediaPlayer/MPMediaPickerController.h>
#import <MediaPlayer/MPMediaQuery.h>
#import <MediaPlayer/MediaPlayer.h>
#interface ViewController ()
#property (strong, nonatomic) MPMusicPlayerController *MusicPlayer;
#property (strong, nonatomic) MPMediaItemCollection *MusicPlayerSongs;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_MusicPlayerSongs = [MPMediaItemCollection alloc];
_MusicPlayer = [MPMusicPlayerController applicationMusicPlayer];
[_MusicPlayer setShuffleMode: MPMusicShuffleModeOff];
[_MusicPlayer setRepeatMode: MPMusicRepeatModeNone];
[_MusicPlayer beginGeneratingPlaybackNotifications];
}
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
NSMutableArray *selectedTracks = [NSMutableArray new];
//Find all tracks that contains an 'a'
MPMediaPropertyPredicate *songPredicate =
[MPMediaPropertyPredicate predicateWithValue:#"a"
forProperty:MPMediaItemPropertyTitle
comparisonType:MPMediaPredicateComparisonContains];
MPMediaQuery *mediaQuery = [[MPMediaQuery alloc] init];
[mediaQuery addFilterPredicate:songPredicate];
[selectedTracks addObjectsFromArray:[mediaQuery items]];
NSLog(#"Number of tracks containing an 'a': %lu",(unsigned long)selectedTracks.count);
self.MusicPlayerSongs = [[MPMediaItemCollection alloc]initWithItems:selectedTracks];
[self.MusicPlayer setQueueWithItemCollection:self.MusicPlayerSongs];
[self.MusicPlayer play];
[self.MusicPlayer beginGeneratingPlaybackNotifications];
[self basicSetup];
[self updateNowPlayingCenter];
}
- (void)basicSetup {
//Listen to remote control events
[MPRemoteCommandCenter sharedCommandCenter].previousTrackCommand.enabled = NO;
[MPRemoteCommandCenter sharedCommandCenter].nextTrackCommand.enabled = NO;
[MPRemoteCommandCenter sharedCommandCenter].playCommand.enabled = YES;
[MPRemoteCommandCenter sharedCommandCenter].pauseCommand.enabled = YES;
[MPRemoteCommandCenter sharedCommandCenter].togglePlayPauseCommand.enabled = YES;
[[MPRemoteCommandCenter sharedCommandCenter].nextTrackCommand addTarget:self action:#selector(remoteNext)];
[[MPRemoteCommandCenter sharedCommandCenter].previousTrackCommand addTarget:self action:#selector(remotePrevious)];
[[MPRemoteCommandCenter sharedCommandCenter].playCommand addTarget:self action:#selector(remotePlay)];
[[MPRemoteCommandCenter sharedCommandCenter].pauseCommand addTarget:self action:#selector(remotePlay)];
[[MPRemoteCommandCenter sharedCommandCenter].togglePlayPauseCommand addTarget:self action:#selector(remoteTogglePlayState)];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}
-(void)remotePlay{
NSLog(#"remotePlay");
[self.MusicPlayer play];
}
-(void)remoteNext{
NSLog(#"remoteNext");
[self.MusicPlayer skipToNextItem];
[self updateNowPlayingCenter];
}
-(void)remotePrevious{
NSLog(#"remotePrevious");
[self.MusicPlayer skipToPreviousItem];
[self updateNowPlayingCenter];
}
-(void)remotePause{
NSLog(#"remotePause");
[self.MusicPlayer pause];
}
-(void)remoteTogglePlayState{
NSLog(#"remoteTogglePlayState");
if([self.MusicPlayer playbackState] == MPMusicPlaybackStatePlaying){
[self.MusicPlayer pause];
}else{
[self.MusicPlayer play];
}
}
-(void)updateNowPlayingCenter{
MPNowPlayingInfoCenter *center = [MPNowPlayingInfoCenter defaultCenter];
NSMutableDictionary *songInfo = [NSMutableDictionary dictionaryWithDictionary:#{
MPMediaItemPropertyArtist: [self.MusicPlayer nowPlayingItem].artist,
MPMediaItemPropertyTitle: [self.MusicPlayer nowPlayingItem].title,
MPMediaItemPropertyAlbumTitle: [self.MusicPlayer nowPlayingItem].albumTitle,
}];
center.nowPlayingInfo = songInfo;
}
I just can't figure out why it is not working :(
PROGRESS UPDATE'S
What I found out so far, if I reboot my iPhone, it works. But every time after that it won't.
The lock screen and control center both show the right track, but still can't control the app.
Not sure if this helps you at all, but here is how I received any changes (in Swift).
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.getNowPlayingItem), name: MPMusicPlayerControllerNowPlayingItemDidChangeNotification, object: nil)
player.beginGeneratingPlaybackNotifications()
}
deinit {
player.endGeneratingPlaybackNotifications()
NSNotificationCenter.defaultCenter().removeObserver(self)
}
It is necessary to (addObserver and beginGeneratingPlaybackNotifications), but also to (removeObserver and endGeneratingPlaybackNotification). I am not yet familiar with remote control events, but you may want to try ending those notifications as well. Hope this helps!
I'm trying to play some music for my game in the background. The music will never stop unless the user turns it off in settings. The music will always play in the background for each view and doesn't pause or something.
For this reason I've made a singleton class for my background music. But when I press "Stop the music", the app breakpoints for an exception (I'm not seeing one, so I don't know what's wrong).
The music still stops, but there is something wrong and I don't know what. Is it right to make it in a singleton class, or do I need to solve this on an other way?
Here is a screenshot of when the exception happens:
Here is the code for my singleton class:
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#interface Music : NSObject
#property AVAudioPlayer *player;
- (void)stop;
- (void)play;
+ (Music *)sharedInstance;
#end
#import "Music.h"
#implementation Music
+ (Music *)sharedInstance {
static Music *sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken,^{
sharedInstance = [[Music alloc] init];
});
return sharedInstance;
}
-(instancetype)init{
self = [super init];
if (self) {
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:#"water_2"
ofType:#"wav"]];
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
self.player.numberOfLoops = -1;
}
return self;
}
- (void)stop{
[self.player stop];
}
- (void)play{
[self.player play];
}
I would switch up your code and I would use an IBAction instead of void stop and void play
-(IBAction)stop {
[player stop];
}
-(IBAction)play {
[player play];
}
The following code plays a song from the user's music library. Works fine on devices running iOS6, but I get no sound at all on devices running iOS5. What am I doing wrong? A search for AVAudioPlayer issues on iOS5 doesn't turn up much.
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:self.songUrl error:nil];
[self.audioPlayer setNumberOfLoops:-1];
[self.audioPlayer play];
self.songUrl is valid. (ipod-library://item/item.m4a?id=557492601628322780)
This is how I have implemented in my apps compatible with both iOS 5.0 and iOS 6.0
In your *.h file
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
#interface v1MusicPicController : UIViewController <MPMediaPickerControllerDelegate, AVAudioPlayerDelegate>
{
MPMusicPlayerController *musicPlayer;
MPMediaItemCollection *userMediaItemCollection;
}
#property (nonatomic, retain) MPMusicPlayerController *musicPlayer;
#property (nonatomic, retain) MPMediaItemCollection *userMediaItemCollection;
--------- In your *.m file
#implementation v1MusicPicController
#synthesize musicPlayer;
#synthesize userMediaItemCollection;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[self setMusicPlayer: [MPMusicPlayerController applicationMusicPlayer]];
// By default, an application music player takes on the shuffle and repeat modes
// of the built-in iPod app. Here they are both turned off.
[musicPlayer setShuffleMode: MPMusicShuffleModeOff];
[musicPlayer setRepeatMode: MPMusicRepeatModeNone];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (IBAction) DoneButtonMusic:(id)sender
{
MPMediaPickerController *mediaPicker = [[MPMediaPickerController alloc] initWithMediaTypes:MPMediaTypeMusic];
mediaPicker.delegate = self;
mediaPicker.allowsPickingMultipleItems = YES; // this is the default
[self presentModalViewController:mediaPicker animated:YES];
}
// To learn about notifications, see "Notifications" in Cocoa Fundamentals Guide.
- (void) registerForMediaPlayerNotifications {
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver: self
selector: #selector (handle_NowPlayingItemChanged:)
name: MPMusicPlayerControllerNowPlayingItemDidChangeNotification
object: musicPlayer];
[notificationCenter addObserver: self
selector: #selector (handle_PlaybackStateChanged:)
name: MPMusicPlayerControllerPlaybackStateDidChangeNotification
object: musicPlayer];
[musicPlayer beginGeneratingPlaybackNotifications];
}
- (void) updatePlayerQueueWithMediaCollection: (MPMediaItemCollection *) mediaItemCollection
{
if (userMediaItemCollection == nil)
{
//NSLog(#"Went here 4");
// apply the new media item collection as a playback queue for the music player
[self setUserMediaItemCollection: mediaItemCollection];
[musicPlayer setQueueWithItemCollection: userMediaItemCollection];
[musicPlayer play];
}
}
// Media picker delegate methods
- (void)mediaPicker: (MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection
{
//NSLog(#"Went here 2");
// We need to dismiss the picker
[self dismissModalViewControllerAnimated:YES];
// Apply the chosen songs to the music player's queue.
[self updatePlayerQueueWithMediaCollection: mediaItemCollection];
}
- (void)mediaPickerDidCancel:(MPMediaPickerController *)mediaPicker
{
// User did not select anything
// We need to dismiss the picker
[self dismissModalViewControllerAnimated:YES];
}
You may already know this but I use AVAudioPlayer for playing sounds that are in my app bundle.
#property (nonatomic, retain) AVAudioPlayer *myAudioPlayer1;
#synthesize myAudioPlayer1;
// ************************
// PLAY AUDIO
// ************************
[myAudioPlayer1 stop];
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#"funny_sound" ofType: #"mp3"];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
myAudioPlayer1 = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
[myAudioPlayer1 play];
I'm seeing the same behavior with ipod-library URLs. More specifically, initWithContentsOfURL sets an error code of -43, which is similar to a file not found error. Apparently either this was fixed, or support was added, in iOS 6, but I haven't found any official explanation.
Loading the audio into an NSData and using AVAudioPlayer initWithData also failed for me with a similar error (NSData code 256).
The best solution I've found so far is to use AVPlayer instead of AVAudioPlayer, but it's going to take some rework because the methods and properties are slightly different.
I'm trying to create an iOS/iPhone radio app using Xcode 4.5.2.
I wanted to stream #"http://xx.xxxxxxx.com/8111/radio.m3u" with play, pause, volume control and able to play on background feature/multitasking.
I've added AVFoundation, Mediaplayer and AudioToolBox frameworks thus far. I've added play, pause and slider objects to xib.
ViewController.h
#interface ViewController : UIViewController
#property (strong,nonatomic) MPMoviePlayerController *myPlayer;
#property (weak, nonatomic) IBOutlet UISlider *myslider;
- (IBAction)playButtonPressed;
- (IBAction)myslider:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#import <MediaPlayer/MediaPlayer.h>
#interface ViewController ()
{
UISlider *volumeSlider;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
UIBackgroundTaskIdentifier newTaskId = UIBackgroundTaskInvalid;
newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
}
- (IBAction)playButtonPressed;
{
NSString *urlAddress = #"http://xxxxxxx.com/8111/listen.m3u";
NSURL *url = [NSURL URLWithString:urlAddress];
MPMoviePlayerController *player = [[MPMoviePlayerController alloc]initWithContentURL:url];
player.movieSourceType = MPMovieSourceTypeStreaming;
[player prepareToPlay];
self.myPlayer = player;
[self.view addSubview:self.myPlayer.view];
[self.myPlayer play];
}
- (IBAction)stopButtonPressed;
{
[self.myPlayer stop];
}
- (IBAction)myslider:(id)sender
{
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame: CGRectMake(10, 10, 200, 40)];
[volumeSlider addSubview:volumeView];
[volumeView sizeToFit];
}
There are Two way to achieve this.
You can directly load you URL in UIWebView and it will properly.
You can also use MPMoviePlayerController.
Create a "MPMoviePlayerController *player" as a strong object in your ViewController.
So you code would look something like below:
#interface ViewController ()
{
UISlider *volumeSlider;
MPMoviePlayerController *player;
}
#end
- (IBAction)playButtonPressed;
{
NSString *urlAddress = #"http://xxxxxxx.com/8111/listen.m3u";
NSURL *url = [NSURL URLWithString:urlAddress];
if(nil != player)
{
player = nil; // Alternatively you can stop and restart with the different stream.
}
player = [[MPMoviePlayerController alloc]initWithContentURL:url];
player.movieSourceType = MPMovieSourceTypeStreaming;
[player prepareToPlay];
self.myPlayer = player;
[self.view addSubview:self.myPlayer.view];
[self.myPlayer play];
}