fixed some bugs on ios
This commit is contained in:
@@ -5,7 +5,7 @@ struct TestView: View {
|
||||
@ObservedObject var controller: PlayerController
|
||||
let onFullscreen: () -> Void
|
||||
|
||||
@State private var recorder: AVAudioRecorder?
|
||||
@State private var recordingSession: AudioRecorderSession?
|
||||
@State private var recordingURL: URL?
|
||||
@State private var isRecording = false
|
||||
@State private var isAssessing = false
|
||||
@@ -13,6 +13,7 @@ struct TestView: View {
|
||||
@State private var scoreSummary = "尚未评测"
|
||||
@State private var scoreDetail = ""
|
||||
@State private var dubSegments: [Int: URL] = [:]
|
||||
@State private var dubRawSegments: [Int: URL] = [:]
|
||||
@State private var latestScores: [Int: ImitationAssessmentResult] = [:]
|
||||
@State private var mergedDubURL: URL?
|
||||
@State private var dubPlayer: AVPlayer?
|
||||
@@ -82,7 +83,7 @@ struct TestView: View {
|
||||
dubButton("播放配音", enabled: !dubSegments.isEmpty && !dubbingPlayback && !isGeneratingDub) {
|
||||
toggleDubPlayback()
|
||||
}
|
||||
dubButton("生成配音", enabled: !dubSegments.isEmpty && !dubbingPlayback && !isGeneratingDub) {
|
||||
dubButton("生成配音", enabled: !dubRawSegments.isEmpty && !dubbingPlayback && !isGeneratingDub) {
|
||||
generateDubShareAudio()
|
||||
}
|
||||
dubButton("分享配音", enabled: mergedDubURL != nil && !dubbingPlayback && !isSharingDub) {
|
||||
@@ -195,58 +196,99 @@ struct TestView: View {
|
||||
private func beginRecording() {
|
||||
let fileURL = FileManager.default.temporaryDirectory
|
||||
.appendingPathComponent("attempt-\(Int(Date().timeIntervalSince1970 * 1000)).m4a")
|
||||
let settings: [String: Any] = [
|
||||
AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
|
||||
AVSampleRateKey: 16_000,
|
||||
AVNumberOfChannelsKey: 1,
|
||||
AVEncoderBitRateKey: 96_000,
|
||||
AVEncoderAudioQualityKey: AVAudioQuality.medium.rawValue,
|
||||
]
|
||||
let newSession = AudioRecorderSession(outputURL: fileURL)
|
||||
do {
|
||||
let session = AVAudioSession.sharedInstance()
|
||||
try session.setCategory(.playAndRecord, mode: .default, options: [.defaultToSpeaker])
|
||||
try session.setActive(true)
|
||||
let newRecorder = try AVAudioRecorder(url: fileURL, settings: settings)
|
||||
guard newRecorder.record() else {
|
||||
testStatus = "录音启动失败:无法开始录制"
|
||||
guard session.isInputAvailable else {
|
||||
testStatus = microphoneInputUnavailableMessage()
|
||||
return
|
||||
}
|
||||
recorder = newRecorder
|
||||
do {
|
||||
try newSession.start()
|
||||
} catch {
|
||||
try session.setActive(false, options: .notifyOthersOnDeactivation)
|
||||
try session.setCategory(.playAndRecord, mode: .default, options: [.defaultToSpeaker])
|
||||
try session.setActive(true)
|
||||
try newSession.start()
|
||||
}
|
||||
recordingSession = newSession
|
||||
recordingURL = fileURL
|
||||
isRecording = true
|
||||
testStatus = "正在录音…读完当前句子后点击“停止并评测”"
|
||||
} catch AudioRecorderSessionError.inputUnavailable {
|
||||
newSession.cancel()
|
||||
testStatus = microphoneInputUnavailableMessage()
|
||||
} catch AudioRecorderSessionError.startFailed {
|
||||
newSession.cancel()
|
||||
testStatus = recordingStartFailedMessage()
|
||||
} catch {
|
||||
newSession.cancel()
|
||||
testStatus = "录音启动失败:\(error.localizedDescription)"
|
||||
}
|
||||
}
|
||||
|
||||
private func microphoneInputUnavailableMessage() -> String {
|
||||
#if targetEnvironment(simulator)
|
||||
return "录音启动失败:未检测到麦克风输入。请在模拟器菜单 I/O → Audio Input 中选择输入设备,并允许“模拟器”使用 Mac 麦克风后重试"
|
||||
#else
|
||||
return "录音启动失败:未检测到麦克风输入。请检查 设置 → 隐私与安全性 → 麦克风 是否允许本 App 使用麦克风"
|
||||
#endif
|
||||
}
|
||||
|
||||
private func recordingStartFailedMessage() -> String {
|
||||
#if targetEnvironment(simulator)
|
||||
return "录音启动失败:无法开始录制。模拟器请确认 I/O → Audio Input 已选择输入设备,再重试"
|
||||
#else
|
||||
return "录音启动失败:无法开始录制。请确认麦克风未被其他应用占用后重试"
|
||||
#endif
|
||||
}
|
||||
|
||||
private func stopRecordingAndAssess() {
|
||||
guard let currentRecorder = recorder else {
|
||||
guard let currentSession = recordingSession else {
|
||||
return
|
||||
}
|
||||
let duration: TimeInterval
|
||||
do {
|
||||
try currentSession.stop()
|
||||
duration = currentSession.recordDuration
|
||||
} catch {
|
||||
testStatus = "录音结束失败:\(error.localizedDescription)"
|
||||
currentSession.cancel()
|
||||
recordingSession = nil
|
||||
isRecording = false
|
||||
restorePlaybackAudioSession()
|
||||
return
|
||||
}
|
||||
let duration = currentRecorder.currentTime
|
||||
currentRecorder.stop()
|
||||
restorePlaybackAudioSession()
|
||||
recorder = nil
|
||||
recordingSession = nil
|
||||
isRecording = false
|
||||
guard let url = recordingURL else {
|
||||
return
|
||||
}
|
||||
recordingURL = nil
|
||||
let rawURL = currentSession.rawRecordingURL
|
||||
if duration < 1.0 {
|
||||
testStatus = "录音太短或无法保存"
|
||||
try? FileManager.default.removeItem(at: url)
|
||||
try? FileManager.default.removeItem(at: rawURL)
|
||||
return
|
||||
}
|
||||
guard let sentence = controller.currentSentence else {
|
||||
testStatus = "没有可归属的句子,本次录音已丢弃"
|
||||
try? FileManager.default.removeItem(at: url)
|
||||
try? FileManager.default.removeItem(at: rawURL)
|
||||
return
|
||||
}
|
||||
if let oldURL = dubSegments[sentence.index] {
|
||||
try? FileManager.default.removeItem(at: oldURL)
|
||||
}
|
||||
if let oldRawURL = dubRawSegments[sentence.index] {
|
||||
try? FileManager.default.removeItem(at: oldRawURL)
|
||||
}
|
||||
dubSegments[sentence.index] = url
|
||||
dubRawSegments[sentence.index] = rawURL
|
||||
mergedDubURL = nil
|
||||
submitAssessment(recordingURL: url)
|
||||
}
|
||||
@@ -292,7 +334,6 @@ struct TestView: View {
|
||||
scoreSummary = "评测失败"
|
||||
}
|
||||
isAssessing = false
|
||||
try? FileManager.default.removeItem(at: url)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,8 +440,8 @@ struct TestView: View {
|
||||
}
|
||||
|
||||
private func generateDubShareAudio() {
|
||||
guard !dubSegments.isEmpty else { return }
|
||||
let segments = dubSegments.sorted { $0.key < $1.key }
|
||||
guard !dubRawSegments.isEmpty else { return }
|
||||
let segments = dubRawSegments.sorted { $0.key < $1.key }
|
||||
let outputURL = FileManager.default.temporaryDirectory
|
||||
.appendingPathComponent("dubbing-\(Int(Date().timeIntervalSince1970 * 1000)).m4a")
|
||||
isGeneratingDub = true
|
||||
|
||||
Reference in New Issue
Block a user