簡體   English   中英

AVAudioRecorder / AVAudioPlayer - 將錄音附加到文件

[英]AVAudioRecorder / AVAudioPlayer - append recording to file

有沒有辦法錄制到音頻文件的末尾? 我們不能暫停錄制而不是停止錄制,因為用戶需要以后能夠返回應用並為錄制添加更多音頻。 目前,音頻作為NSData存儲在CoreData中。 NSData的AppendData不起作用,因為生成的音頻文件仍然報告它只與原始數據一樣長。

另一種可能性是將原始音頻文件與新音頻文件連接起來,並將它們連接成一個音頻文件,如果有任何方法可以做到這一點。

這可以使用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;

}];

您可以通過創建一個追加兩個音頻文件AVMutableCompositionTrack添加兩個文件和導出使用該組合物后exportAsynchronouslyWithCompletionHandler的方法AVAssetExportSession

有關詳細信息,請參閱以下鏈接。

AVAssetExportSession類參考

創建新資產

希望這有助於解決您的問題。

我沒有完整的代碼示例,但擴展音頻文件服務可以幫助您連接兩個音頻文件。 在Xcode中搜索擴展音頻文件服務或訪問以下鏈接。

Apple文檔

我們對我們的應用程序的要求與OP描述的相同,並且遇到了相同的問題(即,如果用戶想要聽到她記錄的內容,則必須停止錄制,而不是暫停錄制)。 我們的應用程序( 項目的Github repo )使用AVQueuePlayer進行播放,並使用類似於kermitology連接部分錄音的答案的方法,以及一些顯着的差異:

  • Swift中實現
  • 多個錄音合並為一個
  • 沒有搞亂曲目

最后一項的基本原理是AVAudioRecorder簡單錄音將有一個軌道,這整個解決方法的主要原因是連接資產中的那些單軌(見附錄3 )。 那么為什么不使用AVMutableCompositioninsertTimeRange方法,而是采用AVAsset而不是AVAssetTrack

相關部分:( 完整代碼

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隱含地暗示為沒有繼承箭頭的超類。)

在此輸入圖像描述

附錄1:我對switch部分有所保留,而不是在AVAssetExportSessionStatus上使用KVO,但是文檔很清楚,當寫完成或寫入失敗時,會調用exportAsynchronously的回調塊“。

附錄2:萬一有人AVQueuePlayer問題: 'AVPlayerItem不能與多個AVPlayer實例關聯'

附錄3:除非你是用立體聲錄音,但據我所知,移動設備有一個輸入。 此外,使用精美的音頻混合還需要使用AVCompositionTrack 一個好的SO線程:適當的AVAudioRecorder設置錄制語音?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM