Thursday, June 6, 2013

AVAudioMix inputParameters example in Objective C (iOS).


AVAudioMix inputParameters

The parameters for inputs to the mix (read-only)

@property(nonatomic, readonly, copy) NSArray *inputParameters

Discussion of [AVAudioMix inputParameters]
The array contains instances of AVAudioMixInputParameters. Note that an instance of AVAudioMixInputParameters is not required for each audio track that contributes to the mix; audio for those without associated AVAudioMixInputParameters objects will be included in the mix, processed according to default behavior.

AVAudioMix inputParameters example.
//given an AVAsset called asset...
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];
id audioMix = [[AVAudioMix alloc] init];
id volumeMixInput = [[AVMutableAudioMixInputParameters alloc] init];

//fade volume from muted to full over a period of 3 seconds
[volumeMixInput setVolumeRampFromStartVolume:0 toEndVolume:1 timeRange:
     CMTimeRangeMake(CMTimeMakeWithSeconds(0, 1), CMTimeMakeWithSeconds(3, 1))];
[volumeMixnput setTrackID:[[asset tracks:objectAtIndex:0] trackID]];

[audioMix setInputParameters:[NSArray arrayWithObject:volumeMixInput]];
[playerItem setAudioMix:audioMix];
You can also abruptly set the volume for a mix at a given time with:

[volumeMixInput setVolume:.5 atTime:CMTimeMakeWithSeconds(15, 1)];
Hope this helps. This API is definitely not obvious. I'd highly recommend watching the WWDC 10 video entitled Discovering AV Foundation. It's excellent.

Example of [AVAudioMix inputParameters].
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:[self myAssetURL] options:nil];
NSArray *audioTracks = [asset tracksWithMediaType:AVMediaTypeAudio];

// Mute all the audio tracks
NSMutableArray *allAudioParams = [NSMutableArray array];
for (AVAssetTrack *track in audioTracks) {
    AVMutableAudioMixInputParameters *audioInputParams =[AVMutableAudioMixInputParameters audioMixInputParameters];
    [audioInputParams setVolume:0.0 atTime:kCMTimeZero];
    [audioInputParams setTrackID:[track trackID]];
    [allAudioParams addObject:audioInputParams];
}
AVMutableAudioMix *audioZeroMix = [AVMutableAudioMix audioMix];
[audioZeroMix setInputParameters:allAudioParams];

// Create a player item
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];
[playerItem setAudioMix:audioZeroMix]; // Mute the player item

// Create a new Player, and set the player to use the player item
// with the muted audio mix
AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];

// assign player object to an instance variable
self.mPlayer = player;

// play the muted audio
[mPlayer play];

AVAudioMix inputParameters example.
NSURL *assetURL = [[NSBundle mainBundle] URLForResource:@"DLP" withExtension:@"mp3"];
assert(assetURL);

// Create the AVAsset
AVAsset *asset = [AVAsset assetWithURL:assetURL];
assert(asset);

// Create the AVPlayerItem
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];
assert(playerItem);

assert([asset tracks]);
assert([[asset tracks] count]);

self.player = [AVPlayer playerWithPlayerItem:playerItem];
assert(self.player);

// Continuing on from where we created the AVAsset...
AVAssetTrack *audioTrack = [[asset tracks] objectAtIndex:0];
AVMutableAudioMixInputParameters *inputParams = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:audioTrack];

// Create a processing tap for the input parameters
MTAudioProcessingTapCallbacks callbacks;
callbacks.version = kMTAudioProcessingTapCallbacksVersion_0;
callbacks.clientInfo = (__bridge void *)(self);
callbacks.init = init;
callbacks.prepare = prepare;
callbacks.process = process;
callbacks.unprepare = unprepare;
callbacks.finalize = finalize;

MTAudioProcessingTapRef tap;
// The create function makes a copy of our callbacks struct
OSStatus err = MTAudioProcessingTapCreate(kCFAllocatorDefault, &callbacks,
                                          kMTAudioProcessingTapCreationFlag_PostEffects, &tap);
if (err || !tap) {
    NSLog(@"Unable to create the Audio Processing Tap");
    return;
}
assert(tap);

// Assign the tap to the input parameters
inputParams.audioTapProcessor = tap;
// Create a new AVAudioMix and assign it to our AVPlayerItem
AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];
audioMix.inputParameters = @[inputParams];
playerItem.audioMix = audioMix;

// And then we create the AVPlayer with the playerItem, and send it the play message...
[self.player play];

End of AVAudioMix inputParameters example article.