AVAudioRecorder / AVAudioPlayer - добавить запись в файл
Есть ли способ записи в конец аудиофайла? Мы не можем просто приостановить запись, а не остановить ее, потому что пользователь должен иметь возможность вернуться в приложение позже и добавить больше звука к своей записи. В настоящее время аудио хранится в CoreData как NSData. NSData-х AppendData
не работает, потому что результирующий аудиофайл по-прежнему сообщает, что он содержит только исходные данные.
Другая возможность - взять оригинальный аудиофайл вместе с новым и объединить их в один аудиофайл, если есть какой-либо способ сделать это.
4 ответа
Это можно сделать довольно легко, используя 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
Надеюсь, это поможет решить вашу проблему.
У нас были те же требования к нашему приложению, что и у описанного OP, и мы столкнулись с теми же проблемами (т. Е. Запись должна быть остановлена, а не приостановлена, если пользователь хочет прослушать то, что она записала до этого момента). Наше приложение ( репозиторий Github проекта) использует AVQueuePlayer
для воспроизведения и метода, аналогичного ответу кермитологии, для объединения частичных записей с некоторыми заметными отличиями:
- реализовано в Swift
- объединяет несколько записей в одну
- не возиться с треками
Основанием для последнего пункта является то, что простые записи с AVAudioRecorder
будет иметь одну дорожку, и главная причина для всего этого обходного пути состоит в объединении этих отдельных дорожек в активах (см. Приложение 3). Так почему бы не использовать AVMutableComposition
"s insertTimeRange
метод, который требует 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
, но документы ясно, что exportAsynchronously
Блок обратного вызова "вызывается, когда запись завершена или в случае сбоя записи".
Приложение 2: На всякий случай, если у кого-то есть проблемы с AVQueuePlayer
: "AVPlayerItem не может быть связан с более чем одним экземпляром AVPlayer"
Приложение 3: Если вы не записываете в стерео, но мобильные устройства имеют один вход, насколько я знаю. Кроме того, использование необычного микширования звука также потребует использования AVCompositionTrack
, Хороший SO поток: правильные настройки AVAudioRecorder для записи голоса?
У меня нет полного примера кода, но службы расширенных аудиофайлов могут помочь вам объединить два аудиофайла. Ищите Расширенные Сервисы Аудио Файла в XCode или посетите ссылку ниже.