Need to stop AVPlayer before playing new stream - ios

I have On-line Radio app. Located on the first viewController (tableView) audio streams. Audio streams are made as a table. By clicking on the name of the stream screen opens with AVpalyer. The problem is that when opening the second stream, the ашкые stream is played simultaneously. How to make so that would be played if one thread, and the second was turned down?
avplayer:
#interface RadioViewController ()
#end
#implementation RadioViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSString *restorationId = self.restorationIdentifier;
NSString *streamId = _detail.label;
NSString* identifer = [restorationId stringByAppendingString: streamId];
NSLog(#"%#", identifer);
self.title = apptitle;
self.streamLabel.text = _detail.label;
//Определение потока
NSString *streamURL;
if (_detail.label == #"ПЕРВЫЙ"){
streamURL = streamURLpervyj;
} if (_detail.label == #"РОК") {
streamURL = streamURLrok;
} if (_detail.label == #"БИТ") {
streamURL = streamURLbit;
} if (_detail.label == #"ПО-РУССКИ") {
streamURL = streamURLporusski;
} if (_detail.label == #"ХИП-ХОП") {
streamURL = streamURLhiphop;
} if (_detail.label == #"РЕЛАКС") {
streamURL = streamURLrelax;
} if (_detail.label == #"РЕТРО") {
streamURL = streamURLretro;
}
if(![self connected]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Невозможно установить соединение" message:#"Проверьте соединение с интернетом" delegate:self cancelButtonTitle:#"ОК" otherButtonTitles: nil];
[alert show];
} else {
//Start stream
AVPlayerItem* playerItem = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:streamURL]];
[playerItem addObserver:self forKeyPath:#"timedMetadata" options:NSKeyValueObservingOptionNew context:nil];
music = [AVPlayer playerWithPlayerItem:playerItem];
[music play];
}
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playButton:)
name:#"TogglePlayPause"
object:nil];
//Set Title View
titleView = [[UILabel alloc] initWithFrame:CGRectMake(0, 240, myScrollView.frame.size.width, 40)];
[self setStyle]; //Set style layers
titleView.text = #"Подключаюсь...";
CGFloat textLength = titleView.intrinsicContentSize.width;
[myScrollView addSubview: titleView];
[self.view addSubview:myScrollView];
if (textLength < 240) {
[self centerText];
}
timer = [NSTimer scheduledTimerWithTimeInterval:(1.0/2.0) target:self selector:#selector(timed) userInfo:nil repeats:YES];
}
http://dev.b4u.by/radio.jpg

You can decleare avplayer object "music" in your appdelegate then access it by this way
AppDelegate *mainDelegate = [UIApplication sharedApplication].delegate;
[mainDelegate.music pause];
mainDelegate.music = nil;
when you want to start new stream or before alloc init

StreamViewController.h
#interface APStreamsViewController : UIViewController <UITableViewDataSource>
{
AVPlayer *musicSegue;
}
StreamViewController.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
if (indexPath) {
APStreamsData *item = [_data objectAtIndex:indexPath.row];
[segue.destinationViewController setDetail:item];
}
RadioViewController *music = [segue destinationViewController];
[music setMusic: musicSegue];
}
RadioViewController.h
#property (nonatomic, strong) AVPlayer *music;
And in RadioViewController change music to _music )))

Related

AVPlayer does not show video

I am trying to play a movie at the beginning of my game. I am using AVPlayer to do this. My problem is, when I register a KVO to check the status of my AVPlayer, my game proceeds as usual without waiting for the video to load and finish. As a result, I can only hear the audio from my .mov file and can't see any video (since my game has already started).
I would like the video to load and finish before proceeding with the game.
Here's the code:
#interface RMVideoView : NSView
{
NSURL* _videoURL;
AVPlayer* _player;
AVPlayerLayer* _playerLayer;
}
#property (nonatomic, readonly, strong) AVPlayer* player;
#property (nonatomic, readonly, strong) AVPlayerLayer* playerLayer;
#property (nonatomic, retain) NSURL* videoURL;
- (void) play;
#end
static void *RMVideoViewPlayerLayerReadyForDisplay = &RMVideoViewPlayerLayerReadyForDisplay;
static void *RMVideoViewPlayerItemStatusContext = &RMVideoViewPlayerItemStatusContext;
#interface RMVideoView()
- (void)onError:(NSError*)error;
- (void)onReadyToPlay;
- (void)setUpPlaybackOfAsset:(AVAsset *)asset withKeys:(NSArray *)keys;
#end
#implementation RMVideoView
#synthesize player = _player;
#synthesize playerLayer = _playerLayer;
#synthesize videoURL = _videoURL;
- (id)initWithFrame:(NSRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.wantsLayer = YES;
_player = [[AVPlayer alloc] init];
[self addObserver:self forKeyPath:#"player.currentItem.status" options:NSKeyValueObservingOptionNew context:RMVideoViewPlayerItemStatusContext];
}
return self;
}
- (void) setVideoURL:(NSURL *)videoURL {
_videoURL = videoURL;
[self.player pause];
[self.playerLayer removeFromSuperlayer];
AVURLAsset *asset = [AVAsset assetWithURL:self.videoURL];
[asset retain];
NSArray *assetKeysToLoadAndTest = [NSArray arrayWithObjects:#"playable", #"hasProtectedContent", #"tracks", #"duration", nil];
[asset loadValuesAsynchronouslyForKeys:assetKeysToLoadAndTest completionHandler:^{
dispatch_async(dispatch_get_main_queue(),^{
[self setUpPlaybackOfAsset:asset withKeys:assetKeysToLoadAndTest];
});
}];
}
#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == RMVideoViewPlayerItemStatusContext)
{
AVPlayerStatus status = [[change objectForKey:NSKeyValueChangeNewKey] integerValue];
switch (status)
{
case AVPlayerItemStatusUnknown:
break;
case AVPlayerItemStatusReadyToPlay:
[self onReadyToPlay];
break;
case AVPlayerItemStatusFailed:
[self onError:nil];
break;
}
}
else if (context == RMVideoViewPlayerLayerReadyForDisplay)
{
if ([[change objectForKey:NSKeyValueChangeNewKey] boolValue])
{
self.playerLayer.hidden = NO;
}
}
else
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
#pragma mark - Private
- (void)onError:(NSError*)error {
// Notify delegate
}
- (void)onReadyToPlay {
// Notify delegate
[self.player play];
}
- (void)setUpPlaybackOfAsset:(AVAsset *)asset withKeys:(NSArray *)keys {
for (NSString *key in keys) {
NSError *error = nil;
if ([asset statusOfValueForKey:key error:&error] == AVKeyValueStatusFailed) {
[self onError:error];
return;
}
}
if (!asset.isPlayable || asset.hasProtectedContent) {
[self onError:nil];
return;
}
if ([[asset tracksWithMediaType:AVMediaTypeVideo] count] != 0)
{ // Asset has video tracks
_playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
self.playerLayer.frame = self.layer.bounds;
self.playerLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
self.playerLayer.hidden = NO;
[self.layer addSublayer:self.playerLayer];
[self addObserver:self forKeyPath:#"playerLayer.readyForDisplay" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:RMVideoViewPlayerLayerReadyForDisplay];
}
// Create a new AVPlayerItem and make it our player's current item.
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];
[self.player replaceCurrentItemWithPlayerItem:playerItem];
}
#pragma mark - Public
- (void) play {
[self.player play];
}
#end
I am calling the above code from my entry function's -(void)drawView method this way:
-(void)drawView
{
if(playVideo)
{
RMVideoView *rmVid = [[RMVideoView alloc]init];
NSURL* MovieURL;
NSBundle *bundle = [NSBundle mainBundle];
if(bundle != nil)
{
NSString *moviePath = [bundle pathForResource:#"MyVideoResource" ofType:#"mov"];
if (moviePath)
{
MovieURL = [NSURL fileURLWithPath:moviePath];
[MovieURL retain];
[rmVid setVideoURL:MovieURL];
}
}
playVideo = kFalse;
}
}
The call made to [rmVid setVideoURL:MovieURL] returns when KVO is setup and the game runs forward.
Please help!
You can listen for a notification, when the video playback reaches the end like this:
AVPlayerItem *avPlayerItem =[[AVPlayerItem alloc]initWithAsset:avAsset];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachedEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:avPlayerItem];

AVAudioPlayer is always nill and its isPlaying property is always false. The files are mixed while playing

I've been pulling out my hair past three days to fix this problem. I've checked lots of sample codes, read lots of tutorials, and googled and checked lots and lots of questions and answers on stackoverflow, but I still cannot fix the problem. There are several similar questions like this or this but they don't have any solutions either.
So a little bit about my project:
I have a NIKMasterViewController and a NIKDetailViewController. In the first one I have a list of audio files in a table view; selecting a row, it navigates to the NIKDetailViewController where the user can see some info about the file and play the audio file.
I've defined an AVAudioPlayer property in the NIKMasterViewController and have set it like this:
NIKMasterViewController.h:
#property (nonatomic, strong) AVAudioPlayer *audioPlayer;
NIKMasterViewController.m:
#synthesize audioPlayer;
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showDetail"])
{
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
NIKDetailViewController *detailViewController = (NIKDetailViewController *) segue.destinationViewController;
[detailViewController setAudioPlayer:audioPlayer];
[detailViewController setFeedEntry:[[[self feedParser] feedItems] objectAtIndex:indexPath.row]];
} else {
NSLog(#"Segue Identifier: %#", segue.identifier);
}
}
And that's all about the AVAudioPlayer in NIKMasterViewController. Now in my NIKDetailViewController I have another property of AVAudioPlayer:
NIKDetailViewController.h:
#property (nonatomic, strong) AVAudioPlayer *audioPlayer;
Now in my .m file I have a method called streamAudio which is called in viewDidLoad to prepare the audio playback, and I have an if condition asking to check if the audioPlayer is nill and if not, if the audioPlayer.isPlaying is true so that it stops the player, but it's never called, and when i navigate back to the Master VC to tap on another row to play another file, the second file starts playing while the first file is being played and everything gets mixed up.
Any help will be truly appreciated, since I'm almost about to stop programming after being unable to fix this issue after hours and days!
NIKDetailViewController.m:
#synthesize audioPlayer;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
selectedItem = [[NSString alloc]init];
}
return self;
}
#pragma mark - Managing the Audio Playback
- (IBAction)togglePlayingState:(id)button
{
//Handle the button pressing
[self togglePlayPause];
}
- (void)playAudio
{
//Play the audio and set the button to represent the audio is playing
[audioPlayer play];
[playPauseButton setImage:[UIImage imageNamed:#"player_pause"] forState:UIControlStateNormal];
}
- (void)pauseAudio
{
//Pause the audio and set the button to represent the audio is paused
[audioPlayer pause];
[playPauseButton setImage:[UIImage imageNamed:#"player_play"] forState:UIControlStateNormal];
}
- (void)togglePlayPause
{
//Toggle if the music is playing or paused
if (!audioPlayer.playing)
{
[self playAudio];
}
else if (audioPlayer.playing)
{
[self pauseAudio];
}
}
- (void)streamAudio
{
currentFileName = [[feedEntry podcastDownloadURL] lastPathComponent];
NSString* documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* path = [documentPath stringByAppendingPathComponent:currentFileName];
NSURL* audioURL = [NSURL fileURLWithPath: path];
if (audioPlayer != nil)
{
if (audioPlayer.isPlaying)
{
[audioPlayer stop]; //THIS IS NEVER CALLED
}
audioPlayer = nil; //THIS IS NEVER CALLED
}
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:nil];
// Set a timer which keep getting the current music time and update the UISlider in 1 sec interval
playbackTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateSlider) userInfo:nil repeats:YES];
// Set the maximum value of the UISlider
seekSlider.maximumValue = audioPlayer.duration;
currentTime.text = [NSString stringWithFormat:#"%d:%02d", (int)audioPlayer.currentTime / 60, (int)audioPlayer.currentTime % 60, nil];
remainingTime.text = [NSString stringWithFormat:#"%d:%02d", (int)(audioPlayer.duration - audioPlayer.currentTime) / 60, (int)(audioPlayer.duration - audioPlayer.currentTime) % 60, nil];
// Set the valueChanged target
[seekSlider addTarget:self action:#selector(sliderChanged:) forControlEvents:UIControlEventValueChanged];
audioPlayer.delegate = self;
[audioPlayer prepareToPlay]; //Add the audio to the memory.
}
- (void)updateSlider
{
// Update the slider about the music time
seekSlider.value = audioPlayer.currentTime;
}
- (IBAction)sliderChanged:(UISlider *)sender {
// Fast skip the music when user scrolls the slider
[audioPlayer stop];
[audioPlayer setCurrentTime:seekSlider.value];
audioPlayer.delegate = self;
[audioPlayer prepareToPlay];
[audioPlayer play];
}
// Stop the timer when the music is finished (Need to implement the AVAudioPlayerDelegate in the Controller header)
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
// Music completed
if (flag) {
[playbackTimer invalidate];
}
}
- (IBAction)forwardAudio:(id)sender
{
int currentTime = [audioPlayer currentTime];
[audioPlayer setCurrentTime:currentTime+10];
}
- (IBAction)rewindAudio:(id)sender
{
int currentTime = [audioPlayer currentTime];
[audioPlayer setCurrentTime:currentTime-10];
}
//Make sure we can recieve remote control events
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
//if it is a remote control event handle it correctly
if (event.type == UIEventTypeRemoteControl) {
if (event.subtype == UIEventSubtypeRemoteControlPlay) {
[self playAudio];
} else if (event.subtype == UIEventSubtypeRemoteControlPause) {
[self pauseAudio];
} else if (event.subtype == UIEventSubtypeRemoteControlTogglePlayPause) {
[self togglePlayPause];
}
}
}
#pragma mark - view life cycle
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
//Once the view has loaded then we can register to begin recieving controls and we can become the first responder
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
//End recieving events
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self streamAudio];
//Make sure the system follows our playback status - to support the playback when the app enters the background mode.
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
NOTE: I have tried setting the property in the Detail VC as weak but then, I get a warning, and the property is release before I can play the file.
So... I could finally fix this problem by creating a singleton of the audioplayer. This is how:
First of all, I removed all the code related to the audioPlayer from my NIKMasterViewController class, that includes the audioPlayer declaration and setting it in prepareForSegue.
I created a new class called NIKAudioPlayer.
In NIKAudioPlayer.h:
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#interface NIKAudioPlayer : NSObject <AVAudioPlayerDelegate>
{
AVAudioPlayer *currentPlayer;
}
#property (nonatomic, strong) AVAudioPlayer *currentPlayer;
+(NIKAudioPlayer *) sharedPlayer;
-(void)playURL:(NSURL*)url;
#end
In NIKAudioPlayer.m:
#import "NIKAudioPlayer.h"
#implementation NIKAudioPlayer
#synthesize currentPlayer;
+(NIKAudioPlayer *) sharedPlayer
{
static NIKAudioPlayer* sharedPlayer;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedPlayer = [[NIKAudioPlayer alloc] init];
});
return sharedPlayer;
}
-(void)playURL:(NSURL*)url
{
[currentPlayer stop];
currentPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
[currentPlayer prepareToPlay];
}
#end
Now in everywhere else in the code (in my case in NIKDetailViewController) whenever I need to play an audio file, I call the sharedPlayer from NIKAudioPlayer:
[[NIKPlayer sharedPlayer] playURL:audioURL];
[[NIKPlayer sharedPlayer].currentPlayer prepareToPlay];
To put in a nutshell, replace all audioPlayers in NIKDetailViewController with [NIKPlayer sharedPlayer].currentPlayer, or even cast it and use it everywhere:
audioPlayer = [NIKPlayer sharedPlayer].currentPlayer

Clean array by using delegate

I made an AR app that recognize image and show the object recognized in an AlertView. In the AlertView I have 2 buttons: Add and Cancel, I'm using the UIAlertViewDelegate to understand which button the user pressed. If the user press the Add button, the object recognized will be stored in an array. I pass this array to another ViewController, in which I set up a TableView. On the bottom of this TableView there's a button "Pay" to go to another ViewController in which I display the total price of the object recognized. From the last ViewController I can press a button to pay the objects I selected by using the AR. Now when I press this button the app close this ViewController and go back to the first ViewController, but the array in which I stored the object that the AR recognized it's full. To delete the content of this array I thought that the best way is to use the delegation methods, so I made this:
PaymentViewController.h
#import <UIKit/UIKit.h>
#protocol PaymentViewControllerDelegate;
#interface PaymentViewController : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *labelTotal;
- (IBAction)buttonClosePaymentVC:(id)sender;
- (IBAction)buttonPay:(id)sender;
#property(nonatomic,strong)NSString *total;
#property(assign) id<PaymentViewControllerDelegate> delegate;
#end
#protocol PaymentViewControllerDelegate <NSObject>
- (void)cleanReportArray;
#end
PaymentViewController.m
#import "PaymentViewController.h"
#interface PaymentViewController () <UIAlertViewDelegate>
#end
#implementation PaymentViewController
#synthesize delegate = _delegate;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.labelTotal.text = self.total;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)buttonClosePaymentVC:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)buttonPay:(id)sender {
NSString *pay = [NSString stringWithFormat:#"Stai per pagare %#, procedi?", self.total];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"HelloMS" message:pay delegate:self cancelButtonTitle:#"Si" otherButtonTitles:#"No", nil];
[alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
// Procedura per il pagamento e cancellazione del file plist
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"objects.plist"];
NSError *error;
if (![[NSFileManager defaultManager]removeItemAtPath:path error:&error]) {
NSLog(#"Errore: %#", error);
}
__weak UIViewController *vcThatPresentedCurrent = self.presentingViewController;
[self dismissViewControllerAnimated:YES completion:^{
[vcThatPresentedCurrent dismissViewControllerAnimated:YES completion:nil];
}];
[self.delegate cleanReportArray];
}
if (buttonIndex == 1) {
// Non deve far nulla: fa scomparire l'UIAlertView
}
}
Here I post to you the method of the class that will use the delegate:
Interface of the ScannerViewController.m
#interface ScannerViewController () <MSScannerSessionDelegate, PaymentViewControllerDelegate, UIActionSheetDelegate, UIAlertViewDelegate>
#property (weak) IBOutlet UIView *videoPreview;
- (IBAction)stopScanner:(id)sender;
#end
In ViewDidLoad I inserted this rows:
PaymentViewController *pay = [[PaymentViewController alloc]init];
[pay setDelegate:self];
And in the ScannerViewController.m I implemented the method I declared in PaymentViewController.h:
- (void)cleanReportArray {
[arrayObjectAdded removeAllObjects];
}
I tested my app on my iPhone, the app works fine until I try to pay the objects I scanned by camera, indeed, I tried to pay the object, but it doesn't clean the array in which I stored the objects scanned.
What's wrong in my code? I used an tutorial on the web to understand better how the delegation method works. I hope you can help me to fix this issue, thank you
UPDATE:
here i will post my ScannerViewController code:
ScannerViewController.h
#import <UIKit/UIKit.h>
#interface ScannerViewController : UIViewController
#end
ScannerViewController.m
#import "ScannerViewController.h"
#import "PaymentViewController.h"
#import "ReportViewController.h"
#import "MSScannerSession.h"
#import "MSResult.h"
#import "XmlReader.h"
static int kMSScanOptions = MS_RESULT_TYPE_IMAGE |
MS_RESULT_TYPE_EAN8 |
MS_RESULT_TYPE_EAN13;
#interface ScannerViewController () <MSScannerSessionDelegate, PaymentViewControllerDelegate, UIActionSheetDelegate, UIAlertViewDelegate>
#property (weak) IBOutlet UIView *videoPreview;
- (IBAction)stopScanner:(id)sender;
#end
#implementation ScannerViewController {
MSScannerSession *_scannerSession;
NSString *nameOfObjectScanned;
XmlReader *reader;
NSMutableArray *arrayObjectAdded;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
_scannerSession = [[MSScannerSession alloc] initWithScanner:[MSScanner sharedInstance]];
[_scannerSession setScanOptions:kMSScanOptions];
[_scannerSession setDelegate:self];
}
return self;
}
- (void)session:(MSScannerSession *)scanner didScan:(MSResult *)result {
if (!result) {
return;
}
[_scannerSession pause];
NSString *resultStr = nil;
if (result) {
switch ([result getType]) {
case MS_RESULT_TYPE_IMAGE:
resultStr = [NSString stringWithFormat:#"Immagine trovata: %#", [result getValue]];
break;
case MS_RESULT_TYPE_EAN8:
case MS_RESULT_TYPE_EAN13:
resultStr = [NSString stringWithFormat:#"EAN trovato: %#", [result getValue]];
break;
default:
break;
}
}
dispatch_async(dispatch_get_main_queue(), ^{
UIActionSheet *asView = [[UIActionSheet alloc]initWithTitle:resultStr delegate:self cancelButtonTitle:#"OK" destructiveButtonTitle:nil otherButtonTitles:nil, nil];
asView.actionSheetStyle = UIActionSheetStyleBlackTranslucent;
[asView showInView:self.view];
[self addObjectToList:resultStr];
});
}
- (void)addObjectToList:(NSString *)objectName {
// Ricerca dell'oggetto
NSString *object = [objectName substringFromIndex:18];
if ([object isEqualToString:#"Binario_con_coppia"]) {
[self showAlert:object];
}
if ([object isEqualToString:#"Dadi_colorati"]) {
[self showAlert:object];
}
if ([object isEqualToString:#"Dadi_rossi"]) {
[self showAlert:object];
}
if ([object isEqualToString:#"Bici_da_corsa"]) {
[self showAlert:object];
}
}
- (void)showAlert:(NSString*)name {
name = [name stringByReplacingOccurrencesOfString:#"_" withString:#" "];
nameOfObjectScanned = name;
NSString *message = [NSString stringWithFormat:#"Ho riconosciuto questo oggetto: %#, vuoi aggiungerlo al carrello?", name];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"HelloMS" message:message delegate:self cancelButtonTitle:#"Aggiungi" otherButtonTitles:#"Annulla", nil];
[alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
NSLog(#"Aggiungi");
for (int i = 0; i < [reader.objArray count]; i++) {
if ([[reader.objArray[i]objectForKey:#"name"] isEqualToString:nameOfObjectScanned]) {
// Salvo il nome dell'oggetto trovato, il prezzo e la descrizione
NSString *name = [reader.objArray[i]objectForKey:#"name"];
NSString *desc = [reader.objArray[i]objectForKey:#"desc"];
NSString *price = [reader.objArray[i]objectForKey:#"price"];
NSDictionary *newObjectAdded = [[NSDictionary alloc]init];
newObjectAdded = #{#"name": name,
#"desc": desc,
#"price": price};
[arrayObjectAdded addObject:newObjectAdded];
}
}
} else {
NSLog(#"Annulla");
}
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
[_scannerSession resume];
}
- (void)viewDidLoad
{
[super viewDidLoad];
arrayObjectAdded = [[NSMutableArray alloc]init];
CALayer *videoPreviewLayer = [self.videoPreview layer];
[videoPreviewLayer setMasksToBounds:YES];
CALayer *captureLayer = [_scannerSession previewLayer];
[captureLayer setFrame:[self.videoPreview bounds]];
[videoPreviewLayer insertSublayer:captureLayer below:[[videoPreviewLayer sublayers] objectAtIndex:0]];
reader = [[XmlReader alloc]init];
[reader parseXml];
[_scannerSession startCapture];
PaymentViewController *pay = [[PaymentViewController alloc]init];
[pay setDelegate:self];
}
- (void)cleanReportArray {
[arrayObjectAdded removeAllObjects];
}
- (void)dealloc {
[_scannerSession stopCapture];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)stopScanner:(id)sender {
ReportViewController *reportVC = [[ReportViewController alloc]initWithNibName:#"ReportViewController" bundle:nil];
reportVC.reportArray = arrayObjectAdded;
[reportVC setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[self presentViewController:reportVC animated:YES completion:nil];
}
#end
To recognize picture I'm using this AR SDK. I hope you can help me to understand where's my issue
Your problem is that in viewDidLoad you have the code:
PaymentViewController *pay = [[PaymentViewController alloc]init];
[pay setDelegate:self];
this is the last thing you do in that method. So the instance of PaymentViewController that you create and set the delegate on is immediately destroyed (by ARC).
You need to modify your code so that you call setDelegate: on the actual instance of PaymentViewController that is presented on screen as this is the instance that needs to use the delegate (it receives the callback from the alert view).

App Crashing from multiple videos

I have four videos in four different view controllers and they randomly crash the app. Generally the first one I click (regardless of which it is) will work and then if I click the button to play any other video the app crashes. It does not matter which one I click first, generally. The app behaves strangely. Here is the error code I get:
2013-07-26 10:56:40.590 Capture Controller[6558:907]
-[ShoreViewController moviePlayBackDidFinish:]: unrecognized selector sent to instance 0x2088bb20 2013-07-26 10:56:40.592 Capture
Controller[6558:907] * Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[ShoreViewController
moviePlayBackDidFinish:]: unrecognized selector sent to instance
0x2088bb20'
* First throw call stack: (0x339c43e7 0x3b84e963 0x339c7f31 0x339c664d 0x3391e208 0x33915349 0x3422cb7f 0x3484fec7 0x3484d251
0x33915349 0x3422cb7f 0x34866557 0x3486916f 0x34253b85 0x342537dd
0x3422dcbb 0x348ef73f 0x34253b85 0x342537dd 0x3422dcbb 0x348f208d
0x348f4149 0x348f1f2d 0x348f3d59 0x348f05d9 0x34862bcb 0x3484ddc7
0x33915349 0x3422cb7f 0x3484fc5b 0x3484f6a7 0x3484c055 0x49e61
0x358be087 0x358be03b 0x358be015 0x358bd8cb 0x358bddb9 0x357e65f9
0x357d38e1 0x357d31ef 0x374c75f7 0x374c7227 0x339993e7 0x3399938b
0x3399820f 0x3390b23d 0x3390b0c9 0x374c633b 0x358272b9 0x26a2d
0x3bc7bb20) libc++abi.dylib: terminate called throwing an exception
Here is some code:
EBViewController.h:
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
#import "ReaderViewController.h"
#interface EBViewController : UIViewController <ReaderViewControllerDelegate>
#property (strong, nonatomic) MPMoviePlayerController *movieEBPlayer;
- (IBAction)playEBFilm:(id)sender;
- (IBAction)readEBDocument:(id)sender;
#end
EBViewController.m
#import "EBViewController.h"
#interface EBViewController ()
#end
#implementation EBViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
UIButton *EBFilmButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[EBFilmButton addTarget:self action:#selector(playEBFilm) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:EBFilmButton];
UIButton *readEBButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[readEBButton addTarget:self action:#selector(readEBDocument) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:readEBButton];
}
-(void)readEBDocument:(id)sender {
NSString *file = [[NSBundle mainBundle] pathForResource:#"Rig" ofType:#"pdf"];
ReaderDocument *document = [ReaderDocument withDocumentFilePath:file password:nil];
if (document != nil)
{
ReaderViewController *readerViewController = [[ReaderViewController alloc] initWithReaderDocument:document];
readerViewController.delegate = self;
readerViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
readerViewController.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentModalViewController:readerViewController animated:YES];
}
}
-(void)playEBFilm:(id)sender
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"118409050" ofType:#"mp4"]; NSURL *url = [NSURL fileURLWithPath:path]; MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentURL:url]; [player play]; //- See more at: http://getsetgames.com/2009/12/20/iphonedev-advent-tip-20-how-to-play-a-video-with-mpmovieplayercontroller/#sthash.dznrF0UO.J8xsiXHT.dpuf
_movieEBPlayer = [[MPMoviePlayerController alloc]
initWithContentURL:url];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:_movieEBPlayer];
_movieEBPlayer.controlStyle = MPMovieControlStyleDefault;
_movieEBPlayer.shouldAutoplay = YES;
[self.view addSubview:_movieEBPlayer.view];
[_movieEBPlayer setFullscreen:YES animated:YES];
}
- (void)dismissReaderViewController:(ReaderViewController *)viewController {
[self dismissModalViewControllerAnimated:YES];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
PebbleViewController.h:
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
#import "ReaderViewController.h"
#interface PebbleViewController : UIViewController <ReaderViewControllerDelegate>
#property (strong, nonatomic) MPMoviePlayerController *moviePebblePlayer;
- (IBAction)playPebbleFilm:(id)sender;
- (IBAction)readPebbleDocument:(id)sender;
#end
PebbleViewController.m:
#import "PebbleViewController.h"
#interface PebbleViewController ()
#end
#implementation PebbleViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
UIButton *pebbleFilmButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[pebbleFilmButton addTarget:self action:#selector(playPebbleFilm) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:pebbleFilmButton];
UIButton *readPebbleButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[readPebbleButton addTarget:self action:#selector(readPebbleDocument) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:readPebbleButton];
}
-(void)readPebbleDocument:(id)sender {
NSString *file = [[NSBundle mainBundle] pathForResource:#"Rig" ofType:#"pdf"];
ReaderDocument *document = [ReaderDocument withDocumentFilePath:file password:nil];
if (document != nil)
{
ReaderViewController *readerViewController = [[ReaderViewController alloc] initWithReaderDocument:document];
readerViewController.delegate = self;
readerViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
readerViewController.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentModalViewController:readerViewController animated:YES];
}
}
-(void)playPebbleFilm:(id)sender
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"Pebble2" ofType:#"mov"]; NSURL *url = [NSURL fileURLWithPath:path]; MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentURL:url]; [player play]; //- See more at: http://getsetgames.com/2009/12/20/iphonedev-advent-tip-20-how-to-play-a-video-with-mpmovieplayercontroller/#sthash.dznrF0UO.J8xsiXHT.dpuf
_moviePebblePlayer = [[MPMoviePlayerController alloc]
initWithContentURL:url];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:_moviePebblePlayer];
_moviePebblePlayer.controlStyle = MPMovieControlStyleDefault;
_moviePebblePlayer.shouldAutoplay = YES;
[self.view addSubview:_moviePebblePlayer.view];
[_moviePebblePlayer setFullscreen:YES animated:YES];
}
- (void)dismissReaderViewController:(ReaderViewController *)viewController {
[self dismissModalViewControllerAnimated:YES];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
The rest of the view controllers are basically the same, just with of course different names for the IBActions and moviePlayers.
Any advice would be much appreciated! Thanks!
I don't see a method named:
- (void) moviePlayBackDidFinish:(NSNotification*)notification
in any of the code snippets you've cut & pasted (although it's not obvious if either view controller is actually your "ShoreViewController" object, either)
If it doesn't exist in your code, that would explain the "unrecognized selector sent to instance" crash.

Background audio wont play

I'm struggling for couple of days now to sort this thing out and simply just can't find the way. I want to play audio in background when app exits or when i click on link to go to Safari, but i just wont go to background mode. Please help.
FirstViewController.h file :
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVAudioPlayer.h>
#import <AVFoundation/AVFoundation.h>
#interface RygestopFirstViewController : UIViewController <AVAudioPlayerDelegate> {
IBOutlet UIButton *playButton;
IBOutlet UISlider *volumeSlider;
IBOutlet UISlider *progressBar;
IBOutlet UILabel *currentTime;
IBOutlet UILabel *duration;
AVAudioPlayer *player;
UIImage *playBtnBG;
UIImage *pauseBtnBG;
NSTimer *updateTimer;
BOOL inBackground;
}
- (IBAction)playButtonPressed:(UIButton*)sender;
- (IBAction)volumeSliderMoved:(UISlider*)sender;
- (IBAction)progressSliderMoved:(UISlider*)sender;
#property (nonatomic, retain) UIButton *playButton;
#property (nonatomic, retain) UISlider *volumeSlider;
#property (nonatomic, retain) UISlider *progressBar;
#property (nonatomic, retain) UILabel *currentTime;
#property (nonatomic, retain) UILabel *duration;
#property (nonatomic, retain) NSTimer *updateTimer;
#property (nonatomic, assign) AVAudioPlayer *player;
#property (nonatomic, assign) BOOL inBackground;
#end
FirstViewController.m code:
// amount to skip on rewind or fast forward
#define SKIP_TIME 1.0
// amount to play between skips
#define SKIP_INTERVAL .2
#implementation RygestopFirstViewController
#synthesize playButton;
#synthesize volumeSlider;
#synthesize progressBar;
#synthesize currentTime;
#synthesize duration;
#synthesize updateTimer;
#synthesize player;
#synthesize inBackground;
-(void)updateCurrentTimeForPlayer:(AVAudioPlayer *)p
{
currentTime.text = [NSString stringWithFormat:#"%d:%02d", (int)p.currentTime / 60, (int)p.currentTime % 60, nil];
progressBar.value = p.currentTime;
}
- (void)updateCurrentTime
{
[self updateCurrentTimeForPlayer:self.player];
}
- (void)updateViewForPlayerState:(AVAudioPlayer *)p
{
[self updateCurrentTimeForPlayer:p];
if (updateTimer)
[updateTimer invalidate];
if (p.playing)
{
[playButton setImage:((p.playing == YES) ? pauseBtnBG : playBtnBG) forState:UIControlStateNormal];
updateTimer = [NSTimer scheduledTimerWithTimeInterval:.01 target:self selector:#selector(updateCurrentTime) userInfo:p repeats:YES];
}
else
{
[playButton setImage:((p.playing == YES) ? pauseBtnBG : playBtnBG) forState:UIControlStateNormal];
updateTimer = nil;
}
}
- (void)updateViewForPlayerStateInBackground:(AVAudioPlayer *)p
{
[self updateCurrentTimeForPlayer:p];
if (p.playing)
{
[playButton setImage:((p.playing == YES) ? pauseBtnBG : playBtnBG) forState:UIControlStateNormal];
}
else
{
[playButton setImage:((p.playing == YES) ? pauseBtnBG : playBtnBG) forState:UIControlStateNormal];
}
}
-(void)updateViewForPlayerInfo:(AVAudioPlayer*)p
{
duration.text = [NSString stringWithFormat:#"%d:%02d", (int)p.duration / 60, (int)p.duration % 60, nil];
progressBar.maximumValue = p.duration;
volumeSlider.value = p.volume;
}
-(void)pausePlaybackForPlayer:(AVAudioPlayer*)p
{
[p pause];
[self updateViewForPlayerState:p];
}
-(void)startPlaybackForPlayer:(AVAudioPlayer*)p
{
if ([p play])
{
[self updateViewForPlayerState:p];
}
else
NSLog(#"Could not play %#\n", p.url);
}
- (IBAction)playButtonPressed:(UIButton *)sender
{
if (player.playing == YES)
[self pausePlaybackForPlayer: player];
else
[self startPlaybackForPlayer: player];
}
- (IBAction)volumeSliderMoved:(UISlider *)sender
{
player.volume = [sender value];
}
- (IBAction)progressSliderMoved:(UISlider *)sender
{
player.currentTime = sender.value;
[self updateCurrentTimeForPlayer:player];
}
- (void)dealloc
{
[super dealloc];
[playButton release];
[volumeSlider release];
[progressBar release];
[currentTime release];
[duration release];
[updateTimer release];
[player release];
[playBtnBG release];
[pauseBtnBG release];
}
#pragma mark AVAudioPlayer delegate methods
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)p successfully:(BOOL)flag
{
if (flag == NO)
NSLog(#"Playback finished unsuccessfully");
[p setCurrentTime:0.];
if (inBackground)
{
[self updateViewForPlayerStateInBackground:p];
}
else
{
[self updateViewForPlayerState:p];
}
}
- (void)playerDecodeErrorDidOccur:(AVAudioPlayer *)p error:(NSError *)error
{
NSLog(#"ERROR IN DECODE: %#\n", error);
}
// we will only get these notifications if playback was interrupted
- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)p
{
NSLog(#"Interruption begin. Updating UI for new state");
// the object has already been paused, we just need to update UI
if (inBackground)
{
[self updateViewForPlayerStateInBackground:p];
}
else
{
[self updateViewForPlayerState:p];
}
}
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)p
{
NSLog(#"Interruption ended. Resuming playback");
[self startPlaybackForPlayer:p];
}
#pragma mark background notifications
- (void)registerForBackgroundNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(setInBackgroundFlag)
name:UIApplicationWillResignActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(clearInBackgroundFlag)
name:UIApplicationWillEnterForegroundNotification
object:nil];
}
- (void)setInBackgroundFlag
{
inBackground = true;
}
- (void)clearInBackgroundFlag
{
inBackground = false;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = NSLocalizedString(#"Play", #"First");
self.tabBarItem.image = [UIImage imageNamed:#"Home"];
}
return self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
//Make sure we can recieve remote control events
- (BOOL)canBecomeFirstResponder {
return YES;
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
playBtnBG = [[UIImage imageNamed:#"Player.png"] retain];
pauseBtnBG = [[UIImage imageNamed:#"Pause.png"] retain];
[playButton setImage:playBtnBG forState:UIControlStateNormal];
[self registerForBackgroundNotifications];
updateTimer = nil;
duration.adjustsFontSizeToFitWidth = YES;
currentTime.adjustsFontSizeToFitWidth = YES;
progressBar.minimumValue = 0.0;
// Load the the sample file, use mono or stero sample
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: [[NSBundle mainBundle] pathForResource:#"Sound1" ofType:#"m4a"]];
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
if (self.player)
{
[self updateViewForPlayerInfo:player];
[self updateViewForPlayerState:player];
player.numberOfLoops = 0;
player.delegate = self;
}
[fileURL release];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#end
And, by the way, i want to run thin in tab bar application, so the background mode must be present always.
Here's what you're looking for: https://devforums.apple.com/message/264397 and set your background mode to 'App plays audio' in your app's .plist file.

Resources