SpeechService.swift 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  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(
  32. !Constants.apiKey.isEmpty,
  33. "Please refer to the README on how to configure your API Key properly."
  34. )
  35. // Make EventLoopGroup for the specific platform (NIOTSEventLoopGroup for iOS)
  36. // see https://github.com/grpc/grpc-swift/blob/main/docs/apple-platforms.md for more details
  37. let group = PlatformSupport.makeEventLoopGroup(loopCount: 1)
  38. // Create a connection secured with TLS to Google's speech service running on our `EventLoopGroup`
  39. let channel = ClientConnection
  40. .secure(group: group)
  41. .connect(host: "speech.googleapis.com", port: 443)
  42. // Specify call options to be used for gRPC calls
  43. let callOptions = CallOptions(customMetadata: [
  44. "x-goog-api-key": Constants.apiKey,
  45. ])
  46. // Now we have a client!
  47. self.client = Google_Cloud_Speech_V1_SpeechClient(
  48. channel: channel,
  49. defaultCallOptions: callOptions
  50. )
  51. }
  52. func stream(_ data: Data,
  53. completion: ((Google_Cloud_Speech_V1_StreamingRecognizeResponse) -> Void)? = nil) {
  54. switch self.state {
  55. case .idle:
  56. // Initialize the bidirectional stream
  57. let call = self.client.streamingRecognize { response in
  58. // Message received from Server, execute provided closure from caller
  59. completion?(response)
  60. }
  61. self.state = .streaming(call)
  62. // Specify audio details
  63. let config = Google_Cloud_Speech_V1_RecognitionConfig.with {
  64. $0.encoding = .linear16
  65. $0.sampleRateHertz = Int32(Constants.sampleRate)
  66. $0.languageCode = "en-US"
  67. $0.enableAutomaticPunctuation = true
  68. $0.metadata = Google_Cloud_Speech_V1_RecognitionMetadata.with {
  69. $0.interactionType = .dictation
  70. $0.microphoneDistance = .nearfield
  71. $0.recordingDeviceType = .smartphone
  72. }
  73. }
  74. // Create streaming request
  75. let request = Google_Cloud_Speech_V1_StreamingRecognizeRequest.with {
  76. $0.streamingConfig = Google_Cloud_Speech_V1_StreamingRecognitionConfig.with {
  77. $0.config = config
  78. }
  79. }
  80. // Send first message consisting of the streaming request details
  81. call.sendMessage(request, promise: nil)
  82. // Stream request to send that contains the audio details
  83. let streamAudioDataRequest = Google_Cloud_Speech_V1_StreamingRecognizeRequest.with {
  84. $0.audioContent = data
  85. }
  86. // Send audio data
  87. call.sendMessage(streamAudioDataRequest, promise: nil)
  88. case let .streaming(call):
  89. // Stream request to send that contains the audio details
  90. let streamAudioDataRequest = Google_Cloud_Speech_V1_StreamingRecognizeRequest.with {
  91. $0.audioContent = data
  92. }
  93. // Send audio data
  94. call.sendMessage(streamAudioDataRequest, promise: nil)
  95. }
  96. }
  97. func stopStreaming() {
  98. // Send end message to the stream
  99. switch self.state {
  100. case .idle:
  101. return
  102. case let .streaming(stream):
  103. stream.sendEnd(promise: nil)
  104. self.state = .idle
  105. }
  106. }
  107. }