dmrschmidt / DSWaveformImage

Generate waveform images from audio files on iOS, macOS & visionOS in Swift. Native SwiftUI & UIKit views.
MIT License
978 stars 109 forks source link

Fatal error #69

Closed Patresko closed 1 year ago

Patresko commented 1 year ago

Im getting fatal error

Thread 1: Fatal error: 'try!' expression unexpectedly raised an error: DSWaveformImage.WaveformImageDrawer.GenerationError.generic

This is my model

func downloadVoiceMessage() {

        if let url = file?.url {
            let task = URLSession.shared.downloadTask(with: url) { downloadedURL, urlResponse, error in

                if error != nil {
                    NSLog("Downloading Voice Message Error: \(error!.localizedDescription)")
                }

                guard let downloadedURL = downloadedURL else { return }

                let cachesFolderURL = try? FileManager.default.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: false)

                let audioFileURL = cachesFolderURL!.appendingPathComponent("\(self.file?.fileName ?? "VoiceMemo")")
                   try? FileManager.default.copyItem(at: downloadedURL, to: audioFileURL)

                   DispatchQueue.main.async {
                       print("MEMO URL: \(audioFileURL)")
                       self.voiceMemoURL = audioFileURL
                   }
            }
            task.resume()
        }
    }

Inside the view Im unwraping optional

if let url = fileModel.voiceMemoURL {
                    ProgressWaveformView(audioURL: url, progress: progress, color: colorScheme == .light && msgDirection == .left ? Color(UIColor.systemGray).opacity(0.5) :.white.opacity(0.5))
                }

And this is ProgressWaveformView

import SwiftUI
import DSWaveformImage

struct ProgressWaveformView: View {

    let audioURL: URL
    let progress: Double

    @State var color: Color = .white

    private let configuration = Waveform.Configuration(
        style: .striped(.init(color: .red, width: 3, spacing: 4)),
        damping: .init(percentage: 0.125, sides: .right)
    )

    @StateObject private var waveformDrawer = WaveformImageDrawer()
    @State private var waveformImage: UIImage = UIImage()

    var body: some View {
        GeometryReader { geometry in
            ZStack {
                Image(uiImage: waveformImage)
                    .resizable()
                    .renderingMode(.template)
                    .foregroundColor(color)

                Image(uiImage: waveformImage)
                    .resizable()
                    .mask(alignment: .leading) {
                        Rectangle().frame(width: geometry.size.width * progress)
                    }
            }
            .onAppear {
                guard waveformImage.size == .zero else { return }
                update(size: geometry.size, url: audioURL, configuration: configuration)
            }
            .onChange(of: geometry.size) { update(size: $0, url: audioURL, configuration: configuration) }
            .onChange(of: audioURL) { update(size: geometry.size, url: $0, configuration: configuration) }
            .onChange(of: configuration) { update(size: geometry.size, url: audioURL, configuration: $0) }
        }
    }

    private func update(size: CGSize, url: URL, configuration: Waveform.Configuration) {
        Task(priority: .userInitiated) {
            let image = try! await waveformDrawer.waveformImage(fromAudioAt: url, with: configuration.with(size: size))
            await MainActor.run { waveformImage = image }
        }
    }
dmrschmidt commented 1 year ago

Hey @Patresko, I still need to do the error logging a bit more robust for others, but that would likely require breaking changes, so I had pushed this aside so far.

There should be debug info though in the console before you get this error. Can you look for text there starting with failed to load due to:? The part after the colon will be the localizedDescription of the original error.

My best guess is that the format of the file is not supported. What format does it have? Is it possible to share the file causing the issue here?

Patresko commented 1 year ago

Its .mp4 file

file:///var/mobile/Containers/Data/Application/6CC937DA-402D-45F2-9A74-5F0B906B7931/Library/Caches/vocalMessage_00:00_15-05-2023_92645.mp4 ERROR loading asset Error Domain=AVFoundationErrorDomain Code=-11829 "Nie je možné otvoriť" UserInfo={NSUnderlyingError=0x282827780 {Error Domain=NSOSStatusErrorDomain Code=-12848 "(null)"}, NSLocalizedFailureReason=Médium je pravdepodobne poškodené., NSURL=file:///var/mobile/Containers/Data/Application/6CC937DA-402D-45F2-9A74-5F0B906B7931/Library/Caches/vocalMessage_00:00_15-05-2023_92645.mp4, NSLocalizedDescription=Nie je možné otvoriť} DholRainbow/ProgressWaveformView.swift:52: Fatal error: 'try!' expression unexpectedly raised an error: DSWaveformImage.WaveformImageDrawer.GenerationError.generic 2023-05-16 11:59:24.478067+0200 DholRainbow[19678:6467172] DholRainbow/ProgressWaveformView.swift:52: Fatal error: 'try!' expression unexpectedly raised an error: DSWaveformImage.WaveformImageDrawer.GenerationError.generic

dmrschmidt commented 1 year ago

So there you have it. AVFoundationErrorDomain Code=-11829 "Nie je možné otvoriť" and NSLocalizedFailureReason=Médium je pravdepodobne poškodené.. These error messages are coming from iOS itself, so they are OS level messages, indicating that AVFoundation cannot read the file.

"Something" is not good with your audio file for iOS to read it. What that is I cannot tell, but the problem sits outside of the library.

Maybe you are storing the file wrong, writing it wrong, using a wrong file extension (ie if it is an mp3 but your ending declares it an mp4 file - this happened to a few people here before already that had downloaded audio from the internet, iOS's audio classes only look for file endings when trying to open them), or the file is genuinely corrupted.