Ios 尝试使用UISlider更改Swift audio应用程序中的速率时出错
我收到一个读取线程1:EX_BAD_指令的错误(代码=EXC_1386_INVOP,子代码=0x0)。具体地说,这一行,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. *
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
}
}