0

I have an application which plays some audio and also records a video+audio while that sound is playing. I would like to figure out a way to process the video so that the audio that was picked up by the microphone is removed from the resulting video.

For example, if I'm playing audioA, and then recording videoB with audioB (from the microphone), I want to somehow cancel out audioA from the resulting audioB, so that audioB is only the ambient noise and not the noise from the device speakers.

Any idea if there's a way to do this?

Bonus points if it can be done without any offline processing.

Liron
  • 2,012
  • 19
  • 39

1 Answers1

0

You have to deal with Playback part. But here is a code to Mix the selected Audio to the Recorded Video.

- (void)mixAudio:(AVAsset*)audioAsset startTime:(CMTime)startTime withVideo:(NSURL*)inputUrl affineTransform:(CGAffineTransform)affineTransform  toUrl:(NSURL*)outputUrl outputFileType:(NSString*)outputFileType withMaxDuration:(CMTime)maxDuration withCompletionBlock:(void(^)(NSError *))completionBlock {
    NSError * error = nil;
    AVMutableComposition * composition = [[AVMutableComposition alloc] init];

    AVMutableCompositionTrack * videoTrackComposition = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];

    AVMutableCompositionTrack * audioTrackComposition = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];

    AVURLAsset * fileAsset = [AVURLAsset URLAssetWithURL:inputUrl options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:AVURLAssetPreferPreciseDurationAndTimingKey]];

    NSArray * videoTracks = [fileAsset tracksWithMediaType:AVMediaTypeVideo];

    CMTime duration = ((AVAssetTrack*)[videoTracks objectAtIndex:0]).timeRange.duration;

    if (CMTIME_COMPARE_INLINE(duration, >, maxDuration)) {
        duration = maxDuration;
    }

    for (AVAssetTrack * track in [audioAsset tracksWithMediaType:AVMediaTypeAudio]) {
        [audioTrackComposition insertTimeRange:CMTimeRangeMake(startTime, duration) ofTrack:track atTime:kCMTimeZero error:&error];

        if (error != nil) {
            completionBlock(error);
            return;
        }
    }

    for (AVAssetTrack * track in videoTracks) {
        [videoTrackComposition insertTimeRange:CMTimeRangeMake(kCMTimeZero, duration) ofTrack:track atTime:kCMTimeZero error:&error];

        if (error != nil) {
            completionBlock(error);
            return;
        }
    }

    videoTrackComposition.preferredTransform = affineTransform;

    AVAssetExportSession * exportSession = [[AVAssetExportSession alloc] initWithAsset:composition presetName:AVAssetExportPresetPassthrough];
    exportSession.outputFileType = outputFileType;
    exportSession.shouldOptimizeForNetworkUse = YES;
    exportSession.outputURL = outputUrl;

    [exportSession exportAsynchronouslyWithCompletionHandler:^ {
        NSError * error = nil;
        if (exportSession.error != nil) {
            NSMutableDictionary * userInfo = [NSMutableDictionary dictionaryWithDictionary:exportSession.error.userInfo];
            NSString * subLocalizedDescription = [userInfo objectForKey:NSLocalizedDescriptionKey];
            [userInfo removeObjectForKey:NSLocalizedDescriptionKey];
            [userInfo setObject:@"Failed to mix audio and video" forKey:NSLocalizedDescriptionKey];
            [userInfo setObject:exportSession.outputFileType forKey:@"OutputFileType"];
            [userInfo setObject:exportSession.outputURL forKey:@"OutputUrl"];
            [userInfo setObject:subLocalizedDescription forKey:@"CauseLocalizedDescription"];

            [userInfo setObject:[AVAssetExportSession allExportPresets] forKey:@"AllExportSessions"];

            error = [NSError errorWithDomain:@"Error" code:500 userInfo:userInfo];
        }

        completionBlock(error);
    }];
}
Xcoder
  • 1,762
  • 13
  • 17
  • Looks like a cool project, but I'm not seeing at first glance how to do what I'm suggesting. – Liron Apr 23 '15 at 06:43
  • I don't think you understand my question. I have the video and audio joining together fine. The problem is, that the recording also includes the ambient noise which is coming out of the speakers (which is the audio that I am playing in-app.) I want some way to noise-cancel that sound out of the final recording. – Liron Apr 24 '15 at 11:33
  • So to say it in other words. Imagine my app is playing Mozart from the speakers, and at the same time recording the user saying something. I want that recording to somehow not include the Mozart, even though the microphone is picking it up. – Liron Apr 24 '15 at 11:35
  • This would presumably need some sort of signal processing to figure out or something like that. – Liron Apr 24 '15 at 11:36
  • Ok. Its more involved than I thought. Look at this link here http://stackoverflow.com/questions/10903542/using-avcapturesession-and-avaudioplayer-together You could try out setting Audio session category to different values and just give it a try before going the audio cancellation route (eg [AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback] ). – Xcoder Apr 24 '15 at 12:36
  • For more info on this https://developer.apple.com/library/ios/documentation/Audio/Conceptual/AudioSessionProgrammingGuide/AudioSessionCategoriesandModes/AudioSessionCategoriesandModes.html – Xcoder Apr 24 '15 at 12:41
  • Already tried that, which didn't work I was wondering if I could somehow use AudioUnit to accomplish this, but it seems that https://developer.apple.com/library/ios/documentation/AudioUnit/Reference/AUComponentServicesReference/index.html#//apple_ref/c/econst/kAudioUnitSubType_VoiceProcessingIO isn't really what I want it to be. – Liron Apr 26 '15 at 14:18
  • Hey @Liron did you by any chance figure out a way to achieve this? Im trying to do somewhat the same thing. – OriginalAlchemist Jan 30 '17 at 03:19
  • No, sorry. Offline, if you know both audio streams, you could probably run some dsp to remove one from the other, but I didn't find a way to do it myself. – Liron Jan 30 '17 at 04:54