Ios 尝试使用UISlider更改Swift audio应用程序中的速率时出错

Ios 尝试使用UISlider更改Swift audio应用程序中的速率时出错,ios,swift,audio,avfoundation,avaudioplayer,Ios,Swift,Audio,Avfoundation,Avaudioplayer,我收到一个读取线程1:EX_BAD_指令的错误(代码=EXC_1386_INVOP,子代码=0x0)。具体地说,这一行,player.rate=sliderValue.value正在被标记 // RecorderViewController.swift import UIKit import AVFoundation /** Uses AVAudioRecorder to record a sound file and an AVAudioPlayer to play it back. *

我收到一个读取线程1:EX_BAD_指令的错误(代码=EXC_1386_INVOP,子代码=0x0)。具体地说,这一行,
player.rate=sliderValue.value
正在被标记

//  RecorderViewController.swift

import UIKit
import AVFoundation

/**
Uses AVAudioRecorder to record a sound file and an AVAudioPlayer to play it back.
*/
class RecorderViewController: UIViewController {

var recorder: AVAudioRecorder!

var player:AVAudioPlayer!

@IBOutlet var recordButton: UIButton!

@IBOutlet var stopButton: UIButton!

@IBOutlet var playButton: UIButton!

@IBOutlet var statusLabel: UILabel!

@IBOutlet weak var sliderValue: UISlider!

var meterTimer:NSTimer!

var soundFileURL:NSURL!

override func viewDidLoad() {
    super.viewDidLoad()

    stopButton.enabled = false
    playButton.enabled = false
    setSessionPlayback()
    askForNotifications()
    checkHeadphones()
}

func updateAudioMeter(timer:NSTimer) {

    if recorder.recording {
        let min = Int(recorder.currentTime / 60)
        let sec = Int(recorder.currentTime % 60)
        let s = String(format: "%02d:%02d", min, sec)
        statusLabel.text = s
        recorder.updateMeters()
        // if you want to draw some graphics...
        //var apc0 = recorder.averagePowerForChannel(0)
        //var peak0 = recorder.peakPowerForChannel(0)
    }
}


override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    recorder = nil
    player = nil
}

@IBAction func removeAll(sender: AnyObject) {
    deleteAllRecordings()
}

@IBAction func record(sender: UIButton) {

    if player != nil && player.playing {
        player.stop()
    }

    if recorder == nil {
        print("recording. recorder nil")
        recordButton.setTitle("Pause", forState:.Normal)
        playButton.enabled = false
        stopButton.enabled = true
        recordWithPermission(true)
        return
    }

    if recorder != nil && recorder.recording {
        print("pausing")
        recorder.pause()
        recordButton.setTitle("Continue", forState:.Normal)

    } else {
        print("recording")
        recordButton.setTitle("Pause", forState:.Normal)
        playButton.enabled = false
        stopButton.enabled = true
        //            recorder.record()
        recordWithPermission(false)
    }
}


@IBAction func stop(sender: UIButton) {
    print("stop")

    recorder?.stop()
    player?.stop()

    meterTimer.invalidate()

    recordButton.setTitle("Record", forState:.Normal)
    let session = AVAudioSession.sharedInstance()
    do {
        try session.setActive(false)
        playButton.enabled = true
        stopButton.enabled = false
        recordButton.enabled = true
    } catch let error as NSError {
        print("could not make session inactive")
        print(error.localizedDescription)
    }

    //recorder = nil
}

@IBAction func play(sender: UIButton) {
    setSessionPlayback()
    play()
}

func play() {

    var url:NSURL?
    if self.recorder != nil {
        url = self.recorder.url
    } else {
        url = self.soundFileURL!
    }
    print("playing \(url)")

    do {
        self.player = try AVAudioPlayer(contentsOfURL: url!)
        stopButton.enabled = true
        player.enableRate = true
        player.delegate = self
        player.prepareToPlay()
        player.volume = 1.0
        player.play()
    } catch let error as NSError {
        self.player = nil
        print(error.localizedDescription)
    }

}


@IBAction func slideChange(sender: AnyObject) {
    player.rate = sliderValue.value
}

func setupRecorder() {
    let format = NSDateFormatter()
    format.dateFormat="yyyy-MM-dd-HH-mm-ss"
    let currentFileName = "recording-\(format.stringFromDate(NSDate())).m4a"
    print(currentFileName)

    let documentsDirectory = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
     self.soundFileURL = documentsDirectory.URLByAppendingPathComponent(currentFileName)

    if NSFileManager.defaultManager().fileExistsAtPath(soundFileURL.absoluteString) {
        // probably won't happen. want to do something about it?
        print("soundfile \(soundFileURL.absoluteString) exists")
    }

    let recordSettings:[String : AnyObject] = [
        AVFormatIDKey: NSNumber(unsignedInt:kAudioFormatAppleLossless),
        AVEncoderAudioQualityKey : AVAudioQuality.Max.rawValue,
        AVEncoderBitRateKey : 320000,
        AVNumberOfChannelsKey: 2,
        AVSampleRateKey : 44100.0
    ]

    do {
        recorder = try AVAudioRecorder(URL: soundFileURL, settings: recordSettings)
        recorder.delegate = self
        recorder.meteringEnabled = true
        recorder.prepareToRecord() // creates/overwrites the file at soundFileURL
    } catch let error as NSError {
        recorder = nil
        print(error.localizedDescription)
    }

}

func recordWithPermission(setup:Bool) {
    let session:AVAudioSession = AVAudioSession.sharedInstance()
    // ios 8 and later
    if (session.respondsToSelector("requestRecordPermission:")) {
           AVAudioSession.sharedInstance().requestRecordPermission({(granted: Bool)-> Void in
            if granted {
                print("Permission to record granted")
                self.setSessionPlayAndRecord()
                if setup {
                    self.setupRecorder()
                }
                self.recorder.record()
                self.meterTimer = NSTimer.scheduledTimerWithTimeInterval(0.1,
                    target:self,
                    selector:"updateAudioMeter:",
                    userInfo:nil,
                    repeats:true)
            } else {
                print("Permission to record not granted")
            }
        })
    } else {
        print("requestRecordPermission unrecognized")
    }
}

func setSessionPlayback() {
    let session:AVAudioSession = AVAudioSession.sharedInstance()

    do {
        try session.setCategory(AVAudioSessionCategoryPlayback)
    } catch let error as NSError {
        print("could not set session category")
        print(error.localizedDescription)
    }
    do {
        try session.setActive(true)
    } catch let error as NSError {
        print("could not make session active")
        print(error.localizedDescription)
    }
}

func setSessionPlayAndRecord() {
    let session = AVAudioSession.sharedInstance()
    do {
        try session.setCategory(AVAudioSessionCategoryPlayAndRecord)
    } catch let error as NSError {
        print("could not set session category")
        print(error.localizedDescription)
    }
    do {
        try session.setActive(true)
    } catch let error as NSError {
        print("could not make session active")
        print(error.localizedDescription)
    }
}

func deleteAllRecordings() {
    let docsDir =
    NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]

    let fileManager = NSFileManager.defaultManager()

    do {
        let files = try fileManager.contentsOfDirectoryAtPath(docsDir)
        var recordings = files.filter( { (name: String) -> Bool in
            return name.hasSuffix("m4a")
        })
        for var i = 0; i < recordings.count; i++ {
            let path = docsDir + "/" + recordings[i]

            print("removing \(path)")
            do {
                try fileManager.removeItemAtPath(path)
            } catch let error as NSError {
                NSLog("could not remove \(path)")
                print(error.localizedDescription)
            }
        }

    } catch let error as NSError {
        print("could not get contents of directory at \(docsDir)")
        print(error.localizedDescription)
    }

}

func askForNotifications() {

    NSNotificationCenter.defaultCenter().addObserver(self,
        selector:"background:",
        name:UIApplicationWillResignActiveNotification,
        object:nil)

    NSNotificationCenter.defaultCenter().addObserver(self,
        selector:"foreground:",
        name:UIApplicationWillEnterForegroundNotification,
        object:nil)

    NSNotificationCenter.defaultCenter().addObserver(self,
        selector:"routeChange:",
        name:AVAudioSessionRouteChangeNotification,
        object:nil)
}

func background(notification:NSNotification) {
    print("background")
}

func foreground(notification:NSNotification) {
    print("foreground")
}


func routeChange(notification:NSNotification) {
    print("routeChange \(notification.userInfo)")

    if let userInfo = notification.userInfo {
        //print("userInfo \(userInfo)")
        if let reason = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt {
            //print("reason \(reason)")
            switch AVAudioSessionRouteChangeReason(rawValue: reason)! {
            case AVAudioSessionRouteChangeReason.NewDeviceAvailable:
                print("NewDeviceAvailable")
                print("did you plug in headphones?")
                checkHeadphones()
            case AVAudioSessionRouteChangeReason.OldDeviceUnavailable:
                print("OldDeviceUnavailable")
                print("did you unplug headphones?")
                checkHeadphones()
            case AVAudioSessionRouteChangeReason.CategoryChange:
                print("CategoryChange")
            case AVAudioSessionRouteChangeReason.Override:
                print("Override")
            case AVAudioSessionRouteChangeReason.WakeFromSleep:
                print("WakeFromSleep")
            case AVAudioSessionRouteChangeReason.Unknown:
                print("Unknown")
            case AVAudioSessionRouteChangeReason.NoSuitableRouteForCategory:
                print("NoSuitableRouteForCategory")
            case AVAudioSessionRouteChangeReason.RouteConfigurationChange:
                print("RouteConfigurationChange")

            }
        }
    }
}

func checkHeadphones() {
    // check NewDeviceAvailable and OldDeviceUnavailable for them being plugged in/unplugged
    let currentRoute = AVAudioSession.sharedInstance().currentRoute
    if currentRoute.outputs.count > 0 {
        for description in currentRoute.outputs {
            if description.portType == AVAudioSessionPortHeadphones {
                print("headphones are plugged in")
                break
            } else {
                print("headphones are unplugged")
            }
        }
    } else {
        print("checking headphones requires a connection to a device")
    }
}


@IBAction
func trim() {
    if self.soundFileURL == nil {
        print("no sound file")
        return
    }

    print("trimming \(soundFileURL!.absoluteString)")
    print("trimming path \(soundFileURL!.lastPathComponent)")
    let asset = AVAsset(URL:self.soundFileURL!)
    exportAsset(asset, fileName: "trimmed.m4a")
}

func exportAsset(asset:AVAsset, fileName:String) {
    let documentsDirectory = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
    let trimmedSoundFileURL = documentsDirectory.URLByAppendingPathComponent(fileName)
    print("saving to \(trimmedSoundFileURL.absoluteString)")



    if NSFileManager.defaultManager().fileExistsAtPath(trimmedSoundFileURL.absoluteString) {
        print("sound exists, removing \(trimmedSoundFileURL.absoluteString)")
        do {
            var error:NSError?
            if trimmedSoundFileURL.checkResourceIsReachableAndReturnError(&error) {
                print("is reachable")
            }
            if let e = error {
                print(e.localizedDescription)
            }

            try    NSFileManager.defaultManager().removeItemAtPath(trimmedSoundFileURL.absoluteString)
        } catch let error as NSError {
            NSLog("could not remove \(trimmedSoundFileURL)")
            print(error.localizedDescription)
        }

    }

    if let exporter = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A) {
        exporter.outputFileType = AVFileTypeAppleM4A
        exporter.outputURL = trimmedSoundFileURL

        let duration = CMTimeGetSeconds(asset.duration)
        if (duration < 5.0) {
            print("sound is not long enough")
            return
        }
        // e.g. the first 5 seconds
        let startTime = CMTimeMake(0, 1)
        let stopTime = CMTimeMake(5, 1)
        exporter.timeRange = CMTimeRangeFromTimeToTime(startTime, stopTime)

       // do it
        exporter.exportAsynchronouslyWithCompletionHandler({
            switch exporter.status {
            case  AVAssetExportSessionStatus.Failed:

                if let e = exporter.error {
                    print("export failed \(e)")
                    switch e.code {
                    case AVError.FileAlreadyExists.rawValue:
                        print("File Exists")
                        break
                    default: break
                    }
                } else {
                    print("export failed")
                }
            case AVAssetExportSessionStatus.Cancelled:
                print("export cancelled \(exporter.error)")
            default:
                print("export complete")
            }
        })
    }

}

@IBAction
func speed() {
    let asset = AVAsset(URL:self.soundFileURL!)
    exportSpeedAsset(asset, fileName: "trimmed.m4a")
}

func exportSpeedAsset(asset:AVAsset, fileName:String) {
    let documentsDirectory =  NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory,  inDomains: .UserDomainMask)[0]
    let trimmedSoundFileURL = documentsDirectory.URLByAppendingPathComponent(fileName)

    let filemanager = NSFileManager.defaultManager()
    if filemanager.fileExistsAtPath(trimmedSoundFileURL.absoluteString)    {
        print("sound exists")
    }

    if let exporter = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A) {
        exporter.outputFileType = AVFileTypeAppleM4A
        exporter.outputURL = trimmedSoundFileURL

        exporter.audioTimePitchAlgorithm = AVAudioTimePitchAlgorithmVarispeed




        let duration = CMTimeGetSeconds(asset.duration)
        if (duration < 5.0) {
            print("sound is not long enough")
            return
        }

        // do it
        exporter.exportAsynchronouslyWithCompletionHandler({
            switch exporter.status {
            case  AVAssetExportSessionStatus.Failed:
                print("export failed \(exporter.error)")
            case AVAssetExportSessionStatus.Cancelled:
                print("export cancelled \(exporter.error)")
            default:
                print("export complete")
            }
        })
    }
}


}

// MARK: AVAudioRecorderDelegate
extension RecorderViewController : AVAudioRecorderDelegate {

func audioRecorderDidFinishRecording(recorder: AVAudioRecorder,
    successfully flag: Bool) {
        print("finished recording \(flag)")
        stopButton.enabled = false
        playButton.enabled = true
        recordButton.setTitle("Record", forState:.Normal)

        // iOS8 and later
        let alert = UIAlertController(title: "Recorder",
            message: "Finished Recording",
            preferredStyle: .Alert)
        alert.addAction(UIAlertAction(title: "Keep", style: .Default, handler: {action in
            print("keep was tapped")
        }))
        alert.addAction(UIAlertAction(title: "Delete", style: .Default, handler: {action in
            print("delete was tapped")
            self.recorder.deleteRecording()
        }))
        self.presentViewController(alert, animated:true, completion:nil)
}

func audioRecorderEncodeErrorDidOccur(recorder: AVAudioRecorder,
    error: NSError?) {

        if let e = error {
            print("\(e.localizedDescription)")
        }
}

}

// MARK: AVAudioPlayerDelegate
extension RecorderViewController : AVAudioPlayerDelegate {
func audioPlayerDidFinishPlaying(player: AVAudioPlayer, successfully flag: Bool) {
    print("finished playing \(flag)")
    recordButton.enabled = true
    stopButton.enabled = false
}

func audioPlayerDecodeErrorDidOccur(player: AVAudioPlayer, error: NSError?) {
    if let e = error {
        print("\(e.localizedDescription)")
    }

}
}
//RecorderViewController.swift
导入UIKit
进口AVF基金会
/**
使用AVAudioRecorder录制声音文件,使用AVAudioPlayer播放。
*/
类RecorderViewController:UIViewController{
var记录器:AVAudioRecorder!
var玩家:AVAudioPlayer!
@IBVAR记录按钮:UIButton!
@IBVAR停止按钮:UIButton!
@IBVAR播放按钮:UIButton!
@IBOutlet var状态标签:UILabel!
@IBOutlet弱var sliderValue:UISlider!
var meterTimer:NSTimer!
var soundFileURL:NSURL!
重写func viewDidLoad(){
super.viewDidLoad()
stopButton.enabled=false
playButton.enabled=false
setSessionPlayback()
askForNotifications()
检查耳机()
}
func updateAudioMeter(计时器:NSTimer){
如果是录音机{
设min=Int(recorder.currentTime/60)
设秒=Int(recorder.currentTime%60)
设s=字符串(格式:“%02d:%02d”,分钟,秒)
statusLabel.text=s
recorder.updateMeters()
//如果你想画一些图形。。。
//var apc0=记录器。信道平均功率(0)
//var peak0=记录器。peakPowerForChannel(0)
}
}
重写函数didReceiveMemoryWarning(){
超级。我收到了记忆警告()
记录器=零
玩家=零
}
@iAction func removeAll(发送方:AnyObject){
deleteAllRecordings()
}
@iAction func记录(发件人:UIButton){
如果玩家!=nil&&player.playing{
player.stop()
}
如果记录器==nil{
打印(“记录。记录器无”)
recordButton.setTitle(“暂停”,状态:。正常)
playButton.enabled=false
stopButton.enabled=true
recordWithPermission(true)
返回
}
if recorder!=nil&&recorder.recording{
打印(“暂停”)
录音机暂停()
recordButton.setTitle(“继续”,状态:。正常)
}否则{
打印(“记录”)
recordButton.setTitle(“暂停”,状态:。正常)
playButton.enabled=false
stopButton.enabled=true
//录音机
recordWithPermission(false)
}
}
@iAction功能停止(发送方:UIButton){
打印(“停止”)
录音机?.stop()
玩家?.stop()
meterTimer.invalidate()
recordButton.setTitle(“记录”,用于状态:。正常)
let session=AVAudioSession.sharedInstance()
做{
try session.setActive(false)
playButton.enabled=true
stopButton.enabled=false
recordButton.enabled=true
}将let错误捕获为NSError{
打印(“无法使会话处于非活动状态”)
打印(错误。本地化描述)
}
//记录器=零
}
@iAction func播放(发送方:UIButton){
setSessionPlayback()
play()
}
func play(){
var-url:NSURL?
如果自记!=无{
url=self.recorder.url
}否则{
url=self.soundFileURL!
}
打印(“播放\(url)”)
做{
self.player=尝试AVAudioPlayer(contentsOfURL:url!)
stopButton.enabled=true
player.enableRate=true
player.delegate=self
player.prepareToPlay()
player.volume=1.0
player.play()
}将let错误捕获为NSError{
self.player=nil
打印(错误。本地化描述)
}
}
@iAction func slideChange(发件人:AnyObject){
player.rate=sliderValue.value
}
函数设置记录器(){
let format=NSDateFormatter()
format.dateFormat=“yyyy-MM-dd-HH-MM-ss”
让currentFileName=“录制-\(format.stringFromDate(NSDate())).m4a”
打印(当前文件名)
让documentsDirectory=NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory,inDomains:.UserDomainMask)[0]
self.soundFileURL=documentsDirectory.URLByAppendingPathComponent(currentFileName)
如果NSFileManager.defaultManager().fileExistsAtPath(soundFileURL.absoluteString){
//可能不会发生。想做点什么吗?
打印(“声音文件\(声音文件URL.absoluteString)存在”)
}
let recordSettings:[字符串:AnyObject]=[
AVFormatIDKey:NSNumber(未签名:kAudioFormatAppleLossless),
AVEncoderAudioQualityKey:AVAudioQuality.Max.rawValue,
AvencoderBitatekey:320000,
AVNumberOfChannelsKey:2,
AVSampleRateKey:44100.0
]
做{
recorder=尝试AVAudioRecorder(URL:soundFileURL,设置:recordSettings)
recorder.delegate=self
recorder.meteringEnabled=真
recorder.prepareToRecord()//在soundFileURL处创建/覆盖文件
}将let错误捕获为NSError{
记录器=零
打印(错误。本地化描述)
}
}
func recordWithPermission(设置:Bool){
let session:AVAudioSession=AVAudioSession.sharedInstance()
//ios 8及更高版本
if(session.respondsToSelector(“requestRecordPermission:)){
AVAudioSession.sharedInstance().requestRecordPermission({(已授予:Bool)->中的Void
如果允许的话{
打印(“已授予记录权限”)
self.setSessionPlayAndRecord()文件
如果设置{
self.setupRecorder()
}
self.recorder.record()
self.meterTimer=NSTimer.scheduledTimerWithTimeInterval(0.1,
目标:自我,
选择器:“updateAudioMeter:”,
userInfo:nil,
重复:正确)
}否则{
打印(“未授予记录权限”)
}
})
}否则{
打印(“requestRecordPermission未识别”)
}
}
func setSessionPlayback(){
let session:AVAudioSession=AVAudioSession.sharedInstance()
做{
try session.setCategory(AVAudioSessionCategoryPlayback)
@IBAction func slideChange(sender: AnyObject) {
   if(player != nil)
     {
    player.rate = sliderValue.value
     }
}