Objective-C: How to make AVPlayer keep playing in the background - ios

I know that there are a lot questions like mine but nothing is working
for me.
I'm trying to let the AVPlayer keep playing when i exit the app, i have implemented the following Singleton Class :
.h file:
#import <AVFoundation/AVFoundation.h>
#import <Foundation/Foundation.h>
#interface LiveStreamSingleton : NSObject<AVAudioPlayerDelegate>{
}
+(LiveStreamSingleton *)sharedInstance;
-(void)playStream;
-(void)stopStream;
-(bool)status;
#end
.m file:
#import "LiveStreamSingleton.h"
static LiveStreamSingleton *sharedInstance = nil;
#interface LiveStreamSingleton (){
AVPlayer *audioPlayer;
}
#end
#implementation LiveStreamSingleton
+ (LiveStreamSingleton*) sharedInstance {
static dispatch_once_t _singletonPredicate;
static LiveStreamSingleton *_singleton = nil;
dispatch_once(&_singletonPredicate, ^{
_singleton = [[super allocWithZone:nil] init];
});
return _singleton;
}
+ (id) allocWithZone:(NSZone *)zone {
return [self sharedInstance];
}
-(void)playStream{
//NSError *error = nil;
NSURL *urlStream;
NSString *urlAddress = #"http://198.178.123.23:8662/stream/1/;listen.mp3";
urlStream = [[NSURL alloc] initWithString:urlAddress];
AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:urlStream options:nil];
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:avAsset];
audioPlayer = [AVPlayer playerWithPlayerItem:playerItem];
//This enables background music playing
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
audioPlayer = [AVPlayer playerWithURL:urlStream];
if(!audioPlayer.error){
NSLog(#"Trying to play from singleton!");
[audioPlayer play];
NSLog(#"rate: %f",audioPlayer.rate);
}
}
-(void)stopStream{
NSLog(#"Trying to stop from singleton!");
[audioPlayer pause];
}
-(bool)status{
bool stat;
if(audioPlayer.rate > 0){
stat = true;
}else{
stat = false;
}
return stat;
}
#end
I have set the [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; for playing in the background, but i tried it on my real ipad, it's not working.
Any ideas?

add a key named Required background modes in property list (.plist) file ..
as following picture..
and add following code in
Objective-C
AppDelegate.h
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
AppDelegate.m
in application didFinishLaunchingWithOptions
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
Swift
import AVFoundation
import AudioToolbox
class AppDelegate: UIResponder, UIApplicationDelegate
{
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
{
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
try AVAudioSession.sharedInstance().setActive(true)
UIApplication.sharedApplication().beginReceivingRemoteControlEvents()
}
catch {
}
}
}
Hope it helps.

Related

AVPlayer Works on Simulator, but not on device

playerItem=[AVPlayerItem playerItemWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://www.radio.com.lk/y-fm/"]]];
player=[AVPlayer playerWithPlayerItem:playerItem] ;
[player play];
It's working on Simulator but in the device, it's not. In the console,
I have the following error:
CredStore - performQuery - Error copying matching creds.
Error=-25300, query={
class = inet;
"m_Limit" = "m_LimitAll";
"r_Attributes" = 1;
sync = syna; }
Can anyone help me with a clue?
Please add below code in your app delegate. It may help you
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[AVAudioSession sharedInstance] setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&activationError];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:&setCategoryError];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}
My answer is for you
ViewController.h
#import <UIKit/UIKit.h>
#import <AVKit/AVKit.h>
#interface ViewController : UIViewController
#property (strong, nonatomic) AVPlayerViewController *playerViewController;
#property (nonatomic,strong)AVAudioPlayer *player;
- (IBAction)actionPlay:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize player;
#synthesize playerViewController;
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction)actionPlay:(id)sender {
AVPlayerItem* playerItem = [AVPlayerItem playerItemWithURL:yourURL];
AVPlayer* playVideo = [[AVPlayer alloc] initWithPlayerItem:playerItem];
playerViewController = [[AVPlayerViewController alloc] init];
playerViewController.player = playVideo;
playerViewController.player.volume = 0;
playerViewController.view.frame = self.view.bounds;
[self.view addSubview:playerViewController.view];
[playVideo play];
}

How can I keep background music playing when switching ViewControllers?

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];

Background music game play goes right but stop gives an exception

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];
}

playing a mp3 file in iOS app [duplicate]

This question already has answers here:
How do I programmatically play an MP3 on an iPhone?
(4 answers)
Closed 4 years ago.
I can't figure out how to play a music file in an iPhone game.
Im creating a Game and I am trying to figure out how to play music whenever the app is launched.
I tried this:
- (void)awakeFromNib {
NSString *path = [[NSBundle mainBundle] pathForResource:#"musicamenu" ofType:#"mp3"];
AVAudioPlayer *theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
[theAudio play];
}
This is how you do it. In your v1AppDelegate.h file add
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
#interface v1AppDelegate : UIResponder <UIApplicationDelegate>
{
AVAudioPlayer *myAudioPlayer;
}
#property (nonatomic, retain) AVAudioPlayer *myAudioPlayer;
#property (strong, nonatomic) UIWindow *window;
#end
Now in your v1AppDelegate.m file add this
#import "v1AppDelegate.h"
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
#implementation v1AppDelegate
#synthesize window = _window;
#synthesize myAudioPlayer;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//start a background sound
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#"Soothing_Music2_Long" ofType: #"mp3"];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:soundFilePath ];
myAudioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
myAudioPlayer.numberOfLoops = -1; //infinite loop
[myAudioPlayer play];
// Override point for customization after application launch.
return YES;
}
If you wish to stop or start this music from anywhere else in your code then simply add this
#import "v1AppDelegate.h"
- (IBAction)stopMusic
{
v1AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate.myAudioPlayer stop];
}
- (IBAction)startMusic
{
v1AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate.myAudioPlayer play];
}
I recommend to add the play music method in applicationDidBecomeActive: method. Because you want the music played every time the app is launched. Note you should hold a reference to the player. Else the music will not be played.
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Play music on another queue so that the main queue is not blocked.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self playMusic];
});
}
- (void)playMusic
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"done" ofType:#"mp3"];
NSError *error = nil;
NSURL *url = [NSURL fileURLWithPath:path];
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
[self.player play];
}
For Swift 3.1 :
Use this two imports :
import AVFoundation
import AudioToolbox
Create a reference for your AVAudioPlayer :
private var mAudioPlayer : AVAudioPlayer?
Use this function for play a sound you are storing in your app :
func onTapSound(){
let soundFile = Bundle.main.path(forResource: "slap_placeholder.wav", ofType: nil)
let url = URL(fileURLWithPath: soundFile!)
self.mAudioPlayer = try! AVAudioPlayer(contentsOf: url as URL)
self.mAudioPlayer?.play()
}

Stop background music

I have this app that has several view controllers. In the app delegate, I set it so that as soon as the app finishes launching, the background music starts. However, on another view controller, I have this button that plays this video. My problem is that when I play the movie, the background audio overlaps with the movie. My question is, how do I stop the music when I play the movie and play the music after the movie ends.
Here is my app_delegate.h:
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#interface App_Delegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
UINavigationController *navigationController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
#end
Here is my App_Delegate.m
#import "App_Delegate.h"
#import "RootViewController.h"
#implementation App_Delegate
#synthesize window;
#synthesize navigationController;
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
{NSString* soundFilePath = [[NSBundle mainBundle] pathForResource:#"beethoven_sym_5_i" ofType:#"mp3"];
NSURL* soundFileURL = [NSURL fileURLWithPath:soundFilePath];
AVAudioPlayer* player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:nil];
player.numberOfLoops=-1;
[player play];
}
// Override point for customization after application launch.
// Set the navigation controller as the window's root view controller and display.
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)dealloc {
[navigationController release];
[window release];
[super dealloc];
}
#end
My MovieViewController.h:
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
#import <AVFoundation/AVFoundation.h>
#interface MovieViewController : UIViewController {
IBOutlet UIScrollView *sesamescroller;
}
- (IBAction)playsesamemovie:(id)sender;
#end
Finally, my MovieViewController.m
#import "MovieViewController.h"
#interface MovieViewController ()
#end
#implementation MovieViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
- (void)viewDidUnload
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (IBAction)playsesamemovie:(id)sender {
NSString *filepath = [[NSBundle mainBundle] pathForResource:#"How to make Sesame chicken" ofType:#"mp4"];
NSURL *fileURL = [NSURL fileURLWithPath:filepath];
MPMoviePlayerController *moviePlayerController = [[MPMoviePlayerController alloc] initWithContentURL:fileURL];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlaybackComplete:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayerController];
[self.view addSubview:moviePlayerController.view];
moviePlayerController.fullscreen = YES;
[moviePlayerController play];
}
- (void)moviePlaybackComplete:(NSNotification *)notification
{
MPMoviePlayerController *moviePlayerController = [notification object];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayerController];
[moviePlayerController.view removeFromSuperview];
[moviePlayerController release];
}
- (void)dealloc {
[sesamescroller release];
[super dealloc];
}
#end
The code you show has a local variable pointing to the player object. To control the player, other code needs to be able to find it. Like this:
In App_Delegate.h:
#property (strong) AVAudioPlayer *player;
in App_Delegate.m: (where did this underbar come from? Most unconventional!)
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:nil];
self.player.numberOfLoops=-1;
[self.player play];
Then, wherever you want to control it:
[((App_Delegate *)([UIApplication sharedApplication].delegate)).player pause];
// ...
[((App_Delegate *)([UIApplication sharedApplication].delegate)).player play];
set scalling mode to your player
for Paused :
[moviePlayerController setScalingMode:MPMoviePlaybackStatePaused];
for Stopped:
[moviePlayerController setScalingMode:MPMoviePlaybackStateStopped];
If possible on iOS, you can use scriptable feature to send message to mute. I did this sometime back for Mac OS X where I used to control iTunes from another app.
First add start to songs in application delegate
.h application delegate
#import <UIKit/UIKit.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>
#class ViewController;
#interface AppDelegate : UIResponder <UIApplicationDelegate,AVAudioPlayerDelegate>
{
AVAudioPlayer *myAudioPlayer;
NSDictionary *config;
NSMutableArray *ARRAY;
}
-(void)stop;
#property(retain,nonatomic) NSDictionary *config;
#property (nonatomic, retain) AVAudioPlayer *myAudioPlayer;
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) ViewController *viewController;
#end
.m application delegate
#implementation AppDelegate
{
AVAudioPlayer* audioPlayer;
}
#synthesize myAudioPlayer;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
audioPlayer.delegate = self;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
audioPlayer.numberOfLoops = 1;
audioPlayer.delegate=self;
[audioPlayer play];
}
-(void)stop
{
[audioPlayer stop];
}
-(void)star
{
[audioPlayer play];
}
when use required start and stop background music in application
directly call this method -start and -stop
..it really work

Resources