diff --git a/ListenerGS/GSConnection.swift b/ListenerGS/GSConnection.swift
index fec9795..c6c1c94 100644
--- a/ListenerGS/GSConnection.swift
+++ b/ListenerGS/GSConnection.swift
@@ -20,6 +20,7 @@ enum GSConnectionState {
case connected
case listening
case stoplistening
+ case deleting
}
extension GSConnectionState: CustomStringConvertible
@@ -36,6 +37,8 @@ extension GSConnectionState: CustomStringConvertible
return "listening"
case .stoplistening:
return "stop listening"
+ case .deleting:
+ return "deleting"
}
}
}
@@ -95,6 +98,9 @@ class GSConnection : ObservableObject {
case .stoplistening:
legalTransition = ((oldState == .connected) || (oldState == .listening))
+
+ case .deleting:
+ legalTransition = true
}
if (!legalTransition) {
@@ -182,6 +188,7 @@ class GSConnection : ObservableObject {
}
deinit {
+ changeState(newState:.deleting)
disconnect()
}
@@ -197,7 +204,10 @@ class GSConnection : ObservableObject {
waitForWriteQueue()
waitForReadQueue()
- self.changeState(newState:.disconnected)
+
+ if (state != .deleting) {
+ changeState(newState:.disconnected)
+ }
}
func stopListening() {
@@ -230,7 +240,8 @@ class GSConnection : ObservableObject {
func listen(speechForwarder: SpeechForwarderProtocol) {
textHeard = ""
lastSent = ""
- writeQueue.addOperation {
+ writeQueue.addOperation { [weak self] in
+ guard let self = self else { return }
if (!self.sendListenMsg(isListening: true)) {
self.errorOccurred(title: "Write Error", message: "Unable to send data to the GS")
return
diff --git a/ListenerGS/GSView.swift b/ListenerGS/GSView.swift
index 1c784dc..2090cdb 100644
--- a/ListenerGS/GSView.swift
+++ b/ListenerGS/GSView.swift
@@ -56,7 +56,7 @@ struct GSView: View {
.disabled(true)
.buttonStyle(GSButtonStyle())
- case .connected, .listening, .stoplistening:
+ case .connected, .listening, .stoplistening, .deleting:
Button("\(Image(systemName: "desktopcomputer.trianglebadge.exclamationmark")) Disconnect from \(ipAddress)") {
connection.disconnect()
}
@@ -66,7 +66,7 @@ struct GSView: View {
switch (connection.state)
{
- case .disconnected, .stoplistening, .connecting:
+ case .disconnected, .stoplistening, .connecting, .deleting:
Button("\(Image(systemName: "ear.and.waveform")) Listen and Send Text") {
}
.disabled(true)
diff --git a/ListenerGS/Info.plist b/ListenerGS/Info.plist
index a7357aa..15b61f5 100644
--- a/ListenerGS/Info.plist
+++ b/ListenerGS/Info.plist
@@ -19,7 +19,7 @@
CFBundleShortVersionString
1.0
CFBundleVersion
- 645
+ 759
LSApplicationCategoryType
public.app-category.utilities
LSRequiresIPhoneOS
diff --git a/ListenerGS/SpeechForwarder.swift b/ListenerGS/SpeechForwarder.swift
index 59b3035..da93e98 100644
--- a/ListenerGS/SpeechForwarder.swift
+++ b/ListenerGS/SpeechForwarder.swift
@@ -21,6 +21,8 @@ class SpeechForwarder : SpeechForwarderProtocol {
private let logger = Logger()
+ private let audioQueue = DispatchQueue.global()
+
func startListening(connection : GSConnection) -> Bool {
SFSpeechRecognizer.requestAuthorization { authStatus in
OperationQueue.main.addOperation {
@@ -71,18 +73,42 @@ class SpeechForwarder : SpeechForwarderProtocol {
try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
let inputNode = audioEngine.inputNode
- // Configure the microphone input.
- let recordingFormat = inputNode.outputFormat(forBus: 0)
- inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer: AVAudioPCMBuffer, when: AVAudioTime) in
- self.recognitionRequest?.append(buffer)
- }
-
// Create and configure the speech recognition request.
recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
guard let recognitionRequest = recognitionRequest else { fatalError("Unable to create a SFSpeechAudioBufferRecognitionRequest object") }
recognitionRequest.shouldReportPartialResults = true
recognitionRequest.requiresOnDeviceRecognition = false
+ // Configure the microphone input.
+ let inputFormat = inputNode.outputFormat(forBus: 0)
+ let speechFormat = recognitionRequest.nativeAudioFormat
+ logger.debug("Recording format \(inputFormat), speech format \(speechFormat)")
+ var formatConverter: AVAudioConverter?
+ if (!inputFormat.isEqual(speechFormat)) {
+ formatConverter = AVAudioConverter(from:inputFormat, to: speechFormat)
+ formatConverter?.downmix = true
+ }
+ inputNode.installTap(onBus: 0, bufferSize: 1024, format: inputFormat) { (buffer: AVAudioPCMBuffer, when: AVAudioTime) in
+ guard let formatConverter = formatConverter else {
+ self.recognitionRequest?.append(buffer)
+ return
+ }
+ // self.recognitionRequest?.append(buffer)
+ let pcmBuffer = AVAudioPCMBuffer(pcmFormat: speechFormat, frameCapacity: AVAudioFrameCount(Double(buffer.frameLength) * speechFormat.sampleRate / inputFormat.sampleRate))
+ var error: NSError? = nil
+
+ let inputBlock: AVAudioConverterInputBlock = {inNumPackets, outStatus in
+ outStatus.pointee = AVAudioConverterInputStatus.haveData
+ return buffer
+ }
+
+ formatConverter.convert(to: pcmBuffer!, error: &error, withInputFrom: inputBlock)
+
+ if error == nil {
+ self.recognitionRequest?.append(pcmBuffer!)
+ }
+ }
+
// Create a recognition task for the speech recognition session.
// Keep a reference to the task so that it can be canceled.
recognitionTask = speechRecognizer.recognitionTask(with: recognitionRequest) { [weak connection] result, error in
diff --git a/ListenerGSTests/ListenerGSTests.swift b/ListenerGSTests/ListenerGSTests.swift
index e43354a..6d8196e 100644
--- a/ListenerGSTests/ListenerGSTests.swift
+++ b/ListenerGSTests/ListenerGSTests.swift
@@ -364,7 +364,6 @@ class ListenerGSTests: XCTestCase {
XCTAssert(server.getDisconnect())
}
- /* This test hangs at the getDisconnect() line at the end. Something is holding a connection reference.
func testDestructWhileListening() throws {
let server = GSServerMock()
@@ -392,8 +391,9 @@ class ListenerGSTests: XCTestCase {
XCTAssert(!speechForwarder.isListening)
connection.listen(speechForwarder: speechForwarder)
- XCTAssert(server.getListenState(isListening: true))
+ connection.waitForWriteQueue()
connection.waitForMain()
+ XCTAssert(server.getListenState(isListening: true))
XCTAssert(speechForwarder.isListening)
XCTAssertEqual(connection.state, .listening)
@@ -403,7 +403,6 @@ class ListenerGSTests: XCTestCase {
XCTAssert(server.getDisconnect())
}
- */
/*
func testPerformanceExample() throws {