iOS: AVAudioPlayer can it only play one file? - ios

It´s only possible to give the AVAudioPlayer an URL of the file to play via it´s init method.
And as I understand it if one want´s to play another file, the old instance needs to be stopped from playing, and a new instance of AVAudioPlayer initialized with the URL to the new audiofile to play.
But this is making it hard cause I have a navigation controller, and when the user leaves the player screen the sound should keep playing, and it does. But when the user selects a new audio file to play from the tableview a new instance of the viewController and AVAudioPlayer is initalized and I have no way of stopping the old from playing. How do I get this working?

You can do something like this
In your v1AppDelegate.h file add,
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#include <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>
#include <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:#"Startsound" ofType: #"m4a"];
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];
}

Related

Using AVAudioPlayer from class outside ViewController not working

New to iOS and Objective-C, have been struggling to figure this out. I have a class that holds a strong reference to an AVAudioPlayer object and defines a method to play an mp3 depending on the parameter 'tag', which belongs to a UIButton. In my view controller I have a method that uses this class to play a sound when a button is pressed. But when I run the simulator and press the button, the mp3 is not being played. When I don't use the other class and make the AVAudioPlayer belong to my ViewController, initialize it in viewDidLoad, and call play right in the IBAction method, it works fine. I checked that the files are available to my project and that they are being referenced correctly in the code.
I looked around and found this and this, neither solved my problem. Here's my code
GuitarTuner.h
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#interface GuitarTuner : NSObject
- (void) play: (NSUInteger)tag;
#end
GuitarTuner.m
#import "GuitarTuner.h"
#import <AVFoundation/AVFoundation.h>
#interface GuitarTuner()
#property (strong, nonatomic) AVAudioPlayer *audioPlayer;
#end
#implementation GuitarTuner
- (void) play:(NSUInteger)tag
{
NSString *note;
switch (tag) {
case 0:
note = #"Low-E";
break;
case 1:
note = #"A";
break;
case 2:
note = #"D";
break;
case 3:
note = #"G";
break;
case 4:
note = #"B";
break;
case 5:
note = #"Hi-E";
break;
}
NSString *path = [[NSBundle mainBundle] pathForResource:note ofType:#"mp3"];
NSURL *soundURL = [NSURL fileURLWithPath:path];
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundURL error:nil];
[self.audioPlayer play];
}
#end
ViewController.m
#import "ViewController.h"
#import "GuitarTuner.h"
#interface ViewController ()
#property (strong, nonatomic) GuitarTuner *tuner;
#end
#implementation ViewController
- (GuitarTuner *) tuner
{
if (!_tuner) return [[GuitarTuner alloc] init];
return _tuner;
}
- (IBAction)noteButton:(id)sender
{
UIButton *button = (UIButton*)sender;
[self.tuner play:button.tag];
}
#end
Thanks in advance
EDIT:
Silly mistake! Just didn't properly initialize GuitarTuner property in the getter in ViewController -- should be _tuner = [[GuitarTuner alloc] init] Answer below works too.
Try to initialise AVAudioPlayer like this
NSError *error;
self.audioPlayer = [[AVAudioPlayer alloc]
initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:note withExtension:#"mp3"] error:&error];
UPDATE:
You give yourself your answer:
When I don't use the other class and make the AVAudioPlayer belong to
my ViewController, initialize it in viewDidLoad, and call play right
in the IBAction method, it works fine.
Try to alloc tuner in viewDidLoad or create from your class GuitarTuner a singleton and from there everything will be much easier.
Also comment this:
- (GuitarTuner *) tuner
{
if (!_tuner) return [[GuitarTuner alloc] init];
return _tuner;
}

iOS MPMoviePlayerViewController only works on debug not in final

I implemented a MPMoviePlayerViewControllerlike this:
ViewController.h
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
#interface ViewController : UITableViewController
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
/* SOME CODE AND A TAPGESTURERECOGNIZER */
/* CALLS [self playVideo] */
-(void) playVideo{
#try {
NSURL *URL = [NSURL URLWithString:#"myGeneratedURL"];
NSLog(#"URL: %#",URL);
MPMoviePlayerViewController *video = [[MPMoviePlayerViewController alloc]
initWithContentURL:URL];
[self.navigationController presentMoviePlayerViewControllerAnimated:video];
}
#catch (NSException *exception) {
}
}
So now my problem is that it works just fine on both simulator and on my iphone (if i debug it), but when i upload a build to itunesconnect and download it via TestFlight the MPMoviePlayerViewController does not show up. The URL in NSLog is definitely the same in all three cases ( sim , iphone debug, testflight ).
I don't know where i should start searching the error...
I would suggest using strong reference rather than an local variable.
You can follow this tutorial

iOS: Playing a video on application launch

I am new to Xcode so I've been trying to follow along to tutorials but haven't come across any that explain what I'm trying to achieve. I just want to play a video automatically when you open an application. I have it somewhat working in that the audio plays, but I cannot see any video. Am I missing something? I am getting this Warning in my output window:
Warning: Attempt to present MPMoviePlayerViewController: 0x831d7a0 on ViewController: 0x9d10540 whose view is not in the window hierarchy!
In my ViewController.h:
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
#interface ViewController : UIViewController
#end
ViewController.m:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *url =[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"Placeholder" ofType:#"mp4"]];
MPMoviePlayerViewController *playercontroller = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
[self presentMoviePlayerViewControllerAnimated:playercontroller];
playercontroller.moviePlayer.movieSourceType = MPMovieSourceTypeFile;
[playercontroller.moviePlayer play];
playercontroller = nil;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Instead of
[playercontroller.moviePlayer play];
do
[playercontroller play];
Side note:
Also check up on your naming convention. In Objective-C variable names "should" have capital letter on each new word in the variable. E.g. instead of playercontroller use playerController.
I know your status.
it's warning from Xcode.
So, you just change the code.
like this,
[playercontroller performSelector:#selector(player)];

Compile Errors in untouched AppDelegate.m

I have been creating a simple example app to demonstrate playing sound files in IOS.
For this I have created a very simple XCode project with one view controller. However, although my AppDelegate.h and .m files have remained unedited I am getting strange parse issues in the AppDelegate.m.
On the line #Implimentation the compiler tells me its missing '#end'.
On the line -(BOOL) application: (UIApplication ) application didFinishLaunchingWithOptions: (NSDictionary) launch options it tells me Expected ';' after method prototype.
The issues seem to stem from the #import "ViewController.h" reference in the AppDelegate.m file. As when I remove this these two errors go away, and get replaced with Receiver 'ViewController' for class message is a forward declaration, which is what I would expect with a missing import.
This is an odd problem. I've built several IOS apps before but never encountered this issue. For background info the project was created as a Single View App in XCode 4. I have properly lined the IBOutlets and Properties of the ViewController.h to the XIB in interface builder. I have also added in the AudioToolbox framework in via the build phases > Link Library with Libraries feature.
Here is the delegete and view controller files files
AppDelegate.m
#import "AppDelegate.h"
#import "ViewController.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (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.
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
#end
AppDelegate.h
#import <UIKit/UIKit.h>
#class ViewController;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) ViewController *viewController;
#end
ViewContoller.m
#import "ViewController.h"
#import <AudioToolbox/AudioToolbox.h>
#interface ViewController ()
SystemSoundID pig;
SystemSoundID cow;
SystemSoundID sheep;
SystemSoundID chicken;
#end
#implementation ViewController
#Synthesize but_cow, but_pig, but_sheep, but_chicken;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSString * cowSoundURL= [[NSBundle mainBundle] pathForResource:#"cow" ofType: #"mp3"];
NSString * pigSoundURL= [[NSBundle mainBundle] pathForResource:#"pig" ofType: #"mp3"];
NSString * sheepSoundURL= [[NSBundle mainBundle] pathForResource:#"sheep" ofType: #"mp3"];
NSString * chiickenSoundURL= [[NSBundle mainBundle] pathForResource:#"chicken" ofType: #"mp3"];
AudioServicesCreateSystemSoundID(cowSoundURL, &cow);
AudioServicesCreateSystemSoundID(pigSoundURL, &pig);
AudioServicesCreateSystemSoundID( sheepSoundURL, &sheep);
AudioServicesCreateSystemSoundID(chickenSoundURL, &chicken);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//====================================================
/**
Called when a button is pressed
**/
//====================================================
-(IBAction)buttonPressed:(id)sender
{
if (sender == but_cow)
{
AudioServicesPlaySystem(cow);
}
else if (sender == but_sheep)
{
AudioServicesPlaySystem(sheep);
}
else if (sender == but_pig)
{
AudioServicesPlaySystem(pig);
}
else if (sender == but_chicken)
{
AudioServicesPlaySystem(chicken);
}
}//===================================================
#end
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (nonatomic, retain) IBOutlet UIButton * but_cow;
#property (nonatomic, retain) IBOutlet UIButton * but_pig;
#property (nonatomic, retain) IBOutlet UIButton * but_sheep;
#property (nonatomic, retain) IBOutlet UIButton * but_chicken;
-(IBAction)buttonPressed:(id)sender;
Thanks very much for taking the time to read this.
ViewController.h seems to be missing an #end
The line:
#import "ViewController.h"
will basically copy in the entire file, so if there is an error in ViewController.h, it will show up everywhere that file is imported as well.
You are not adding #end in viewcontroller.h

ios single AVAudioPlayer

I'm working on an ios app with uitabviewcontroller that plays some music. I don't want each tab viewcontroller to create it's own audio player. I want to have one single audio player and have all the viewcontrollers share it.
so I have created a class called player, which would initiate avaudioplayer with the song url and plays the song,
#import <AVFoundation/AVFoundation.h>
#interface player : NSObject {
AVAudioPlayer *theMainAudio;
}
-(void)playSong:(NSString *)songName;
#end
I want to create only one instance of this class and all my viewcontrollers share it. I've tried creating it in my delegate,
#interface AppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> {
UIWindow *window;
UITabBarController *tabBarController;
player *theMainPlayer;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#property (nonatomic, retain) player *theMainPlayer;
#end
in .m file,
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//some other stuff here....
theMainPlayer = [[player alloc]init];
return YES;
}
and then I called it in my viewcontrollers,
player myPlayer = ((AppDelegate *)[UIApplication sharedApplication].delegate).theMainPlayer;
but this didn't work.
can anyone tell me what's wrong with what I've done or if there is any other way to do what I want to do, which is to create a player object and share it among all of my viewcontrollers.
Thanks
create a singleton, in your player.m
#import "player.h"
#implementation player
static player *sharedInstance = nil;
+ (player *)sharedInstance {
if (sharedInstance == nil) {
sharedInstance = [[super allocWithZone:NULL] init];
}
return sharedInstance;
}
- (id)init
{
self = [super init];
if (self) {
// Work your initialising here as you normally would
}
return self;
}
-(void)playSong:(NSString *)songName
{
// do your stuff here
}
to use this class, just import the player.h
[[player sharedInstance] playSong:#"something"];
How did it go wrong? To me it seems the last line would cause compile error. You should add asterisk for class declaration :
player * myPlayer = ((AppDelegate *)[UIApplication sharedApplication].delegate).theMainPlayer;
Other than that, I didn't catch anything.
But I prefer using Singleton pattern for cases like this.
Reference :
http://developer.apple.com/library/mac/#documentation/General/Conceptual/DevPedia-CocoaCore/Singleton.html
http://www.galloway.me.uk/tutorials/singleton-classes/

Resources