You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中播放部分音频文件报错,求兼容3GP等格式的解决方案

Hey there! Let's break down what's happening and fix this audio playback issue with 3GP files in Swift.

The error you're seeing (NSOSStatusErrorDomain Code=2003334207) translates to kAudioFileUnsupportedDataFormatError — this means AVAudioPlayer doesn't natively support 3GP audio containers (or their underlying codecs). AVAudioPlayer has limited format support focused on common consumer formats like MP3, M4A, WAV, etc., so we need to adjust our approach to handle 3GP and other unsupported formats.

Here are two solid solutions depending on your needs:

Solution 1: Switch to AVPlayer (Simplest Fix)

AVPlayer (from the AVFoundation framework) supports a much wider range of media formats, including 3GP, because it leverages Apple's full media playback stack. This is the quickest way to get 3GP files playing without extra work.

Here's how to refactor your function to use AVPlayer:

func setAVPlayer() {
    // Safely unwrap the filename to avoid force unwraps
    guard let fileName = URL(string: audioFilename)?.lastPathComponent else {
        print("Invalid audio filename provided")
        return
    }
    
    let baseURL = URL(fileURLWithPath: myPath)
    let audioFileURL = baseURL.appendingPathComponent(fileName)
    let filePath = audioFileURL.path
    
    let fileManager = FileManager.default
    guard fileManager.fileExists(atPath: filePath) else {
        print("Audio file not found at path: \(filePath)")
        return
    }
    
    // Initialize AVPlayer with the file URL
    let player = AVPlayer(url: audioFileURL)
    // Update your array to hold AVPlayer instances (adjust the array type to [AVPlayer?])
    ChannelViewController.audioPlayerArrayList[indexPathRow] = player
}

Note: You'll need to update your audioPlayerArrayList to be an array of AVPlayer? instead of AVAudioPlayer?. To play the audio, call player.play() instead of the AVAudioPlayer play method.

Solution 2: Transcode Unsupported Formats (If You Must Use AVAudioPlayer)

If you have a hard requirement to stick with AVAudioPlayer, we can add logic to transcode unsupported files (like 3GP) to a compatible format (e.g., M4A) before initializing the player.

First, add a helper function to handle transcoding:

// Helper to transcode audio to M4A (a format AVAudioPlayer supports)
func transcodeAudio(at sourceURL: URL, to destinationURL: URL, completion: @escaping (Bool, Error?) -> Void) {
    let audioAsset = AVAsset(url: sourceURL)
    
    // Create an export session for M4A output
    guard let exportSession = AVAssetExportSession(asset: audioAsset, presetName: AVAssetExportPresetAppleM4A) else {
        let error = NSError(domain: "TranscodingError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to create export session"])
        completion(false, error)
        return
    }
    
    exportSession.outputURL = destinationURL
    exportSession.outputFileType = .m4a
    
    exportSession.exportAsynchronously {
        switch exportSession.status {
        case .completed:
            completion(true, nil)
        case .failed, .cancelled:
            completion(false, exportSession.error)
        default:
            let error = NSError(domain: "TranscodingError", code: -2, userInfo: [NSLocalizedDescriptionKey: "Unknown export failure"])
            completion(false, error)
        }
    }
}

Then update your original function to check for supported formats and transcode when needed:

func setAVAudioPlayer() {
    guard let fileName = URL(string: audioFilename)?.lastPathComponent else {
        print("Invalid audio filename")
        return
    }
    
    let baseURL = URL(fileURLWithPath: myPath)
    let sourceFileURL = baseURL.appendingPathComponent(fileName)
    let filePath = sourceFileURL.path
    
    let fileManager = FileManager.default
    guard fileManager.fileExists(atPath: filePath) else {
        print("Audio file does not exist at path: \(filePath)")
        return
    }
    
    // Check if the file format is natively supported by AVAudioPlayer
    let supportedExtensions = AVAudioPlayer.audioFileTypes()
    let fileExtension = sourceFileURL.pathExtension.lowercased()
    
    if supportedExtensions.contains(fileExtension) {
        // Load directly with AVAudioPlayer
        do {
            let player = try AVAudioPlayer(contentsOf: sourceFileURL)
            ChannelViewController.audioPlayerArrayList[indexPathRow] = player
        } catch {
            print("Error loading audio file:")
            print(error)
        }
    } else {
        // Transcode to M4A first
        let transcodedFileName = "\(sourceFileURL.deletingPathExtension().lastPathComponent).m4a"
        let transcodedFileURL = baseURL.appendingPathComponent(transcodedFileName)
        
        transcodeAudio(at: sourceFileURL, to: transcodedFileURL) { [weak self] success, error in
            guard let self = self else { return }
            
            if success {
                do {
                    let player = try AVAudioPlayer(contentsOf: transcodedFileURL)
                    ChannelViewController.audioPlayerArrayList[self.indexPathRow] = player
                } catch {
                    print("Error loading transcoded audio file:")
                    print(error)
                }
            } else {
                print("Transcoding failed: \(error?.localizedDescription ?? "Unknown error")")
            }
        }
    }
}

Pro Tip: Add caching logic to avoid re-transcoding the same file every time — you can check if the transcoded file exists before starting the transcode process.

内容的提问来源于stack exchange,提问作者Maryam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:35:01