optimize the appicon of iOS
This commit is contained in:
62
ios/OralTrainer/Services/DubbingCompositor.swift
Normal file
62
ios/OralTrainer/Services/DubbingCompositor.swift
Normal file
@@ -0,0 +1,62 @@
|
||||
import AVFoundation
|
||||
import Foundation
|
||||
|
||||
enum DubbingCompositorError: LocalizedError {
|
||||
case noAudioTracks
|
||||
case cannotReadDuration
|
||||
|
||||
var errorDescription: String? {
|
||||
switch self {
|
||||
case .noAudioTracks:
|
||||
return "录音没有音频轨道"
|
||||
case .cannotReadDuration:
|
||||
return "无法读取录音时长"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum DubbingCompositor {
|
||||
static func merge(urls: [URL], outputURL: URL) async throws {
|
||||
try await mergeSync(urls: urls, outputURL: outputURL)
|
||||
}
|
||||
|
||||
private static func mergeSync(urls: [URL], outputURL: URL) async throws {
|
||||
try? FileManager.default.removeItem(at: outputURL)
|
||||
let composition = AVMutableComposition()
|
||||
var currentTime = CMTime.zero
|
||||
for url in urls {
|
||||
let source = AVURLAsset(url: url)
|
||||
let tracks = try await source.loadTracks(withMediaType: .audio)
|
||||
guard let track = tracks.first else {
|
||||
throw DubbingCompositorError.noAudioTracks
|
||||
}
|
||||
let duration = try await source.load(.duration)
|
||||
guard duration.seconds.isFinite, duration.seconds > 0 else {
|
||||
throw DubbingCompositorError.cannotReadDuration
|
||||
}
|
||||
let timeRange = CMTimeRange(start: .zero, duration: duration)
|
||||
let compositionTrack = composition.addMutableTrack(
|
||||
withMediaType: .audio,
|
||||
preferredTrackID: kCMPersistentTrackID_Invalid
|
||||
)
|
||||
guard let compositionTrack else {
|
||||
throw DubbingCompositorError.noAudioTracks
|
||||
}
|
||||
try compositionTrack.insertTimeRange(timeRange, of: track, at: currentTime)
|
||||
currentTime = currentTime + duration
|
||||
}
|
||||
|
||||
guard let exporter = AVAssetExportSession(
|
||||
asset: composition,
|
||||
presetName: AVAssetExportPresetAppleM4A
|
||||
) else {
|
||||
throw DubbingCompositorError.noAudioTracks
|
||||
}
|
||||
exporter.outputURL = outputURL
|
||||
exporter.outputFileType = .m4a
|
||||
await exporter.export()
|
||||
guard exporter.status == .completed else {
|
||||
throw exporter.error ?? DubbingCompositorError.noAudioTracks
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user