Displaying AVAudio player duration and elapsed time on iPad lock screen (background) - ios

So far this is my attempt to have the lock screen display how much time has passed (elapsed) in the audio mp3 file and how much time in total the audio mp3 file is...
Here is my array of objects:
NSArray *madMoneyArray = [NSArray arrayWithObjects:[NSString stringWithFormat:#"Episode %d", a],
#"Jim Cramer",
#"Mad Money Podcast",
madMoneyArtwork,
[NSNumber numberWithFloat:(float)_audioPlayer.currentPlaybackTime],
[NSNumber numberWithDouble:(double)_audioPlayer.duration],
[NSNumber numberWithDouble:(double)1.0],
#"MadMoneyPodcast.png",
madMoneyURL, nil];
Here is my array of keys:
NSArray *array = [NSArray arrayWithObjects:MPMediaItemPropertyTitle,
MPMediaItemPropertyArtist,
MPMediaItemPropertyAlbumTitle,
MPMediaItemPropertyArtwork,
MPNowPlayingInfoPropertyElapsedPlaybackTime,
MPMediaItemPropertyPlaybackDuration,
MPNowPlayingInfoPropertyPlaybackRate, nil];
I successfully put the objects and their keys into the MPNowPlayingInfoCenter defaultCenter with this:
songInfo = [NSDictionary dictionaryWithObjects:[[_podcastArray objectAtIndex:(value - 1)] subarrayWithRange:NSMakeRange(0, imageIndex)] forKeys:_keys];
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:songInfo];
Where podcast array is where I hold several arrays with these objects and keys. Now when I go to the lock screen, everything I want to be shown is shown (i.e.: title, artist name, album name, album artwork). However, the one thing I can't get to show up is the stupid elapsed time and duration.
I have done a lot of research and implemented what I thought was the right thing to do, but apparently it isn't right/working.
I could really use some help here, thanks.

Try replacing
[NSNumber numberWithFloat:(float)_audioPlayer.currentPlaybackTime]
with
[NSNumber numberWithDouble:_audioPlayer.currentPlaybackTime]
Also check that _audioPlayer.duration is not 0.

Your madMoneyArray has some extra values replace this array with this
NSArray *madMoneyArray = [NSArray arrayWithObjects:[NSString stringWithFormat:#"Episode %d", a],
#"Jim Cramer",
#"Mad Money Podcast",
madMoneyArtwork,
[NSNumber numberWithFloat:(float)_audioPlayer.currentPlaybackTime],
[NSNumber numberWithDouble:(double)_audioPlayer.duration],
[NSNumber numberWithInt:1],
nil];
try this , hope this helps !!!

Related

AVAssetWriterInput does not currently support AVVideoScalingModeFit - IOS Error

I'm attempting to use the AVAssetWriterInput to crop a video that I read in a screencast of my application. Here is my current configuration.
NSDictionary *videoCleanApertureSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:320], AVVideoCleanApertureWidthKey,
[NSNumber numberWithInt:480], AVVideoCleanApertureHeightKey,
[NSNumber numberWithInt:10], AVVideoCleanApertureHorizontalOffsetKey,
[NSNumber numberWithInt:10], AVVideoCleanApertureVerticalOffsetKey,
nil];
NSDictionary *videoAspectRatioSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:3], AVVideoPixelAspectRatioHorizontalSpacingKey,
[NSNumber numberWithInt:3],AVVideoPixelAspectRatioVerticalSpacingKey,
nil];
NSDictionary *codecSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:960000], AVVideoAverageBitRateKey,
[NSNumber numberWithInt:1],AVVideoMaxKeyFrameIntervalKey,
videoCleanApertureSettings, AVVideoCleanApertureKey,
videoAspectRatioSettings, AVVideoPixelAspectRatioKey,
AVVideoProfileLevelH264BaselineAutoLevel, AVVideoProfileLevelKey,
nil];
NSDictionary *videoSettings = #{AVVideoCodecKey:AVVideoCodecH264,
AVVideoCompressionPropertiesKey:codecSettings,
AVVideoScalingModeKey:AVVideoScalingModeResizeAspectFill,
AVVideoWidthKey:[NSNumber numberWithInt:320],
AVVideoHeightKey:[NSNumber numberWithInt:480]};
_videoWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];
I'm receiving the following error: "AVAssetWriterInput does not currently support AVVideoScalingModeFit"
This is a common error for anyone using this library, but I can't find the actual solution to it. I just see people saying: "I figured it out eventually" without explaining it. The problem is definitely related to this line: "AVVideoScalingModeKey:AVVideoScalingModeResizeAspectFill," which tells the AVAssetWriter to crop the video and maintain the aspect ratio. Anyone know the solution to this?
There is no "solution to it" per se. It's simply unsupported. You'll need to scale the video frames yourself using Core Image or a VTPixelTransferSession or whatever is appropriate for your pipeline.

Writing and Reading Data to an NSMutableArray at the same time

I am trying to make a progressive download audio player that will store as much as of the audio while playing it.
The format of the audio is stream optimized m4a.
For this problem I thought get the audio packets with a streamer into the memory, dont save it to anyfile in order to keep things faster.
And by the nature of m4a files I can't write and read the file at the same time from disk anyways...
So I stream and parse audiopackets from a remote source then put them into a Singleton NSMutableArray...
While streamer downloads the audiopackets, player reads and play audio packets from NSMutableArray at the same time...
Average file has around 11000 audiopackets so the count of the array reaches to 11000.
NSMutableDictionary * myDict = [[NSMutableDictionary alloc] init];
NSData *inputData = [NSData dataWithBytes:inInputData length:inPacketDescriptions[i].mDataByteSize];
[myDict setObject:inputData forKey:#"inInputData"];
NSNumber *numberBytes = [NSNumber numberWithInt:inNumberBytes];
[myDict setObject:numberBytes forKey:#"inNumberBytes"];
NSNumber *numberPackets = [NSNumber numberWithInt:inNumberPackets];
[myDict setObject:numberPackets forKey:#"inNumberPackets"];
NSNumber *mStartOffset = [NSNumber numberWithInt:inPacketDescriptions[i].mStartOffset];
NSNumber *mDataByteSize = [NSNumber numberWithInt:inPacketDescriptions[i].mDataByteSize];
NSNumber *mVariableFramesInPacket = [NSNumber numberWithInt:inPacketDescriptions[i].mVariableFramesInPacket];
[myDict setObject:mStartOffset forKey:#"mStartOffset"];
[myDict setObject:mDataByteSize forKey:#"mDataByteSize"];
[myDict setObject:mVariableFramesInPacket forKey:#"mVariableFramesInPacket"];
[sharedCache.baseAudioCache addObject:myDict];
My question is at some point will I encounter deadlocks?
Is this a good practice for audio streaming?
I would really recommend to use NSArrays after you've built the NSMutableArray.
You can synchronize to lock the NSMutableArray too.
#synchronized(yourMutableArray) {
[yourMutableArray stuffMethod];
}

writing data into firebase using an iphone app

This was the question I had asked in order to write data into firebase through an android app, I want to represent the information in the same way in an iphone app.
I am using a dictionary to represent the key-value pairs.
f = [[Firebase alloc] initWithUrl:#"https://ums-ios.firebaseio.com/"];
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
#"latitude",[[NSNumber numberWithFloat:latitude] stringValue],
#"longitude",[[NSNumber numberWithFloat:longitude] stringValue],
#"timestamp",[[NSNumber numberWithDouble:timeStamp] stringValue],
nil];
Firebase* tempRef = [f childByAppendingPath:#"mobileNum"];
[tempRef setValue:dictionary];
I am getting an exception when I try to run this. But when I replace the NSDictionary with NSArray my data is getting mapped to array indices, which is not what I would require.
any suggestions ?
I think it's unrelated, butyour dictionary is backwards. I also find it terribly annoying, and I feel like I always have to double check, but values come before keys for iOS
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
[[NSNumber numberWithFloat:latitude] stringValue], #"latitude",
[[NSNumber numberWithFloat:longitude] stringValue], #"longitude",
[[NSNumber numberWithDouble:timeStamp] stringValue], #"timestamp",
nil];
The full code would be this
float latitude = 30.472;
float longitude = 42.467;
double timeStamp = NSTimeIntervalSince1970;
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
[[NSNumber numberWithFloat:latitude] stringValue], #"latitude",
[[NSNumber numberWithFloat:longitude] stringValue], #"longitude",
[[NSNumber numberWithDouble:timeStamp] stringValue], #"timestamp",
nil];
Firebase * f = [[Firebase alloc]initWithUrl:#"https://ums-ios.firebaseio.com/"];
Firebase* tempRef = [f childByAppendingPath:#"mobileNum"];
[tempRef setValue:dictionary];
This will create the following URL scheme (added .json so you can see easy)
https://ums-ios.firebaseio.com/mobileNum/.json = the dictionary
https://ums-ios.firebaseio.com/mobileNum/latitude/.json = value for latitude
https://ums-ios.firebaseio.com/mobileNum/longitude/.json = value for longitude
https://ums-ios.firebaseio.com/mobileNum/timestamp/.json = value for timestamp
A note on security,
I just saved this data to your firebase, make sure you update security before releasing!

Iterating through a Dictionary

I'm trying to iterate over an NSMutableDictionary and I cannot seem to get what I want. I have a dictionary mapping strings to colors like so...
squareColors = [NSMutableDictionary dictionaryWithObjects: [NSMutableArray arrayWithObjects:
[NSNumber numberWithInt:0],
[NSNumber numberWithInt:0],
[NSNumber numberWithInt:0],
[NSNumber numberWithInt:0],
[NSNumber numberWithInt:0],
nil]
forKeys: [NSMutableArray arrayWithObjects:
#"yellow",
#"blue",
#"green",
#"purple",
#"orange",
nil]];
Over time the value of each entry will increase. Every once in a while I want to look into the dictionary and select the color with the highest count. How might I do that? Here's what I'm trying, but I'm unfamiliar with blocks.
__block int mostSquares = 0;
__block NSString* color = #"";
/* Look through the dictionary to find the color with the most number of squares */
[squareColors enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
NSLog(#"%# => %#", key, obj);
NSInteger count = [key integerValue];
if (count > mostSquares)
{
color = key;
mostSquares = count;
}
}];
You have a very simple bug in your code. This line:
NSInteger count = [key integerValue];
should be:
NSInteger count = [obj integerValue];
'key' is the color name, obj is the number. As you have it, count gets set to 0 for each iteration because calling integerValue on a non-numeric string gives you 0.
Simple solution using your example:
NSMutableArray *arrayNumbers = [NSMutableArray arrayWithObjects:
[NSNumber numberWithInt:0],
[NSNumber numberWithInt:1],
[NSNumber numberWithInt:2],
[NSNumber numberWithInt:6],
[NSNumber numberWithInt:4],
nil];
NSMutableArray *arrayColours = [NSMutableArray arrayWithObjects:
#"yellow",
#"blue",
#"green",
#"purple",
#"orange",
nil];
NSMutableDictionary *squareColors = [NSMutableDictionary dictionaryWithObjects:arrayNumbers
forKeys:arrayColours];
NSUInteger indexOfArray = [arrayNumbers indexOfObject:[arrayNumbers valueForKeyPath:#"#max.intValue"]];
NSLog (#"Colour with largest value is %#", [arrayColours objectAtIndex:indexOfArray]);
Can you store your Keys into an array and iterate using that array? That would probably be the most efficient solution, since you'll need to know every key anyway.

Save game level in my app even when the app is closed?

I am making an RPG game for the iPhone and everything is working out great but I need to know how to save my game level so that even if the user were to close the app running in the background the entire game wouldn't start over again. I was even thinking of bringing back old style gaming and making it so that you have to enter a password to start from where you left off. But even then I wouldn't know how to save the game properly. Plus even if I did save the game how would I be able to make it stay saved even when the app closes completely? So far I have tried adding save data code to the AppWillTerminate line but still nothing. Any help is appreciated.
I'm not sure if you want to save which level the user was on, or if you want to save the game state. If you simply want to save which level the user was on, you should go with #EricS's method (NSUserDefaults). It's a little more complicated to save game state. I would do something like this:
//Writing game state to file
//Some sample data
int lives = player.kLives;
int enemiesKilled = player.kEnemiesKilled;
int ammo = player.currentAmmo;
//Storing the sample data in an array
NSArray *gameState = [[NSArray alloc] initWithObjects: [NSNumber numberWithInt:lives], [NSNumber numberWithInt:enemiesKilled], [NSNumber numberWithInt:ammo], nil];
//Writing the array to a .plist file located at "path"
if([gameState writeToFile:path atomically:YES]) {
NSLog(#"Success!");
}
//Reading from file
//Reads the array stored in a .plist located at "path"
NSArray *lastGameState = [NSArray arrayWithContentsOfFile:path];
The .plist would look like this:
Using an array would mean that upon reloading the game state, you would have to know the order that you stored the items in, which isn't that bad, but if you want a more reliable method, you could try using an NSDictionary like this:
//Writing game state to file
//Some sample data
int lives = player.kLives;
int enemiesKilled = player.kEnemiesKilled;
int ammo = player.currentAmmo;
int points = player.currentPoints;
//Store the sample data objects in an array
NSArray *gameStateObjects = [NSArray arrayWithObjects:[NSNumber numberWithInt:lives], [NSNumber numberWithInt:enemiesKilled], [NSNumber numberWithInt:points], [NSNumber numberWithInt:ammo], nil];
//Store their keys in a separate array
NSArray *gameStateKeys = [NSArray arrayWithObjects:#"lives", #"enemiesKilled", #"points", #"ammo", nil];
//Storing the objects and keys in a dictionary
NSDictionary *gameStateDict = [NSDictionary dictionaryWithObjects:gameStateObjects forKeys:gameStateKeys];
//Write to file
[gameStateDict writeToFile:path atomically: YES];
//Reading from file
//Reads the array stored in a .plist located at "path"
NSDictionary *lastGameState = [NSDictionary dictionaryWithContentsOfFile:path];
The dictionary .plist would look like this:
To save the level:
[[NSUserDefaults standardUserDefaults] setInteger:5 forKey:#"level"];
To read the level:
NSInteger level = [[NSUserDefaults standardUserDefaults] integerForKey:#"level"];
I would set it whenever the user enters that level. You could wait until you are sent into the background, but there's really no point in waiting.

Resources