Как записать аудиопоток для сохранения его в файл / swift 4.2 - PullRequest
0 голосов
/ 15 января 2019

Я создаю радио-приложение для iPhone (написано в Swift 4.2) и хочу добавить функцию, позволяющую мне записывать и сохранять в файл звук, воспроизводимый моим радио (считываемым с AVPlayer), когда я нажимаю кнопка. Какой код я должен использовать?

Код в Swift 4.2, с Xcode 10.1. Я ищу в Интернете: «Как записать аудиопоток swift 4.2», «Как записать звук с AVPlayer swift 4.2», но я не могу найти ответ.

Мой код:

import UIKit
import AVFoundation
import MediaPlayer

class ViewControllerPlayer: UIViewController { 

    var URl = "http://link_of_audio_stream"
    var player:AVPlayer?
    var playerItem:AVPlayerItem?
    var playerLayer:AVPlayerLayer?

    override func viewDidLoad() {
        super.viewDidLoad()

        let url = URL(string: URl)
        let playerItem1:AVPlayerItem = AVPlayerItem(url: url!)
        player = AVPlayer(playerItem: playerItem1)

    }

    @IBAction func Play(_ sender: Any) {
            player?.play()
    }
    @IBAction func Pause(_ sender: Any) {
            player?.pause()
    }
private var audioRecorder: AVAudioRecorder!

    func startRecording() throws {
        guard let newFileURL = createURLForNewRecord() else {
            throw RecordingServiceError.canNotCreatePath
        }
        do {
            var urlString = URL(string: URl)
            urlString = newFileURL
            audioRecorder = try AVAudioRecorder(url: newFileURL,
                                                settings: [AVFormatIDKey:Int(kAudioFormatMPEG4AAC),
                                                           AVSampleRateKey: 8000,
                                                           AVNumberOfChannelsKey: 1,
                                                           AVEncoderAudioQualityKey: AVAudioQuality.min.rawValue])
            audioRecorder.delegate = self as? AVAudioRecorderDelegate
            audioRecorder.prepareToRecord()

            audioRecorder.record(forDuration: TimeConstants.recordDuration) 
            //error: Use of unresolved identifier 'TimeConstants'

        } catch let error {
            print(error)
        }
    }

    func STOPREC1() throws {
        audioRecorder.stop()
        audioRecorder = nil
            print("Recording finished successfully.")
    }

    enum RecordingServiceError: String, Error {
        case canNotCreatePath = "Can not create path for new recording"
    }

    private func createURLForNewRecord() -> URL? {
        guard let appGroupFolderUrl = FileManager.getAppFolderURL() else {
            return nil
        }

        let date = String(describing: Date())
        let fullFileName = "Enregistrement radio " + date + ".m4a"
        let newRecordFileName = appGroupFolderUrl.appendingPathComponent(fullFileName)
        return newRecordFileName
    }
}
    extension FileManager {
        class func getAppFolderURL() -> URL? {
            let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
            let documentsDirectory = paths[0]
            return documentsDirectory
        }
    }

Ответы [ 2 ]

0 голосов
/ 18 марта 2019

Мне было очень тяжело с этим, поэтому я отправляю ответ.

Не забудьте добавить эти строки в ваш info.plist:

enter image description here

Вот мой контроллер, который записывает голосовой ввод и возвращает его на предыдущий контроллер:

import Foundation
import UIKit
import Speech

class SpeechToTextViewController: UIViewController {

@IBOutlet weak var animationView: UIView!
@IBOutlet weak var circleView: UIView!
@IBOutlet weak var micImage: UIImageView!
@IBOutlet weak var listeningLabel: UILabel!
@IBOutlet weak var buttonStartView: UIView!
@IBOutlet weak var cancelRecordingButton: UIButton!
@IBOutlet weak var stopRecordingButton: UIButton!
@IBOutlet weak var startRecordingButton: UIButton!

private let audioEngine = AVAudioEngine()
private let speechRecognizer = SFSpeechRecognizer(locale: Locale.init(identifier:"en-US"))
private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest!
private var recognitionTask: SFSpeechRecognitionTask?
private var isRecording: Bool = false

var delegate: SpeechToTextViewDelegate?

override func viewDidLoad() {
    super.viewDidLoad()
    self.view.backgroundColor = UIColor(white: 1.0, alpha: 0.25)
    self.stopRecordingButton.isHidden = true
    self.listeningLabel.isHidden = true
}

@IBAction func startStopRecording(_ sender: Any) {
    isRecording = !isRecording
    if isRecording && !audioEngine.isRunning {
        self.cancelRecordingButton.isHidden = true
        self.startRecordingButton.isHidden = true
        self.stopRecordingButton.isHidden = false
        self.listeningLabel.isHidden = false
        UIView.animate(withDuration: 1, animations: {}) { _ in
            UIView.animate(withDuration: 1, delay: 0.25, options: [.autoreverse, .repeat], animations: {
                self.circleView.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
            })
        }
        do {
            try recordSpeech()
        } catch {
            print(error)
        }
    } else {
        self.listeningLabel.isHidden = true
        stopRecording()
    }
}

func recordSpeech() throws {
    recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
    let node = audioEngine.inputNode
    let recordingFormat = node.outputFormat(forBus: 0)
    node.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) {buffer, _ in
        self.recognitionRequest.append(buffer)
    }
    audioEngine.prepare()
    try audioEngine.start()
    guard let myRecognizer = SFSpeechRecognizer() else {
        print("myRecognizer is unable to be created")
        return
    }
    if !myRecognizer.isAvailable
    {
        print("myRecognizer is not available")
        return
    }
    recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest, resultHandler: { result, error in
        var isFinal = false
        if let result = result
        {
            isFinal = result.isFinal
            self.delegate?.appendMessage(result.bestTranscription.formattedString)
        }
        if error != nil || isFinal {
            if error != nil {
                print("error trying to capture speech to text")
                print(error!)
            }
            self.stopRecording()
        }
    })
}

func stopRecording() {
    if audioEngine.isRunning {
        self.audioEngine.stop()
        self.recognitionRequest.endAudio()
        // Cancel the previous task if it's running
        if let recognitionTask = recognitionTask {
            recognitionTask.cancel()
            self.recognitionTask = nil
        }
    }
    delegate?.doneTalking()
    self.dismiss(animated: true, completion: nil)
}

@IBAction func cancelRecording(_ sender: Any) {
    delegate?.doneTalking()
    self.dismiss(animated: true, completion: nil)
}

}

0 голосов
/ 16 января 2019

Используйте AVAudioRecorder для записи:

private var audioRecorder: AVAudioRecorder!

После того, как вы объявили диктофон, вы можете написать метод записи:

func startRecording() throws {
        guard let newFileURL = createURLForNewRecord() else {
            throw RecordingServiceError.canNotCreatePath
        }
        do {
            currentFileURL = newFileURL
            audioRecorder = try AVAudioRecorder(url: newFileURL,
                                                settings: [AVFormatIDKey:Int(kAudioFormatMPEG4AAC),
                                                           AVSampleRateKey: 8000,
                                                           AVNumberOfChannelsKey: 1,
                                                           AVEncoderAudioQualityKey: AVAudioQuality.min.rawValue])
            audioRecorder.delegate = self
            audioRecorder.prepareToRecord()
            audioRecorder.record(forDuration: TimeConstants.recordDuration)
        } catch let error {
            print(error)
        }
}

И использовать некоторые вспомогательные методы и структуры:

enum RecordingServiceError: String, Error {
    case canNotCreatePath = "Can not create path for new recording"
}

private func createURLForNewRecord() -> URL? {
        guard let appGroupFolderUrl = FileManager.getAppFolderURL() else {
            return nil
        }

        let fileNamePrefix = DateFormatter.stringFromDate(Date())
        let fullFileName = "Record_" + fileNamePrefix + ".m4a"
        let newRecordFileName = appGroupFolderUrl.appendingPathComponent(fullFileName)
        return newRecordFileName
}

extension FileManager {
    class func getAppFolderURL() -> URL? {
        return FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "you app bundle")
    }
}
...