Browse Source

Updated Speech sample

Tim Burks 9 years ago
parent
commit
1aa64c9265

+ 8 - 6
Examples/Speech/Speech/Base.lproj/LaunchScreen.storyboard

@@ -1,7 +1,9 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="8150" systemVersion="15A204g" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11201" systemVersion="15G1004" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
     <dependencies>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8122"/>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11161"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <scenes>
         <!--View Controller-->
@@ -13,15 +15,15 @@
                         <viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
                     </layoutGuides>
                     <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
-                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                        <animations/>
-                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+                        <color key="backgroundColor" red="0.15686274510000001" green="0.61176470589999998" blue="0.23921568630000001" alpha="1" colorSpace="calibratedRGB"/>
                     </view>
+                    <simulatedStatusBarMetrics key="simulatedStatusBarMetrics" statusBarStyle="lightContent"/>
                 </viewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
             </objects>
-            <point key="canvasLocation" x="53" y="375"/>
+            <point key="canvasLocation" x="169" y="298"/>
         </scene>
     </scenes>
 </document>

+ 2 - 0
Examples/Speech/Speech/Info.plist

@@ -32,6 +32,8 @@
 	<array>
 		<string>armv7</string>
 	</array>
+	<key>UIStatusBarStyle</key>
+	<string>UIStatusBarStyleLightContent</string>
 	<key>UISupportedInterfaceOrientations</key>
 	<array>
 		<string>UIInterfaceOrientationPortrait</string>

+ 41 - 56
Examples/Speech/Speech/Main.storyboard

@@ -1,9 +1,10 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11198.2" systemVersion="15G31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11201" systemVersion="15G1004" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
     <dependencies>
         <deployment identifier="iOS"/>
         <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11161"/>
         <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
+        <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <scenes>
@@ -19,76 +20,60 @@
                         <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <subviews>
-                            <button opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aJY-83-MIx">
-                                <frame key="frameInset" minX="200" minY="70" width="200" height="60"/>
-                                <color key="backgroundColor" red="0.75" green="0.75" blue="0.75" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                <constraints>
-                                    <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="60" id="Ob5-s4-nYg"/>
-                                    <constraint firstAttribute="height" constant="30" id="QTK-6F-b35"/>
-                                    <constraint firstAttribute="width" constant="200" id="aXK-qO-hb0"/>
-                                </constraints>
-                                <state key="normal" title="Start Streaming"/>
-                                <variation key="default">
-                                    <mask key="constraints">
-                                        <exclude reference="QTK-6F-b35"/>
-                                    </mask>
-                                </variation>
+                            <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" allowsSelection="NO" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="Fjy-ZP-KpP">
+                                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                <sections/>
                                 <connections>
-                                    <action selector="recordAudio:" destination="BYZ-38-t0r" eventType="touchUpInside" id="3jT-bC-3nM"/>
+                                    <outlet property="dataSource" destination="BYZ-38-t0r" id="4Jm-4E-Sl7"/>
+                                    <outlet property="delegate" destination="BYZ-38-t0r" id="6Nk-B8-Sb2"/>
                                 </connections>
-                            </button>
-                            <button opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="wgH-jh-Nuq">
-                                <frame key="frameInset" minX="200" minY="180" width="200" height="60"/>
-                                <color key="backgroundColor" red="0.75" green="0.75" blue="0.75" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                            </tableView>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3od-GX-JIX">
+                                <subviews>
+                                    <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" text="Listening..." textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="vtY-SX-V3c">
+                                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                        <fontDescription key="fontDescription" type="system" pointSize="12"/>
+                                        <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
+                                    </textView>
+                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Speech" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mkr-uG-IHd">
+                                        <fontDescription key="fontDescription" type="system" pointSize="30"/>
+                                        <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+                                        <nil key="highlightedColor"/>
+                                    </label>
+                                </subviews>
+                                <color key="backgroundColor" red="0.15686274509803921" green="0.60784313725490191" blue="0.23921568627450981" alpha="1" colorSpace="calibratedRGB"/>
                                 <constraints>
-                                    <constraint firstAttribute="height" constant="30" id="6lu-81-t2K"/>
-                                    <constraint firstAttribute="width" constant="200" id="8b8-bw-kQK"/>
-                                    <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="60" id="kpU-Gc-YS7"/>
+                                    <constraint firstItem="mkr-uG-IHd" firstAttribute="leading" secondItem="3od-GX-JIX" secondAttribute="leading" constant="20" id="1RE-DB-S5c"/>
+                                    <constraint firstAttribute="trailing" secondItem="vtY-SX-V3c" secondAttribute="trailing" constant="20" id="602-o7-yeY"/>
+                                    <constraint firstAttribute="bottom" secondItem="vtY-SX-V3c" secondAttribute="bottom" constant="8" id="9AJ-li-cWC"/>
+                                    <constraint firstItem="vtY-SX-V3c" firstAttribute="leading" secondItem="3od-GX-JIX" secondAttribute="leading" constant="20" id="CVz-HN-5ct"/>
+                                    <constraint firstItem="mkr-uG-IHd" firstAttribute="top" secondItem="3od-GX-JIX" secondAttribute="top" constant="40" id="HZL-Xt-Iyq"/>
+                                    <constraint firstAttribute="trailing" secondItem="mkr-uG-IHd" secondAttribute="trailing" constant="20" id="WyJ-Or-cXf"/>
+                                    <constraint firstItem="vtY-SX-V3c" firstAttribute="top" secondItem="mkr-uG-IHd" secondAttribute="bottom" constant="16" id="g89-qL-lrl"/>
                                 </constraints>
-                                <state key="normal" title="Stop Streaming"/>
-                                <variation key="default">
-                                    <mask key="constraints">
-                                        <exclude reference="6lu-81-t2K"/>
-                                    </mask>
-                                </variation>
-                                <connections>
-                                    <action selector="stopAudio:" destination="BYZ-38-t0r" eventType="touchUpInside" id="TWm-My-dhj"/>
-                                </connections>
-                            </button>
-                            <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" misplaced="YES" editable="NO" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="vtY-SX-V3c">
-                                <frame key="frameInset" minX="20" minY="290" width="560" height="310"/>
-                                <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                                <string key="text">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.</string>
-                                <fontDescription key="fontDescription" type="system" pointSize="14"/>
-                                <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
-                            </textView>
+                            </view>
                         </subviews>
                         <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                         <constraints>
-                            <constraint firstItem="vtY-SX-V3c" firstAttribute="top" secondItem="wgH-jh-Nuq" secondAttribute="bottom" constant="50" id="BNf-SR-fGy"/>
-                            <constraint firstItem="vtY-SX-V3c" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leadingMargin" id="Gyx-9P-zrc"/>
-                            <constraint firstItem="wfy-db-euE" firstAttribute="top" secondItem="vtY-SX-V3c" secondAttribute="bottom" id="Qq3-q5-MGO"/>
-                            <constraint firstItem="wgH-jh-Nuq" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="bjq-My-Edw"/>
-                            <constraint firstItem="aJY-83-MIx" firstAttribute="top" secondItem="y3c-jy-aDJ" secondAttribute="bottom" constant="50" id="d2d-EP-JYj"/>
-                            <constraint firstItem="wgH-jh-Nuq" firstAttribute="centerX" secondItem="aJY-83-MIx" secondAttribute="centerX" id="hZX-d6-ANs"/>
-                            <constraint firstItem="wgH-jh-Nuq" firstAttribute="top" secondItem="aJY-83-MIx" secondAttribute="bottom" constant="50" id="kIe-ML-fFZ"/>
-                            <constraint firstItem="aJY-83-MIx" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="ntQ-pz-44R"/>
-                            <constraint firstAttribute="trailingMargin" secondItem="vtY-SX-V3c" secondAttribute="trailing" id="oW1-J1-PO7"/>
+                            <constraint firstItem="3od-GX-JIX" firstAttribute="height" secondItem="8bC-Xf-vdC" secondAttribute="height" multiplier="0.3" id="2Z9-VM-WKY"/>
+                            <constraint firstAttribute="trailingMargin" secondItem="Fjy-ZP-KpP" secondAttribute="trailing" id="7hO-DZ-NGK"/>
+                            <constraint firstItem="wfy-db-euE" firstAttribute="top" secondItem="Fjy-ZP-KpP" secondAttribute="bottom" id="CmS-eA-Thb"/>
+                            <constraint firstAttribute="trailing" secondItem="3od-GX-JIX" secondAttribute="trailing" id="MOB-Xr-f8B"/>
+                            <constraint firstItem="Fjy-ZP-KpP" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leadingMargin" id="TXO-uM-Sgk"/>
+                            <constraint firstItem="3od-GX-JIX" firstAttribute="top" secondItem="8bC-Xf-vdC" secondAttribute="top" id="fQq-ov-7Ph"/>
+                            <constraint firstItem="Fjy-ZP-KpP" firstAttribute="top" secondItem="3od-GX-JIX" secondAttribute="bottom" constant="4" id="rWF-jn-sTp"/>
+                            <constraint firstItem="3od-GX-JIX" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="rZq-NS-pju"/>
                         </constraints>
-                        <variation key="default">
-                            <mask key="constraints">
-                                <exclude reference="hZX-d6-ANs"/>
-                            </mask>
-                        </variation>
                     </view>
+                    <simulatedStatusBarMetrics key="simulatedStatusBarMetrics" statusBarStyle="lightContent"/>
                     <connections>
+                        <outlet property="tableView" destination="Fjy-ZP-KpP" id="54a-uK-IhF"/>
                         <outlet property="textView" destination="vtY-SX-V3c" id="aym-NZ-3gu"/>
-                        <outlet property="view" destination="8bC-Xf-vdC" id="I19-bM-Qp4"/>
                     </connections>
                 </viewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
             </objects>
-            <point key="canvasLocation" x="301" y="275"/>
+            <point key="canvasLocation" x="300" y="274.81259370314842"/>
         </scene>
     </scenes>
 </document>

+ 11 - 14
Examples/Speech/Speech/SpeechRecognitionService.swift

@@ -28,6 +28,8 @@ class SpeechRecognitionService {
   var channel: Channel
   var call: Call?
 
+  var completion: SpeechRecognitionCompletionHandler!
+
   static let sharedInstance = SpeechRecognitionService()
 
   private init() {
@@ -35,7 +37,8 @@ class SpeechRecognitionService {
     channel = Channel(address:HOST, certificates: nil, host: nil)
   }
 
-  func streamAudioData(_ audioData: NSData, completion: SpeechRecognitionCompletionHandler) {
+  func streamAudioData(_ audioData: NSData, completion: @escaping SpeechRecognitionCompletionHandler) {
+    self.completion = completion
 
     do {
 
@@ -63,9 +66,8 @@ class SpeechRecognitionService {
           streamingRecognizeRequest.addField("streaming_config", value:streamingRecognitionConfig)
 
           let messageData = streamingRecognizeRequest.data()
-          call.sendMessage(data:messageData)
+          let success = call.sendMessage(data:messageData)
           nowStreaming = true
-
           self.receiveMessage()
         }
       }
@@ -74,7 +76,10 @@ class SpeechRecognitionService {
         let streamingRecognizeRequest = fileDescriptorSet.makeMessage("StreamingRecognizeRequest")!
         streamingRecognizeRequest.addField("audio_content", value: audioData)
         let messageData = streamingRecognizeRequest.data()
-        call.sendMessage(data:messageData)
+        let success = call.sendMessage(data:messageData)
+        if (!success) {
+          stopStreaming() // restart
+        }
       }
 
     } catch (let error) {
@@ -89,19 +94,11 @@ class SpeechRecognitionService {
           if let data = data {
             if let responseMessage =
               self.fileDescriptorSet.readMessage("StreamingRecognizeResponse", data:data) {
-              responseMessage.forEachField("results") {(field) in
-                if let _ = field.message().oneField("is_final"),
-                  let alternativesField = field.message().oneField("alternatives") {
-                  let alternativeMessage = alternativesField.message()
-                  if let transcript = alternativeMessage.oneField("transcript") {
-                    print(transcript.string())
-                  }
-                }
-              }
+              self.completion(responseMessage, nil)
             }
           }
+          self.receiveMessage()
         }
-        self.receiveMessage()
       }
     } catch (let error) {
       print("Receive error: \(error)")

+ 93 - 24
Examples/Speech/Speech/ViewController.swift

@@ -20,24 +20,44 @@ let SAMPLE_RATE = 16000
 
 class ViewController : UIViewController, AudioControllerDelegate {
   @IBOutlet weak var textView: UITextView!
+  @IBOutlet weak var tableView: UITableView!
+
+  var transcripts : [String] = []
+
   var audioData: NSMutableData!
 
+  required init?(coder:NSCoder) {
+    super.init(coder:coder)
+    audioData = NSMutableData()
+    AudioController.sharedInstance.delegate = self
+
+    transcripts = []
+  }
+
+  override var preferredStatusBarStyle: UIStatusBarStyle {
+    return .lightContent
+  }
+
   override func viewDidLoad() {
     super.viewDidLoad()
-    AudioController.sharedInstance.delegate = self
+    tableView.rowHeight = 80
+    let backgroundColor = UIColor(white: 0.9, alpha: 1.0)
+    tableView.backgroundColor = backgroundColor
+    view.backgroundColor = backgroundColor
+    tableView.clipsToBounds = false
   }
 
-  @IBAction func recordAudio(_ sender: NSObject) {
-    let audioSession = AVAudioSession.sharedInstance()
-    do {
-      try audioSession.setCategory(AVAudioSessionCategoryRecord)
-    } catch {
+  override func viewDidAppear(_ animated: Bool) {
+    try! AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryRecord)
 
-    }
-    audioData = NSMutableData()
     _ = AudioController.sharedInstance.prepare(specifiedSampleRate: SAMPLE_RATE)
+
     SpeechRecognitionService.sharedInstance.sampleRate = SAMPLE_RATE
-    _ = AudioController.sharedInstance.start()
+
+    DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {
+      _ = AudioController.sharedInstance.start()
+
+    }
   }
 
   @IBAction func stopAudio(_ sender: NSObject) {
@@ -57,27 +77,76 @@ class ViewController : UIViewController, AudioControllerDelegate {
       SpeechRecognitionService.sharedInstance.streamAudioData(audioData,
                                                               completion:
         { (response, error) in
-          if let error = error {
-            self.textView.text = error.localizedDescription
-          } else if let response = response {
-            var finished = false
-            print(response)
-            /*
-            for result in response.resultsArray! {
-              if let result = result as? StreamingRecognitionResult {
-                if result.isFinal {
-                  finished = true
+          DispatchQueue.main.async {
+
+            if let error = error {
+              self.textView.text = error.localizedDescription
+            } else if let response = response as? Message {
+              var finished = false
+              response.display()
+              response.forEachField("results") {(field) in
+                if let alternativesField = field.message().oneField("alternatives") {
+                  let alternativeMessage = alternativesField.message()
+                  if let transcript = alternativeMessage.oneField("transcript") {
+
+                    if let _ = field.message().oneField("is_final") {
+                      self.transcripts.insert(transcript.string(), at:0)
+                      self.tableView.insertRows(at:[IndexPath(row:0, section:0)], with: .automatic)
+                      while(self.transcripts.count > 12) {
+                        self.transcripts.removeLast(1)
+                      }
+                      self.textView.text = ""
+                      finished = true
+                    } else {
+                      self.textView.text = transcript.string()
+                    }
+                  }
                 }
               }
+              if finished {
+                SpeechRecognitionService.sharedInstance.stopStreaming()
+              }
             }
-            self.textView.text = response.description
-            if finished {
-              self.stopAudio(self)
-            }
- */
           }
       })
       self.audioData = NSMutableData()
     }
   }
 }
+
+extension ViewController : UITableViewDataSource {
+
+  func numberOfSections(in tableView: UITableView) -> Int {
+    return 1
+  }
+
+  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+    return transcripts.count
+  }
+
+  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+    return TableViewCell(text:transcripts[indexPath.row])
+  }
+
+}
+
+
+class TableViewCell : UITableViewCell {
+  convenience init(text: String) {
+    self.init(style: .default, reuseIdentifier: "cell")
+    self.backgroundColor = UIColor.clear
+    self.contentView.backgroundColor = UIColor.white
+    if let textLabel = textLabel {
+      textLabel.text = text
+      textLabel.font = UIFont.systemFont(ofSize: 12)
+      textLabel.numberOfLines = 0
+    }
+  }
+
+  override func layoutSubviews() {
+    self.contentView.frame = self.bounds.insetBy(dx: 10, dy: 6)
+    if let textLabel = textLabel {
+      textLabel.frame = contentView.bounds.insetBy(dx: 10, dy: 0)
+    }
+  }
+}