diff --git a/iOS/Ringo/Ringo.xcodeproj/project.pbxproj b/iOS/Ringo/Ringo.xcodeproj/project.pbxproj index af83d33..d7e6cc8 100644 --- a/iOS/Ringo/Ringo.xcodeproj/project.pbxproj +++ b/iOS/Ringo/Ringo.xcodeproj/project.pbxproj @@ -23,6 +23,7 @@ 9410C9402C87067A00B006A7 /* VideoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9410C93F2C87067A00B006A7 /* VideoViewController.swift */; }; 9410C9442C90468E00B006A7 /* CallingBell.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 9410C9432C90468E00B006A7 /* CallingBell.mp3 */; }; 9410C9462C90580800B006A7 /* Canvas.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9410C9452C90580800B006A7 /* Canvas.swift */; }; + 9410C9482C9934BA00B006A7 /* STT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9410C9472C9934BA00B006A7 /* STT.swift */; }; 941C657E2C69D5BB002BA61E /* ConnectingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 941C657D2C69D5BB002BA61E /* ConnectingView.swift */; }; 94470A8A2B71050700F0A942 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 94470A892B71050700F0A942 /* Alamofire */; }; 94470A8D2B710A3100F0A942 /* Starscream in Frameworks */ = {isa = PBXBuildFile; productRef = 94470A8C2B710A3100F0A942 /* Starscream */; }; @@ -71,6 +72,7 @@ 9410C93F2C87067A00B006A7 /* VideoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoViewController.swift; sourceTree = ""; }; 9410C9432C90468E00B006A7 /* CallingBell.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = CallingBell.mp3; sourceTree = ""; }; 9410C9452C90580800B006A7 /* Canvas.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Canvas.swift; sourceTree = ""; }; + 9410C9472C9934BA00B006A7 /* STT.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = STT.swift; sourceTree = ""; }; 941C657D2C69D5BB002BA61E /* ConnectingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectingView.swift; sourceTree = ""; }; 94470A922B7163E900F0A942 /* Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = ""; }; 94470A942B71680100F0A942 /* SigninService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SigninService.swift; sourceTree = ""; }; @@ -228,6 +230,7 @@ 94470A942B71680100F0A942 /* SigninService.swift */, 940C25652B74EF4D00E069D0 /* FriendService.swift */, 94FB0A6C2BAAD64A005A4915 /* TTS.swift */, + 9410C9472C9934BA00B006A7 /* STT.swift */, 9410C9452C90580800B006A7 /* Canvas.swift */, 945CF9832B67E1CE00396E4E /* Assets.xcassets */, 945CF9852B67E1CE00396E4E /* LaunchScreen.storyboard */, @@ -351,6 +354,7 @@ 94FB0A6B2B858F66005A4915 /* STTViewController.swift in Sources */, 945603232B6D31D9002F4B33 /* ContactsTableViewCell.swift in Sources */, 945CF97D2B67E1CD00396E4E /* SceneDelegate.swift in Sources */, + 9410C9482C9934BA00B006A7 /* STT.swift in Sources */, 9410C9402C87067A00B006A7 /* VideoViewController.swift in Sources */, 94C3E5432C351A6A00EBF588 /* UserManager.swift in Sources */, 94470A932B7163E900F0A942 /* Model.swift in Sources */, @@ -525,7 +529,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.1; + MARKETING_VERSION = 1.0.3; PRODUCT_BUNDLE_IDENTIFIER = com.tukcomCD2024.Ringo; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -560,7 +564,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.1; + MARKETING_VERSION = 1.0.3; PRODUCT_BUNDLE_IDENTIFIER = com.tukcomCD2024.Ringo; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/iOS/Ringo/Ringo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/iOS/Ringo/Ringo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index d43db56..29f8c1f 100644 --- a/iOS/Ringo/Ringo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/iOS/Ringo/Ringo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -6,8 +6,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/Alamofire/Alamofire.git", "state" : { - "revision" : "3dc6a42c7727c49bf26508e29b0a0b35f9c7e1ad", - "version" : "5.8.1" + "revision" : "f455c2975872ccd2d9c81594c658af65716e9b9a", + "version" : "5.9.1" } }, { @@ -15,8 +15,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/SnapKit/SnapKit.git", "state" : { - "revision" : "e74fe2a978d1216c3602b129447c7301573cc2d8", - "version" : "5.7.0" + "revision" : "2842e6e84e82eb9a8dac0100ca90d9444b0307f4", + "version" : "5.7.1" } }, { @@ -24,8 +24,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/daltoniam/Starscream.git", "state" : { - "revision" : "ac6c0fc9da221873e01bd1a0d4818498a71eef33", - "version" : "4.0.6" + "revision" : "c6bfd1af48efcc9a9ad203665db12375ba6b145a", + "version" : "4.0.8" } }, { diff --git a/iOS/Ringo/Ringo.xcodeproj/project.xcworkspace/xcuserdata/jinhyuk.xcuserdatad/UserInterfaceState.xcuserstate b/iOS/Ringo/Ringo.xcodeproj/project.xcworkspace/xcuserdata/jinhyuk.xcuserdatad/UserInterfaceState.xcuserstate index 8651790..bf4853d 100644 Binary files a/iOS/Ringo/Ringo.xcodeproj/project.xcworkspace/xcuserdata/jinhyuk.xcuserdatad/UserInterfaceState.xcuserstate and b/iOS/Ringo/Ringo.xcodeproj/project.xcworkspace/xcuserdata/jinhyuk.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/iOS/Ringo/Ringo/FriendService.swift b/iOS/Ringo/Ringo/FriendService.swift index c269c0c..ee0531c 100644 --- a/iOS/Ringo/Ringo/FriendService.swift +++ b/iOS/Ringo/Ringo/FriendService.swift @@ -16,7 +16,8 @@ class FriendService { func loadFriendsList(email: String, completion: @escaping(NetworkResult) -> Void) { - let url = "https://4kringo.shop:8080/friendship/findByUserIdAndStatusOrFriendIdAndStatus" +// let url = "https://4kringo.shop:8080/friendship/findByUserIdAndStatusOrFriendIdAndStatus" + let url = "http://192.168.21.187:7800/friendship/findByUserIdAndStatusOrFriendIdAndStatus" let header : HTTPHeaders = [ "Content-Type" : "application/json" @@ -48,7 +49,8 @@ class FriendService { } func loadRequestList(email: String, completion: @escaping(NetworkResult) -> Void) { - let url = "https://4kringo.shop:8080/friendship/findByFriendIdAndStatus" +// let url = "https://4kringo.shop:8080/friendship/findByFriendIdAndStatus" + let url = "http://192.168.21.187:7800/friendship/findByFriendIdAndStatus" let header : HTTPHeaders = [ "Content-Type" : "application/json" @@ -95,7 +97,8 @@ class FriendService { func sendFriendRequest(sender: String, receiver: String, completion: @escaping(NetworkResult) -> Void) { - let url = "https://4kringo.shop:8080/friendship/sendFriendRequest" +// let url = "https://4kringo.shop:8080/friendship/sendFriendRequest" + let url = "http://192.168.21.187:7800/friendship/sendFriendRequest" let header : HTTPHeaders = ["Content-Type" : "application/json"] let body : Parameters = [ @@ -127,7 +130,8 @@ class FriendService { } func acceptRequest(sender: String, receiver: String, completion: @escaping(NetworkResult) -> Void) { - let url = "https://4kringo.shop:8080/friendship/acceptFriendRequestById" +// let url = "https://4kringo.shop:8080/friendship/acceptFriendRequestById" + let url = "http://192.168.21.187:7800/friendship/acceptFriendRequestById" let header : HTTPHeaders = ["Content-Type" : "application/json"] let body : Parameters = [ @@ -159,7 +163,8 @@ class FriendService { } func rejectRequest(sender: String, receiver: String, completion: @escaping(NetworkResult) -> Void) { - let url = "https://4kringo.shop:8080/friendship/rejectFriendRequestById" +// let url = "https://4kringo.shop:8080/friendship/rejectFriendRequestById" + let url = "http://192.168.21.187:7800/friendship/rejectFriendRequestById" let header : HTTPHeaders = ["Content-Type" : "application/json"] let body : Parameters = [ diff --git a/iOS/Ringo/Ringo/STT.swift b/iOS/Ringo/Ringo/STT.swift new file mode 100644 index 0000000..43a2c99 --- /dev/null +++ b/iOS/Ringo/Ringo/STT.swift @@ -0,0 +1,125 @@ +// +// STT.swift +// Ringo +// +// Created by 강진혁 on 9/17/24. +// + +import Foundation +import Speech + +class STT { + + static let shared = STT(language: "en") + + private var speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "en"))! + + private var recognitionRequest: SFSpeechAudioBufferRecognitionRequest? + + private var recognitionTask: SFSpeechRecognitionTask? + + private let audioEngine = AVAudioEngine() + + init(language: String) { + self.speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: language))! + self.recognitionRequest = nil + self.recognitionTask = nil + } + + private func startRecording() throws { + + // Cancel the previous task if it's running. + if let recognitionTask = recognitionTask { + recognitionTask.cancel() + self.recognitionTask = nil + } + + // Configure the audio session for the app. + let audioSession = AVAudioSession.sharedInstance() + try audioSession.setCategory(.playAndRecord, mode: .measurement, options: .mixWithOthers) + try audioSession.setActive(true, options: .notifyOthersOnDeactivation) + let inputNode = audioEngine.inputNode + + // Create and configure the speech recognition request. + recognitionRequest = SFSpeechAudioBufferRecognitionRequest() + guard let recognitionRequest = recognitionRequest else { fatalError("Unable to created a SFSpeechAudioBufferRecognitionRequest object") } + recognitionRequest.shouldReportPartialResults = true + + // Keep speech recognition data on device + if #available(iOS 13, *) { + recognitionRequest.requiresOnDeviceRecognition = true + } + + // 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) { result, error in + var isFinal = false + + if let result = result { + // Update the text view with the results. + // self.textView2.text = result.bestTranscription.formattedString + isFinal = result.isFinal + debugPrint(result.bestTranscription.formattedString) + if result.speechRecognitionMetadata != nil { + var message = Message(type: .stt_message, name: UserManager.getData(type: String.self, forKey: .email)!, target: UserManager.getData(type: String.self, forKey: .receiver)!) + message.data = .response(result.bestTranscription.formattedString) + CallService.shared.signalClient.send(message: message) + debugPrint("send trans msg") + } + } + + if error != nil || isFinal { + // Stop recognizing speech if there is a problem. + self.audioEngine.stop() + inputNode.removeTap(onBus: 0) + + self.recognitionRequest = nil + self.recognitionTask = nil + } + } + + // 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) + } + + audioEngine.prepare() + try audioEngine.start() + } + + private func stopRecording() { +// let inputNode = audioEngine.inputNode +// audioEngine.stop() + recognitionRequest?.endAudio() +// inputNode.removeTap(onBus: 0) + } + + func start() { + SFSpeechRecognizer.requestAuthorization { authStatus in + switch authStatus{ + case.authorized: + do { + try self.startRecording() + debugPrint("Translate start") + } catch { + debugPrint("Recognition Not Available") + } + case.denied: + debugPrint("User denied access to speech recognition") + case.restricted: + debugPrint("Speech recognition restricted on this device") + case.notDetermined: + debugPrint("Speech recognition not yet authorized") + default: + break + } + } + } + func stop() { + stopRecording() + } + func reinit(language: String) { + self.speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: language))! + } +} diff --git a/iOS/Ringo/Ringo/Screens/ConnectionViewController.swift b/iOS/Ringo/Ringo/Screens/ConnectionViewController.swift index 83e7847..85d9243 100644 --- a/iOS/Ringo/Ringo/Screens/ConnectionViewController.swift +++ b/iOS/Ringo/Ringo/Screens/ConnectionViewController.swift @@ -155,24 +155,22 @@ class ConnectionViewController: UIViewController { } @objc func pressedMuteBtn() { + muteBtn.isSelected.toggle() switch self.muteBtn.state { case .selected: - muteBtn.isSelected.toggle() - CallService.shared.webRTCClient.unmuteAudio() - default: - muteBtn.isSelected.toggle() CallService.shared.webRTCClient.muteAudio() + default: + CallService.shared.webRTCClient.unmuteAudio() } } @objc func pressedSpeakerBtn() { + speakerBtn.isSelected.toggle() switch self.speakerBtn.state { case .selected: - speakerBtn.isSelected.toggle() - CallService.shared.webRTCClient.speakerOff() - default: - speakerBtn.isSelected.toggle() CallService.shared.webRTCClient.speakerOn() + default: + CallService.shared.webRTCClient.speakerOff() } } @@ -182,6 +180,16 @@ class ConnectionViewController: UIViewController { } @objc func pressedTransBtn() { +// switch self.translateBtn.state { +// case .selected: +// translateBtn.isSelected.toggle() +// debugPrint("stt stop") +// stt.stop() +// default: +// translateBtn.isSelected.toggle() +// debugPrint("stt start") +// stt.start() +// } let sttVC = STTViewController.shared sttVC.reinit(lang: UserManager.getData(type: String.self, forKey: .language)!, callerName: Names.first!) sttVC.modalPresentationStyle = .fullScreen diff --git a/iOS/Ringo/Ringo/Screens/STTViewController.swift b/iOS/Ringo/Ringo/Screens/STTViewController.swift index 79aa950..3e855b3 100644 --- a/iOS/Ringo/Ringo/Screens/STTViewController.swift +++ b/iOS/Ringo/Ringo/Screens/STTViewController.swift @@ -124,9 +124,9 @@ class STTViewController: UIViewController, SFSpeechRecognizerDelegate { DispatchQueue.global().async { do { try self.startRecording() - self.textView2.text = "Translate start" + debugPrint("Translate start") } catch { - self.textView2.text = "Recognition Not Available" + debugPrint("Recognition Not Available") } } case .denied: @@ -213,10 +213,6 @@ class STTViewController: UIViewController, SFSpeechRecognizerDelegate { audioEngine.prepare() try audioEngine.start() - - // Let the user know to start talking. - textView.text = "..." - textView2.text = "..." } // MARK: SFSpeechRecognizerDelegate diff --git a/iOS/Ringo/Ringo/SigninService.swift b/iOS/Ringo/Ringo/SigninService.swift index 33b90fd..12450e8 100644 --- a/iOS/Ringo/Ringo/SigninService.swift +++ b/iOS/Ringo/Ringo/SigninService.swift @@ -17,7 +17,8 @@ class SigninSercive { func login(email: String, password: String, completion: @escaping(NetworkResult) -> Void) { - let url = "https://4kringo.shop:8080/member/login" //통신할 API 주소 +// let url = "https://4kringo.shop:8080/member/login" //통신할 API 주소 + let url = "http://192.168.21.187:7800/member/login" //통신할 API 주소 //HTTP Headers : 요청 헤더 let header : HTTPHeaders = ["Content-Type" : "application/json"] @@ -61,7 +62,8 @@ class SigninSercive { func refresh(token: String, completion: @escaping(NetworkResult) -> Void) { - let url = "https://4kringo.shop:8080/member/reissue" //통신할 API 주소 +// let url = "https://4kringo.shop:8080/member/reissue" //통신할 API 주소 + let url = "http://192.168.21.187:7800/member/reissue" //통신할 API 주소 //HTTP Headers : 요청 헤더 let header : HTTPHeaders = [ @@ -109,7 +111,8 @@ class SigninSercive { func signup(email: String, password: String, name: String, languageCode: String, completion: @escaping(NetworkResult) -> Void) { - let url = "https://4kringo.shop:8080/member/signup" //통신할 API 주소 +// let url = "https://4kringo.shop:8080/member/signup" //통신할 API 주소 + let url = "http://192.168.21.187:7800/member/signup" //통신할 API 주소 //HTTP Headers : 요청 헤더 let header : HTTPHeaders = ["Content-Type" : "application/json"] @@ -149,7 +152,8 @@ class SigninSercive { func signout(refreshToken: String, completion: @escaping(NetworkResult) -> Void) { - let url = "https://4kringo.shop:8080/member/logout" //통신할 API 주소 +// let url = "https://4kringo.shop:8080/member/logout" //통신할 API 주소 + let url = "http://192.168.21.187:7800/member/logout" //통신할 API 주소 //HTTP Headers : 요청 헤더 let header : HTTPHeaders = [ @@ -185,7 +189,8 @@ class SigninSercive { func update(email: String, password: String, newPassword: String, name: String, languageCode: String, completion: @escaping(NetworkResult) -> Void) { - let url = "https://4kringo.shop:8080/member/update" //통신할 API 주소 +// let url = "https://4kringo.shop:8080/member/update" //통신할 API 주소 + let url = "http://192.168.21.187:7800/member/update" //통신할 API 주소 //HTTP Headers : 요청 헤더 let header : HTTPHeaders = ["Content-Type" : "application/json"] @@ -227,7 +232,8 @@ class SigninSercive { func delete(email: String, password: String, completion: @escaping(NetworkResult) -> Void) { - let url = "https://4kringo.shop:8080/member/delete" //통신할 API 주소 +// let url = "https://4kringo.shop:8080/member/delete" //통신할 API 주소 + let url = "http://192.168.21.187:7800/member/delete" //통신할 API 주소 //HTTP Headers : 요청 헤더 let header : HTTPHeaders = ["Content-Type" : "application/json"] diff --git a/iOS/Ringo/Ringo/WebRTC/Config.swift b/iOS/Ringo/Ringo/WebRTC/Config.swift index de4ba4c..b5dac07 100644 --- a/iOS/Ringo/Ringo/WebRTC/Config.swift +++ b/iOS/Ringo/Ringo/WebRTC/Config.swift @@ -10,9 +10,9 @@ import Foundation import WebRTC // Set this to the machine's address which runs the signaling server. Do not use 'localhost' or '127.0.0.1' -//fileprivate let defaultSignalingServerUrl = URL(string: "ws://localhost:8080/signal")! +fileprivate let defaultSignalingServerUrl = URL(string: "ws://192.168.21.187:7800/signal")! //fileprivate let defaultSignalingServerUrl = URL(string: "ws://192.168.0.7:7080/signal")! -fileprivate let defaultSignalingServerUrl = URL(string: "wss://4kringo.shop:8080/signal")! +//fileprivate let defaultSignalingServerUrl = URL(string: "wss://4kringo.shop:8080/signal")! // We use Google's public stun servers. For production apps you should deploy your own stun/turn servers. fileprivate let stunServers = ["stun:stun.l.google.com:19302",