How can I stop the audio recording once the user stops taking? Like Siri. Once you say, Hi Siri it will respond to your voice. Means Siri app listening to the audio until you stop the taking.
I'm trying to do the same thing. If I say, Get weather details once I stop my voice. I want to trigger one method or call the API with recorded audio till is stop.
My requirement is app should continuously listen to the user find the voice end event send data to the server or just trigger a method.
Code:
import UIKit
import CoreAudio
import CoreAudioKit
import AVFoundation
import Foundation
import AVKit
class ViewController: UIViewController, AVAudioRecorderDelegate {
private var recorder : AVAudioRecorder? = nil
private var isRecording : Bool = false
private var timer : Timer? = nil
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
permissionWasGranted { (isValied) in
print("isValied")
self.isRecording = false;
self.intiateTimer()
}
}
@objc func intiateTimer() {
self.timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(self.updateTimer), userInfo: nil, repeats: true)
}
@objc func updateTimer() {
if !isRecording {
//recorder = nil
self.initRecorder()
print("Recording intiated")
}
else {
print("Recording Started")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func getDocumentsDirectory() -> URL {
let fileManager = FileManager.default
let urls = fileManager.urls(for: .documentDirectory, in: .userDomainMask)
let documentDirectory = urls.first!
return documentDirectory.appendingPathComponent("recording.m4a")
}
// MARK: protocol
func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
recorder.stop()
recorder.deleteRecording()
recorder.prepareToRecord()
isRecording = false
self.updateTimer()
}
func permissionWasGranted(result: @escaping (_: Bool)->()) {
switch AVAudioSession.sharedInstance().recordPermission() {
case AVAudioSessionRecordPermission.granted:
//if IS_DEBUG { print("Permission granted") }
print("Permission granted")
result(true)
return
case AVAudioSessionRecordPermission.denied:
//if IS_DEBUG { print("Pemission denied") }
print("Pemission denied")
case AVAudioSessionRecordPermission.undetermined:
//if IS_DEBUG { print("Request permission here") }
print("Request permission here")
AVAudioSession.sharedInstance().requestRecordPermission({ (granted) in
if granted {
result(true)
return
}
})
}
result(false)
}
func initRecorder() {
let settings = [
AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
AVSampleRateKey: 12000,
AVNumberOfChannelsKey: 1,
AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
]
do {
let session = AVAudioSession.sharedInstance()
try session.setCategory(AVAudioSessionCategoryPlayAndRecord)
try session.overrideOutputAudioPort(AVAudioSessionPortOverride.speaker)
try session.setActive(true)
try recorder = AVAudioRecorder(url: getDocumentsDirectory(), settings: settings)
recorder!.delegate = self
recorder!.isMeteringEnabled = true
if !recorder!.prepareToRecord() {
print("Error: AVAudioRecorder prepareToRecord failed")
}
let decibels = self.getDispersyPercent()
if decibels > -120 && decibels < -20 {
self.timer?.invalidate()
isRecording = true;
self.start()
}
} catch {
print("Error: AVAudioRecorder creation failed")
}
}
func start() {
recorder?.record()
recorder?.updateMeters()
}
func update() {
if let recorder = recorder {
recorder.updateMeters()
}
}
func getDispersyPercent() -> Float {
if let recorder = recorder {
let decibels = recorder.averagePower(forChannel: 0)
return decibels
}
return 0
}
}
here I Have created my function that will actually detect silence for 5 seconds and if condition is satisfied you can stop recording that time
-- I had used Recording Manager NSObject class so you can get the code from below function and manage to use it in yours
Code
//StartNewRecordingIfSilenceFor5Second
func newSessionIfSilence(){
//get Audio file name to store
let AudioFileName = getDocumentsDirectory().appendingPathComponent("\(getUniqueName()).wav")
//Declare a value that will be updated when silence is detected
var statusForDetection = Float()
//Recorder Settings used
let settings: [String: Any] = [
AVFormatIDKey: Int(kAudioFormatLinearPCM),
AVSampleRateKey: 16000,
AVNumberOfChannelsKey: 1,
AVLinearPCMBitDepthKey: 16,
AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue,
AVLinearPCMIsBigEndianKey: false,
AVLinearPCMIsFloatKey: false,
]
//Try block
do {
//Start Recording With Audio File name
Manager.recorder = try AVAudioRecorder(url: AudioFileName, settings: settings)
Manager.recorder?.delegate = self
Manager.recorder?.isMeteringEnabled = true
Manager.recorder?.prepareToRecord()
Manager.recorder?.record()
//Tracking Metering values here only
Manager.meterTimer = Timer.scheduledTimer(withTimeInterval: 0.10, repeats: true, block: { (timer: Timer) in
//Update Recording Meter Values so we can track voice loudness
//Getting Recorder from another class
//i managed my recorder from Manager class
if let recorder = Manager.recorder
{
//Start Metering Updates
recorder.updateMeters()
//Get peak values
Manager.recorderApc0 = recorder.averagePower(forChannel: 0)
Manager.recorderPeak0 = recorder.peakPower(forChannel: 0)
//it’s converted to a 0-1 scale, where zero is complete quiet and one is full volume.
let ALPHA: Double = 0.05
let peakPowerForChannel = pow(Double(10), (0.05 * Double(Manager.recorderPeak0)))
// static var lowPassResults: Double = 0.0
RecordingManager.lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * RecordingManager.lowPassResults
if(RecordingManager.lowPassResults > 0){
print("Mic blow detected")
//Do what you wanted to do here
//if blow is detected update silence value as zero
statusForDetection = 0.0
}
else
{
//Update Value for Status is blow being detected or not
//As timer is called at interval of 0.10 i.e 0.1 So add value each time in silence Value with 0.1
statusForDetection += 0.1
//if blow is not Detected for 5 seconds
if statusForDetection > 5.0 {
//Update value to zero
//When value of silence is greater than 5 Seconds
//Time to Stop recording
statusForDetection = 0.0
//Stop Audio recording
recorder.stop()
}
}
}
})
} catch {
//Finish Recording with a Error
print("Error Handling: \(error.localizedDescription)")
self.finishRecording(success: false)
}
}