Xcode for iOS
The issue that I'm having is in the playback of an AVMutableComposition. I'm creating the composition then adding AVURLAssets to it inside a for loop. I'm adding everything as I would similarly add an object to a mutable array and then attempting to play it back afterwards, but playback isn't occuring. Here is my code:
AVMutableComposition *composition = [AVMutableComposition composition];
int count;
count = array.count;
for (int y=0;y<count;y++){
NSURL *url;
url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@.mp3", [[NSBundle mainBundle] resourcePath],[array objectAtIndex:y]]];
NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:AVURLAssetPreferPreciseDurationAndTimingKey];
AVURLAsset *sourceAsset = [[AVURLAsset alloc] initWithURL:url options:options];
//calculate times
NSNumber *time = [soundArray1 objectAtIndex:1];
double timenow = [time doubleValue];
double insertTime = (240*y);
CMTime douTime = CMTimeMake(240, timenow);
CMTime staTime = CMTimeMake(0, 1);
CMTimeRange editRange = CMTimeRangeMake(staTime,douTime);
CMTime insTime = CMTimeMake(insertTime, timenow);
NSError *editError;
[composition insertTimeRange:editRange ofAsset:sourceAsset atTime:insTime error:&editError];
}
AVPlayer* mp = [AVPlayer playerWithPlayerItem:[AVPlayerItem playerItemWithAsset:composition]];
[mp play];
I'd assume that I am getting it completely wrong, but I then added this inside the loop instead of after, inside an if and opening a NSRunLoop to check (a little bad, but it was just to test!):
AVMutableComposition *composition = [AVMutableComposition composition];
int count;
count = array.count;
for (int y=0;y<count;y++){
NSURL *url;
url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@.mp3", [[NSBundle mainBundle] resourcePath],[array objectAtIndex:y]]];
NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:AVURLAssetPreferPreciseDurationAndTimingKey];
AVURLAsset *sourceAsset = [[AVURLAsset alloc] initWithURL:url options:options];
//calculate times
NSNumber *time = [soundArray1 objectAtIndex:1];
double timenow = [time doubleValue];
double insertTime = (240*y);
CMTime douTime = CMTimeMake(240, timenow);
CMTime staTime = CMTimeMake(0, 1);
CMTimeRange editRange = CMTimeRangeMake(staTime,douTime);
CMTime insTime = CMTimeMake(insertTime, timenow);
NSError *editError;
[composition insertTimeRange:editRange ofAsset:sourceAsset atTime:insTime error:&editError];
if(y==3){
AVPlayer* mp = [AVPlayer playerWithPlayerItem:[AVPlayerItem playerItemWithAsset:composition]];
[mp play];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:20]];
}
}
Here, I just gave my array 4 elements and made it play the composition on the 4th run-through. It worked and played my 4 audio files in perfect order.
What do I need to do to make my composition play after this loop rather than in it? Am I mis-using the system?
EDIT: by sticking my open RunLoop code on the end, it plays. Should I be doing it this way, or is there a better way to do this?
So I was going about this the wrong way. I needed to create an AVMutableCompositionTrack for each element and add that to my composition
NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES]
forKey:AVURLAssetPreferPreciseDurationAndTimingKey];
AVURLAsset *sourceAsset = [[AVURLAsset alloc] initWithURL:url options:options];
//calculate times
NSNumber *time = [soundArray1 objectAtIndex:1];
double timenow = [time doubleValue];
double insertTime = (240*y);
AVMutableCompositionTrack *track =
[composition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID:kCMPersistentTrackID_Invalid];
//insert the audio track from the asset into the track added to the mutable composition
AVAssetTrack *myTrack = [[sourceAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
CMTimeRange myTrackRange = myTrack.timeRange;
NSError *error = nil;
[track insertTimeRange:myTrackRange
ofTrack:myTrack
atTime:CMTimeMake(insertTime, timenow)
error:&error];
[sourceAsset release];
followed by
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:composition];
self.player = [[AVPlayer alloc] initWithPlayerItem:playerItem];
[self.player play];
with player declared as a property in the interface section
@interface SecondViewController ()
@property (nonatomic, assign) AVPlayer *player;
@end