AVQueuePlayer with SWRevealViewController in iOS - objective-c

I am using SWRevealViewController for left side menu in my application.I am using objcetive c. 5 menu option in SWRevealViewController. I am using AVQueuePlayer in home menu(first view).
My problem is when I am clicking another option in menu bar and navigating on another view at that time AVQueuePlayer stop playing it self. How can I fix this?
Note: AVQueuePlayer is Properly working while application is in background with home menu.
NSError *setCategoryErr = nil;
NSError *activationErr = nil;
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error:&setCategoryErr];
[[AVAudioSession sharedInstance] setActive:YES error:&activationErr];
NSError *sessionError = nil;
[[AVAudioSession sharedInstance] setDelegate:self];
[[AVAudioSession sharedInstance]setCategory:AVAudioSessionCategoryPlayback error:NULL];
// Change the default output audio route
UInt32 doChangeDefaultRoute = 1;
AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryDefaultToSpeaker, sizeof(doChangeDefaultRoute), &doChangeDefaultRoute);
NSArray *queue = #[
[AVPlayerItem playerItemWithURL:[NSURL URLWithString:chanel_url_str]],
];
self.player1 = [[AVQueuePlayer alloc] initWithItems:queue];
self.player1.actionAtItemEnd = AVPlayerActionAtItemEndAdvance;
[self.player1 addObserver:self
forKeyPath:#"currentItem"
options:NSKeyValueObservingOptionNew
context:nil];
void (^observerBlock)(CMTime time) = ^(CMTime time) {
NSString *timeString = [NSString stringWithFormat:#"%02.2f", (float)time.value / (float)time.timescale];
if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive) {
} else {
NSLog(#"App is backgrounded. Time is: %#", timeString);
}
};
self.timeObserver = [self.player1 addPeriodicTimeObserverForInterval:CMTimeMake(10, 1000)
queue:dispatch_get_main_queue()
usingBlock:observerBlock];
[self.player1 play];
Here chanel_url_str is NSString with URL format.

Related

AVQueuePlayer (or AVPlayer) with a Soundcloud stream item block the UI (Main Thread)

Thank to those two posts, I resolve this problem during the creation of the AVPLayerItem
AVQueuePlayer playback without gap and freeze
AVPlayer "freezes" the app at the start of buffering an audio stream
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:[NSURL URLWithString:urlString] options:#{AVURLAssetPreferPreciseDurationAndTimingKey : #(YES)}];
NSArray *keys = #[#"playable", #"tracks",#"duration" ];
[asset loadValuesAsynchronouslyForKeys:keys completionHandler:^()
{
for (NSString *thisKey in keys) {
NSError *error = nil;
AVKeyValueStatus keyStatus = [asset statusOfValueForKey:thisKey error:&error];
if (keyStatus == AVKeyValueStatusFailed) {
return ;
}
}
AVPlayerItem *item = [[AVPlayerItem alloc] initWithAsset:asset];
dispatch_async(dispatch_get_main_queue(), ^ {
[item addObserver:self forKeyPath:#"status" options:NSKeyValueObservingOptionNew context:nil];
[player insertItem:item afterItem:nil];
});
}];
});
But, with a stream from Soundcloud (https://api.soundcloud.com/tracks/146924238/stream?client_id=76395c48f97de903ff44861e230116bd), after the item's status is ready to play (AVPlayerStatusReadyToPlay), the AVQueueplayer keep doing something in the main thread "freezing" the UI (Track keep playing in background thread).
I noticed this problem is more important when the network is low, Then I made the conclusion that this freeze exist when the item is buffering the stream.
Someone have the solution or a trick?

NSString set from a url doesn't read?

I am having trouble getting my NSString to read my string that I have set. The play action is hooked to a UIButton OnTouchDown if it matters.
- (IBAction)play {
if (audioPlayer.playing == NO) {
urlSong = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/k.mp3", [[NSBundle mainBundle] resourcePath]]];
[audioPlayer release];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:urlSong error:&error];
audioPlayer.numberOfLoops = 0;
//if i set this line to stringSong = #"k"; then comment out the next line everything works fine
stringSong = [[urlSong lastPathComponent] stringByDeletingPathExtension];
label.text = stringSong;
AVAudioSession *audiosession = [AVAudioSession sharedInstance];
[audiosession setCategory:AVAudioSessionCategoryAmbient error:nil];
[audioPlayer play];
[start setTitle:#"Stop" forState:UIControlStateNormal];
}
else
if ([stringSong isEqualToString:#"k"]){
label.text = #"audio stopped";
[audioPlayer stop];
}
}
When I run the code on my iPhone Xcode returns
EXC_BAD_ACCESS
on this line
if ([stringSong isEqualToString:#"k"]){
I know this is due to me trying to set the string from the url because when I plainly set my string to 'k' the code executes just fine.
If anybody is wondering the overall point of this, I am trying to have my audio buttons set to stop all other audio when this button is pressed and start the audio assigned to this button which in this case is 'k.mp3'. But if this audio is already playing just to stop playing all audio. Thank you.
You aren't retaining stringSong.
This line:
stringSong = [[urlSong lastPathComponent] stringByDeletingPathExtension];
Should be:
stringSong = [[[urlSong lastPathComponent] stringByDeletingPathExtension] retain];
At some point this needs to be released.

IOS can I use AVAudioPlayer on the appDelegate?

I have a TabBarController with two tabs and I want to play music on both tabs. Right now I have my code on the main appDelegate
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:#"My Song"
ofType:#"m4a"]]; // My Song.m4a
NSError *error;
self.audioPlayer = [[AVAudioPlayer alloc]
initWithContentsOfURL:url
error:&error];
if (error)
{
NSLog(#"Error in audioPlayer: %#",
[error localizedDescription]);
} else {
//audioPlayer.delegate = self;
[audioPlayer prepareToPlay];
}
but I'm getting the error Program received signal: "SIGABRT" on UIApplicationMain
Is there a better way to accomplish what I'm trying to do? If this is how I should do it, where do I start checking for problems?
yes you can use AVAudioPlayer in App Delegate.
What you need to do is:-
In appDelegate.h file do:-
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
AVAudioPlayer *_backgroundMusicPlayer;
BOOL _backgroundMusicPlaying;
BOOL _backgroundMusicInterrupted;
UInt32 _otherMusicIsPlaying;
Make backgroundMusicPlayer property and sythesize it.
In appDelegate.m file do:-
Add these lines in did FinishLaunching method
NSError *setCategoryError = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:&setCategoryError];
// Create audio player with background music
NSString *backgroundMusicPath = [[NSBundle mainBundle] pathForResource:#"SplashScreen" ofType:#"wav"];
NSURL *backgroundMusicURL = [NSURL fileURLWithPath:backgroundMusicPath];
NSError *error;
_backgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:backgroundMusicURL error:&error];
[_backgroundMusicPlayer setDelegate:self]; // We need this so we can restart after interruptions
[_backgroundMusicPlayer setNumberOfLoops:-1]; // Negative number means loop forever
Now implement delegate methods
#pragma mark -
#pragma mark AVAudioPlayer delegate methods
- (void) audioPlayerBeginInterruption: (AVAudioPlayer *) player {
_backgroundMusicInterrupted = YES;
_backgroundMusicPlaying = NO;
}
- (void) audioPlayerEndInterruption: (AVAudioPlayer *) player {
if (_backgroundMusicInterrupted) {
[self tryPlayMusic];
_backgroundMusicInterrupted = NO;
}
}
- (void)tryPlayMusic {
// Check to see if iPod music is already playing
UInt32 propertySize = sizeof(_otherMusicIsPlaying);
AudioSessionGetProperty(kAudioSessionProperty_OtherAudioIsPlaying, &propertySize, &_otherMusicIsPlaying);
// Play the music if no other music is playing and we aren't playing already
if (_otherMusicIsPlaying != 1 && !_backgroundMusicPlaying) {
[_backgroundMusicPlayer prepareToPlay];
if (soundsEnabled==YES) {
[_backgroundMusicPlayer play];
_backgroundMusicPlaying = YES;
}
}
}

Updating a managedObject in Core Data

WHAT I HAVE SO FAR:
In one splitview, I have a a tableview as its master, and a UIView as the detail. The tableview has 2 columns: "Days" and then "Sessions". I get the data from the Core Data, the entities called "Sessions". When I click on a "Session" tableviewcell, the detailview gets updated.
In the detailview, I added an "Add" button in the navigation bar. When you click on this, I add a new entity called "NewSession" to the core data.
if ([_sessionData.added isEqualToNumber:[NSNumber numberWithBool:NO]]) {
[_sessionData setValue:[NSNumber numberWithBool:YES] forKey:#"added"];
SessionData *session = (SessionData*) [NSEntityDescription insertNewObjectForEntityForName:#"NewSessions" inManagedObjectContext:[DataSingleton sharedMySingleton].managedObjectContext];
session.startDate = _sessionData.startDate;
session.endDate = _sessionData.endDate;
session.sessionLocation = nil;
session.sessionTitle = _sessionData.sessionTitle;
session.sessionDescription = _sessionData.sessionDescription;
[session setValue: [NSNumber numberWithBool:YES] forKey:#"added"];
_addButton = [[[UIBarButtonItem alloc] initWithTitle:#"Remove" style:UIBarButtonSystemItemAdd target:self action:nil] autorelease];
NSError *error = nil;
if (![[DataSingleton sharedMySingleton].managedObjectContext save:&error]) {
DebugLog(#"Whoops, couldn't save:%#", [error localizedDescription]);
}
}
else {
NSLog(#"SESSION ALREADY ADDED");
}
ANOTHER splitview's tableview fetches the "NewSession" entity, and gets all the data and displays it.
THE PROBLEM:
Whenever I exit the application and relaunch it, the sessions in the other splitview are still there, BUT I can add the SAME session again.
In the "add" code, I have the following:
[_sessionData setValue:[NSNumber numberWithBool:YES] forKey:#"added"];
Now, my sessionData is an NSManagedObject; and I thought that just setting the values will update them in the core data.
Can anyone help?
I had similar problem, but similar doesn't mean the same. I don't know if it works for you but you can try it. This method was described to me by #macbirdie and it works for me.
First of all, import your AppDelegate header file:
#import "YourAppDelegate.h"
Then, update your code:
if ([_sessionData.added isEqualToNumber:[NSNumber numberWithBool:NO]]) {
[_sessionData setValue:[NSNumber numberWithBool:YES] forKey:#"added"];
NSManagedObjectContext *moc = [[DataSingleton sharedMySingleton] managedObjectContext];
SessionData *session = (SessionData*) [NSEntityDescription insertNewObjectForEntityForName:#"NewSessions" inManagedObjectContext:moc];
session.startDate = _sessionData.startDate;
session.endDate = _sessionData.endDate;
session.sessionLocation = nil;
session.sessionTitle = _sessionData.sessionTitle;
session.sessionDescription = _sessionData.sessionDescription;
session.added = [NSNumber numberWithBool:YES];
_addButton = [[[UIBarButtonItem alloc] initWithTitle:#"Remove" style:UIBarButtonSystemItemAdd target:self action:nil] autorelease];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(saveMoc:) name:NSManagedObjectContextDidSaveNotification object:moc];
NSError *error = nil;
if (![moc save:&error]) {
DebugLog(#"Whoops, couldn't save:%#", [error localizedDescription]);
}
} else {
NSLog(#"SESSION ALREADY ADDED");
}
And add this methode somewhere in your file:
- (void)saveMoc:(NSNotification *)notification {
YourAppDelegate *appDel = (YourAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDel.managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
}

QTMovie not playing in new window

I have a MAC OSX application in which I would like to press a button in the main window and open a new window in which a movie is played. This is my IBAction code;
- (IBAction) playButtonClicked: (id) sender
{
MoviePlayerController *moviePlayerWindow = [[MoviePlayerController alloc] initWithWindowNibName:#"MoviePlayer"];
[moviePlayerWindow showWindow:self];
NSError *error;
NSString *moviePath = [[NSBundle mainBundle] pathForResource:#"sample_iTunes" ofType:#"mov"];
QTMovie *movie = [QTMovie movieWithFile:moviePath error:&error];
if (error) {
NSLog(#"%#", [error localizedDescription]);
} else {
[movie gotoBeginning];
[moviePlayerWindow.movieViewer setMovie:movie];
[moviePlayerWindow.movieViewer play:nil];
}
}
movieViewer is a QTMovieViewer outlet inside the new window.
The window opens but no movie is played; can someone understand what I am doing wrong ? I can send the complete project (it is a test one, very small) if needed.
Try changing NSError *error; to NSError *error = nil;