SpeechService.swift 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /*
  2. * Copyright 2020, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import GRPC
  17. typealias Request = Google_Cloud_Speech_V1_StreamingRecognizeRequest
  18. typealias Response = Google_Cloud_Speech_V1_StreamingRecognizeResponse
  19. typealias StreamingRecognizeCall = BidirectionalStreamingCall
  20. final class SpeechService {
  21. // Track whether we are currently streaming or not
  22. enum State {
  23. case idle
  24. case streaming(StreamingRecognizeCall<Request, Response>)
  25. }
  26. // Generated SpeechClient for making calls
  27. private var client: Google_Cloud_Speech_V1_SpeechClient
  28. // Track if we are streaming or not
  29. private var state: State = .idle
  30. init() {
  31. precondition(!Constants.apiKey.isEmpty, "Please refer to the README on how to configure your API Key properly.")
  32. // Make EventLoopGroup for the specific platform (NIOTSEventLoopGroup for iOS)
  33. // see https://github.com/grpc/grpc-swift/blob/master/docs/apple-platforms.md for more details
  34. let group = PlatformSupport.makeEventLoopGroup(loopCount: 1)
  35. // Create a connection secured with TLS to Google's speech service running on our `EventLoopGroup`
  36. let channel = ClientConnection
  37. .secure(group: group)
  38. .connect(host: "speech.googleapis.com", port: 443)
  39. // Specify call options to be used for gRPC calls
  40. let callOptions = CallOptions(customMetadata: [
  41. "x-goog-api-key": Constants.apiKey
  42. ])
  43. // Now we have a client!
  44. self.client = Google_Cloud_Speech_V1_SpeechClient(channel: channel, defaultCallOptions: callOptions)
  45. }
  46. func stream(_ data: Data,
  47. completion: ((Google_Cloud_Speech_V1_StreamingRecognizeResponse) -> Void)? = nil) {
  48. switch self.state {
  49. case .idle:
  50. // Initialize the bidirectional stream
  51. let call = self.client.streamingRecognize { response in
  52. // Message received from Server, execute provided closure from caller
  53. completion?(response)
  54. }
  55. self.state = .streaming(call)
  56. // Specify audio details
  57. let config = Google_Cloud_Speech_V1_RecognitionConfig.with {
  58. $0.encoding = .linear16
  59. $0.sampleRateHertz = Int32(Constants.sampleRate)
  60. $0.languageCode = "en-US"
  61. $0.enableAutomaticPunctuation = true
  62. $0.metadata = Google_Cloud_Speech_V1_RecognitionMetadata.with {
  63. $0.interactionType = .dictation
  64. $0.microphoneDistance = .nearfield
  65. $0.recordingDeviceType = .smartphone
  66. }
  67. }
  68. // Create streaming request
  69. let request = Google_Cloud_Speech_V1_StreamingRecognizeRequest.with {
  70. $0.streamingConfig = Google_Cloud_Speech_V1_StreamingRecognitionConfig.with {
  71. $0.config = config
  72. }
  73. }
  74. // Send first message consisting of the streaming request details
  75. call.sendMessage(request, promise: nil)
  76. // Stream request to send that contains the audio details
  77. let streamAudioDataRequest = Google_Cloud_Speech_V1_StreamingRecognizeRequest.with {
  78. $0.audioContent = data
  79. }
  80. // Send audio data
  81. call.sendMessage(streamAudioDataRequest, promise: nil)
  82. case .streaming(let call):
  83. // Stream request to send that contains the audio details
  84. let streamAudioDataRequest = Google_Cloud_Speech_V1_StreamingRecognizeRequest.with {
  85. $0.audioContent = data
  86. }
  87. // Send audio data
  88. call.sendMessage(streamAudioDataRequest, promise: nil)
  89. }
  90. }
  91. func stopStreaming() {
  92. // Send end message to the stream
  93. switch self.state {
  94. case .idle:
  95. return
  96. case .streaming(let stream):
  97. stream.sendEnd(promise: nil)
  98. self.state = .idle
  99. }
  100. }
  101. }