AVAudioRecorder / AVAudioPlayer - добавить запись в файл - PullRequest
8 голосов
/ 10 января 2011

Есть ли способ записи в конец аудиофайла? Мы не можем просто приостановить запись, а не остановить ее, потому что пользователь должен иметь возможность вернуться к приложению позже и добавить больше звука к своей записи. В настоящее время аудио хранится в CoreData как NSData. AppendData NSData не работает, потому что результирующий аудиофайл по-прежнему сообщает, что он только столько же, сколько исходные данные.

Еще одна возможность - взять оригинальный аудиофайл вместе с новым и объединить их в один аудиофайл, если есть какой-либо способ сделать это.

Ответы [ 4 ]

7 голосов
/ 16 апреля 2013

Это можно сделать довольно легко, используя AVMutableComposionTrack insertTimeRange:ofTrack:atTime:error.Код несколько длинен, но на самом деле это всего лишь 4 шага:

// Create a new audio track we can append to
AVMutableComposition* composition = [AVMutableComposition composition];
AVMutableCompositionTrack* appendedAudioTrack = 
    [composition addMutableTrackWithMediaType:AVMediaTypeAudio
                             preferredTrackID:kCMPersistentTrackID_Invalid];

// Grab the two audio tracks that need to be appended
AVURLAsset* originalAsset = [[AVURLAsset alloc]
    initWithURL:[NSURL fileURLWithPath:originalAudioPath] options:nil];
AVURLAsset* newAsset = [[AVURLAsset alloc] 
    initWithURL:[NSURL fileURLWithPath:newAudioPath] options:nil];

NSError* error = nil;

// Grab the first audio track and insert it into our appendedAudioTrack 
AVAssetTrack *originalTrack = [originalAsset tracksWithMediaType:AVMediaTypeAudio];
CMTimeRange timeRange = CMTimeRangeMake(kCMTimeZero, originalAsset.duration);
[appendedAudioTrack insertTimeRange:timeRange 
                            ofTrack:[originalTrack objectAtIndex:0]
                             atTime:kCMTimeZero
                              error:&error];
if (error)
{
    // do something
    return;
}

// Grab the second audio track and insert it at the end of the first one
AVAssetTrack *newTrack = [newAsset tracksWithMediaType:AVMediaTypeAudio]; 
timeRange = CMTimeRangeMake(kCMTimeZero, newAsset.duration);   
[appendedAudioTrack insertTimeRange:timeRange
                            ofTrack:[newTrack objectAtIndex:0]
                             atTime:originalAsset.duration
                              error:&error];

if (error)
{
    // do something
    return;
}

// Create a new audio file using the appendedAudioTrack      
AVAssetExportSession* exportSession = [AVAssetExportSession
                                       exportSessionWithAsset:composition
                                       presetName:AVAssetExportPresetAppleM4A];
if (!exportSession)
{
    // do something
    return;
}


NSString* appendedAudioPath= @""; // make sure to fill this value in    
exportSession.outputURL = [NSURL fileURLWithPath:appendedAudioPath];
exportSession.outputFileType = AVFileTypeAppleM4A; 
[exportSession exportAsynchronouslyWithCompletionHandler:^{

    // exported successfully?
    switch (exportSession.status)
    {
        case AVAssetExportSessionStatusFailed:
            break;
        case AVAssetExportSessionStatusCompleted:
            // you should now have the appended audio file
            break;
        case AVAssetExportSessionStatusWaiting:
            break;
        default:
            break;
    }
    NSError* error = nil;

}];
4 голосов
/ 31 января 2012

Вы можете добавить два аудиофайла, создав AVMutableCompositionTrack после добавления двух файлов и экспортировав композицию, используя exportAsynchronouslyWithCompletionHandler метод AVAssetExportSession.

Пожалуйста, обратитесь к ссылкам ниже для более подробной информации.

Ссылка на класс AVAssetExportSession

Создание новых активов

Надеюсь, это поможет решить вашу проблему.

1 голос
/ 13 января 2011

У меня нет полного примера кода, но службы расширенных аудиофайлов могут помочь вам объединить два аудиофайла.Ищите Расширенные Сервисы Аудио Файла в XCode или посетите ссылку ниже.

Документация Apple

0 голосов
/ 23 апреля 2018

Мы предъявляли те же требования к нашему приложению, что и описанный OP, и столкнулись с теми же проблемами (т. Е. Запись должна быть остановлена, а не приостановлена, если пользователь хочет прослушать то, что он записал до этого точка). Наше приложение ( Github repo проекта ) использует AVQueuePlayer для воспроизведения и метод, похожий на ответ Kermitology для объединения частичных записей, с некоторыми заметными отличиями:

  • реализовано в Swift
  • объединяет несколько записей в одну
  • нет путаницы с треками

Обоснование последнего элемента заключается в том, что в простых записях с AVAudioRecorder будет один трек, и главная причина всего этого обходного пути - объединить эти отдельные треки в ресурсах (см. Добавление 3 ). , Так почему бы не использовать метод AVMutableComposition insertTimeRange вместо этого, вместо AVAssetTrack?

вместо *1028*?

Соответствующие части: ( полный код )

import UIKit
import AVFoundation

class RecordViewController: UIViewController {

    /* App allows volunteers to record newspaper articles for the
       blind and print-impaired, hence the name.
    */
    var articleChunks = [AVURLAsset]()

    func concatChunks() {
        let composition = AVMutableComposition()

        /* `CMTimeRange` to store total duration and know when to
           insert subsequent assets.
        */
        var insertAt = CMTimeRange(start: kCMTimeZero, end: kCMTimeZero)

        repeat {
            let asset = self.articleChunks.removeFirst()

            let assetTimeRange = 
                CMTimeRange(start: kCMTimeZero, end: asset.duration)

            do {
                try composition.insertTimeRange(assetTimeRange, 
                                                of: asset, 
                                                at: insertAt.end)
            } catch {
                NSLog("Unable to compose asset track.")
            }

            let nextDuration = insertAt.duration + assetTimeRange.duration
            insertAt = CMTimeRange(start: kCMTimeZero, duration: nextDuration)
        } while self.articleChunks.count != 0

        let exportSession =
            AVAssetExportSession(
                asset:      composition,
                presetName: AVAssetExportPresetAppleM4A)

        exportSession?.outputFileType = AVFileType.m4a
        exportSession?.outputURL = /* create URL for output */
        // exportSession?.metadata = ...

        exportSession?.exportAsynchronously {

            switch exportSession?.status {
            case .unknown?: break
            case .waiting?: break
            case .exporting?: break
            case .completed?: break
            case .failed?: break
            case .cancelled?: break
            case .none: break
            }
        }

        /* Clean up (delete partial recordings, etc.) */
    }

Эта диаграмма помогла мне обойти то, что ожидает, что и откуда унаследовано. (NSObject неявно подразумевается как суперкласс, где нет стрелки наследования.)

enter image description here

Приложение 1: У меня были оговорки относительно части switch вместо использования KVO на AVAssetExportSessionStatus, но документы ясно, что блок обратного вызова exportAsynchronously вызывается, когда запись завершить или в случае ошибки записи ".

Приложение 2: На всякий случай, если у кого-то возникли проблемы с AVQueuePlayer: 'AVPlayerItem не может быть связан с более чем одним экземпляром AVPlayer'

Приложение 3: Если вы не записываете стерео, но, насколько мне известно, мобильные устройства имеют один вход. Кроме того, использование необычного микширования звука также потребует использования AVCompositionTrack. Хороший SO поток: Правильные AVAudioRecorder Настройки для записи голоса?

...