[
  {
    "path": ".gitignore",
    "content": "__pycache__\n*.pyc\n\nazure_key.txt\n\n# data\n*.jpg\n*mp3\n*mp4\n# data/\n\n# models\nmodels/\n*.pkl\n*.h5\n*.scorer\n#*.tflite\n*.pbmm\n*.pth\n*.pt\n*.tar\n\n#other\n# data/\n\n#ANDROID\n# Built application files\n*.apk\n#*.aar\n*.ap_\n*.aab\n\n# Files for the ART/Dalvik VM\n*.dex\n\n# Java class files\n*.class\n\n# Generated files\nbin/\ngen/\nout/\n#  Uncomment the following line in case you need and you don't have the release build type files in your app\n# release/\n\n# Gradle files\n.gradle/\nbuild/\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# Proguard folder generated by Eclipse\nproguard/\n\n# Log Files\n*.log\n\n# Android Studio Navigation editor temp files\n.navigation/\n\n# Android Studio captures folder\ncaptures/\n\n# IntelliJ\n*.iml\n.idea/workspace.xml\n.idea/misc.xml\n.idea/tasks.xml\n.idea/gradle.xml\n.idea/assetWizardSettings.xml\n.idea/dictionaries\n.idea/libraries\n# IntelliJ\n*.iml\n.idea/\nmisc.xml\ndeploymentTargetDropDown.xml\nrender.experimental.xml\n\n# Android Studio 3 in .gitignore file.\n.idea/caches\n.idea/modules.xml\n# Comment next line if keeping position of elements in Navigation Editor is relevant for you\n.idea/navEditor.xml\n\n# Keystore files\n# Uncomment the following lines if you do not want to check your keystore files in.\n#*.jks\n#*.keystore\n\n# External native build folder generated in Android Studio 2.2 and later\n.externalNativeBuild\n.cxx/\n\n# Google Services (e.g. APIs or Firebase)\n# google-services.json\n\n# Freeline\nfreeline.py\nfreeline/\nfreeline_project_description.json\n\n# fastlane\nfastlane/report.xml\nfastlane/Preview.html\nfastlane/screenshots\nfastlane/test_output\nfastlane/readme.md\n\n# Version control\nvcs.xml\n\n# lint\nlint/intermediates/\nlint/generated/\nlint/outputs/\nlint/tmp/\n# lint/reports/\n\n# Android Profiling\n*.hprof\n\n\n.classpath\n.project\n.settings\n\nkeys/\n"
  },
  {
    "path": ".gitmodules",
    "content": ""
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 Cayden Pierce\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# SmartGlassesManager\n\n### Update 2024 - **SmartGlassesManager** is now part of [AugmentOS](https://augmentos.org/), a unifying OS for smart glasses such as *Even Reality G1* and *Vuzix Z100*. It combines your favorite smart glasses apps, an app store, and SDK. We hope you like it <3\n\n<p align=\"center\">\n    <img src=\"./res/SGM_app_icon_google_play.png\" width=\"25%\">\n</p>\n\n## Why Use The Smart Glasses Manager?\n\n### Developers\nBuilding apps that run on a smart phone and stream data to smart glasses is hard, but it’s how today’s lightweight smart glasses work. We handle the connection, UI, data streaming, and transcription, allowing you to rapidly develop smart glasses applications that run on any pair of smart glasses.\n\n### Industry\nYour smart glasses won’t see massive consumer adoption if third party developers can’t make awesome apps for your hardware. The SmartGlassesManager is a middleware which already supports many apps and makes it easy for developers to build more. That means, if you add support to your hardware for a single application – the SmartGlassesManager – your glasses will instantly support a plethora of consumer-facing applications.\n\n<p align=\"center\">\n    <img src=\"./res/SmartGlassesManager_Screenshots_20230405.png\" width=\"80%\" margin-left=\"auto\" margin-right=\"auto\">\n</p>\n\n## Features\n\n1. Connect smart phone to smart glasses, auto-reconnect\n    - Wifi, Bluetooth, Android, MCU glasses all supported\n2. Receive audio + sensors from glasses\n3. Transcribe audio\n4. Abstracted interface to show info on the glasses\n\n## Fork of the Wearable Intelligence System\n\nThis repo is a fork of the [Wearable Intelligence System](https://github.com/emexlabs/WearableIntelligenceSystem). The Wearable Intelligence System was started at [Emex Labs](https://emexwearables.com) by [Cayden Pierce](https://caydenpierce.com/). This repo has a lot of the history cleaned to make it easier to manage, see the WIS repo for full history.\n\n## Install / Use\n\nYou will need two pieces of hardware to run the system:  \n\n1. ASP - Android Smart Phone running Android 12+\n2. A pair of smart glasses:\n    - Vuzix Z100 / Ultralite OEM Reference Platform\n    - Vuzix Shield\n    - Activelook Engo 1 or Activelook Engo 2\n    - Inmo Air 1 or Inmo Air 2\n    - Vuzix Blade 2\n    - TCL RayNeo X2\n\n### Install\n\n1. On your Android smart phone, flash the ASP app from Android Studio, the releases page, or from Google Play.\n    - Play Store: Coming soon\n    - [Github latest release](https://github.com/TeamOpenSmartGlasses/SmartGlassesManager/releases)\n2. If using Android Smart Glasses, then on your smart glasses, download or flash the ASG client app:\n    - [Github latest release](https://github.com/TeamOpenSmartGlasses/SmartGlassesManager/releases)\n3. \n    * Launch the \"Smart Glasses Manager\" app on your smart phone\n    * Accept permissions.\n    * If using Android Smart Glasses -> Tap \"Start Wifi Hotspot\", turn on (configure password if necessary) your wifi hotspot, then go \"Back\" to return\n        - Connect smart glasses WiFi to the smart phone WiFi hotspot\n        - Enable mobile data (or wifi sharing) on Android smart phone\n        - Start ASG application on smart glasses\n        - The phone connection icon will be green if the glasses are connected to your phone. If you speak, you'll see a live transcript on the smart glasses screen.\n    * If using Bluetooth Smart Glasses -> Turn on Bluetooth on phone.\n3. Tap \"Connect Smart Glasses\" and choose your glasses.\n4. Setup complete.\n\n### Normal Use\n    \nHere's how to launch the system after you've already done the initial setup above:  \n\n1. Launch \"Smart Glasses Manager\" app on smart phone\n2. Enable mobile hotspot on smart phone with the \"Start WiFi Hotspot\" button\n3. Connect Android smart glasses to Android smart phone WiFi hotspot.\n4. Launch \"WIS\" app on smart glasses.\n5. Verify system is running by the \"Smart Glasses Conection Indicator\" icon turning white on the smart glasses HUD.\n    \n## Documentation / Developers\n\n(WIP)\nHere are the docs: https://github.com/TeamOpenSmartGlasses/SmartGlassesManager/wiki\n   \n## Authors\n\nThe system is fully open source and built by [TeamOpenSmartGlasses](https://teamopensmartglasses.com). We're a team building open source smart glasses technology to enhance user's intelligence in daily life. Join us: https://discord.gg/5ukNvkEAqT\n\nThe TeamOpenSmartGlasses members who are contributing to this project include:\n\n- [Cayden Pierce](https://caydenpierce.com)\n- [Alex Israelov](http://www.alexisraelov.com/)\n\nWe are building a community that is building cognitive augmentation technologies together. \n"
  },
  {
    "path": "SGM_android/.gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/caches\n/.idea/libraries\n/.idea/modules.xml\n/.idea/workspace.xml\n/.idea/navEditor.xml\n/.idea/assetWizardSettings.xml\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n.cxx\nlocal.properties\n"
  },
  {
    "path": "SGM_android/README.md",
    "content": "### Special instructions if you need to mess with the OGG streaming CPP JNI. \n\n\n0. Run Linux (as you should be).\n1. Install Java 17.\n2. Ensure Java 17 is default Java (can set with `sudo update-java-alternatives`).\n3. Run `chmod 777 ./gradle/` and `chmod 777 ./gradle/`.\n4. Set your ANDROID_SDK_PATH WITH `export $ANDROID_SDK_PATH=<path to you Android>`.\n5. Go into android folder and run `bash build_all.sh` to build everything.\n6. If you get gradle version issues, install gradle 8.0.2: https://linuxhint.com/installing_gradle_ubuntu/ (follow the instructions, but replace 7.4.2 with 8.0.2).\n7. Subsequent builds, you can just run `./gradlew assembleDebug --stacktrace` to build the APK.\n8. Now that CPP/JNI is built, you can use Android Studio to edit app and install APK on phone (located in app/build/outputs/debug/). If you change anything related to CPP/JNI code, you may have to rebuild.\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/.gitignore",
    "content": "/build"
  },
  {
    "path": "SGM_android/SmartGlassesManager/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.22.1)\n\nproject(\"some-name-needed-here\")\n\nadd_subdirectory(src/main/cpp)\nadd_subdirectory(src/main/cpp/jni)\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/build.gradle",
    "content": "plugins {\n    id 'com.android.library'\n//    id 'kotlin-android'\n    id 'com.google.protobuf' version '0.9.2'\n}\n\next {\n    kotlin_version = '1.6.21'\n    roomVersion = '2.2.3'\n    archLifecycleVersion = '2.2.0-rc03'\n    coreTestingVersion = '2.1.0'\n    kotlinVersion = '1.6.21'\n}\n\nandroid {\n    namespace \"com.teamopensmartglasses.smartglassesmanager\"\n    compileSdk 33\n\n//    aaptOptions {\n//        noCompress \"tflite\"\n//    }\n\n    packagingOptions {\n        exclude 'META-INF/proguard/androidx-annotations.pro'\n        resources {\n            excludes += '/META-INF/{AL2.0,LGPL2.1,DEPENDENCIES}'\n            excludes += '/META-INF/INDEX.LIST'\n        }\n    }\n\n    defaultConfig {\n        minSdk 30\n        targetSdk 32\n        versionCode 3\n        versionName \"0.1\"\n\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n\n//        ndk {\n//            abiFilters 'armeabi-v7a', 'arm64-v8a'\n//        }\n\n    }\n\n    externalNativeBuild {\n        cmake {\n            '-DANDROID_STL=c++_static'\n        }\n    }\n\n//    buildTypes {\n//        release {\n//            minifyEnabled false\n//            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n//        }\n////        debug {\n////            applicationIdSuffix \".debug\" //so we can have both release and debug on the same phone\n////        }\n//    }\n//    compileOptions {\n//        sourceCompatibility JavaVersion.VERSION_1_8\n//        targetCompatibility JavaVersion.VERSION_1_8\n//    }\n//\n//    sourceSets {\n//        main {\n//            assets.srcDirs += \"$buildDir/generated/assets\"\n//            java.srcDirs += 'src/main/java'\n//            proto.srcDirs += 'src/main/proto'\n//        }\n//    }\n//\n//    externalNativeBuild {\n//        cmake {\n//            path file('CMakeLists.txt')\n//            version '3.22.1'\n//        }\n//    }\n\n}\n\ndependencies {\n    implementation fileTree(dir: 'libs', include: ['*.jar'])\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion\"\n    implementation 'androidx.navigation:navigation-fragment:2.2.0'\n    implementation 'androidx.navigation:navigation-ui:2.2.0'\n    testImplementation 'junit:junit:4.+'\n    androidTestImplementation 'androidx.test.ext:junit:1.1.3'\n\n    implementation 'com.google.protobuf:protobuf-java:3.21.12'\n    implementation 'com.google.protobuf:protobuf-java-util:3.21.12'\n    implementation 'com.google.api.grpc:grpc-google-cloud-speech-v1p1beta1:2.6.0'\n    implementation \"androidx.concurrent:concurrent-futures:1.0.0-alpha03\"\n    implementation \"androidx.lifecycle:lifecycle-common:2.2.0\"\n    implementation 'androidx.preference:preference:1.2.0'\n    implementation 'joda-time:joda-time:2.12.2'\n    implementation \"androidx.annotation:annotation:1.1.0\"\n    implementation \"androidx.appcompat:appcompat:1.1.0\"\n    implementation \"androidx.constraintlayout:constraintlayout:2.1.0\"\n    implementation \"androidx.core:core:1.1.0-rc03\"\n    \"androidx.legacy:legacy-support-v4:1.0.0\"\n    implementation 'io.grpc:grpc-okhttp:1.53.0'\n    implementation \"androidx.recyclerview:recyclerview:1.1.0-beta02\"\n    implementation \"com.github.bumptech.glide:glide:4.11.0\"\n    implementation \"com.google.android.material:material:1.6.0-alpha01\"\n    implementation \"com.google.code.findbugs:jsr305:3.0.2\"\n    implementation \"com.google.flogger:flogger-system-backend:0.3.1\"\n    implementation \"com.google.flogger:flogger:0.3.1\"\n    implementation \"com.google.guava:listenablefuture:1.0\"\n    implementation \"junit:junit:4.12\"\n    implementation \"org.hamcrest:hamcrest-library:1.3\"\n\n    implementation 'com.squareup.picasso:picasso:2.8'\n\n    implementation \"org.java-websocket:Java-WebSocket:1.5.2\"\n    implementation \"io.reactivex.rxjava3:rxandroid:3.0.0\"\n    implementation \"io.reactivex.rxjava3:rxjava:3.0.0\"\n    implementation \"com.google.android.gms:play-services-tasks:18.0.0\"\n    implementation \"com.google.android.gms:play-services-location:18.0.0\"\n    implementation \"com.google.code.gson:gson:2.8.6\"\n\n    //ROOM\n    // Room components\n    implementation \"androidx.room:room-runtime:$roomVersion\"\n    annotationProcessor \"androidx.room:room-compiler:$roomVersion\"\n    androidTestImplementation \"androidx.room:room-testing:$roomVersion\"\n\n    // Lifecycle components\n    implementation \"androidx.lifecycle:lifecycle-extensions:$archLifecycleVersion\"\n    annotationProcessor \"androidx.lifecycle:lifecycle-compiler:$archLifecycleVersion\"\n    implementation \"com.google.guava:guava:28.1-android\"\n\n    //VOSK ASR\n    implementation 'net.java.dev.jna:jna:5.8.0@aar'\n    implementation \"com.alphacephei:vosk-android:0.3.34@aar\"\n\n    //java.util.time backport\n    implementation \"org.threeten:threetenbp:1.5.2\"\n\n    //http(s) lib\n    implementation \"com.android.volley:volley:1.2.1\"\n\n    //EventBus, greenrobot\n    implementation(\"org.greenrobot:eventbus:3.3.1\")\n\n    //activelook SDK\n    //implementation 'com.github.activelook:android-sdk:v4.4.0'\n\n    //Json (de/)serialization\n    implementation 'com.google.code.gson:gson:2.10.1'\n\n    //for VAD (using Silero DNN)\n    implementation 'com.github.gkonovalov:android-vad:2.0.1'\n    implementation 'com.microsoft.onnxruntime:onnxruntime-android:1.15.0'\n\n    //Vuzix Ultralite OEM Platform / Vuzix Z100\n    implementation 'com.vuzix:ultralite-sdk-android:1.4.1'\n\n    //Azure ASR\n    implementation \"com.microsoft.cognitiveservices.speech:client-sdk:1.38.0\"\n\n    implementation project(path: ':AugmentOSLib')\n}\n\n//VOSK ASR prep models - need one for each language\ntasks.register('genUUID_en') {\n    def uuid = UUID.randomUUID().toString()\n    def odir = file(\"$buildDir/generated/assets/model-en-us\")\n    def ofile = file(\"$odir/uuid\")\n    doLast {\n        mkdir odir\n        ofile.text = uuid\n    }\n}\ntasks.register('genUUID_fr') {\n    def uuid = UUID.randomUUID().toString()\n    def odir = file(\"$buildDir/generated/assets/model-fr-small\")\n    def ofile = file(\"$odir/uuid\")\n    doLast {\n        mkdir odir\n        ofile.text = uuid\n    }\n}\n\npreBuild.dependsOn(genUUID_en)\npreBuild.dependsOn(genUUID_fr)\n\nprotobuf {\n    protoc {\n        // use this compiler, from the maven repo (instead of a local file, for instance)\n        artifact = 'com.google.protobuf:protoc:3.21.12'\n    }\n    generateProtoTasks {\n        all().configureEach { task ->\n            // remove the default java output\n            task.builtins {\n                remove java\n            }\n            // add the java output with lite runtime\n            task.builtins {\n                java {\n                    option 'lite'\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n\n#don't leave logs in release build:\n-dontskipnonpubliclibraryclasses\n-dontobfuscate\n-forceprocessing\n-optimizationpasses 5\n\n-keep class * extends android.app.Activity\n-assumenosideeffects class android.util.Log {\n    public static *** d(...);\n    public static *** v(...);\n}"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/androidTest/java/com/teamopensmartglasses/smartglassesmanager/ExampleInstrumentedTest.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager;\n\nimport android.content.Context;\n\nimport androidx.test.platform.app.InstrumentationRegistry;\nimport androidx.test.ext.junit.runners.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();\n        assertEquals(\"com.wearableintelligencesystem.androidsmartphone\", appContext.getPackageName());\n    }\n}"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    package=\"com.teamopensmartglasses.smartglassesmanager\">\n\n  <uses-sdk android:minSdkVersion=\"34\"\n      android:targetSdkVersion=\"34\"\n      />\n\n    <!--    NETWORK-->\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n    <uses-permission android:name = \"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>\n    <!--    SERVICE-->\n    <uses-permission android:name=\"android.permission.FOREGROUND_SERVICE\"/>\n    <!--    LOCATION-->\n    <uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />\n    <!--    BLUETOOTH-->\n    <uses-permission android:name=\"android.permission.BLUETOOTH\" />\n    <uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\" />\n    <uses-permission android:name=\"android.permission.BLUETOOTH_CONNECT\"/>\n    <uses-permission android:name=\"android.permission.BLUETOOTH_SCAN\"\n                        android:usesPermissionFlags=\"neverForLocation\"/>\n\n    <!--    AUDIO-->\n    <uses-permission android:name=\"android.permission.RECORD_AUDIO\" />\n    <uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>\n\n<!--    <queries>-->\n<!--        <intent>-->\n<!--            <action android:name=\"AUGMENTOS_INTENT\" />-->\n<!--        </intent>-->\n<!--    </queries>-->\n\n    <queries>\n        <intent>\n            <action android:name=\"android.intent.action.TTS_SERVICE\" />\n        </intent>\n    </queries>\n</manifest>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/cpp/CMakeLists.txt",
    "content": "# Builds the ogg and opus encoder library which used third party module.\ncmake_minimum_required(VERSION 3.22.1)\n\n# set related path of third party libraries.\nset(third_party_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../third_party)\n\n# libogg library refer from https://github.com/xiph/ogg.\nset(libogg_INCLUDE ${third_party_DIR}/libogg/include)\nset(libogg_LIB ${third_party_DIR}/libogg/lib/${ANDROID_ABI})\nadd_library(lib_ogg STATIC IMPORTED)\nset_target_properties(lib_ogg PROPERTIES IMPORTED_LOCATION ${libogg_LIB}/libogg.a)\n\n# libopus library refer from https://github.com/xiph/opus.\nset(libopus_INCLUDE ${third_party_DIR}/libopus/include)\nset(libopus_LIB ${third_party_DIR}/libopus/lib/${ANDROID_ABI})\nadd_library(lib_opus STATIC IMPORTED)\nset_target_properties(lib_opus PROPERTIES IMPORTED_LOCATION ${libopus_LIB}/libopus.a)\n\n# opus-tools https://github.com/xiph/opus-tools.\nset(opus_tools_INCLUDE ${third_party_DIR}/opus_tools/include)\nset(opus_tools_LIB ${third_party_DIR}/opus_tools/lib/${ANDROID_ABI})\nadd_library(lib_opus_header STATIC IMPORTED)\nset_target_properties(lib_opus_header PROPERTIES IMPORTED_LOCATION\n        ${opus_tools_LIB}/libopus_header.a)\n\n# Build ogg_opus_encoder_tool shared lib.\nset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=gnu++11\")\nadd_library(ogg_opus_encoder_tool SHARED ogg_opus_encoder.cc)\ntarget_include_directories(ogg_opus_encoder_tool PRIVATE ${libogg_INCLUDE})\ntarget_link_libraries(ogg_opus_encoder_tool lib_opus lib_ogg lib_opus_header)\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/cpp/jni/CMakeLists.txt",
    "content": "#build for ogg_opus_encoder shared library\ncmake_minimum_required(VERSION 3.22.1)\n\nadd_library(ogg_opus_encoder SHARED ogg_opus_encoder.cc ../ogg_opus_encoder.cc)\n\n# Include libraries needed for ogg_opus_encoder\ntarget_link_libraries(ogg_opus_encoder ogg_opus_encoder_tool)\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/cpp/jni/ogg_opus_encoder.cc",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"ogg_opus_encoder.h\"\n#include <jni.h>\n#include <cassert>\n#include <cstdint>\n#include \"../ogg_opus_encoder.h\"\n\nnamespace {\n\nusing audio_util::OggOpusEncoder;\n\nOggOpusEncoder* GetInstanceOrDie(jlong ptr) {\n  assert(ptr);\n  return reinterpret_cast<OggOpusEncoder*>(ptr);\n}\n\nbool VerifyInitialized(const std::string& function_name, jlong instance_ptr) {\n  if (instance_ptr == 0) {\n    fprintf(stderr, \"%s called prior to allocate() or after destroy()!\\n\",\n            function_name.c_str());\n    return false;\n  }\n  OggOpusEncoder* instance = GetInstanceOrDie(instance_ptr);\n  if (instance == nullptr) {\n    fprintf(stderr, \"%s called prior to init()!\\n\", function_name.c_str());\n    return false;\n  }\n  return true;\n}\n\nJNIEXPORT jbyteArray convertToByteArray(const std::vector<unsigned char>& data,\n                                        JNIEnv* env) {\n  jbyteArray byteArray = env->NewByteArray(data.size());\n  env->SetByteArrayRegion(byteArray, 0, data.size(),\n                          reinterpret_cast<const jbyte*>(data.data()));\n  return byteArray;\n}\n\n}  // namespace\n\nJNIEXPORT jlong JNICALL JNI_METHOD(init)(JNIEnv* env, jobject instance,\n                                         jint num_channels,\n                                         jint bitrate_bits_per_second,\n                                         jint sample_rate_hz,\n                                         jboolean use_vbr) {\n  constexpr bool low_latency_mode = true;\n  return reinterpret_cast<jlong>(new OggOpusEncoder(\n      num_channels, sample_rate_hz, bitrate_bits_per_second, use_vbr,\n      low_latency_mode));\n}\n\nJNIEXPORT jbyteArray JNICALL\nJNI_METHOD(processAudioBytes)(JNIEnv* env, jobject instance, jlong instance_ptr,\n                              jbyteArray samples, jint offset, jint length) {\n  if (!VerifyInitialized(\"processAudioBytes\", instance_ptr)) {\n    return convertToByteArray(std::vector<unsigned char>(0), env);\n  }\n  jsize array_length_bytes = length;\n  if (!array_length_bytes) {\n    fprintf(stdout, \"Found empty array\\n\");\n  }\n  assert(array_length_bytes % 2 == 0 && \"int16 formatted stream missing bytes!\");\n  std::vector<int16_t> pcm(array_length_bytes / 2);\n  env->GetByteArrayRegion(samples, offset, array_length_bytes,\n                          reinterpret_cast<jbyte*>(pcm.data()));\n  if (env->ExceptionOccurred()) {\n    fprintf(stderr, \"Exception occurred in java Environment object\\n\");\n  }\n\n  return convertToByteArray(GetInstanceOrDie(instance_ptr)->Process(pcm), env);\n}\n\nJNIEXPORT jbyteArray JNICALL JNI_METHOD(flush)(JNIEnv* env, jobject instance,\n                                               jlong instance_ptr) {\n  return convertToByteArray(GetInstanceOrDie(instance_ptr)->Flush(), env);\n}\n\nJNIEXPORT void JNICALL JNI_METHOD(free)(JNIEnv* env, jobject instance,\n                                        jlong instance_ptr) {\n  delete reinterpret_cast<OggOpusEncoder*>(instance_ptr);\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/cpp/jni/ogg_opus_encoder.h",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef AUDIO_UTIL_JNI_OGG_OPUS_ENCODER_H_\n#define AUDIO_UTIL_JNI_OGG_OPUS_ENCODER_H_\n\n#include <jni.h>\n\n// https://stackoverflow.com/questions/25363027/jni-getmethodid-not-working-for-constructor-of-inner-class\n#define JNI_METHOD(fn) \\\n  Java_com_teamopensmartglasses_smartglassesmanager_speechrecognition_google_asr_asrhelpers_StreamingAudioEncoder_00024OggOpusEncoder_##fn  // NOLINT\n\nextern \"C\" {\n// Create opus encoder instance. The pointer is returned in a\n// jlong. Remember to call destroy with the returned value when you're done.\nJNIEXPORT jlong JNICALL JNI_METHOD(init)(JNIEnv* env,\n                                         jobject instance,\n                                         jint num_channels,\n                                         jint bitrate_bits_per_second,\n                                         jint sample_rate_hz,\n                                         jboolean use_vbr);\n\n// samples must be an even number of bytes, as it represents 16-bit audio data.\nJNIEXPORT jbyteArray JNICALL JNI_METHOD(processAudioBytes)(JNIEnv* env,\n                                                           jobject instance,\n                                                           jlong instance_ptr,\n                                                           jbyteArray samples,\n                                                           jint offset,\n                                                           jint length);\n\n// Tell the encoder that there will be no more samples.\nJNIEXPORT jbyteArray JNICALL JNI_METHOD(flush)(JNIEnv* env, jobject instance,\n                                               jlong instance_ptr);\n\n// Releases all resources.\nJNIEXPORT void JNICALL JNI_METHOD(free)(JNIEnv* env, jobject instance,\n    jlong instance_ptr);\n\n}  // extern \"C\"\n#endif  // AUDIO_UTIL_JNI_OGG_OPUS_ENCODER_H_\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/cpp/libogg/Makefile.am",
    "content": "## Process this file with automake to produce Makefile.in\n\noggincludedir = $(includedir)/ogg\n\nogginclude_HEADERS = ogg.h os_types.h\nnodist_ogginclude_HEADERS = config_types.h\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/cpp/libogg/config_types.h",
    "content": "#ifndef __CONFIG_TYPES_H__\n#define __CONFIG_TYPES_H__\n\n/* these are filled in by configure or cmake*/\n#define INCLUDE_INTTYPES_H 1\n#define INCLUDE_STDINT_H 1\n#define INCLUDE_SYS_TYPES_H 1\n\n#if INCLUDE_INTTYPES_H\n#  include <inttypes.h>\n#endif\n#if INCLUDE_STDINT_H\n#  include <stdint.h>\n#endif\n#if INCLUDE_SYS_TYPES_H\n#  include <sys/types.h>\n#endif\n\ntypedef int16_t ogg_int16_t;\ntypedef uint16_t ogg_uint16_t;\ntypedef int32_t ogg_int32_t;\ntypedef uint32_t ogg_uint32_t;\ntypedef int64_t ogg_int64_t;\ntypedef uint64_t ogg_uint64_t;\n\n#endif\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/cpp/libogg/config_types.h.in",
    "content": "#ifndef __CONFIG_TYPES_H__\n#define __CONFIG_TYPES_H__\n\n/* these are filled in by configure or cmake*/\n#define INCLUDE_INTTYPES_H @INCLUDE_INTTYPES_H@\n#define INCLUDE_STDINT_H @INCLUDE_STDINT_H@\n#define INCLUDE_SYS_TYPES_H @INCLUDE_SYS_TYPES_H@\n\n#if INCLUDE_INTTYPES_H\n#  include <inttypes.h>\n#endif\n#if INCLUDE_STDINT_H\n#  include <stdint.h>\n#endif\n#if INCLUDE_SYS_TYPES_H\n#  include <sys/types.h>\n#endif\n\ntypedef @SIZE16@ ogg_int16_t;\ntypedef @USIZE16@ ogg_uint16_t;\ntypedef @SIZE32@ ogg_int32_t;\ntypedef @USIZE32@ ogg_uint32_t;\ntypedef @SIZE64@ ogg_int64_t;\ntypedef @USIZE64@ ogg_uint64_t;\n\n#endif\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/cpp/libogg/ogg.h",
    "content": "/********************************************************************\n *                                                                  *\n * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *\n * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *\n * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *\n * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *\n *                                                                  *\n * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007             *\n * by the Xiph.Org Foundation http://www.xiph.org/                  *\n *                                                                  *\n ********************************************************************\n\n function: toplevel libogg include\n\n ********************************************************************/\n#ifndef _OGG_H\n#define _OGG_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stddef.h>\n#include \"os_types.h\"\n\ntypedef struct {\n  void *iov_base;\n  size_t iov_len;\n} ogg_iovec_t;\n\ntypedef struct {\n  long endbyte;\n  int  endbit;\n\n  unsigned char *buffer;\n  unsigned char *ptr;\n  long storage;\n} oggpack_buffer;\n\n/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/\n\ntypedef struct {\n  unsigned char *header;\n  long header_len;\n  unsigned char *body;\n  long body_len;\n} ogg_page;\n\n/* ogg_stream_state contains the current encode/decode state of a logical\n   Ogg bitstream **********************************************************/\n\ntypedef struct {\n  unsigned char   *body_data;    /* bytes from packet bodies */\n  long    body_storage;          /* storage elements allocated */\n  long    body_fill;             /* elements stored; fill mark */\n  long    body_returned;         /* elements of fill returned */\n\n\n  int     *lacing_vals;      /* The values that will go to the segment table */\n  ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact\n                                this way, but it is simple coupled to the\n                                lacing fifo */\n  long    lacing_storage;\n  long    lacing_fill;\n  long    lacing_packet;\n  long    lacing_returned;\n\n  unsigned char    header[282];      /* working space for header encode */\n  int              header_fill;\n\n  int     e_o_s;          /* set when we have buffered the last packet in the\n                             logical bitstream */\n  int     b_o_s;          /* set after we've written the initial page\n                             of a logical bitstream */\n  long    serialno;\n  long    pageno;\n  ogg_int64_t  packetno;  /* sequence number for decode; the framing\n                             knows where there's a hole in the data,\n                             but we need coupling so that the codec\n                             (which is in a separate abstraction\n                             layer) also knows about the gap */\n  ogg_int64_t   granulepos;\n\n} ogg_stream_state;\n\n/* ogg_packet is used to encapsulate the data and metadata belonging\n   to a single raw Ogg/Vorbis packet *************************************/\n\ntypedef struct {\n  unsigned char *packet;\n  long  bytes;\n  long  b_o_s;\n  long  e_o_s;\n\n  ogg_int64_t  granulepos;\n\n  ogg_int64_t  packetno;     /* sequence number for decode; the framing\n                                knows where there's a hole in the data,\n                                but we need coupling so that the codec\n                                (which is in a separate abstraction\n                                layer) also knows about the gap */\n} ogg_packet;\n\ntypedef struct {\n  unsigned char *data;\n  int storage;\n  int fill;\n  int returned;\n\n  int unsynced;\n  int headerbytes;\n  int bodybytes;\n} ogg_sync_state;\n\n/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/\n\nextern void  oggpack_writeinit(oggpack_buffer *b);\nextern int   oggpack_writecheck(oggpack_buffer *b);\nextern void  oggpack_writetrunc(oggpack_buffer *b,long bits);\nextern void  oggpack_writealign(oggpack_buffer *b);\nextern void  oggpack_writecopy(oggpack_buffer *b,void *source,long bits);\nextern void  oggpack_reset(oggpack_buffer *b);\nextern void  oggpack_writeclear(oggpack_buffer *b);\nextern void  oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);\nextern void  oggpack_write(oggpack_buffer *b,unsigned long value,int bits);\nextern long  oggpack_look(oggpack_buffer *b,int bits);\nextern long  oggpack_look1(oggpack_buffer *b);\nextern void  oggpack_adv(oggpack_buffer *b,int bits);\nextern void  oggpack_adv1(oggpack_buffer *b);\nextern long  oggpack_read(oggpack_buffer *b,int bits);\nextern long  oggpack_read1(oggpack_buffer *b);\nextern long  oggpack_bytes(oggpack_buffer *b);\nextern long  oggpack_bits(oggpack_buffer *b);\nextern unsigned char *oggpack_get_buffer(oggpack_buffer *b);\n\nextern void  oggpackB_writeinit(oggpack_buffer *b);\nextern int   oggpackB_writecheck(oggpack_buffer *b);\nextern void  oggpackB_writetrunc(oggpack_buffer *b,long bits);\nextern void  oggpackB_writealign(oggpack_buffer *b);\nextern void  oggpackB_writecopy(oggpack_buffer *b,void *source,long bits);\nextern void  oggpackB_reset(oggpack_buffer *b);\nextern void  oggpackB_writeclear(oggpack_buffer *b);\nextern void  oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);\nextern void  oggpackB_write(oggpack_buffer *b,unsigned long value,int bits);\nextern long  oggpackB_look(oggpack_buffer *b,int bits);\nextern long  oggpackB_look1(oggpack_buffer *b);\nextern void  oggpackB_adv(oggpack_buffer *b,int bits);\nextern void  oggpackB_adv1(oggpack_buffer *b);\nextern long  oggpackB_read(oggpack_buffer *b,int bits);\nextern long  oggpackB_read1(oggpack_buffer *b);\nextern long  oggpackB_bytes(oggpack_buffer *b);\nextern long  oggpackB_bits(oggpack_buffer *b);\nextern unsigned char *oggpackB_get_buffer(oggpack_buffer *b);\n\n/* Ogg BITSTREAM PRIMITIVES: encoding **************************/\n\nextern int      ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op);\nextern int      ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov,\n                                   int count, long e_o_s, ogg_int64_t granulepos);\nextern int      ogg_stream_pageout(ogg_stream_state *os, ogg_page *og);\nextern int      ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill);\nextern int      ogg_stream_flush(ogg_stream_state *os, ogg_page *og);\nextern int      ogg_stream_flush_fill(ogg_stream_state *os, ogg_page *og, int nfill);\n\n/* Ogg BITSTREAM PRIMITIVES: decoding **************************/\n\nextern int      ogg_sync_init(ogg_sync_state *oy);\nextern int      ogg_sync_clear(ogg_sync_state *oy);\nextern int      ogg_sync_reset(ogg_sync_state *oy);\nextern int      ogg_sync_destroy(ogg_sync_state *oy);\nextern int      ogg_sync_check(ogg_sync_state *oy);\n\nextern char    *ogg_sync_buffer(ogg_sync_state *oy, long size);\nextern int      ogg_sync_wrote(ogg_sync_state *oy, long bytes);\nextern long     ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og);\nextern int      ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og);\nextern int      ogg_stream_pagein(ogg_stream_state *os, ogg_page *og);\nextern int      ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op);\nextern int      ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op);\n\n/* Ogg BITSTREAM PRIMITIVES: general ***************************/\n\nextern int      ogg_stream_init(ogg_stream_state *os,int serialno);\nextern int      ogg_stream_clear(ogg_stream_state *os);\nextern int      ogg_stream_reset(ogg_stream_state *os);\nextern int      ogg_stream_reset_serialno(ogg_stream_state *os,int serialno);\nextern int      ogg_stream_destroy(ogg_stream_state *os);\nextern int      ogg_stream_check(ogg_stream_state *os);\nextern int      ogg_stream_eos(ogg_stream_state *os);\n\nextern void     ogg_page_checksum_set(ogg_page *og);\n\nextern int      ogg_page_version(const ogg_page *og);\nextern int      ogg_page_continued(const ogg_page *og);\nextern int      ogg_page_bos(const ogg_page *og);\nextern int      ogg_page_eos(const ogg_page *og);\nextern ogg_int64_t  ogg_page_granulepos(const ogg_page *og);\nextern int      ogg_page_serialno(const ogg_page *og);\nextern long     ogg_page_pageno(const ogg_page *og);\nextern int      ogg_page_packets(const ogg_page *og);\n\nextern void     ogg_packet_clear(ogg_packet *op);\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif  /* _OGG_H */\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/cpp/libogg/os_types.h",
    "content": "/********************************************************************\n *                                                                  *\n * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *\n * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *\n * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *\n * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *\n *                                                                  *\n * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002             *\n * by the Xiph.Org Foundation http://www.xiph.org/                  *\n *                                                                  *\n ********************************************************************\n\n function: Define a consistent set of types on each platform.\n\n ********************************************************************/\n#ifndef _OS_TYPES_H\n#define _OS_TYPES_H\n\n/* make it easy on the folks that want to compile the libs with a\n   different malloc than stdlib */\n#define _ogg_malloc  malloc\n#define _ogg_calloc  calloc\n#define _ogg_realloc realloc\n#define _ogg_free    free\n\n#if defined(_WIN32)\n\n#  if defined(__CYGWIN__)\n#    include <stdint.h>\n     typedef int16_t ogg_int16_t;\n     typedef uint16_t ogg_uint16_t;\n     typedef int32_t ogg_int32_t;\n     typedef uint32_t ogg_uint32_t;\n     typedef int64_t ogg_int64_t;\n     typedef uint64_t ogg_uint64_t;\n#  elif defined(__MINGW32__)\n#    include <sys/types.h>\n     typedef short ogg_int16_t;\n     typedef unsigned short ogg_uint16_t;\n     typedef int ogg_int32_t;\n     typedef unsigned int ogg_uint32_t;\n     typedef long long ogg_int64_t;\n     typedef unsigned long long ogg_uint64_t;\n#  elif defined(__MWERKS__)\n     typedef long long ogg_int64_t;\n     typedef unsigned long long ogg_uint64_t;\n     typedef int ogg_int32_t;\n     typedef unsigned int ogg_uint32_t;\n     typedef short ogg_int16_t;\n     typedef unsigned short ogg_uint16_t;\n#  else\n#    if defined(_MSC_VER) && (_MSC_VER >= 1800) /* MSVC 2013 and newer */\n#      include <stdint.h>\n       typedef int16_t ogg_int16_t;\n       typedef uint16_t ogg_uint16_t;\n       typedef int32_t ogg_int32_t;\n       typedef uint32_t ogg_uint32_t;\n       typedef int64_t ogg_int64_t;\n       typedef uint64_t ogg_uint64_t;\n#    else\n       /* MSVC/Borland */\n       typedef __int64 ogg_int64_t;\n       typedef __int32 ogg_int32_t;\n       typedef unsigned __int32 ogg_uint32_t;\n       typedef unsigned __int64 ogg_uint64_t;\n       typedef __int16 ogg_int16_t;\n       typedef unsigned __int16 ogg_uint16_t;\n#    endif\n#  endif\n\n#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */\n\n#  include <inttypes.h>\n   typedef int16_t ogg_int16_t;\n   typedef uint16_t ogg_uint16_t;\n   typedef int32_t ogg_int32_t;\n   typedef uint32_t ogg_uint32_t;\n   typedef int64_t ogg_int64_t;\n   typedef uint64_t ogg_uint64_t;\n\n#elif defined(__HAIKU__)\n\n  /* Haiku */\n#  include <sys/types.h>\n   typedef short ogg_int16_t;\n   typedef unsigned short ogg_uint16_t;\n   typedef int ogg_int32_t;\n   typedef unsigned int ogg_uint32_t;\n   typedef long long ogg_int64_t;\n   typedef unsigned long long ogg_uint64_t;\n\n#elif defined(__BEOS__)\n\n   /* Be */\n#  include <inttypes.h>\n   typedef int16_t ogg_int16_t;\n   typedef uint16_t ogg_uint16_t;\n   typedef int32_t ogg_int32_t;\n   typedef uint32_t ogg_uint32_t;\n   typedef int64_t ogg_int64_t;\n   typedef uint64_t ogg_uint64_t;\n\n#elif defined (__EMX__)\n\n   /* OS/2 GCC */\n   typedef short ogg_int16_t;\n   typedef unsigned short ogg_uint16_t;\n   typedef int ogg_int32_t;\n   typedef unsigned int ogg_uint32_t;\n   typedef long long ogg_int64_t;\n   typedef unsigned long long ogg_uint64_t;\n\n\n#elif defined (DJGPP)\n\n   /* DJGPP */\n   typedef short ogg_int16_t;\n   typedef int ogg_int32_t;\n   typedef unsigned int ogg_uint32_t;\n   typedef long long ogg_int64_t;\n   typedef unsigned long long ogg_uint64_t;\n\n#elif defined(R5900)\n\n   /* PS2 EE */\n   typedef long ogg_int64_t;\n   typedef unsigned long ogg_uint64_t;\n   typedef int ogg_int32_t;\n   typedef unsigned ogg_uint32_t;\n   typedef short ogg_int16_t;\n\n#elif defined(__SYMBIAN32__)\n\n   /* Symbian GCC */\n   typedef signed short ogg_int16_t;\n   typedef unsigned short ogg_uint16_t;\n   typedef signed int ogg_int32_t;\n   typedef unsigned int ogg_uint32_t;\n   typedef long long int ogg_int64_t;\n   typedef unsigned long long int ogg_uint64_t;\n\n#elif defined(__TMS320C6X__)\n\n   /* TI C64x compiler */\n   typedef signed short ogg_int16_t;\n   typedef unsigned short ogg_uint16_t;\n   typedef signed int ogg_int32_t;\n   typedef unsigned int ogg_uint32_t;\n   typedef long long int ogg_int64_t;\n   typedef unsigned long long int ogg_uint64_t;\n\n#else\n\n#  include \"config_types.h\"\n\n#endif\n\n#endif  /* _OS_TYPES_H */\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/cpp/libopus/opus.h",
    "content": "/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited\n   Written by Jean-Marc Valin and Koen Vos */\n/*\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n\n   - Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n   - Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER\n   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n/**\n * @file opus.h\n * @brief Opus reference implementation API\n */\n\n#ifndef OPUS_H\n#define OPUS_H\n\n#include \"opus_types.h\"\n#include \"opus_defines.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @mainpage Opus\n *\n * The Opus codec is designed for interactive speech and audio transmission over the Internet.\n * It is designed by the IETF Codec Working Group and incorporates technology from\n * Skype's SILK codec and Xiph.Org's CELT codec.\n *\n * The Opus codec is designed to handle a wide range of interactive audio applications,\n * including Voice over IP, videoconferencing, in-game chat, and even remote live music\n * performances. It can scale from low bit-rate narrowband speech to very high quality\n * stereo music. Its main features are:\n\n * @li Sampling rates from 8 to 48 kHz\n * @li Bit-rates from 6 kb/s to 510 kb/s\n * @li Support for both constant bit-rate (CBR) and variable bit-rate (VBR)\n * @li Audio bandwidth from narrowband to full-band\n * @li Support for speech and music\n * @li Support for mono and stereo\n * @li Support for multichannel (up to 255 channels)\n * @li Frame sizes from 2.5 ms to 60 ms\n * @li Good loss robustness and packet loss concealment (PLC)\n * @li Floating point and fixed-point implementation\n *\n * Documentation sections:\n * @li @ref opus_encoder\n * @li @ref opus_decoder\n * @li @ref opus_repacketizer\n * @li @ref opus_multistream\n * @li @ref opus_libinfo\n * @li @ref opus_custom\n */\n\n/** @defgroup opus_encoder Opus Encoder\n  * @{\n  *\n  * @brief This page describes the process and functions used to encode Opus.\n  *\n  * Since Opus is a stateful codec, the encoding process starts with creating an encoder\n  * state. This can be done with:\n  *\n  * @code\n  * int          error;\n  * OpusEncoder *enc;\n  * enc = opus_encoder_create(Fs, channels, application, &error);\n  * @endcode\n  *\n  * From this point, @c enc can be used for encoding an audio stream. An encoder state\n  * @b must @b not be used for more than one stream at the same time. Similarly, the encoder\n  * state @b must @b not be re-initialized for each frame.\n  *\n  * While opus_encoder_create() allocates memory for the state, it's also possible\n  * to initialize pre-allocated memory:\n  *\n  * @code\n  * int          size;\n  * int          error;\n  * OpusEncoder *enc;\n  * size = opus_encoder_get_size(channels);\n  * enc = malloc(size);\n  * error = opus_encoder_init(enc, Fs, channels, application);\n  * @endcode\n  *\n  * where opus_encoder_get_size() returns the required size for the encoder state. Note that\n  * future versions of this code may change the size, so no assuptions should be made about it.\n  *\n  * The encoder state is always continuous in memory and only a shallow copy is sufficient\n  * to copy it (e.g. memcpy())\n  *\n  * It is possible to change some of the encoder's settings using the opus_encoder_ctl()\n  * interface. All these settings already default to the recommended value, so they should\n  * only be changed when necessary. The most common settings one may want to change are:\n  *\n  * @code\n  * opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate));\n  * opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));\n  * opus_encoder_ctl(enc, OPUS_SET_SIGNAL(signal_type));\n  * @endcode\n  *\n  * where\n  *\n  * @arg bitrate is in bits per second (b/s)\n  * @arg complexity is a value from 1 to 10, where 1 is the lowest complexity and 10 is the highest\n  * @arg signal_type is either OPUS_AUTO (default), OPUS_SIGNAL_VOICE, or OPUS_SIGNAL_MUSIC\n  *\n  * See @ref opus_encoderctls and @ref opus_genericctls for a complete list of parameters that can be set or queried. Most parameters can be set or changed at any time during a stream.\n  *\n  * To encode a frame, opus_encode() or opus_encode_float() must be called with exactly one frame (2.5, 5, 10, 20, 40 or 60 ms) of audio data:\n  * @code\n  * len = opus_encode(enc, audio_frame, frame_size, packet, max_packet);\n  * @endcode\n  *\n  * where\n  * <ul>\n  * <li>audio_frame is the audio data in opus_int16 (or float for opus_encode_float())</li>\n  * <li>frame_size is the duration of the frame in samples (per channel)</li>\n  * <li>packet is the byte array to which the compressed data is written</li>\n  * <li>max_packet is the maximum number of bytes that can be written in the packet (4000 bytes is recommended).\n  *     Do not use max_packet to control VBR target bitrate, instead use the #OPUS_SET_BITRATE CTL.</li>\n  * </ul>\n  *\n  * opus_encode() and opus_encode_float() return the number of bytes actually written to the packet.\n  * The return value <b>can be negative</b>, which indicates that an error has occurred. If the return value\n  * is 2 bytes or less, then the packet does not need to be transmitted (DTX).\n  *\n  * Once the encoder state if no longer needed, it can be destroyed with\n  *\n  * @code\n  * opus_encoder_destroy(enc);\n  * @endcode\n  *\n  * If the encoder was created with opus_encoder_init() rather than opus_encoder_create(),\n  * then no action is required aside from potentially freeing the memory that was manually\n  * allocated for it (calling free(enc) for the example above)\n  *\n  */\n\n/** Opus encoder state.\n  * This contains the complete state of an Opus encoder.\n  * It is position independent and can be freely copied.\n  * @see opus_encoder_create,opus_encoder_init\n  */\ntypedef struct OpusEncoder OpusEncoder;\n\n/** Gets the size of an <code>OpusEncoder</code> structure.\n  * @param[in] channels <tt>int</tt>: Number of channels.\n  *                                   This must be 1 or 2.\n  * @returns The size in bytes.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_encoder_get_size(int channels);\n\n/**\n */\n\n/** Allocates and initializes an encoder state.\n * There are three coding modes:\n *\n * @ref OPUS_APPLICATION_VOIP gives best quality at a given bitrate for voice\n *    signals. It enhances the  input signal by high-pass filtering and\n *    emphasizing formants and harmonics. Optionally  it includes in-band\n *    forward error correction to protect against packet loss. Use this\n *    mode for typical VoIP applications. Because of the enhancement,\n *    even at high bitrates the output may sound different from the input.\n *\n * @ref OPUS_APPLICATION_AUDIO gives best quality at a given bitrate for most\n *    non-voice signals like music. Use this mode for music and mixed\n *    (music/voice) content, broadcast, and applications requiring less\n *    than 15 ms of coding delay.\n *\n * @ref OPUS_APPLICATION_RESTRICTED_LOWDELAY configures low-delay mode that\n *    disables the speech-optimized mode in exchange for slightly reduced delay.\n *    This mode can only be set on an newly initialized or freshly reset encoder\n *    because it changes the codec delay.\n *\n * This is useful when the caller knows that the speech-optimized modes will not be needed (use with caution).\n * @param [in] Fs <tt>opus_int32</tt>: Sampling rate of input signal (Hz)\n *                                     This must be one of 8000, 12000, 16000,\n *                                     24000, or 48000.\n * @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal\n * @param [in] application <tt>int</tt>: Coding mode (@ref OPUS_APPLICATION_VOIP/@ref OPUS_APPLICATION_AUDIO/@ref OPUS_APPLICATION_RESTRICTED_LOWDELAY)\n * @param [out] error <tt>int*</tt>: @ref opus_errorcodes\n * @note Regardless of the sampling rate and number channels selected, the Opus encoder\n * can switch to a lower audio bandwidth or number of channels if the bitrate\n * selected is too low. This also means that it is safe to always use 48 kHz stereo input\n * and let the encoder optimize the encoding.\n */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusEncoder *opus_encoder_create(\n    opus_int32 Fs,\n    int channels,\n    int application,\n    int *error\n);\n\n/** Initializes a previously allocated encoder state\n  * The memory pointed to by st must be at least the size returned by opus_encoder_get_size().\n  * This is intended for applications which use their own allocator instead of malloc.\n  * @see opus_encoder_create(),opus_encoder_get_size()\n  * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.\n  * @param [in] st <tt>OpusEncoder*</tt>: Encoder state\n  * @param [in] Fs <tt>opus_int32</tt>: Sampling rate of input signal (Hz)\n *                                      This must be one of 8000, 12000, 16000,\n *                                      24000, or 48000.\n  * @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal\n  * @param [in] application <tt>int</tt>: Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO/OPUS_APPLICATION_RESTRICTED_LOWDELAY)\n  * @retval #OPUS_OK Success or @ref opus_errorcodes\n  */\nOPUS_EXPORT int opus_encoder_init(\n    OpusEncoder *st,\n    opus_int32 Fs,\n    int channels,\n    int application\n) OPUS_ARG_NONNULL(1);\n\n/** Encodes an Opus frame.\n  * @param [in] st <tt>OpusEncoder*</tt>: Encoder state\n  * @param [in] pcm <tt>opus_int16*</tt>: Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(opus_int16)\n  * @param [in] frame_size <tt>int</tt>: Number of samples per channel in the\n  *                                      input signal.\n  *                                      This must be an Opus frame size for\n  *                                      the encoder's sampling rate.\n  *                                      For example, at 48 kHz the permitted\n  *                                      values are 120, 240, 480, 960, 1920,\n  *                                      and 2880.\n  *                                      Passing in a duration of less than\n  *                                      10 ms (480 samples at 48 kHz) will\n  *                                      prevent the encoder from using the LPC\n  *                                      or hybrid modes.\n  * @param [out] data <tt>unsigned char*</tt>: Output payload.\n  *                                            This must contain storage for at\n  *                                            least \\a max_data_bytes.\n  * @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated\n  *                                                 memory for the output\n  *                                                 payload. This may be\n  *                                                 used to impose an upper limit on\n  *                                                 the instant bitrate, but should\n  *                                                 not be used as the only bitrate\n  *                                                 control. Use #OPUS_SET_BITRATE to\n  *                                                 control the bitrate.\n  * @returns The length of the encoded packet (in bytes) on success or a\n  *          negative error code (see @ref opus_errorcodes) on failure.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode(\n    OpusEncoder *st,\n    const opus_int16 *pcm,\n    int frame_size,\n    unsigned char *data,\n    opus_int32 max_data_bytes\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);\n\n/** Encodes an Opus frame from floating point input.\n  * @param [in] st <tt>OpusEncoder*</tt>: Encoder state\n  * @param [in] pcm <tt>float*</tt>: Input in float format (interleaved if 2 channels), with a normal range of +/-1.0.\n  *          Samples with a range beyond +/-1.0 are supported but will\n  *          be clipped by decoders using the integer API and should\n  *          only be used if it is known that the far end supports\n  *          extended dynamic range.\n  *          length is frame_size*channels*sizeof(float)\n  * @param [in] frame_size <tt>int</tt>: Number of samples per channel in the\n  *                                      input signal.\n  *                                      This must be an Opus frame size for\n  *                                      the encoder's sampling rate.\n  *                                      For example, at 48 kHz the permitted\n  *                                      values are 120, 240, 480, 960, 1920,\n  *                                      and 2880.\n  *                                      Passing in a duration of less than\n  *                                      10 ms (480 samples at 48 kHz) will\n  *                                      prevent the encoder from using the LPC\n  *                                      or hybrid modes.\n  * @param [out] data <tt>unsigned char*</tt>: Output payload.\n  *                                            This must contain storage for at\n  *                                            least \\a max_data_bytes.\n  * @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated\n  *                                                 memory for the output\n  *                                                 payload. This may be\n  *                                                 used to impose an upper limit on\n  *                                                 the instant bitrate, but should\n  *                                                 not be used as the only bitrate\n  *                                                 control. Use #OPUS_SET_BITRATE to\n  *                                                 control the bitrate.\n  * @returns The length of the encoded packet (in bytes) on success or a\n  *          negative error code (see @ref opus_errorcodes) on failure.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode_float(\n    OpusEncoder *st,\n    const float *pcm,\n    int frame_size,\n    unsigned char *data,\n    opus_int32 max_data_bytes\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);\n\n/** Frees an <code>OpusEncoder</code> allocated by opus_encoder_create().\n  * @param[in] st <tt>OpusEncoder*</tt>: State to be freed.\n  */\nOPUS_EXPORT void opus_encoder_destroy(OpusEncoder *st);\n\n/** Perform a CTL function on an Opus encoder.\n  *\n  * Generally the request and subsequent arguments are generated\n  * by a convenience macro.\n  * @param st <tt>OpusEncoder*</tt>: Encoder state.\n  * @param request This and all remaining parameters should be replaced by one\n  *                of the convenience macros in @ref opus_genericctls or\n  *                @ref opus_encoderctls.\n  * @see opus_genericctls\n  * @see opus_encoderctls\n  */\nOPUS_EXPORT int opus_encoder_ctl(OpusEncoder *st, int request, ...) OPUS_ARG_NONNULL(1);\n/**@}*/\n\n/** @defgroup opus_decoder Opus Decoder\n  * @{\n  *\n  * @brief This page describes the process and functions used to decode Opus.\n  *\n  * The decoding process also starts with creating a decoder\n  * state. This can be done with:\n  * @code\n  * int          error;\n  * OpusDecoder *dec;\n  * dec = opus_decoder_create(Fs, channels, &error);\n  * @endcode\n  * where\n  * @li Fs is the sampling rate and must be 8000, 12000, 16000, 24000, or 48000\n  * @li channels is the number of channels (1 or 2)\n  * @li error will hold the error code in case of failure (or #OPUS_OK on success)\n  * @li the return value is a newly created decoder state to be used for decoding\n  *\n  * While opus_decoder_create() allocates memory for the state, it's also possible\n  * to initialize pre-allocated memory:\n  * @code\n  * int          size;\n  * int          error;\n  * OpusDecoder *dec;\n  * size = opus_decoder_get_size(channels);\n  * dec = malloc(size);\n  * error = opus_decoder_init(dec, Fs, channels);\n  * @endcode\n  * where opus_decoder_get_size() returns the required size for the decoder state. Note that\n  * future versions of this code may change the size, so no assuptions should be made about it.\n  *\n  * The decoder state is always continuous in memory and only a shallow copy is sufficient\n  * to copy it (e.g. memcpy())\n  *\n  * To decode a frame, opus_decode() or opus_decode_float() must be called with a packet of compressed audio data:\n  * @code\n  * frame_size = opus_decode(dec, packet, len, decoded, max_size, 0);\n  * @endcode\n  * where\n  *\n  * @li packet is the byte array containing the compressed data\n  * @li len is the exact number of bytes contained in the packet\n  * @li decoded is the decoded audio data in opus_int16 (or float for opus_decode_float())\n  * @li max_size is the max duration of the frame in samples (per channel) that can fit into the decoded_frame array\n  *\n  * opus_decode() and opus_decode_float() return the number of samples (per channel) decoded from the packet.\n  * If that value is negative, then an error has occurred. This can occur if the packet is corrupted or if the audio\n  * buffer is too small to hold the decoded audio.\n  *\n  * Opus is a stateful codec with overlapping blocks and as a result Opus\n  * packets are not coded independently of each other. Packets must be\n  * passed into the decoder serially and in the correct order for a correct\n  * decode. Lost packets can be replaced with loss concealment by calling\n  * the decoder with a null pointer and zero length for the missing packet.\n  *\n  * A single codec state may only be accessed from a single thread at\n  * a time and any required locking must be performed by the caller. Separate\n  * streams must be decoded with separate decoder states and can be decoded\n  * in parallel unless the library was compiled with NONTHREADSAFE_PSEUDOSTACK\n  * defined.\n  *\n  */\n\n/** Opus decoder state.\n  * This contains the complete state of an Opus decoder.\n  * It is position independent and can be freely copied.\n  * @see opus_decoder_create,opus_decoder_init\n  */\ntypedef struct OpusDecoder OpusDecoder;\n\n/** Gets the size of an <code>OpusDecoder</code> structure.\n  * @param [in] channels <tt>int</tt>: Number of channels.\n  *                                    This must be 1 or 2.\n  * @returns The size in bytes.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_size(int channels);\n\n/** Allocates and initializes a decoder state.\n  * @param [in] Fs <tt>opus_int32</tt>: Sample rate to decode at (Hz).\n  *                                     This must be one of 8000, 12000, 16000,\n  *                                     24000, or 48000.\n  * @param [in] channels <tt>int</tt>: Number of channels (1 or 2) to decode\n  * @param [out] error <tt>int*</tt>: #OPUS_OK Success or @ref opus_errorcodes\n  *\n  * Internally Opus stores data at 48000 Hz, so that should be the default\n  * value for Fs. However, the decoder can efficiently decode to buffers\n  * at 8, 12, 16, and 24 kHz so if for some reason the caller cannot use\n  * data at the full sample rate, or knows the compressed data doesn't\n  * use the full frequency range, it can request decoding at a reduced\n  * rate. Likewise, the decoder is capable of filling in either mono or\n  * interleaved stereo pcm buffers, at the caller's request.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusDecoder *opus_decoder_create(\n    opus_int32 Fs,\n    int channels,\n    int *error\n);\n\n/** Initializes a previously allocated decoder state.\n  * The state must be at least the size returned by opus_decoder_get_size().\n  * This is intended for applications which use their own allocator instead of malloc. @see opus_decoder_create,opus_decoder_get_size\n  * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.\n  * @param [in] st <tt>OpusDecoder*</tt>: Decoder state.\n  * @param [in] Fs <tt>opus_int32</tt>: Sampling rate to decode to (Hz).\n  *                                     This must be one of 8000, 12000, 16000,\n  *                                     24000, or 48000.\n  * @param [in] channels <tt>int</tt>: Number of channels (1 or 2) to decode\n  * @retval #OPUS_OK Success or @ref opus_errorcodes\n  */\nOPUS_EXPORT int opus_decoder_init(\n    OpusDecoder *st,\n    opus_int32 Fs,\n    int channels\n) OPUS_ARG_NONNULL(1);\n\n/** Decode an Opus packet.\n  * @param [in] st <tt>OpusDecoder*</tt>: Decoder state\n  * @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss\n  * @param [in] len <tt>opus_int32</tt>: Number of bytes in payload*\n  * @param [out] pcm <tt>opus_int16*</tt>: Output signal (interleaved if 2 channels). length\n  *  is frame_size*channels*sizeof(opus_int16)\n  * @param [in] frame_size Number of samples per channel of available space in \\a pcm.\n  *  If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will\n  *  not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1),\n  *  then frame_size needs to be exactly the duration of audio that is missing, otherwise the\n  *  decoder will not be in the optimal state to decode the next incoming packet. For the PLC and\n  *  FEC cases, frame_size <b>must</b> be a multiple of 2.5 ms.\n  * @param [in] decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band forward error correction data be\n  *  decoded. If no such data is available, the frame is decoded as if it were lost.\n  * @returns Number of decoded samples or @ref opus_errorcodes\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode(\n    OpusDecoder *st,\n    const unsigned char *data,\n    opus_int32 len,\n    opus_int16 *pcm,\n    int frame_size,\n    int decode_fec\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);\n\n/** Decode an Opus packet with floating point output.\n  * @param [in] st <tt>OpusDecoder*</tt>: Decoder state\n  * @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss\n  * @param [in] len <tt>opus_int32</tt>: Number of bytes in payload\n  * @param [out] pcm <tt>float*</tt>: Output signal (interleaved if 2 channels). length\n  *  is frame_size*channels*sizeof(float)\n  * @param [in] frame_size Number of samples per channel of available space in \\a pcm.\n  *  If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will\n  *  not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1),\n  *  then frame_size needs to be exactly the duration of audio that is missing, otherwise the\n  *  decoder will not be in the optimal state to decode the next incoming packet. For the PLC and\n  *  FEC cases, frame_size <b>must</b> be a multiple of 2.5 ms.\n  * @param [in] decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band forward error correction data be\n  *  decoded. If no such data is available the frame is decoded as if it were lost.\n  * @returns Number of decoded samples or @ref opus_errorcodes\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode_float(\n    OpusDecoder *st,\n    const unsigned char *data,\n    opus_int32 len,\n    float *pcm,\n    int frame_size,\n    int decode_fec\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);\n\n/** Perform a CTL function on an Opus decoder.\n  *\n  * Generally the request and subsequent arguments are generated\n  * by a convenience macro.\n  * @param st <tt>OpusDecoder*</tt>: Decoder state.\n  * @param request This and all remaining parameters should be replaced by one\n  *                of the convenience macros in @ref opus_genericctls or\n  *                @ref opus_decoderctls.\n  * @see opus_genericctls\n  * @see opus_decoderctls\n  */\nOPUS_EXPORT int opus_decoder_ctl(OpusDecoder *st, int request, ...) OPUS_ARG_NONNULL(1);\n\n/** Frees an <code>OpusDecoder</code> allocated by opus_decoder_create().\n  * @param[in] st <tt>OpusDecoder*</tt>: State to be freed.\n  */\nOPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st);\n\n/** Parse an opus packet into one or more frames.\n  * Opus_decode will perform this operation internally so most applications do\n  * not need to use this function.\n  * This function does not copy the frames, the returned pointers are pointers into\n  * the input packet.\n  * @param [in] data <tt>char*</tt>: Opus packet to be parsed\n  * @param [in] len <tt>opus_int32</tt>: size of data\n  * @param [out] out_toc <tt>char*</tt>: TOC pointer\n  * @param [out] frames <tt>char*[48]</tt> encapsulated frames\n  * @param [out] size <tt>opus_int16[48]</tt> sizes of the encapsulated frames\n  * @param [out] payload_offset <tt>int*</tt>: returns the position of the payload within the packet (in bytes)\n  * @returns number of frames\n  */\nOPUS_EXPORT int opus_packet_parse(\n   const unsigned char *data,\n   opus_int32 len,\n   unsigned char *out_toc,\n   const unsigned char *frames[48],\n   opus_int16 size[48],\n   int *payload_offset\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5);\n\n/** Gets the bandwidth of an Opus packet.\n  * @param [in] data <tt>char*</tt>: Opus packet\n  * @retval OPUS_BANDWIDTH_NARROWBAND Narrowband (4kHz bandpass)\n  * @retval OPUS_BANDWIDTH_MEDIUMBAND Mediumband (6kHz bandpass)\n  * @retval OPUS_BANDWIDTH_WIDEBAND Wideband (8kHz bandpass)\n  * @retval OPUS_BANDWIDTH_SUPERWIDEBAND Superwideband (12kHz bandpass)\n  * @retval OPUS_BANDWIDTH_FULLBAND Fullband (20kHz bandpass)\n  * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_bandwidth(const unsigned char *data) OPUS_ARG_NONNULL(1);\n\n/** Gets the number of samples per frame from an Opus packet.\n  * @param [in] data <tt>char*</tt>: Opus packet.\n  *                                  This must contain at least one byte of\n  *                                  data.\n  * @param [in] Fs <tt>opus_int32</tt>: Sampling rate in Hz.\n  *                                     This must be a multiple of 400, or\n  *                                     inaccurate results will be returned.\n  * @returns Number of samples per frame.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_samples_per_frame(const unsigned char *data, opus_int32 Fs) OPUS_ARG_NONNULL(1);\n\n/** Gets the number of channels from an Opus packet.\n  * @param [in] data <tt>char*</tt>: Opus packet\n  * @returns Number of channels\n  * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_channels(const unsigned char *data) OPUS_ARG_NONNULL(1);\n\n/** Gets the number of frames in an Opus packet.\n  * @param [in] packet <tt>char*</tt>: Opus packet\n  * @param [in] len <tt>opus_int32</tt>: Length of packet\n  * @returns Number of frames\n  * @retval OPUS_BAD_ARG Insufficient data was passed to the function\n  * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1);\n\n/** Gets the number of samples of an Opus packet.\n  * @param [in] packet <tt>char*</tt>: Opus packet\n  * @param [in] len <tt>opus_int32</tt>: Length of packet\n  * @param [in] Fs <tt>opus_int32</tt>: Sampling rate in Hz.\n  *                                     This must be a multiple of 400, or\n  *                                     inaccurate results will be returned.\n  * @returns Number of samples\n  * @retval OPUS_BAD_ARG Insufficient data was passed to the function\n  * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, opus_int32 Fs) OPUS_ARG_NONNULL(1);\n\n/** Gets the number of samples of an Opus packet.\n  * @param [in] dec <tt>OpusDecoder*</tt>: Decoder state\n  * @param [in] packet <tt>char*</tt>: Opus packet\n  * @param [in] len <tt>opus_int32</tt>: Length of packet\n  * @returns Number of samples\n  * @retval OPUS_BAD_ARG Insufficient data was passed to the function\n  * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_nb_samples(const OpusDecoder *dec, const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);\n\n/** Applies soft-clipping to bring a float signal within the [-1,1] range. If\n  * the signal is already in that range, nothing is done. If there are values\n  * outside of [-1,1], then the signal is clipped as smoothly as possible to\n  * both fit in the range and avoid creating excessive distortion in the\n  * process.\n  * @param [in,out] pcm <tt>float*</tt>: Input PCM and modified PCM\n  * @param [in] frame_size <tt>int</tt> Number of samples per channel to process\n  * @param [in] channels <tt>int</tt>: Number of channels\n  * @param [in,out] softclip_mem <tt>float*</tt>: State memory for the soft clipping process (one float per channel, initialized to zero)\n  */\nOPUS_EXPORT void opus_pcm_soft_clip(float *pcm, int frame_size, int channels, float *softclip_mem);\n\n\n/**@}*/\n\n/** @defgroup opus_repacketizer Repacketizer\n  * @{\n  *\n  * The repacketizer can be used to merge multiple Opus packets into a single\n  * packet or alternatively to split Opus packets that have previously been\n  * merged. Splitting valid Opus packets is always guaranteed to succeed,\n  * whereas merging valid packets only succeeds if all frames have the same\n  * mode, bandwidth, and frame size, and when the total duration of the merged\n  * packet is no more than 120 ms. The 120 ms limit comes from the\n  * specification and limits decoder memory requirements at a point where\n  * framing overhead becomes negligible.\n  *\n  * The repacketizer currently only operates on elementary Opus\n  * streams. It will not manipualte multistream packets successfully, except in\n  * the degenerate case where they consist of data from a single stream.\n  *\n  * The repacketizing process starts with creating a repacketizer state, either\n  * by calling opus_repacketizer_create() or by allocating the memory yourself,\n  * e.g.,\n  * @code\n  * OpusRepacketizer *rp;\n  * rp = (OpusRepacketizer*)malloc(opus_repacketizer_get_size());\n  * if (rp != NULL)\n  *     opus_repacketizer_init(rp);\n  * @endcode\n  *\n  * Then the application should submit packets with opus_repacketizer_cat(),\n  * extract new packets with opus_repacketizer_out() or\n  * opus_repacketizer_out_range(), and then reset the state for the next set of\n  * input packets via opus_repacketizer_init().\n  *\n  * For example, to split a sequence of packets into individual frames:\n  * @code\n  * unsigned char *data;\n  * int len;\n  * while (get_next_packet(&data, &len))\n  * {\n  *   unsigned char out[1276];\n  *   opus_int32 out_len;\n  *   int nb_frames;\n  *   int err;\n  *   int i;\n  *   err = opus_repacketizer_cat(rp, data, len);\n  *   if (err != OPUS_OK)\n  *   {\n  *     release_packet(data);\n  *     return err;\n  *   }\n  *   nb_frames = opus_repacketizer_get_nb_frames(rp);\n  *   for (i = 0; i < nb_frames; i++)\n  *   {\n  *     out_len = opus_repacketizer_out_range(rp, i, i+1, out, sizeof(out));\n  *     if (out_len < 0)\n  *     {\n  *        release_packet(data);\n  *        return (int)out_len;\n  *     }\n  *     output_next_packet(out, out_len);\n  *   }\n  *   opus_repacketizer_init(rp);\n  *   release_packet(data);\n  * }\n  * @endcode\n  *\n  * Alternatively, to combine a sequence of frames into packets that each\n  * contain up to <code>TARGET_DURATION_MS</code> milliseconds of data:\n  * @code\n  * // The maximum number of packets with duration TARGET_DURATION_MS occurs\n  * // when the frame size is 2.5 ms, for a total of (TARGET_DURATION_MS*2/5)\n  * // packets.\n  * unsigned char *data[(TARGET_DURATION_MS*2/5)+1];\n  * opus_int32 len[(TARGET_DURATION_MS*2/5)+1];\n  * int nb_packets;\n  * unsigned char out[1277*(TARGET_DURATION_MS*2/2)];\n  * opus_int32 out_len;\n  * int prev_toc;\n  * nb_packets = 0;\n  * while (get_next_packet(data+nb_packets, len+nb_packets))\n  * {\n  *   int nb_frames;\n  *   int err;\n  *   nb_frames = opus_packet_get_nb_frames(data[nb_packets], len[nb_packets]);\n  *   if (nb_frames < 1)\n  *   {\n  *     release_packets(data, nb_packets+1);\n  *     return nb_frames;\n  *   }\n  *   nb_frames += opus_repacketizer_get_nb_frames(rp);\n  *   // If adding the next packet would exceed our target, or it has an\n  *   // incompatible TOC sequence, output the packets we already have before\n  *   // submitting it.\n  *   // N.B., The nb_packets > 0 check ensures we've submitted at least one\n  *   // packet since the last call to opus_repacketizer_init(). Otherwise a\n  *   // single packet longer than TARGET_DURATION_MS would cause us to try to\n  *   // output an (invalid) empty packet. It also ensures that prev_toc has\n  *   // been set to a valid value. Additionally, len[nb_packets] > 0 is\n  *   // guaranteed by the call to opus_packet_get_nb_frames() above, so the\n  *   // reference to data[nb_packets][0] should be valid.\n  *   if (nb_packets > 0 && (\n  *       ((prev_toc & 0xFC) != (data[nb_packets][0] & 0xFC)) ||\n  *       opus_packet_get_samples_per_frame(data[nb_packets], 48000)*nb_frames >\n  *       TARGET_DURATION_MS*48))\n  *   {\n  *     out_len = opus_repacketizer_out(rp, out, sizeof(out));\n  *     if (out_len < 0)\n  *     {\n  *        release_packets(data, nb_packets+1);\n  *        return (int)out_len;\n  *     }\n  *     output_next_packet(out, out_len);\n  *     opus_repacketizer_init(rp);\n  *     release_packets(data, nb_packets);\n  *     data[0] = data[nb_packets];\n  *     len[0] = len[nb_packets];\n  *     nb_packets = 0;\n  *   }\n  *   err = opus_repacketizer_cat(rp, data[nb_packets], len[nb_packets]);\n  *   if (err != OPUS_OK)\n  *   {\n  *     release_packets(data, nb_packets+1);\n  *     return err;\n  *   }\n  *   prev_toc = data[nb_packets][0];\n  *   nb_packets++;\n  * }\n  * // Output the final, partial packet.\n  * if (nb_packets > 0)\n  * {\n  *   out_len = opus_repacketizer_out(rp, out, sizeof(out));\n  *   release_packets(data, nb_packets);\n  *   if (out_len < 0)\n  *     return (int)out_len;\n  *   output_next_packet(out, out_len);\n  * }\n  * @endcode\n  *\n  * An alternate way of merging packets is to simply call opus_repacketizer_cat()\n  * unconditionally until it fails. At that point, the merged packet can be\n  * obtained with opus_repacketizer_out() and the input packet for which\n  * opus_repacketizer_cat() needs to be re-added to a newly reinitialized\n  * repacketizer state.\n  */\n\ntypedef struct OpusRepacketizer OpusRepacketizer;\n\n/** Gets the size of an <code>OpusRepacketizer</code> structure.\n  * @returns The size in bytes.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_size(void);\n\n/** (Re)initializes a previously allocated repacketizer state.\n  * The state must be at least the size returned by opus_repacketizer_get_size().\n  * This can be used for applications which use their own allocator instead of\n  * malloc().\n  * It must also be called to reset the queue of packets waiting to be\n  * repacketized, which is necessary if the maximum packet duration of 120 ms\n  * is reached or if you wish to submit packets with a different Opus\n  * configuration (coding mode, audio bandwidth, frame size, or channel count).\n  * Failure to do so will prevent a new packet from being added with\n  * opus_repacketizer_cat().\n  * @see opus_repacketizer_create\n  * @see opus_repacketizer_get_size\n  * @see opus_repacketizer_cat\n  * @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state to\n  *                                       (re)initialize.\n  * @returns A pointer to the same repacketizer state that was passed in.\n  */\nOPUS_EXPORT OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1);\n\n/** Allocates memory and initializes the new repacketizer with\n * opus_repacketizer_init().\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusRepacketizer *opus_repacketizer_create(void);\n\n/** Frees an <code>OpusRepacketizer</code> allocated by\n  * opus_repacketizer_create().\n  * @param[in] rp <tt>OpusRepacketizer*</tt>: State to be freed.\n  */\nOPUS_EXPORT void opus_repacketizer_destroy(OpusRepacketizer *rp);\n\n/** Add a packet to the current repacketizer state.\n  * This packet must match the configuration of any packets already submitted\n  * for repacketization since the last call to opus_repacketizer_init().\n  * This means that it must have the same coding mode, audio bandwidth, frame\n  * size, and channel count.\n  * This can be checked in advance by examining the top 6 bits of the first\n  * byte of the packet, and ensuring they match the top 6 bits of the first\n  * byte of any previously submitted packet.\n  * The total duration of audio in the repacketizer state also must not exceed\n  * 120 ms, the maximum duration of a single packet, after adding this packet.\n  *\n  * The contents of the current repacketizer state can be extracted into new\n  * packets using opus_repacketizer_out() or opus_repacketizer_out_range().\n  *\n  * In order to add a packet with a different configuration or to add more\n  * audio beyond 120 ms, you must clear the repacketizer state by calling\n  * opus_repacketizer_init().\n  * If a packet is too large to add to the current repacketizer state, no part\n  * of it is added, even if it contains multiple frames, some of which might\n  * fit.\n  * If you wish to be able to add parts of such packets, you should first use\n  * another repacketizer to split the packet into pieces and add them\n  * individually.\n  * @see opus_repacketizer_out_range\n  * @see opus_repacketizer_out\n  * @see opus_repacketizer_init\n  * @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state to which to\n  *                                       add the packet.\n  * @param[in] data <tt>const unsigned char*</tt>: The packet data.\n  *                                                The application must ensure\n  *                                                this pointer remains valid\n  *                                                until the next call to\n  *                                                opus_repacketizer_init() or\n  *                                                opus_repacketizer_destroy().\n  * @param len <tt>opus_int32</tt>: The number of bytes in the packet data.\n  * @returns An error code indicating whether or not the operation succeeded.\n  * @retval #OPUS_OK The packet's contents have been added to the repacketizer\n  *                  state.\n  * @retval #OPUS_INVALID_PACKET The packet did not have a valid TOC sequence,\n  *                              the packet's TOC sequence was not compatible\n  *                              with previously submitted packets (because\n  *                              the coding mode, audio bandwidth, frame size,\n  *                              or channel count did not match), or adding\n  *                              this packet would increase the total amount of\n  *                              audio stored in the repacketizer state to more\n  *                              than 120 ms.\n  */\nOPUS_EXPORT int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);\n\n\n/** Construct a new packet from data previously submitted to the repacketizer\n  * state via opus_repacketizer_cat().\n  * @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state from which to\n  *                                       construct the new packet.\n  * @param begin <tt>int</tt>: The index of the first frame in the current\n  *                            repacketizer state to include in the output.\n  * @param end <tt>int</tt>: One past the index of the last frame in the\n  *                          current repacketizer state to include in the\n  *                          output.\n  * @param[out] data <tt>const unsigned char*</tt>: The buffer in which to\n  *                                                 store the output packet.\n  * @param maxlen <tt>opus_int32</tt>: The maximum number of bytes to store in\n  *                                    the output buffer. In order to guarantee\n  *                                    success, this should be at least\n  *                                    <code>1276</code> for a single frame,\n  *                                    or for multiple frames,\n  *                                    <code>1277*(end-begin)</code>.\n  *                                    However, <code>1*(end-begin)</code> plus\n  *                                    the size of all packet data submitted to\n  *                                    the repacketizer since the last call to\n  *                                    opus_repacketizer_init() or\n  *                                    opus_repacketizer_create() is also\n  *                                    sufficient, and possibly much smaller.\n  * @returns The total size of the output packet on success, or an error code\n  *          on failure.\n  * @retval #OPUS_BAD_ARG <code>[begin,end)</code> was an invalid range of\n  *                       frames (begin < 0, begin >= end, or end >\n  *                       opus_repacketizer_get_nb_frames()).\n  * @retval #OPUS_BUFFER_TOO_SMALL \\a maxlen was insufficient to contain the\n  *                                complete output packet.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);\n\n/** Return the total number of frames contained in packet data submitted to\n  * the repacketizer state so far via opus_repacketizer_cat() since the last\n  * call to opus_repacketizer_init() or opus_repacketizer_create().\n  * This defines the valid range of packets that can be extracted with\n  * opus_repacketizer_out_range() or opus_repacketizer_out().\n  * @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state containing the\n  *                                       frames.\n  * @returns The total number of frames contained in the packet data submitted\n  *          to the repacketizer state.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1);\n\n/** Construct a new packet from data previously submitted to the repacketizer\n  * state via opus_repacketizer_cat().\n  * This is a convenience routine that returns all the data submitted so far\n  * in a single packet.\n  * It is equivalent to calling\n  * @code\n  * opus_repacketizer_out_range(rp, 0, opus_repacketizer_get_nb_frames(rp),\n  *                             data, maxlen)\n  * @endcode\n  * @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state from which to\n  *                                       construct the new packet.\n  * @param[out] data <tt>const unsigned char*</tt>: The buffer in which to\n  *                                                 store the output packet.\n  * @param maxlen <tt>opus_int32</tt>: The maximum number of bytes to store in\n  *                                    the output buffer. In order to guarantee\n  *                                    success, this should be at least\n  *                                    <code>1277*opus_repacketizer_get_nb_frames(rp)</code>.\n  *                                    However,\n  *                                    <code>1*opus_repacketizer_get_nb_frames(rp)</code>\n  *                                    plus the size of all packet data\n  *                                    submitted to the repacketizer since the\n  *                                    last call to opus_repacketizer_init() or\n  *                                    opus_repacketizer_create() is also\n  *                                    sufficient, and possibly much smaller.\n  * @returns The total size of the output packet on success, or an error code\n  *          on failure.\n  * @retval #OPUS_BUFFER_TOO_SMALL \\a maxlen was insufficient to contain the\n  *                                complete output packet.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1);\n\n/** Pads a given Opus packet to a larger size (possibly changing the TOC sequence).\n  * @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the\n  *                                                   packet to pad.\n  * @param len <tt>opus_int32</tt>: The size of the packet.\n  *                                 This must be at least 1.\n  * @param new_len <tt>opus_int32</tt>: The desired size of the packet after padding.\n  *                                 This must be at least as large as len.\n  * @returns an error code\n  * @retval #OPUS_OK \\a on success.\n  * @retval #OPUS_BAD_ARG \\a len was less than 1 or new_len was less than len.\n  * @retval #OPUS_INVALID_PACKET \\a data did not contain a valid Opus packet.\n  */\nOPUS_EXPORT int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len);\n\n/** Remove all padding from a given Opus packet and rewrite the TOC sequence to\n  * minimize space usage.\n  * @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the\n  *                                                   packet to strip.\n  * @param len <tt>opus_int32</tt>: The size of the packet.\n  *                                 This must be at least 1.\n  * @returns The new size of the output packet on success, or an error code\n  *          on failure.\n  * @retval #OPUS_BAD_ARG \\a len was less than 1.\n  * @retval #OPUS_INVALID_PACKET \\a data did not contain a valid Opus packet.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len);\n\n/** Pads a given Opus multi-stream packet to a larger size (possibly changing the TOC sequence).\n  * @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the\n  *                                                   packet to pad.\n  * @param len <tt>opus_int32</tt>: The size of the packet.\n  *                                 This must be at least 1.\n  * @param new_len <tt>opus_int32</tt>: The desired size of the packet after padding.\n  *                                 This must be at least 1.\n  * @param nb_streams <tt>opus_int32</tt>: The number of streams (not channels) in the packet.\n  *                                 This must be at least as large as len.\n  * @returns an error code\n  * @retval #OPUS_OK \\a on success.\n  * @retval #OPUS_BAD_ARG \\a len was less than 1.\n  * @retval #OPUS_INVALID_PACKET \\a data did not contain a valid Opus packet.\n  */\nOPUS_EXPORT int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams);\n\n/** Remove all padding from a given Opus multi-stream packet and rewrite the TOC sequence to\n  * minimize space usage.\n  * @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the\n  *                                                   packet to strip.\n  * @param len <tt>opus_int32</tt>: The size of the packet.\n  *                                 This must be at least 1.\n  * @param nb_streams <tt>opus_int32</tt>: The number of streams (not channels) in the packet.\n  *                                 This must be at least 1.\n  * @returns The new size of the output packet on success, or an error code\n  *          on failure.\n  * @retval #OPUS_BAD_ARG \\a len was less than 1 or new_len was less than len.\n  * @retval #OPUS_INVALID_PACKET \\a data did not contain a valid Opus packet.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams);\n\n/**@}*/\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* OPUS_H */\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/cpp/libopus/opus_custom.h",
    "content": "/* Copyright (c) 2007-2008 CSIRO\n   Copyright (c) 2007-2009 Xiph.Org Foundation\n   Copyright (c) 2008-2012 Gregory Maxwell\n   Written by Jean-Marc Valin and Gregory Maxwell */\n/*\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n\n   - Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n   - Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER\n   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n/**\n  @file opus_custom.h\n  @brief Opus-Custom reference implementation API\n */\n\n#ifndef OPUS_CUSTOM_H\n#define OPUS_CUSTOM_H\n\n#include \"opus_defines.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifdef CUSTOM_MODES\n# define OPUS_CUSTOM_EXPORT OPUS_EXPORT\n# define OPUS_CUSTOM_EXPORT_STATIC OPUS_EXPORT\n#else\n# define OPUS_CUSTOM_EXPORT\n# ifdef OPUS_BUILD\n#  define OPUS_CUSTOM_EXPORT_STATIC static OPUS_INLINE\n# else\n#  define OPUS_CUSTOM_EXPORT_STATIC\n# endif\n#endif\n\n/** @defgroup opus_custom Opus Custom\n  * @{\n  *  Opus Custom is an optional part of the Opus specification and\n  * reference implementation which uses a distinct API from the regular\n  * API and supports frame sizes that are not normally supported.\\ Use\n  * of Opus Custom is discouraged for all but very special applications\n  * for which a frame size different from 2.5, 5, 10, or 20 ms is needed\n  * (for either complexity or latency reasons) and where interoperability\n  * is less important.\n  *\n  * In addition to the interoperability limitations the use of Opus custom\n  * disables a substantial chunk of the codec and generally lowers the\n  * quality available at a given bitrate. Normally when an application needs\n  * a different frame size from the codec it should buffer to match the\n  * sizes but this adds a small amount of delay which may be important\n  * in some very low latency applications. Some transports (especially\n  * constant rate RF transports) may also work best with frames of\n  * particular durations.\n  *\n  * Libopus only supports custom modes if they are enabled at compile time.\n  *\n  * The Opus Custom API is similar to the regular API but the\n  * @ref opus_encoder_create and @ref opus_decoder_create calls take\n  * an additional mode parameter which is a structure produced by\n  * a call to @ref opus_custom_mode_create. Both the encoder and decoder\n  * must create a mode using the same sample rate (fs) and frame size\n  * (frame size) so these parameters must either be signaled out of band\n  * or fixed in a particular implementation.\n  *\n  * Similar to regular Opus the custom modes support on the fly frame size\n  * switching, but the sizes available depend on the particular frame size in\n  * use. For some initial frame sizes on a single on the fly size is available.\n  */\n\n/** Contains the state of an encoder. One encoder state is needed\n    for each stream. It is initialized once at the beginning of the\n    stream. Do *not* re-initialize the state for every frame.\n   @brief Encoder state\n */\ntypedef struct OpusCustomEncoder OpusCustomEncoder;\n\n/** State of the decoder. One decoder state is needed for each stream.\n    It is initialized once at the beginning of the stream. Do *not*\n    re-initialize the state for every frame.\n   @brief Decoder state\n */\ntypedef struct OpusCustomDecoder OpusCustomDecoder;\n\n/** The mode contains all the information necessary to create an\n    encoder. Both the encoder and decoder need to be initialized\n    with exactly the same mode, otherwise the output will be\n    corrupted.\n   @brief Mode configuration\n */\ntypedef struct OpusCustomMode OpusCustomMode;\n\n/** Creates a new mode struct. This will be passed to an encoder or\n  * decoder. The mode MUST NOT BE DESTROYED until the encoders and\n  * decoders that use it are destroyed as well.\n  * @param [in] Fs <tt>int</tt>: Sampling rate (8000 to 96000 Hz)\n  * @param [in] frame_size <tt>int</tt>: Number of samples (per channel) to encode in each\n  *        packet (64 - 1024, prime factorization must contain zero or more 2s, 3s, or 5s and no other primes)\n  * @param [out] error <tt>int*</tt>: Returned error code (if NULL, no error will be returned)\n  * @return A newly created mode\n  */\nOPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error);\n\n/** Destroys a mode struct. Only call this after all encoders and\n  * decoders using this mode are destroyed as well.\n  * @param [in] mode <tt>OpusCustomMode*</tt>: Mode to be freed.\n  */\nOPUS_CUSTOM_EXPORT void opus_custom_mode_destroy(OpusCustomMode *mode);\n\n\n#if !defined(OPUS_BUILD) || defined(CELT_ENCODER_C)\n\n/* Encoder */\n/** Gets the size of an OpusCustomEncoder structure.\n  * @param [in] mode <tt>OpusCustomMode *</tt>: Mode configuration\n  * @param [in] channels <tt>int</tt>: Number of channels\n  * @returns size\n  */\nOPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_encoder_get_size(\n    const OpusCustomMode *mode,\n    int channels\n) OPUS_ARG_NONNULL(1);\n\n# ifdef CUSTOM_MODES\n/** Initializes a previously allocated encoder state\n  * The memory pointed to by st must be the size returned by opus_custom_encoder_get_size.\n  * This is intended for applications which use their own allocator instead of malloc.\n  * @see opus_custom_encoder_create(),opus_custom_encoder_get_size()\n  * To reset a previously initialized state use the OPUS_RESET_STATE CTL.\n  * @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state\n  * @param [in] mode <tt>OpusCustomMode *</tt>: Contains all the information about the characteristics of\n  *  the stream (must be the same characteristics as used for the\n  *  decoder)\n  * @param [in] channels <tt>int</tt>: Number of channels\n  * @return OPUS_OK Success or @ref opus_errorcodes\n  */\nOPUS_CUSTOM_EXPORT int opus_custom_encoder_init(\n    OpusCustomEncoder *st,\n    const OpusCustomMode *mode,\n    int channels\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);\n# endif\n#endif\n\n\n/** Creates a new encoder state. Each stream needs its own encoder\n  * state (can't be shared across simultaneous streams).\n  * @param [in] mode <tt>OpusCustomMode*</tt>: Contains all the information about the characteristics of\n  *  the stream (must be the same characteristics as used for the\n  *  decoder)\n  * @param [in] channels <tt>int</tt>: Number of channels\n  * @param [out] error <tt>int*</tt>: Returns an error code\n  * @return Newly created encoder state.\n*/\nOPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomEncoder *opus_custom_encoder_create(\n    const OpusCustomMode *mode,\n    int channels,\n    int *error\n) OPUS_ARG_NONNULL(1);\n\n\n/** Destroys a an encoder state.\n  * @param[in] st <tt>OpusCustomEncoder*</tt>: State to be freed.\n  */\nOPUS_CUSTOM_EXPORT void opus_custom_encoder_destroy(OpusCustomEncoder *st);\n\n/** Encodes a frame of audio.\n  * @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state\n  * @param [in] pcm <tt>float*</tt>: PCM audio in float format, with a normal range of +/-1.0.\n  *          Samples with a range beyond +/-1.0 are supported but will\n  *          be clipped by decoders using the integer API and should\n  *          only be used if it is known that the far end supports\n  *          extended dynamic range. There must be exactly\n  *          frame_size samples per channel.\n  * @param [in] frame_size <tt>int</tt>: Number of samples per frame of input signal\n  * @param [out] compressed <tt>char *</tt>: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long.\n  * @param [in] maxCompressedBytes <tt>int</tt>: Maximum number of bytes to use for compressing the frame\n  *          (can change from one frame to another)\n  * @return Number of bytes written to \"compressed\".\n  *       If negative, an error has occurred (see error codes). It is IMPORTANT that\n  *       the length returned be somehow transmitted to the decoder. Otherwise, no\n  *       decoding is possible.\n  */\nOPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode_float(\n    OpusCustomEncoder *st,\n    const float *pcm,\n    int frame_size,\n    unsigned char *compressed,\n    int maxCompressedBytes\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);\n\n/** Encodes a frame of audio.\n  * @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state\n  * @param [in] pcm <tt>opus_int16*</tt>: PCM audio in signed 16-bit format (native endian).\n  *          There must be exactly frame_size samples per channel.\n  * @param [in] frame_size <tt>int</tt>: Number of samples per frame of input signal\n  * @param [out] compressed <tt>char *</tt>: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long.\n  * @param [in] maxCompressedBytes <tt>int</tt>: Maximum number of bytes to use for compressing the frame\n  *          (can change from one frame to another)\n  * @return Number of bytes written to \"compressed\".\n  *       If negative, an error has occurred (see error codes). It is IMPORTANT that\n  *       the length returned be somehow transmitted to the decoder. Otherwise, no\n  *       decoding is possible.\n */\nOPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode(\n    OpusCustomEncoder *st,\n    const opus_int16 *pcm,\n    int frame_size,\n    unsigned char *compressed,\n    int maxCompressedBytes\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);\n\n/** Perform a CTL function on an Opus custom encoder.\n  *\n  * Generally the request and subsequent arguments are generated\n  * by a convenience macro.\n  * @see opus_encoderctls\n  */\nOPUS_CUSTOM_EXPORT int opus_custom_encoder_ctl(OpusCustomEncoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1);\n\n\n#if !defined(OPUS_BUILD) || defined(CELT_DECODER_C)\n/* Decoder */\n\n/** Gets the size of an OpusCustomDecoder structure.\n  * @param [in] mode <tt>OpusCustomMode *</tt>: Mode configuration\n  * @param [in] channels <tt>int</tt>: Number of channels\n  * @returns size\n  */\nOPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_decoder_get_size(\n    const OpusCustomMode *mode,\n    int channels\n) OPUS_ARG_NONNULL(1);\n\n/** Initializes a previously allocated decoder state\n  * The memory pointed to by st must be the size returned by opus_custom_decoder_get_size.\n  * This is intended for applications which use their own allocator instead of malloc.\n  * @see opus_custom_decoder_create(),opus_custom_decoder_get_size()\n  * To reset a previously initialized state use the OPUS_RESET_STATE CTL.\n  * @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state\n  * @param [in] mode <tt>OpusCustomMode *</tt>: Contains all the information about the characteristics of\n  *  the stream (must be the same characteristics as used for the\n  *  encoder)\n  * @param [in] channels <tt>int</tt>: Number of channels\n  * @return OPUS_OK Success or @ref opus_errorcodes\n  */\nOPUS_CUSTOM_EXPORT_STATIC int opus_custom_decoder_init(\n    OpusCustomDecoder *st,\n    const OpusCustomMode *mode,\n    int channels\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);\n\n#endif\n\n\n/** Creates a new decoder state. Each stream needs its own decoder state (can't\n  * be shared across simultaneous streams).\n  * @param [in] mode <tt>OpusCustomMode</tt>: Contains all the information about the characteristics of the\n  *          stream (must be the same characteristics as used for the encoder)\n  * @param [in] channels <tt>int</tt>: Number of channels\n  * @param [out] error <tt>int*</tt>: Returns an error code\n  * @return Newly created decoder state.\n  */\nOPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomDecoder *opus_custom_decoder_create(\n    const OpusCustomMode *mode,\n    int channels,\n    int *error\n) OPUS_ARG_NONNULL(1);\n\n/** Destroys a an decoder state.\n  * @param[in] st <tt>OpusCustomDecoder*</tt>: State to be freed.\n  */\nOPUS_CUSTOM_EXPORT void opus_custom_decoder_destroy(OpusCustomDecoder *st);\n\n/** Decode an opus custom frame with floating point output\n  * @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state\n  * @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss\n  * @param [in] len <tt>int</tt>: Number of bytes in payload\n  * @param [out] pcm <tt>float*</tt>: Output signal (interleaved if 2 channels). length\n  *  is frame_size*channels*sizeof(float)\n  * @param [in] frame_size Number of samples per channel of available space in *pcm.\n  * @returns Number of decoded samples or @ref opus_errorcodes\n  */\nOPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode_float(\n    OpusCustomDecoder *st,\n    const unsigned char *data,\n    int len,\n    float *pcm,\n    int frame_size\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);\n\n/** Decode an opus custom frame\n  * @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state\n  * @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss\n  * @param [in] len <tt>int</tt>: Number of bytes in payload\n  * @param [out] pcm <tt>opus_int16*</tt>: Output signal (interleaved if 2 channels). length\n  *  is frame_size*channels*sizeof(opus_int16)\n  * @param [in] frame_size Number of samples per channel of available space in *pcm.\n  * @returns Number of decoded samples or @ref opus_errorcodes\n  */\nOPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode(\n    OpusCustomDecoder *st,\n    const unsigned char *data,\n    int len,\n    opus_int16 *pcm,\n    int frame_size\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);\n\n/** Perform a CTL function on an Opus custom decoder.\n  *\n  * Generally the request and subsequent arguments are generated\n  * by a convenience macro.\n  * @see opus_genericctls\n  */\nOPUS_CUSTOM_EXPORT int opus_custom_decoder_ctl(OpusCustomDecoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1);\n\n/**@}*/\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* OPUS_CUSTOM_H */\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/cpp/libopus/opus_defines.h",
    "content": "/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited\n   Written by Jean-Marc Valin and Koen Vos */\n/*\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n\n   - Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n   - Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER\n   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n/**\n * @file opus_defines.h\n * @brief Opus reference implementation constants\n */\n\n#ifndef OPUS_DEFINES_H\n#define OPUS_DEFINES_H\n\n#include \"opus_types.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/** @defgroup opus_errorcodes Error codes\n * @{\n */\n/** No error @hideinitializer*/\n#define OPUS_OK                0\n/** One or more invalid/out of range arguments @hideinitializer*/\n#define OPUS_BAD_ARG          -1\n/** Not enough bytes allocated in the buffer @hideinitializer*/\n#define OPUS_BUFFER_TOO_SMALL -2\n/** An internal error was detected @hideinitializer*/\n#define OPUS_INTERNAL_ERROR   -3\n/** The compressed data passed is corrupted @hideinitializer*/\n#define OPUS_INVALID_PACKET   -4\n/** Invalid/unsupported request number @hideinitializer*/\n#define OPUS_UNIMPLEMENTED    -5\n/** An encoder or decoder structure is invalid or already freed @hideinitializer*/\n#define OPUS_INVALID_STATE    -6\n/** Memory allocation has failed @hideinitializer*/\n#define OPUS_ALLOC_FAIL       -7\n/**@}*/\n\n/** @cond OPUS_INTERNAL_DOC */\n/**Export control for opus functions */\n\n#ifndef OPUS_EXPORT\n# if defined(WIN32)\n#  if defined(OPUS_BUILD) && defined(DLL_EXPORT)\n#   define OPUS_EXPORT __declspec(dllexport)\n#  else\n#   define OPUS_EXPORT\n#  endif\n# elif defined(__GNUC__) && defined(OPUS_BUILD)\n#  define OPUS_EXPORT __attribute__ ((visibility (\"default\")))\n# else\n#  define OPUS_EXPORT\n# endif\n#endif\n\n# if !defined(OPUS_GNUC_PREREQ)\n#  if defined(__GNUC__)&&defined(__GNUC_MINOR__)\n#   define OPUS_GNUC_PREREQ(_maj,_min) \\\n ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))\n#  else\n#   define OPUS_GNUC_PREREQ(_maj,_min) 0\n#  endif\n# endif\n\n#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )\n# if OPUS_GNUC_PREREQ(3,0)\n#  define OPUS_RESTRICT __restrict__\n# elif (defined(_MSC_VER) && _MSC_VER >= 1400)\n#  define OPUS_RESTRICT __restrict\n# else\n#  define OPUS_RESTRICT\n# endif\n#else\n# define OPUS_RESTRICT restrict\n#endif\n\n#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )\n# if OPUS_GNUC_PREREQ(2,7)\n#  define OPUS_INLINE __inline__\n# elif (defined(_MSC_VER))\n#  define OPUS_INLINE __inline\n# else\n#  define OPUS_INLINE\n# endif\n#else\n# define OPUS_INLINE inline\n#endif\n\n/**Warning attributes for opus functions\n  * NONNULL is not used in OPUS_BUILD to avoid the compiler optimizing out\n  * some paranoid null checks. */\n#if defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4)\n# define OPUS_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__))\n#else\n# define OPUS_WARN_UNUSED_RESULT\n#endif\n#if !defined(OPUS_BUILD) && defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4)\n# define OPUS_ARG_NONNULL(_x)  __attribute__ ((__nonnull__(_x)))\n#else\n# define OPUS_ARG_NONNULL(_x)\n#endif\n\n/** These are the actual Encoder CTL ID numbers.\n  * They should not be used directly by applications.\n  * In general, SETs should be even and GETs should be odd.*/\n#define OPUS_SET_APPLICATION_REQUEST         4000\n#define OPUS_GET_APPLICATION_REQUEST         4001\n#define OPUS_SET_BITRATE_REQUEST             4002\n#define OPUS_GET_BITRATE_REQUEST             4003\n#define OPUS_SET_MAX_BANDWIDTH_REQUEST       4004\n#define OPUS_GET_MAX_BANDWIDTH_REQUEST       4005\n#define OPUS_SET_VBR_REQUEST                 4006\n#define OPUS_GET_VBR_REQUEST                 4007\n#define OPUS_SET_BANDWIDTH_REQUEST           4008\n#define OPUS_GET_BANDWIDTH_REQUEST           4009\n#define OPUS_SET_COMPLEXITY_REQUEST          4010\n#define OPUS_GET_COMPLEXITY_REQUEST          4011\n#define OPUS_SET_INBAND_FEC_REQUEST          4012\n#define OPUS_GET_INBAND_FEC_REQUEST          4013\n#define OPUS_SET_PACKET_LOSS_PERC_REQUEST    4014\n#define OPUS_GET_PACKET_LOSS_PERC_REQUEST    4015\n#define OPUS_SET_DTX_REQUEST                 4016\n#define OPUS_GET_DTX_REQUEST                 4017\n#define OPUS_SET_VBR_CONSTRAINT_REQUEST      4020\n#define OPUS_GET_VBR_CONSTRAINT_REQUEST      4021\n#define OPUS_SET_FORCE_CHANNELS_REQUEST      4022\n#define OPUS_GET_FORCE_CHANNELS_REQUEST      4023\n#define OPUS_SET_SIGNAL_REQUEST              4024\n#define OPUS_GET_SIGNAL_REQUEST              4025\n#define OPUS_GET_LOOKAHEAD_REQUEST           4027\n/* #define OPUS_RESET_STATE 4028 */\n#define OPUS_GET_SAMPLE_RATE_REQUEST         4029\n#define OPUS_GET_FINAL_RANGE_REQUEST         4031\n#define OPUS_GET_PITCH_REQUEST               4033\n#define OPUS_SET_GAIN_REQUEST                4034\n#define OPUS_GET_GAIN_REQUEST                4045 /* Should have been 4035 */\n#define OPUS_SET_LSB_DEPTH_REQUEST           4036\n#define OPUS_GET_LSB_DEPTH_REQUEST           4037\n#define OPUS_GET_LAST_PACKET_DURATION_REQUEST 4039\n#define OPUS_SET_EXPERT_FRAME_DURATION_REQUEST 4040\n#define OPUS_GET_EXPERT_FRAME_DURATION_REQUEST 4041\n#define OPUS_SET_PREDICTION_DISABLED_REQUEST 4042\n#define OPUS_GET_PREDICTION_DISABLED_REQUEST 4043\n/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */\n#define OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST 4046\n#define OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST 4047\n#define OPUS_GET_IN_DTX_REQUEST              4049\n\n/** Defines for the presence of extended APIs. */\n#define OPUS_HAVE_OPUS_PROJECTION_H\n\n/* Macros to trigger compilation errors when the wrong types are provided to a CTL */\n#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x))\n#define __opus_check_int_ptr(ptr) ((ptr) + ((ptr) - (opus_int32*)(ptr)))\n#define __opus_check_uint_ptr(ptr) ((ptr) + ((ptr) - (opus_uint32*)(ptr)))\n#define __opus_check_val16_ptr(ptr) ((ptr) + ((ptr) - (opus_val16*)(ptr)))\n/** @endcond */\n\n/** @defgroup opus_ctlvalues Pre-defined values for CTL interface\n  * @see opus_genericctls, opus_encoderctls\n  * @{\n  */\n/* Values for the various encoder CTLs */\n#define OPUS_AUTO                           -1000 /**<Auto/default setting @hideinitializer*/\n#define OPUS_BITRATE_MAX                       -1 /**<Maximum bitrate @hideinitializer*/\n\n/** Best for most VoIP/videoconference applications where listening quality and intelligibility matter most\n * @hideinitializer */\n#define OPUS_APPLICATION_VOIP                2048\n/** Best for broadcast/high-fidelity application where the decoded audio should be as close as possible to the input\n * @hideinitializer */\n#define OPUS_APPLICATION_AUDIO               2049\n/** Only use when lowest-achievable latency is what matters most. Voice-optimized modes cannot be used.\n * @hideinitializer */\n#define OPUS_APPLICATION_RESTRICTED_LOWDELAY 2051\n\n#define OPUS_SIGNAL_VOICE                    3001 /**< Signal being encoded is voice */\n#define OPUS_SIGNAL_MUSIC                    3002 /**< Signal being encoded is music */\n#define OPUS_BANDWIDTH_NARROWBAND            1101 /**< 4 kHz bandpass @hideinitializer*/\n#define OPUS_BANDWIDTH_MEDIUMBAND            1102 /**< 6 kHz bandpass @hideinitializer*/\n#define OPUS_BANDWIDTH_WIDEBAND              1103 /**< 8 kHz bandpass @hideinitializer*/\n#define OPUS_BANDWIDTH_SUPERWIDEBAND         1104 /**<12 kHz bandpass @hideinitializer*/\n#define OPUS_BANDWIDTH_FULLBAND              1105 /**<20 kHz bandpass @hideinitializer*/\n\n#define OPUS_FRAMESIZE_ARG                   5000 /**< Select frame size from the argument (default) */\n#define OPUS_FRAMESIZE_2_5_MS                5001 /**< Use 2.5 ms frames */\n#define OPUS_FRAMESIZE_5_MS                  5002 /**< Use 5 ms frames */\n#define OPUS_FRAMESIZE_10_MS                 5003 /**< Use 10 ms frames */\n#define OPUS_FRAMESIZE_20_MS                 5004 /**< Use 20 ms frames */\n#define OPUS_FRAMESIZE_40_MS                 5005 /**< Use 40 ms frames */\n#define OPUS_FRAMESIZE_60_MS                 5006 /**< Use 60 ms frames */\n#define OPUS_FRAMESIZE_80_MS                 5007 /**< Use 80 ms frames */\n#define OPUS_FRAMESIZE_100_MS                5008 /**< Use 100 ms frames */\n#define OPUS_FRAMESIZE_120_MS                5009 /**< Use 120 ms frames */\n\n/**@}*/\n\n\n/** @defgroup opus_encoderctls Encoder related CTLs\n  *\n  * These are convenience macros for use with the \\c opus_encode_ctl\n  * interface. They are used to generate the appropriate series of\n  * arguments for that call, passing the correct type, size and so\n  * on as expected for each particular request.\n  *\n  * Some usage examples:\n  *\n  * @code\n  * int ret;\n  * ret = opus_encoder_ctl(enc_ctx, OPUS_SET_BANDWIDTH(OPUS_AUTO));\n  * if (ret != OPUS_OK) return ret;\n  *\n  * opus_int32 rate;\n  * opus_encoder_ctl(enc_ctx, OPUS_GET_BANDWIDTH(&rate));\n  *\n  * opus_encoder_ctl(enc_ctx, OPUS_RESET_STATE);\n  * @endcode\n  *\n  * @see opus_genericctls, opus_encoder\n  * @{\n  */\n\n/** Configures the encoder's computational complexity.\n  * The supported range is 0-10 inclusive with 10 representing the highest complexity.\n  * @see OPUS_GET_COMPLEXITY\n  * @param[in] x <tt>opus_int32</tt>: Allowed values: 0-10, inclusive.\n  *\n  * @hideinitializer */\n#define OPUS_SET_COMPLEXITY(x) OPUS_SET_COMPLEXITY_REQUEST, __opus_check_int(x)\n/** Gets the encoder's complexity configuration.\n  * @see OPUS_SET_COMPLEXITY\n  * @param[out] x <tt>opus_int32 *</tt>: Returns a value in the range 0-10,\n  *                                      inclusive.\n  * @hideinitializer */\n#define OPUS_GET_COMPLEXITY(x) OPUS_GET_COMPLEXITY_REQUEST, __opus_check_int_ptr(x)\n\n/** Configures the bitrate in the encoder.\n  * Rates from 500 to 512000 bits per second are meaningful, as well as the\n  * special values #OPUS_AUTO and #OPUS_BITRATE_MAX.\n  * The value #OPUS_BITRATE_MAX can be used to cause the codec to use as much\n  * rate as it can, which is useful for controlling the rate by adjusting the\n  * output buffer size.\n  * @see OPUS_GET_BITRATE\n  * @param[in] x <tt>opus_int32</tt>: Bitrate in bits per second. The default\n  *                                   is determined based on the number of\n  *                                   channels and the input sampling rate.\n  * @hideinitializer */\n#define OPUS_SET_BITRATE(x) OPUS_SET_BITRATE_REQUEST, __opus_check_int(x)\n/** Gets the encoder's bitrate configuration.\n  * @see OPUS_SET_BITRATE\n  * @param[out] x <tt>opus_int32 *</tt>: Returns the bitrate in bits per second.\n  *                                      The default is determined based on the\n  *                                      number of channels and the input\n  *                                      sampling rate.\n  * @hideinitializer */\n#define OPUS_GET_BITRATE(x) OPUS_GET_BITRATE_REQUEST, __opus_check_int_ptr(x)\n\n/** Enables or disables variable bitrate (VBR) in the encoder.\n  * The configured bitrate may not be met exactly because frames must\n  * be an integer number of bytes in length.\n  * @see OPUS_GET_VBR\n  * @see OPUS_SET_VBR_CONSTRAINT\n  * @param[in] x <tt>opus_int32</tt>: Allowed values:\n  * <dl>\n  * <dt>0</dt><dd>Hard CBR. For LPC/hybrid modes at very low bit-rate, this can\n  *               cause noticeable quality degradation.</dd>\n  * <dt>1</dt><dd>VBR (default). The exact type of VBR is controlled by\n  *               #OPUS_SET_VBR_CONSTRAINT.</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_SET_VBR(x) OPUS_SET_VBR_REQUEST, __opus_check_int(x)\n/** Determine if variable bitrate (VBR) is enabled in the encoder.\n  * @see OPUS_SET_VBR\n  * @see OPUS_GET_VBR_CONSTRAINT\n  * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:\n  * <dl>\n  * <dt>0</dt><dd>Hard CBR.</dd>\n  * <dt>1</dt><dd>VBR (default). The exact type of VBR may be retrieved via\n  *               #OPUS_GET_VBR_CONSTRAINT.</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_GET_VBR(x) OPUS_GET_VBR_REQUEST, __opus_check_int_ptr(x)\n\n/** Enables or disables constrained VBR in the encoder.\n  * This setting is ignored when the encoder is in CBR mode.\n  * @warning Only the MDCT mode of Opus currently heeds the constraint.\n  *  Speech mode ignores it completely, hybrid mode may fail to obey it\n  *  if the LPC layer uses more bitrate than the constraint would have\n  *  permitted.\n  * @see OPUS_GET_VBR_CONSTRAINT\n  * @see OPUS_SET_VBR\n  * @param[in] x <tt>opus_int32</tt>: Allowed values:\n  * <dl>\n  * <dt>0</dt><dd>Unconstrained VBR.</dd>\n  * <dt>1</dt><dd>Constrained VBR (default). This creates a maximum of one\n  *               frame of buffering delay assuming a transport with a\n  *               serialization speed of the nominal bitrate.</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_SET_VBR_CONSTRAINT(x) OPUS_SET_VBR_CONSTRAINT_REQUEST, __opus_check_int(x)\n/** Determine if constrained VBR is enabled in the encoder.\n  * @see OPUS_SET_VBR_CONSTRAINT\n  * @see OPUS_GET_VBR\n  * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:\n  * <dl>\n  * <dt>0</dt><dd>Unconstrained VBR.</dd>\n  * <dt>1</dt><dd>Constrained VBR (default).</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_GET_VBR_CONSTRAINT(x) OPUS_GET_VBR_CONSTRAINT_REQUEST, __opus_check_int_ptr(x)\n\n/** Configures mono/stereo forcing in the encoder.\n  * This can force the encoder to produce packets encoded as either mono or\n  * stereo, regardless of the format of the input audio. This is useful when\n  * the caller knows that the input signal is currently a mono source embedded\n  * in a stereo stream.\n  * @see OPUS_GET_FORCE_CHANNELS\n  * @param[in] x <tt>opus_int32</tt>: Allowed values:\n  * <dl>\n  * <dt>#OPUS_AUTO</dt><dd>Not forced (default)</dd>\n  * <dt>1</dt>         <dd>Forced mono</dd>\n  * <dt>2</dt>         <dd>Forced stereo</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_SET_FORCE_CHANNELS(x) OPUS_SET_FORCE_CHANNELS_REQUEST, __opus_check_int(x)\n/** Gets the encoder's forced channel configuration.\n  * @see OPUS_SET_FORCE_CHANNELS\n  * @param[out] x <tt>opus_int32 *</tt>:\n  * <dl>\n  * <dt>#OPUS_AUTO</dt><dd>Not forced (default)</dd>\n  * <dt>1</dt>         <dd>Forced mono</dd>\n  * <dt>2</dt>         <dd>Forced stereo</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_GET_FORCE_CHANNELS(x) OPUS_GET_FORCE_CHANNELS_REQUEST, __opus_check_int_ptr(x)\n\n/** Configures the maximum bandpass that the encoder will select automatically.\n  * Applications should normally use this instead of #OPUS_SET_BANDWIDTH\n  * (leaving that set to the default, #OPUS_AUTO). This allows the\n  * application to set an upper bound based on the type of input it is\n  * providing, but still gives the encoder the freedom to reduce the bandpass\n  * when the bitrate becomes too low, for better overall quality.\n  * @see OPUS_GET_MAX_BANDWIDTH\n  * @param[in] x <tt>opus_int32</tt>: Allowed values:\n  * <dl>\n  * <dt>OPUS_BANDWIDTH_NARROWBAND</dt>    <dd>4 kHz passband</dd>\n  * <dt>OPUS_BANDWIDTH_MEDIUMBAND</dt>    <dd>6 kHz passband</dd>\n  * <dt>OPUS_BANDWIDTH_WIDEBAND</dt>      <dd>8 kHz passband</dd>\n  * <dt>OPUS_BANDWIDTH_SUPERWIDEBAND</dt><dd>12 kHz passband</dd>\n  * <dt>OPUS_BANDWIDTH_FULLBAND</dt>     <dd>20 kHz passband (default)</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_SET_MAX_BANDWIDTH(x) OPUS_SET_MAX_BANDWIDTH_REQUEST, __opus_check_int(x)\n\n/** Gets the encoder's configured maximum allowed bandpass.\n  * @see OPUS_SET_MAX_BANDWIDTH\n  * @param[out] x <tt>opus_int32 *</tt>: Allowed values:\n  * <dl>\n  * <dt>#OPUS_BANDWIDTH_NARROWBAND</dt>    <dd>4 kHz passband</dd>\n  * <dt>#OPUS_BANDWIDTH_MEDIUMBAND</dt>    <dd>6 kHz passband</dd>\n  * <dt>#OPUS_BANDWIDTH_WIDEBAND</dt>      <dd>8 kHz passband</dd>\n  * <dt>#OPUS_BANDWIDTH_SUPERWIDEBAND</dt><dd>12 kHz passband</dd>\n  * <dt>#OPUS_BANDWIDTH_FULLBAND</dt>     <dd>20 kHz passband (default)</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_GET_MAX_BANDWIDTH(x) OPUS_GET_MAX_BANDWIDTH_REQUEST, __opus_check_int_ptr(x)\n\n/** Sets the encoder's bandpass to a specific value.\n  * This prevents the encoder from automatically selecting the bandpass based\n  * on the available bitrate. If an application knows the bandpass of the input\n  * audio it is providing, it should normally use #OPUS_SET_MAX_BANDWIDTH\n  * instead, which still gives the encoder the freedom to reduce the bandpass\n  * when the bitrate becomes too low, for better overall quality.\n  * @see OPUS_GET_BANDWIDTH\n  * @param[in] x <tt>opus_int32</tt>: Allowed values:\n  * <dl>\n  * <dt>#OPUS_AUTO</dt>                    <dd>(default)</dd>\n  * <dt>#OPUS_BANDWIDTH_NARROWBAND</dt>    <dd>4 kHz passband</dd>\n  * <dt>#OPUS_BANDWIDTH_MEDIUMBAND</dt>    <dd>6 kHz passband</dd>\n  * <dt>#OPUS_BANDWIDTH_WIDEBAND</dt>      <dd>8 kHz passband</dd>\n  * <dt>#OPUS_BANDWIDTH_SUPERWIDEBAND</dt><dd>12 kHz passband</dd>\n  * <dt>#OPUS_BANDWIDTH_FULLBAND</dt>     <dd>20 kHz passband</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_SET_BANDWIDTH(x) OPUS_SET_BANDWIDTH_REQUEST, __opus_check_int(x)\n\n/** Configures the type of signal being encoded.\n  * This is a hint which helps the encoder's mode selection.\n  * @see OPUS_GET_SIGNAL\n  * @param[in] x <tt>opus_int32</tt>: Allowed values:\n  * <dl>\n  * <dt>#OPUS_AUTO</dt>        <dd>(default)</dd>\n  * <dt>#OPUS_SIGNAL_VOICE</dt><dd>Bias thresholds towards choosing LPC or Hybrid modes.</dd>\n  * <dt>#OPUS_SIGNAL_MUSIC</dt><dd>Bias thresholds towards choosing MDCT modes.</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_SET_SIGNAL(x) OPUS_SET_SIGNAL_REQUEST, __opus_check_int(x)\n/** Gets the encoder's configured signal type.\n  * @see OPUS_SET_SIGNAL\n  * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:\n  * <dl>\n  * <dt>#OPUS_AUTO</dt>        <dd>(default)</dd>\n  * <dt>#OPUS_SIGNAL_VOICE</dt><dd>Bias thresholds towards choosing LPC or Hybrid modes.</dd>\n  * <dt>#OPUS_SIGNAL_MUSIC</dt><dd>Bias thresholds towards choosing MDCT modes.</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_GET_SIGNAL(x) OPUS_GET_SIGNAL_REQUEST, __opus_check_int_ptr(x)\n\n\n/** Configures the encoder's intended application.\n  * The initial value is a mandatory argument to the encoder_create function.\n  * @see OPUS_GET_APPLICATION\n  * @param[in] x <tt>opus_int32</tt>: Returns one of the following values:\n  * <dl>\n  * <dt>#OPUS_APPLICATION_VOIP</dt>\n  * <dd>Process signal for improved speech intelligibility.</dd>\n  * <dt>#OPUS_APPLICATION_AUDIO</dt>\n  * <dd>Favor faithfulness to the original input.</dd>\n  * <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt>\n  * <dd>Configure the minimum possible coding delay by disabling certain modes\n  * of operation.</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_SET_APPLICATION(x) OPUS_SET_APPLICATION_REQUEST, __opus_check_int(x)\n/** Gets the encoder's configured application.\n  * @see OPUS_SET_APPLICATION\n  * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:\n  * <dl>\n  * <dt>#OPUS_APPLICATION_VOIP</dt>\n  * <dd>Process signal for improved speech intelligibility.</dd>\n  * <dt>#OPUS_APPLICATION_AUDIO</dt>\n  * <dd>Favor faithfulness to the original input.</dd>\n  * <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt>\n  * <dd>Configure the minimum possible coding delay by disabling certain modes\n  * of operation.</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_GET_APPLICATION(x) OPUS_GET_APPLICATION_REQUEST, __opus_check_int_ptr(x)\n\n/** Gets the total samples of delay added by the entire codec.\n  * This can be queried by the encoder and then the provided number of samples can be\n  * skipped on from the start of the decoder's output to provide time aligned input\n  * and output. From the perspective of a decoding application the real data begins this many\n  * samples late.\n  *\n  * The decoder contribution to this delay is identical for all decoders, but the\n  * encoder portion of the delay may vary from implementation to implementation,\n  * version to version, or even depend on the encoder's initial configuration.\n  * Applications needing delay compensation should call this CTL rather than\n  * hard-coding a value.\n  * @param[out] x <tt>opus_int32 *</tt>:   Number of lookahead samples\n  * @hideinitializer */\n#define OPUS_GET_LOOKAHEAD(x) OPUS_GET_LOOKAHEAD_REQUEST, __opus_check_int_ptr(x)\n\n/** Configures the encoder's use of inband forward error correction (FEC).\n  * @note This is only applicable to the LPC layer\n  * @see OPUS_GET_INBAND_FEC\n  * @param[in] x <tt>opus_int32</tt>: Allowed values:\n  * <dl>\n  * <dt>0</dt><dd>Disable inband FEC (default).</dd>\n  * <dt>1</dt><dd>Enable inband FEC.</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_SET_INBAND_FEC(x) OPUS_SET_INBAND_FEC_REQUEST, __opus_check_int(x)\n/** Gets encoder's configured use of inband forward error correction.\n  * @see OPUS_SET_INBAND_FEC\n  * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:\n  * <dl>\n  * <dt>0</dt><dd>Inband FEC disabled (default).</dd>\n  * <dt>1</dt><dd>Inband FEC enabled.</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_GET_INBAND_FEC(x) OPUS_GET_INBAND_FEC_REQUEST, __opus_check_int_ptr(x)\n\n/** Configures the encoder's expected packet loss percentage.\n  * Higher values trigger progressively more loss resistant behavior in the encoder\n  * at the expense of quality at a given bitrate in the absence of packet loss, but\n  * greater quality under loss.\n  * @see OPUS_GET_PACKET_LOSS_PERC\n  * @param[in] x <tt>opus_int32</tt>:   Loss percentage in the range 0-100, inclusive (default: 0).\n  * @hideinitializer */\n#define OPUS_SET_PACKET_LOSS_PERC(x) OPUS_SET_PACKET_LOSS_PERC_REQUEST, __opus_check_int(x)\n/** Gets the encoder's configured packet loss percentage.\n  * @see OPUS_SET_PACKET_LOSS_PERC\n  * @param[out] x <tt>opus_int32 *</tt>: Returns the configured loss percentage\n  *                                      in the range 0-100, inclusive (default: 0).\n  * @hideinitializer */\n#define OPUS_GET_PACKET_LOSS_PERC(x) OPUS_GET_PACKET_LOSS_PERC_REQUEST, __opus_check_int_ptr(x)\n\n/** Configures the encoder's use of discontinuous transmission (DTX).\n  * @note This is only applicable to the LPC layer\n  * @see OPUS_GET_DTX\n  * @param[in] x <tt>opus_int32</tt>: Allowed values:\n  * <dl>\n  * <dt>0</dt><dd>Disable DTX (default).</dd>\n  * <dt>1</dt><dd>Enabled DTX.</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_SET_DTX(x) OPUS_SET_DTX_REQUEST, __opus_check_int(x)\n/** Gets encoder's configured use of discontinuous transmission.\n  * @see OPUS_SET_DTX\n  * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:\n  * <dl>\n  * <dt>0</dt><dd>DTX disabled (default).</dd>\n  * <dt>1</dt><dd>DTX enabled.</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_GET_DTX(x) OPUS_GET_DTX_REQUEST, __opus_check_int_ptr(x)\n/** Configures the depth of signal being encoded.\n  *\n  * This is a hint which helps the encoder identify silence and near-silence.\n  * It represents the number of significant bits of linear intensity below\n  * which the signal contains ignorable quantization or other noise.\n  *\n  * For example, OPUS_SET_LSB_DEPTH(14) would be an appropriate setting\n  * for G.711 u-law input. OPUS_SET_LSB_DEPTH(16) would be appropriate\n  * for 16-bit linear pcm input with opus_encode_float().\n  *\n  * When using opus_encode() instead of opus_encode_float(), or when libopus\n  * is compiled for fixed-point, the encoder uses the minimum of the value\n  * set here and the value 16.\n  *\n  * @see OPUS_GET_LSB_DEPTH\n  * @param[in] x <tt>opus_int32</tt>: Input precision in bits, between 8 and 24\n  *                                   (default: 24).\n  * @hideinitializer */\n#define OPUS_SET_LSB_DEPTH(x) OPUS_SET_LSB_DEPTH_REQUEST, __opus_check_int(x)\n/** Gets the encoder's configured signal depth.\n  * @see OPUS_SET_LSB_DEPTH\n  * @param[out] x <tt>opus_int32 *</tt>: Input precision in bits, between 8 and\n  *                                      24 (default: 24).\n  * @hideinitializer */\n#define OPUS_GET_LSB_DEPTH(x) OPUS_GET_LSB_DEPTH_REQUEST, __opus_check_int_ptr(x)\n\n/** Configures the encoder's use of variable duration frames.\n  * When variable duration is enabled, the encoder is free to use a shorter frame\n  * size than the one requested in the opus_encode*() call.\n  * It is then the user's responsibility\n  * to verify how much audio was encoded by checking the ToC byte of the encoded\n  * packet. The part of the audio that was not encoded needs to be resent to the\n  * encoder for the next call. Do not use this option unless you <b>really</b>\n  * know what you are doing.\n  * @see OPUS_GET_EXPERT_FRAME_DURATION\n  * @param[in] x <tt>opus_int32</tt>: Allowed values:\n  * <dl>\n  * <dt>OPUS_FRAMESIZE_ARG</dt><dd>Select frame size from the argument (default).</dd>\n  * <dt>OPUS_FRAMESIZE_2_5_MS</dt><dd>Use 2.5 ms frames.</dd>\n  * <dt>OPUS_FRAMESIZE_5_MS</dt><dd>Use 5 ms frames.</dd>\n  * <dt>OPUS_FRAMESIZE_10_MS</dt><dd>Use 10 ms frames.</dd>\n  * <dt>OPUS_FRAMESIZE_20_MS</dt><dd>Use 20 ms frames.</dd>\n  * <dt>OPUS_FRAMESIZE_40_MS</dt><dd>Use 40 ms frames.</dd>\n  * <dt>OPUS_FRAMESIZE_60_MS</dt><dd>Use 60 ms frames.</dd>\n  * <dt>OPUS_FRAMESIZE_80_MS</dt><dd>Use 80 ms frames.</dd>\n  * <dt>OPUS_FRAMESIZE_100_MS</dt><dd>Use 100 ms frames.</dd>\n  * <dt>OPUS_FRAMESIZE_120_MS</dt><dd>Use 120 ms frames.</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_SET_EXPERT_FRAME_DURATION(x) OPUS_SET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int(x)\n/** Gets the encoder's configured use of variable duration frames.\n  * @see OPUS_SET_EXPERT_FRAME_DURATION\n  * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:\n  * <dl>\n  * <dt>OPUS_FRAMESIZE_ARG</dt><dd>Select frame size from the argument (default).</dd>\n  * <dt>OPUS_FRAMESIZE_2_5_MS</dt><dd>Use 2.5 ms frames.</dd>\n  * <dt>OPUS_FRAMESIZE_5_MS</dt><dd>Use 5 ms frames.</dd>\n  * <dt>OPUS_FRAMESIZE_10_MS</dt><dd>Use 10 ms frames.</dd>\n  * <dt>OPUS_FRAMESIZE_20_MS</dt><dd>Use 20 ms frames.</dd>\n  * <dt>OPUS_FRAMESIZE_40_MS</dt><dd>Use 40 ms frames.</dd>\n  * <dt>OPUS_FRAMESIZE_60_MS</dt><dd>Use 60 ms frames.</dd>\n  * <dt>OPUS_FRAMESIZE_80_MS</dt><dd>Use 80 ms frames.</dd>\n  * <dt>OPUS_FRAMESIZE_100_MS</dt><dd>Use 100 ms frames.</dd>\n  * <dt>OPUS_FRAMESIZE_120_MS</dt><dd>Use 120 ms frames.</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_GET_EXPERT_FRAME_DURATION(x) OPUS_GET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int_ptr(x)\n\n/** If set to 1, disables almost all use of prediction, making frames almost\n  * completely independent. This reduces quality.\n  * @see OPUS_GET_PREDICTION_DISABLED\n  * @param[in] x <tt>opus_int32</tt>: Allowed values:\n  * <dl>\n  * <dt>0</dt><dd>Enable prediction (default).</dd>\n  * <dt>1</dt><dd>Disable prediction.</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_SET_PREDICTION_DISABLED(x) OPUS_SET_PREDICTION_DISABLED_REQUEST, __opus_check_int(x)\n/** Gets the encoder's configured prediction status.\n  * @see OPUS_SET_PREDICTION_DISABLED\n  * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:\n  * <dl>\n  * <dt>0</dt><dd>Prediction enabled (default).</dd>\n  * <dt>1</dt><dd>Prediction disabled.</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_GET_PREDICTION_DISABLED(x) OPUS_GET_PREDICTION_DISABLED_REQUEST, __opus_check_int_ptr(x)\n\n/**@}*/\n\n/** @defgroup opus_genericctls Generic CTLs\n  *\n  * These macros are used with the \\c opus_decoder_ctl and\n  * \\c opus_encoder_ctl calls to generate a particular\n  * request.\n  *\n  * When called on an \\c OpusDecoder they apply to that\n  * particular decoder instance. When called on an\n  * \\c OpusEncoder they apply to the corresponding setting\n  * on that encoder instance, if present.\n  *\n  * Some usage examples:\n  *\n  * @code\n  * int ret;\n  * opus_int32 pitch;\n  * ret = opus_decoder_ctl(dec_ctx, OPUS_GET_PITCH(&pitch));\n  * if (ret == OPUS_OK) return ret;\n  *\n  * opus_encoder_ctl(enc_ctx, OPUS_RESET_STATE);\n  * opus_decoder_ctl(dec_ctx, OPUS_RESET_STATE);\n  *\n  * opus_int32 enc_bw, dec_bw;\n  * opus_encoder_ctl(enc_ctx, OPUS_GET_BANDWIDTH(&enc_bw));\n  * opus_decoder_ctl(dec_ctx, OPUS_GET_BANDWIDTH(&dec_bw));\n  * if (enc_bw != dec_bw) {\n  *   printf(\"packet bandwidth mismatch!\\n\");\n  * }\n  * @endcode\n  *\n  * @see opus_encoder, opus_decoder_ctl, opus_encoder_ctl, opus_decoderctls, opus_encoderctls\n  * @{\n  */\n\n/** Resets the codec state to be equivalent to a freshly initialized state.\n  * This should be called when switching streams in order to prevent\n  * the back to back decoding from giving different results from\n  * one at a time decoding.\n  * @hideinitializer */\n#define OPUS_RESET_STATE 4028\n\n/** Gets the final state of the codec's entropy coder.\n  * This is used for testing purposes,\n  * The encoder and decoder state should be identical after coding a payload\n  * (assuming no data corruption or software bugs)\n  *\n  * @param[out] x <tt>opus_uint32 *</tt>: Entropy coder state\n  *\n  * @hideinitializer */\n#define OPUS_GET_FINAL_RANGE(x) OPUS_GET_FINAL_RANGE_REQUEST, __opus_check_uint_ptr(x)\n\n/** Gets the encoder's configured bandpass or the decoder's last bandpass.\n  * @see OPUS_SET_BANDWIDTH\n  * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:\n  * <dl>\n  * <dt>#OPUS_AUTO</dt>                    <dd>(default)</dd>\n  * <dt>#OPUS_BANDWIDTH_NARROWBAND</dt>    <dd>4 kHz passband</dd>\n  * <dt>#OPUS_BANDWIDTH_MEDIUMBAND</dt>    <dd>6 kHz passband</dd>\n  * <dt>#OPUS_BANDWIDTH_WIDEBAND</dt>      <dd>8 kHz passband</dd>\n  * <dt>#OPUS_BANDWIDTH_SUPERWIDEBAND</dt><dd>12 kHz passband</dd>\n  * <dt>#OPUS_BANDWIDTH_FULLBAND</dt>     <dd>20 kHz passband</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_GET_BANDWIDTH(x) OPUS_GET_BANDWIDTH_REQUEST, __opus_check_int_ptr(x)\n\n/** Gets the sampling rate the encoder or decoder was initialized with.\n  * This simply returns the <code>Fs</code> value passed to opus_encoder_init()\n  * or opus_decoder_init().\n  * @param[out] x <tt>opus_int32 *</tt>: Sampling rate of encoder or decoder.\n  * @hideinitializer\n  */\n#define OPUS_GET_SAMPLE_RATE(x) OPUS_GET_SAMPLE_RATE_REQUEST, __opus_check_int_ptr(x)\n\n/** If set to 1, disables the use of phase inversion for intensity stereo,\n  * improving the quality of mono downmixes, but slightly reducing normal\n  * stereo quality. Disabling phase inversion in the decoder does not comply\n  * with RFC 6716, although it does not cause any interoperability issue and\n  * is expected to become part of the Opus standard once RFC 6716 is updated\n  * by draft-ietf-codec-opus-update.\n  * @see OPUS_GET_PHASE_INVERSION_DISABLED\n  * @param[in] x <tt>opus_int32</tt>: Allowed values:\n  * <dl>\n  * <dt>0</dt><dd>Enable phase inversion (default).</dd>\n  * <dt>1</dt><dd>Disable phase inversion.</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_SET_PHASE_INVERSION_DISABLED(x) OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int(x)\n/** Gets the encoder's configured phase inversion status.\n  * @see OPUS_SET_PHASE_INVERSION_DISABLED\n  * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:\n  * <dl>\n  * <dt>0</dt><dd>Stereo phase inversion enabled (default).</dd>\n  * <dt>1</dt><dd>Stereo phase inversion disabled.</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_GET_PHASE_INVERSION_DISABLED(x) OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int_ptr(x)\n/** Gets the DTX state of the encoder.\n  * Returns whether the last encoded frame was either a comfort noise update\n  * during DTX or not encoded because of DTX.\n  * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:\n  * <dl>\n  * <dt>0</dt><dd>The encoder is not in DTX.</dd>\n  * <dt>1</dt><dd>The encoder is in DTX.</dd>\n  * </dl>\n  * @hideinitializer */\n#define OPUS_GET_IN_DTX(x) OPUS_GET_IN_DTX_REQUEST, __opus_check_int_ptr(x)\n\n/**@}*/\n\n/** @defgroup opus_decoderctls Decoder related CTLs\n  * @see opus_genericctls, opus_encoderctls, opus_decoder\n  * @{\n  */\n\n/** Configures decoder gain adjustment.\n  * Scales the decoded output by a factor specified in Q8 dB units.\n  * This has a maximum range of -32768 to 32767 inclusive, and returns\n  * OPUS_BAD_ARG otherwise. The default is zero indicating no adjustment.\n  * This setting survives decoder reset.\n  *\n  * gain = pow(10, x/(20.0*256))\n  *\n  * @param[in] x <tt>opus_int32</tt>:   Amount to scale PCM signal by in Q8 dB units.\n  * @hideinitializer */\n#define OPUS_SET_GAIN(x) OPUS_SET_GAIN_REQUEST, __opus_check_int(x)\n/** Gets the decoder's configured gain adjustment. @see OPUS_SET_GAIN\n  *\n  * @param[out] x <tt>opus_int32 *</tt>: Amount to scale PCM signal by in Q8 dB units.\n  * @hideinitializer */\n#define OPUS_GET_GAIN(x) OPUS_GET_GAIN_REQUEST, __opus_check_int_ptr(x)\n\n/** Gets the duration (in samples) of the last packet successfully decoded or concealed.\n  * @param[out] x <tt>opus_int32 *</tt>: Number of samples (at current sampling rate).\n  * @hideinitializer */\n#define OPUS_GET_LAST_PACKET_DURATION(x) OPUS_GET_LAST_PACKET_DURATION_REQUEST, __opus_check_int_ptr(x)\n\n/** Gets the pitch of the last decoded frame, if available.\n  * This can be used for any post-processing algorithm requiring the use of pitch,\n  * e.g. time stretching/shortening. If the last frame was not voiced, or if the\n  * pitch was not coded in the frame, then zero is returned.\n  *\n  * This CTL is only implemented for decoder instances.\n  *\n  * @param[out] x <tt>opus_int32 *</tt>: pitch period at 48 kHz (or 0 if not available)\n  *\n  * @hideinitializer */\n#define OPUS_GET_PITCH(x) OPUS_GET_PITCH_REQUEST, __opus_check_int_ptr(x)\n\n/**@}*/\n\n/** @defgroup opus_libinfo Opus library information functions\n  * @{\n  */\n\n/** Converts an opus error code into a human readable string.\n  *\n  * @param[in] error <tt>int</tt>: Error number\n  * @returns Error string\n  */\nOPUS_EXPORT const char *opus_strerror(int error);\n\n/** Gets the libopus version string.\n  *\n  * Applications may look for the substring \"-fixed\" in the version string to\n  * determine whether they have a fixed-point or floating-point build at\n  * runtime.\n  *\n  * @returns Version string\n  */\nOPUS_EXPORT const char *opus_get_version_string(void);\n/**@}*/\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* OPUS_DEFINES_H */\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/cpp/libopus/opus_multistream.h",
    "content": "/* Copyright (c) 2011 Xiph.Org Foundation\n   Written by Jean-Marc Valin */\n/*\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n\n   - Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n   - Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER\n   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n/**\n * @file opus_multistream.h\n * @brief Opus reference implementation multistream API\n */\n\n#ifndef OPUS_MULTISTREAM_H\n#define OPUS_MULTISTREAM_H\n\n#include \"opus.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/** @cond OPUS_INTERNAL_DOC */\n\n/** Macros to trigger compilation errors when the wrong types are provided to a\n  * CTL. */\n/**@{*/\n#define __opus_check_encstate_ptr(ptr) ((ptr) + ((ptr) - (OpusEncoder**)(ptr)))\n#define __opus_check_decstate_ptr(ptr) ((ptr) + ((ptr) - (OpusDecoder**)(ptr)))\n/**@}*/\n\n/** These are the actual encoder and decoder CTL ID numbers.\n  * They should not be used directly by applications.\n  * In general, SETs should be even and GETs should be odd.*/\n/**@{*/\n#define OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST 5120\n#define OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST 5122\n/**@}*/\n\n/** @endcond */\n\n/** @defgroup opus_multistream_ctls Multistream specific encoder and decoder CTLs\n  *\n  * These are convenience macros that are specific to the\n  * opus_multistream_encoder_ctl() and opus_multistream_decoder_ctl()\n  * interface.\n  * The CTLs from @ref opus_genericctls, @ref opus_encoderctls, and\n  * @ref opus_decoderctls may be applied to a multistream encoder or decoder as\n  * well.\n  * In addition, you may retrieve the encoder or decoder state for an specific\n  * stream via #OPUS_MULTISTREAM_GET_ENCODER_STATE or\n  * #OPUS_MULTISTREAM_GET_DECODER_STATE and apply CTLs to it individually.\n  */\n/**@{*/\n\n/** Gets the encoder state for an individual stream of a multistream encoder.\n  * @param[in] x <tt>opus_int32</tt>: The index of the stream whose encoder you\n  *                                   wish to retrieve.\n  *                                   This must be non-negative and less than\n  *                                   the <code>streams</code> parameter used\n  *                                   to initialize the encoder.\n  * @param[out] y <tt>OpusEncoder**</tt>: Returns a pointer to the given\n  *                                       encoder state.\n  * @retval OPUS_BAD_ARG The index of the requested stream was out of range.\n  * @hideinitializer\n  */\n#define OPUS_MULTISTREAM_GET_ENCODER_STATE(x,y) OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST, __opus_check_int(x), __opus_check_encstate_ptr(y)\n\n/** Gets the decoder state for an individual stream of a multistream decoder.\n  * @param[in] x <tt>opus_int32</tt>: The index of the stream whose decoder you\n  *                                   wish to retrieve.\n  *                                   This must be non-negative and less than\n  *                                   the <code>streams</code> parameter used\n  *                                   to initialize the decoder.\n  * @param[out] y <tt>OpusDecoder**</tt>: Returns a pointer to the given\n  *                                       decoder state.\n  * @retval OPUS_BAD_ARG The index of the requested stream was out of range.\n  * @hideinitializer\n  */\n#define OPUS_MULTISTREAM_GET_DECODER_STATE(x,y) OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST, __opus_check_int(x), __opus_check_decstate_ptr(y)\n\n/**@}*/\n\n/** @defgroup opus_multistream Opus Multistream API\n  * @{\n  *\n  * The multistream API allows individual Opus streams to be combined into a\n  * single packet, enabling support for up to 255 channels. Unlike an\n  * elementary Opus stream, the encoder and decoder must negotiate the channel\n  * configuration before the decoder can successfully interpret the data in the\n  * packets produced by the encoder. Some basic information, such as packet\n  * duration, can be computed without any special negotiation.\n  *\n  * The format for multistream Opus packets is defined in\n  * <a href=\"https://tools.ietf.org/html/rfc7845\">RFC 7845</a>\n  * and is based on the self-delimited Opus framing described in Appendix B of\n  * <a href=\"https://tools.ietf.org/html/rfc6716\">RFC 6716</a>.\n  * Normal Opus packets are just a degenerate case of multistream Opus packets,\n  * and can be encoded or decoded with the multistream API by setting\n  * <code>streams</code> to <code>1</code> when initializing the encoder or\n  * decoder.\n  *\n  * Multistream Opus streams can contain up to 255 elementary Opus streams.\n  * These may be either \"uncoupled\" or \"coupled\", indicating that the decoder\n  * is configured to decode them to either 1 or 2 channels, respectively.\n  * The streams are ordered so that all coupled streams appear at the\n  * beginning.\n  *\n  * A <code>mapping</code> table defines which decoded channel <code>i</code>\n  * should be used for each input/output (I/O) channel <code>j</code>. This table is\n  * typically provided as an unsigned char array.\n  * Let <code>i = mapping[j]</code> be the index for I/O channel <code>j</code>.\n  * If <code>i < 2*coupled_streams</code>, then I/O channel <code>j</code> is\n  * encoded as the left channel of stream <code>(i/2)</code> if <code>i</code>\n  * is even, or  as the right channel of stream <code>(i/2)</code> if\n  * <code>i</code> is odd. Otherwise, I/O channel <code>j</code> is encoded as\n  * mono in stream <code>(i - coupled_streams)</code>, unless it has the special\n  * value 255, in which case it is omitted from the encoding entirely (the\n  * decoder will reproduce it as silence). Each value <code>i</code> must either\n  * be the special value 255 or be less than <code>streams + coupled_streams</code>.\n  *\n  * The output channels specified by the encoder\n  * should use the\n  * <a href=\"https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810004.3.9\">Vorbis\n  * channel ordering</a>. A decoder may wish to apply an additional permutation\n  * to the mapping the encoder used to achieve a different output channel\n  * order (e.g. for outputing in WAV order).\n  *\n  * Each multistream packet contains an Opus packet for each stream, and all of\n  * the Opus packets in a single multistream packet must have the same\n  * duration. Therefore the duration of a multistream packet can be extracted\n  * from the TOC sequence of the first stream, which is located at the\n  * beginning of the packet, just like an elementary Opus stream:\n  *\n  * @code\n  * int nb_samples;\n  * int nb_frames;\n  * nb_frames = opus_packet_get_nb_frames(data, len);\n  * if (nb_frames < 1)\n  *   return nb_frames;\n  * nb_samples = opus_packet_get_samples_per_frame(data, 48000) * nb_frames;\n  * @endcode\n  *\n  * The general encoding and decoding process proceeds exactly the same as in\n  * the normal @ref opus_encoder and @ref opus_decoder APIs.\n  * See their documentation for an overview of how to use the corresponding\n  * multistream functions.\n  */\n\n/** Opus multistream encoder state.\n  * This contains the complete state of a multistream Opus encoder.\n  * It is position independent and can be freely copied.\n  * @see opus_multistream_encoder_create\n  * @see opus_multistream_encoder_init\n  */\ntypedef struct OpusMSEncoder OpusMSEncoder;\n\n/** Opus multistream decoder state.\n  * This contains the complete state of a multistream Opus decoder.\n  * It is position independent and can be freely copied.\n  * @see opus_multistream_decoder_create\n  * @see opus_multistream_decoder_init\n  */\ntypedef struct OpusMSDecoder OpusMSDecoder;\n\n/**\\name Multistream encoder functions */\n/**@{*/\n\n/** Gets the size of an OpusMSEncoder structure.\n  * @param streams <tt>int</tt>: The total number of streams to encode from the\n  *                              input.\n  *                              This must be no more than 255.\n  * @param coupled_streams <tt>int</tt>: Number of coupled (2 channel) streams\n  *                                      to encode.\n  *                                      This must be no larger than the total\n  *                                      number of streams.\n  *                                      Additionally, The total number of\n  *                                      encoded channels (<code>streams +\n  *                                      coupled_streams</code>) must be no\n  *                                      more than 255.\n  * @returns The size in bytes on success, or a negative error code\n  *          (see @ref opus_errorcodes) on error.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_encoder_get_size(\n      int streams,\n      int coupled_streams\n);\n\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_surround_encoder_get_size(\n      int channels,\n      int mapping_family\n);\n\n\n/** Allocates and initializes a multistream encoder state.\n  * Call opus_multistream_encoder_destroy() to release\n  * this object when finished.\n  * @param Fs <tt>opus_int32</tt>: Sampling rate of the input signal (in Hz).\n  *                                This must be one of 8000, 12000, 16000,\n  *                                24000, or 48000.\n  * @param channels <tt>int</tt>: Number of channels in the input signal.\n  *                               This must be at most 255.\n  *                               It may be greater than the number of\n  *                               coded channels (<code>streams +\n  *                               coupled_streams</code>).\n  * @param streams <tt>int</tt>: The total number of streams to encode from the\n  *                              input.\n  *                              This must be no more than the number of channels.\n  * @param coupled_streams <tt>int</tt>: Number of coupled (2 channel) streams\n  *                                      to encode.\n  *                                      This must be no larger than the total\n  *                                      number of streams.\n  *                                      Additionally, The total number of\n  *                                      encoded channels (<code>streams +\n  *                                      coupled_streams</code>) must be no\n  *                                      more than the number of input channels.\n  * @param[in] mapping <code>const unsigned char[channels]</code>: Mapping from\n  *                    encoded channels to input channels, as described in\n  *                    @ref opus_multistream. As an extra constraint, the\n  *                    multistream encoder does not allow encoding coupled\n  *                    streams for which one channel is unused since this\n  *                    is never a good idea.\n  * @param application <tt>int</tt>: The target encoder application.\n  *                                  This must be one of the following:\n  * <dl>\n  * <dt>#OPUS_APPLICATION_VOIP</dt>\n  * <dd>Process signal for improved speech intelligibility.</dd>\n  * <dt>#OPUS_APPLICATION_AUDIO</dt>\n  * <dd>Favor faithfulness to the original input.</dd>\n  * <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt>\n  * <dd>Configure the minimum possible coding delay by disabling certain modes\n  * of operation.</dd>\n  * </dl>\n  * @param[out] error <tt>int *</tt>: Returns #OPUS_OK on success, or an error\n  *                                   code (see @ref opus_errorcodes) on\n  *                                   failure.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_encoder_create(\n      opus_int32 Fs,\n      int channels,\n      int streams,\n      int coupled_streams,\n      const unsigned char *mapping,\n      int application,\n      int *error\n) OPUS_ARG_NONNULL(5);\n\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_surround_encoder_create(\n      opus_int32 Fs,\n      int channels,\n      int mapping_family,\n      int *streams,\n      int *coupled_streams,\n      unsigned char *mapping,\n      int application,\n      int *error\n) OPUS_ARG_NONNULL(4) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6);\n\n/** Initialize a previously allocated multistream encoder state.\n  * The memory pointed to by \\a st must be at least the size returned by\n  * opus_multistream_encoder_get_size().\n  * This is intended for applications which use their own allocator instead of\n  * malloc.\n  * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.\n  * @see opus_multistream_encoder_create\n  * @see opus_multistream_encoder_get_size\n  * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state to initialize.\n  * @param Fs <tt>opus_int32</tt>: Sampling rate of the input signal (in Hz).\n  *                                This must be one of 8000, 12000, 16000,\n  *                                24000, or 48000.\n  * @param channels <tt>int</tt>: Number of channels in the input signal.\n  *                               This must be at most 255.\n  *                               It may be greater than the number of\n  *                               coded channels (<code>streams +\n  *                               coupled_streams</code>).\n  * @param streams <tt>int</tt>: The total number of streams to encode from the\n  *                              input.\n  *                              This must be no more than the number of channels.\n  * @param coupled_streams <tt>int</tt>: Number of coupled (2 channel) streams\n  *                                      to encode.\n  *                                      This must be no larger than the total\n  *                                      number of streams.\n  *                                      Additionally, The total number of\n  *                                      encoded channels (<code>streams +\n  *                                      coupled_streams</code>) must be no\n  *                                      more than the number of input channels.\n  * @param[in] mapping <code>const unsigned char[channels]</code>: Mapping from\n  *                    encoded channels to input channels, as described in\n  *                    @ref opus_multistream. As an extra constraint, the\n  *                    multistream encoder does not allow encoding coupled\n  *                    streams for which one channel is unused since this\n  *                    is never a good idea.\n  * @param application <tt>int</tt>: The target encoder application.\n  *                                  This must be one of the following:\n  * <dl>\n  * <dt>#OPUS_APPLICATION_VOIP</dt>\n  * <dd>Process signal for improved speech intelligibility.</dd>\n  * <dt>#OPUS_APPLICATION_AUDIO</dt>\n  * <dd>Favor faithfulness to the original input.</dd>\n  * <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt>\n  * <dd>Configure the minimum possible coding delay by disabling certain modes\n  * of operation.</dd>\n  * </dl>\n  * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes)\n  *          on failure.\n  */\nOPUS_EXPORT int opus_multistream_encoder_init(\n      OpusMSEncoder *st,\n      opus_int32 Fs,\n      int channels,\n      int streams,\n      int coupled_streams,\n      const unsigned char *mapping,\n      int application\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6);\n\nOPUS_EXPORT int opus_multistream_surround_encoder_init(\n      OpusMSEncoder *st,\n      opus_int32 Fs,\n      int channels,\n      int mapping_family,\n      int *streams,\n      int *coupled_streams,\n      unsigned char *mapping,\n      int application\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6) OPUS_ARG_NONNULL(7);\n\n/** Encodes a multistream Opus frame.\n  * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state.\n  * @param[in] pcm <tt>const opus_int16*</tt>: The input signal as interleaved\n  *                                            samples.\n  *                                            This must contain\n  *                                            <code>frame_size*channels</code>\n  *                                            samples.\n  * @param frame_size <tt>int</tt>: Number of samples per channel in the input\n  *                                 signal.\n  *                                 This must be an Opus frame size for the\n  *                                 encoder's sampling rate.\n  *                                 For example, at 48 kHz the permitted values\n  *                                 are 120, 240, 480, 960, 1920, and 2880.\n  *                                 Passing in a duration of less than 10 ms\n  *                                 (480 samples at 48 kHz) will prevent the\n  *                                 encoder from using the LPC or hybrid modes.\n  * @param[out] data <tt>unsigned char*</tt>: Output payload.\n  *                                           This must contain storage for at\n  *                                           least \\a max_data_bytes.\n  * @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated\n  *                                                 memory for the output\n  *                                                 payload. This may be\n  *                                                 used to impose an upper limit on\n  *                                                 the instant bitrate, but should\n  *                                                 not be used as the only bitrate\n  *                                                 control. Use #OPUS_SET_BITRATE to\n  *                                                 control the bitrate.\n  * @returns The length of the encoded packet (in bytes) on success or a\n  *          negative error code (see @ref opus_errorcodes) on failure.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode(\n    OpusMSEncoder *st,\n    const opus_int16 *pcm,\n    int frame_size,\n    unsigned char *data,\n    opus_int32 max_data_bytes\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);\n\n/** Encodes a multistream Opus frame from floating point input.\n  * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state.\n  * @param[in] pcm <tt>const float*</tt>: The input signal as interleaved\n  *                                       samples with a normal range of\n  *                                       +/-1.0.\n  *                                       Samples with a range beyond +/-1.0\n  *                                       are supported but will be clipped by\n  *                                       decoders using the integer API and\n  *                                       should only be used if it is known\n  *                                       that the far end supports extended\n  *                                       dynamic range.\n  *                                       This must contain\n  *                                       <code>frame_size*channels</code>\n  *                                       samples.\n  * @param frame_size <tt>int</tt>: Number of samples per channel in the input\n  *                                 signal.\n  *                                 This must be an Opus frame size for the\n  *                                 encoder's sampling rate.\n  *                                 For example, at 48 kHz the permitted values\n  *                                 are 120, 240, 480, 960, 1920, and 2880.\n  *                                 Passing in a duration of less than 10 ms\n  *                                 (480 samples at 48 kHz) will prevent the\n  *                                 encoder from using the LPC or hybrid modes.\n  * @param[out] data <tt>unsigned char*</tt>: Output payload.\n  *                                           This must contain storage for at\n  *                                           least \\a max_data_bytes.\n  * @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated\n  *                                                 memory for the output\n  *                                                 payload. This may be\n  *                                                 used to impose an upper limit on\n  *                                                 the instant bitrate, but should\n  *                                                 not be used as the only bitrate\n  *                                                 control. Use #OPUS_SET_BITRATE to\n  *                                                 control the bitrate.\n  * @returns The length of the encoded packet (in bytes) on success or a\n  *          negative error code (see @ref opus_errorcodes) on failure.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode_float(\n      OpusMSEncoder *st,\n      const float *pcm,\n      int frame_size,\n      unsigned char *data,\n      opus_int32 max_data_bytes\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);\n\n/** Frees an <code>OpusMSEncoder</code> allocated by\n  * opus_multistream_encoder_create().\n  * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state to be freed.\n  */\nOPUS_EXPORT void opus_multistream_encoder_destroy(OpusMSEncoder *st);\n\n/** Perform a CTL function on a multistream Opus encoder.\n  *\n  * Generally the request and subsequent arguments are generated by a\n  * convenience macro.\n  * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state.\n  * @param request This and all remaining parameters should be replaced by one\n  *                of the convenience macros in @ref opus_genericctls,\n  *                @ref opus_encoderctls, or @ref opus_multistream_ctls.\n  * @see opus_genericctls\n  * @see opus_encoderctls\n  * @see opus_multistream_ctls\n  */\nOPUS_EXPORT int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...) OPUS_ARG_NONNULL(1);\n\n/**@}*/\n\n/**\\name Multistream decoder functions */\n/**@{*/\n\n/** Gets the size of an <code>OpusMSDecoder</code> structure.\n  * @param streams <tt>int</tt>: The total number of streams coded in the\n  *                              input.\n  *                              This must be no more than 255.\n  * @param coupled_streams <tt>int</tt>: Number streams to decode as coupled\n  *                                      (2 channel) streams.\n  *                                      This must be no larger than the total\n  *                                      number of streams.\n  *                                      Additionally, The total number of\n  *                                      coded channels (<code>streams +\n  *                                      coupled_streams</code>) must be no\n  *                                      more than 255.\n  * @returns The size in bytes on success, or a negative error code\n  *          (see @ref opus_errorcodes) on error.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_decoder_get_size(\n      int streams,\n      int coupled_streams\n);\n\n/** Allocates and initializes a multistream decoder state.\n  * Call opus_multistream_decoder_destroy() to release\n  * this object when finished.\n  * @param Fs <tt>opus_int32</tt>: Sampling rate to decode at (in Hz).\n  *                                This must be one of 8000, 12000, 16000,\n  *                                24000, or 48000.\n  * @param channels <tt>int</tt>: Number of channels to output.\n  *                               This must be at most 255.\n  *                               It may be different from the number of coded\n  *                               channels (<code>streams +\n  *                               coupled_streams</code>).\n  * @param streams <tt>int</tt>: The total number of streams coded in the\n  *                              input.\n  *                              This must be no more than 255.\n  * @param coupled_streams <tt>int</tt>: Number of streams to decode as coupled\n  *                                      (2 channel) streams.\n  *                                      This must be no larger than the total\n  *                                      number of streams.\n  *                                      Additionally, The total number of\n  *                                      coded channels (<code>streams +\n  *                                      coupled_streams</code>) must be no\n  *                                      more than 255.\n  * @param[in] mapping <code>const unsigned char[channels]</code>: Mapping from\n  *                    coded channels to output channels, as described in\n  *                    @ref opus_multistream.\n  * @param[out] error <tt>int *</tt>: Returns #OPUS_OK on success, or an error\n  *                                   code (see @ref opus_errorcodes) on\n  *                                   failure.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSDecoder *opus_multistream_decoder_create(\n      opus_int32 Fs,\n      int channels,\n      int streams,\n      int coupled_streams,\n      const unsigned char *mapping,\n      int *error\n) OPUS_ARG_NONNULL(5);\n\n/** Intialize a previously allocated decoder state object.\n  * The memory pointed to by \\a st must be at least the size returned by\n  * opus_multistream_encoder_get_size().\n  * This is intended for applications which use their own allocator instead of\n  * malloc.\n  * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.\n  * @see opus_multistream_decoder_create\n  * @see opus_multistream_deocder_get_size\n  * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state to initialize.\n  * @param Fs <tt>opus_int32</tt>: Sampling rate to decode at (in Hz).\n  *                                This must be one of 8000, 12000, 16000,\n  *                                24000, or 48000.\n  * @param channels <tt>int</tt>: Number of channels to output.\n  *                               This must be at most 255.\n  *                               It may be different from the number of coded\n  *                               channels (<code>streams +\n  *                               coupled_streams</code>).\n  * @param streams <tt>int</tt>: The total number of streams coded in the\n  *                              input.\n  *                              This must be no more than 255.\n  * @param coupled_streams <tt>int</tt>: Number of streams to decode as coupled\n  *                                      (2 channel) streams.\n  *                                      This must be no larger than the total\n  *                                      number of streams.\n  *                                      Additionally, The total number of\n  *                                      coded channels (<code>streams +\n  *                                      coupled_streams</code>) must be no\n  *                                      more than 255.\n  * @param[in] mapping <code>const unsigned char[channels]</code>: Mapping from\n  *                    coded channels to output channels, as described in\n  *                    @ref opus_multistream.\n  * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes)\n  *          on failure.\n  */\nOPUS_EXPORT int opus_multistream_decoder_init(\n      OpusMSDecoder *st,\n      opus_int32 Fs,\n      int channels,\n      int streams,\n      int coupled_streams,\n      const unsigned char *mapping\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6);\n\n/** Decode a multistream Opus packet.\n  * @param st <tt>OpusMSDecoder*</tt>: Multistream decoder state.\n  * @param[in] data <tt>const unsigned char*</tt>: Input payload.\n  *                                                Use a <code>NULL</code>\n  *                                                pointer to indicate packet\n  *                                                loss.\n  * @param len <tt>opus_int32</tt>: Number of bytes in payload.\n  * @param[out] pcm <tt>opus_int16*</tt>: Output signal, with interleaved\n  *                                       samples.\n  *                                       This must contain room for\n  *                                       <code>frame_size*channels</code>\n  *                                       samples.\n  * @param frame_size <tt>int</tt>: The number of samples per channel of\n  *                                 available space in \\a pcm.\n  *                                 If this is less than the maximum packet duration\n  *                                 (120 ms; 5760 for 48kHz), this function will not be capable\n  *                                 of decoding some packets. In the case of PLC (data==NULL)\n  *                                 or FEC (decode_fec=1), then frame_size needs to be exactly\n  *                                 the duration of audio that is missing, otherwise the\n  *                                 decoder will not be in the optimal state to decode the\n  *                                 next incoming packet. For the PLC and FEC cases, frame_size\n  *                                 <b>must</b> be a multiple of 2.5 ms.\n  * @param decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band\n  *                                 forward error correction data be decoded.\n  *                                 If no such data is available, the frame is\n  *                                 decoded as if it were lost.\n  * @returns Number of samples decoded on success or a negative error code\n  *          (see @ref opus_errorcodes) on failure.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode(\n    OpusMSDecoder *st,\n    const unsigned char *data,\n    opus_int32 len,\n    opus_int16 *pcm,\n    int frame_size,\n    int decode_fec\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);\n\n/** Decode a multistream Opus packet with floating point output.\n  * @param st <tt>OpusMSDecoder*</tt>: Multistream decoder state.\n  * @param[in] data <tt>const unsigned char*</tt>: Input payload.\n  *                                                Use a <code>NULL</code>\n  *                                                pointer to indicate packet\n  *                                                loss.\n  * @param len <tt>opus_int32</tt>: Number of bytes in payload.\n  * @param[out] pcm <tt>opus_int16*</tt>: Output signal, with interleaved\n  *                                       samples.\n  *                                       This must contain room for\n  *                                       <code>frame_size*channels</code>\n  *                                       samples.\n  * @param frame_size <tt>int</tt>: The number of samples per channel of\n  *                                 available space in \\a pcm.\n  *                                 If this is less than the maximum packet duration\n  *                                 (120 ms; 5760 for 48kHz), this function will not be capable\n  *                                 of decoding some packets. In the case of PLC (data==NULL)\n  *                                 or FEC (decode_fec=1), then frame_size needs to be exactly\n  *                                 the duration of audio that is missing, otherwise the\n  *                                 decoder will not be in the optimal state to decode the\n  *                                 next incoming packet. For the PLC and FEC cases, frame_size\n  *                                 <b>must</b> be a multiple of 2.5 ms.\n  * @param decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band\n  *                                 forward error correction data be decoded.\n  *                                 If no such data is available, the frame is\n  *                                 decoded as if it were lost.\n  * @returns Number of samples decoded on success or a negative error code\n  *          (see @ref opus_errorcodes) on failure.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode_float(\n    OpusMSDecoder *st,\n    const unsigned char *data,\n    opus_int32 len,\n    float *pcm,\n    int frame_size,\n    int decode_fec\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);\n\n/** Perform a CTL function on a multistream Opus decoder.\n  *\n  * Generally the request and subsequent arguments are generated by a\n  * convenience macro.\n  * @param st <tt>OpusMSDecoder*</tt>: Multistream decoder state.\n  * @param request This and all remaining parameters should be replaced by one\n  *                of the convenience macros in @ref opus_genericctls,\n  *                @ref opus_decoderctls, or @ref opus_multistream_ctls.\n  * @see opus_genericctls\n  * @see opus_decoderctls\n  * @see opus_multistream_ctls\n  */\nOPUS_EXPORT int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) OPUS_ARG_NONNULL(1);\n\n/** Frees an <code>OpusMSDecoder</code> allocated by\n  * opus_multistream_decoder_create().\n  * @param st <tt>OpusMSDecoder</tt>: Multistream decoder state to be freed.\n  */\nOPUS_EXPORT void opus_multistream_decoder_destroy(OpusMSDecoder *st);\n\n/**@}*/\n\n/**@}*/\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* OPUS_MULTISTREAM_H */\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/cpp/libopus/opus_projection.h",
    "content": "/* Copyright (c) 2017 Google Inc.\n   Written by Andrew Allen */\n/*\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n\n   - Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n   - Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER\n   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n/**\n * @file opus_projection.h\n * @brief Opus projection reference API\n */\n\n#ifndef OPUS_PROJECTION_H\n#define OPUS_PROJECTION_H\n\n#include \"opus_multistream.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/** @cond OPUS_INTERNAL_DOC */\n\n/** These are the actual encoder and decoder CTL ID numbers.\n  * They should not be used directly by applications.c\n  * In general, SETs should be even and GETs should be odd.*/\n/**@{*/\n#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST    6001\n#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST    6003\n#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST         6005\n/**@}*/\n\n\n/** @endcond */\n\n/** @defgroup opus_projection_ctls Projection specific encoder and decoder CTLs\n  *\n  * These are convenience macros that are specific to the\n  * opus_projection_encoder_ctl() and opus_projection_decoder_ctl()\n  * interface.\n  * The CTLs from @ref opus_genericctls, @ref opus_encoderctls,\n  * @ref opus_decoderctls, and @ref opus_multistream_ctls may be applied to a\n  * projection encoder or decoder as well.\n  */\n/**@{*/\n\n/** Gets the gain (in dB. S7.8-format) of the demixing matrix from the encoder.\n  * @param[out] x <tt>opus_int32 *</tt>: Returns the gain (in dB. S7.8-format)\n  *                                      of the demixing matrix.\n  * @hideinitializer\n  */\n#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN(x) OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST, __opus_check_int_ptr(x)\n\n\n/** Gets the size in bytes of the demixing matrix from the encoder.\n  * @param[out] x <tt>opus_int32 *</tt>: Returns the size in bytes of the\n  *                                      demixing matrix.\n  * @hideinitializer\n  */\n#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE(x) OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST, __opus_check_int_ptr(x)\n\n\n/** Copies the demixing matrix to the supplied pointer location.\n  * @param[out] x <tt>unsigned char *</tt>: Returns the demixing matrix to the\n  *                                         supplied pointer location.\n  * @param y <tt>opus_int32</tt>: The size in bytes of the reserved memory at the\n  *                              pointer location.\n  * @hideinitializer\n  */\n#define OPUS_PROJECTION_GET_DEMIXING_MATRIX(x,y) OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST, x, __opus_check_int(y)\n\n\n/**@}*/\n\n/** Opus projection encoder state.\n * This contains the complete state of a projection Opus encoder.\n * It is position independent and can be freely copied.\n * @see opus_projection_ambisonics_encoder_create\n */\ntypedef struct OpusProjectionEncoder OpusProjectionEncoder;\n\n\n/** Opus projection decoder state.\n  * This contains the complete state of a projection Opus decoder.\n  * It is position independent and can be freely copied.\n  * @see opus_projection_decoder_create\n  * @see opus_projection_decoder_init\n  */\ntypedef struct OpusProjectionDecoder OpusProjectionDecoder;\n\n\n/**\\name Projection encoder functions */\n/**@{*/\n\n/** Gets the size of an OpusProjectionEncoder structure.\n  * @param channels <tt>int</tt>: The total number of input channels to encode.\n  *                               This must be no more than 255.\n  * @param mapping_family <tt>int</tt>: The mapping family to use for selecting\n  *                                     the appropriate projection.\n  * @returns The size in bytes on success, or a negative error code\n  *          (see @ref opus_errorcodes) on error.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_projection_ambisonics_encoder_get_size(\n    int channels,\n    int mapping_family\n);\n\n\n/** Allocates and initializes a projection encoder state.\n  * Call opus_projection_encoder_destroy() to release\n  * this object when finished.\n  * @param Fs <tt>opus_int32</tt>: Sampling rate of the input signal (in Hz).\n  *                                This must be one of 8000, 12000, 16000,\n  *                                24000, or 48000.\n  * @param channels <tt>int</tt>: Number of channels in the input signal.\n  *                               This must be at most 255.\n  *                               It may be greater than the number of\n  *                               coded channels (<code>streams +\n  *                               coupled_streams</code>).\n  * @param mapping_family <tt>int</tt>: The mapping family to use for selecting\n  *                                     the appropriate projection.\n  * @param[out] streams <tt>int *</tt>: The total number of streams that will\n  *                                     be encoded from the input.\n  * @param[out] coupled_streams <tt>int *</tt>: Number of coupled (2 channel)\n  *                                 streams that will be encoded from the input.\n  * @param application <tt>int</tt>: The target encoder application.\n  *                                  This must be one of the following:\n  * <dl>\n  * <dt>#OPUS_APPLICATION_VOIP</dt>\n  * <dd>Process signal for improved speech intelligibility.</dd>\n  * <dt>#OPUS_APPLICATION_AUDIO</dt>\n  * <dd>Favor faithfulness to the original input.</dd>\n  * <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt>\n  * <dd>Configure the minimum possible coding delay by disabling certain modes\n  * of operation.</dd>\n  * </dl>\n  * @param[out] error <tt>int *</tt>: Returns #OPUS_OK on success, or an error\n  *                                   code (see @ref opus_errorcodes) on\n  *                                   failure.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusProjectionEncoder *opus_projection_ambisonics_encoder_create(\n    opus_int32 Fs,\n    int channels,\n    int mapping_family,\n    int *streams,\n    int *coupled_streams,\n    int application,\n    int *error\n) OPUS_ARG_NONNULL(4) OPUS_ARG_NONNULL(5);\n\n\n/** Initialize a previously allocated projection encoder state.\n  * The memory pointed to by \\a st must be at least the size returned by\n  * opus_projection_ambisonics_encoder_get_size().\n  * This is intended for applications which use their own allocator instead of\n  * malloc.\n  * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.\n  * @see opus_projection_ambisonics_encoder_create\n  * @see opus_projection_ambisonics_encoder_get_size\n  * @param st <tt>OpusProjectionEncoder*</tt>: Projection encoder state to initialize.\n  * @param Fs <tt>opus_int32</tt>: Sampling rate of the input signal (in Hz).\n  *                                This must be one of 8000, 12000, 16000,\n  *                                24000, or 48000.\n  * @param channels <tt>int</tt>: Number of channels in the input signal.\n  *                               This must be at most 255.\n  *                               It may be greater than the number of\n  *                               coded channels (<code>streams +\n  *                               coupled_streams</code>).\n  * @param streams <tt>int</tt>: The total number of streams to encode from the\n  *                              input.\n  *                              This must be no more than the number of channels.\n  * @param coupled_streams <tt>int</tt>: Number of coupled (2 channel) streams\n  *                                      to encode.\n  *                                      This must be no larger than the total\n  *                                      number of streams.\n  *                                      Additionally, The total number of\n  *                                      encoded channels (<code>streams +\n  *                                      coupled_streams</code>) must be no\n  *                                      more than the number of input channels.\n  * @param application <tt>int</tt>: The target encoder application.\n  *                                  This must be one of the following:\n  * <dl>\n  * <dt>#OPUS_APPLICATION_VOIP</dt>\n  * <dd>Process signal for improved speech intelligibility.</dd>\n  * <dt>#OPUS_APPLICATION_AUDIO</dt>\n  * <dd>Favor faithfulness to the original input.</dd>\n  * <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt>\n  * <dd>Configure the minimum possible coding delay by disabling certain modes\n  * of operation.</dd>\n  * </dl>\n  * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes)\n  *          on failure.\n  */\nOPUS_EXPORT int opus_projection_ambisonics_encoder_init(\n    OpusProjectionEncoder *st,\n    opus_int32 Fs,\n    int channels,\n    int mapping_family,\n    int *streams,\n    int *coupled_streams,\n    int application\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6);\n\n\n/** Encodes a projection Opus frame.\n  * @param st <tt>OpusProjectionEncoder*</tt>: Projection encoder state.\n  * @param[in] pcm <tt>const opus_int16*</tt>: The input signal as interleaved\n  *                                            samples.\n  *                                            This must contain\n  *                                            <code>frame_size*channels</code>\n  *                                            samples.\n  * @param frame_size <tt>int</tt>: Number of samples per channel in the input\n  *                                 signal.\n  *                                 This must be an Opus frame size for the\n  *                                 encoder's sampling rate.\n  *                                 For example, at 48 kHz the permitted values\n  *                                 are 120, 240, 480, 960, 1920, and 2880.\n  *                                 Passing in a duration of less than 10 ms\n  *                                 (480 samples at 48 kHz) will prevent the\n  *                                 encoder from using the LPC or hybrid modes.\n  * @param[out] data <tt>unsigned char*</tt>: Output payload.\n  *                                           This must contain storage for at\n  *                                           least \\a max_data_bytes.\n  * @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated\n  *                                                 memory for the output\n  *                                                 payload. This may be\n  *                                                 used to impose an upper limit on\n  *                                                 the instant bitrate, but should\n  *                                                 not be used as the only bitrate\n  *                                                 control. Use #OPUS_SET_BITRATE to\n  *                                                 control the bitrate.\n  * @returns The length of the encoded packet (in bytes) on success or a\n  *          negative error code (see @ref opus_errorcodes) on failure.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_encode(\n    OpusProjectionEncoder *st,\n    const opus_int16 *pcm,\n    int frame_size,\n    unsigned char *data,\n    opus_int32 max_data_bytes\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);\n\n\n/** Encodes a projection Opus frame from floating point input.\n  * @param st <tt>OpusProjectionEncoder*</tt>: Projection encoder state.\n  * @param[in] pcm <tt>const float*</tt>: The input signal as interleaved\n  *                                       samples with a normal range of\n  *                                       +/-1.0.\n  *                                       Samples with a range beyond +/-1.0\n  *                                       are supported but will be clipped by\n  *                                       decoders using the integer API and\n  *                                       should only be used if it is known\n  *                                       that the far end supports extended\n  *                                       dynamic range.\n  *                                       This must contain\n  *                                       <code>frame_size*channels</code>\n  *                                       samples.\n  * @param frame_size <tt>int</tt>: Number of samples per channel in the input\n  *                                 signal.\n  *                                 This must be an Opus frame size for the\n  *                                 encoder's sampling rate.\n  *                                 For example, at 48 kHz the permitted values\n  *                                 are 120, 240, 480, 960, 1920, and 2880.\n  *                                 Passing in a duration of less than 10 ms\n  *                                 (480 samples at 48 kHz) will prevent the\n  *                                 encoder from using the LPC or hybrid modes.\n  * @param[out] data <tt>unsigned char*</tt>: Output payload.\n  *                                           This must contain storage for at\n  *                                           least \\a max_data_bytes.\n  * @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated\n  *                                                 memory for the output\n  *                                                 payload. This may be\n  *                                                 used to impose an upper limit on\n  *                                                 the instant bitrate, but should\n  *                                                 not be used as the only bitrate\n  *                                                 control. Use #OPUS_SET_BITRATE to\n  *                                                 control the bitrate.\n  * @returns The length of the encoded packet (in bytes) on success or a\n  *          negative error code (see @ref opus_errorcodes) on failure.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_encode_float(\n    OpusProjectionEncoder *st,\n    const float *pcm,\n    int frame_size,\n    unsigned char *data,\n    opus_int32 max_data_bytes\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);\n\n\n/** Frees an <code>OpusProjectionEncoder</code> allocated by\n  * opus_projection_ambisonics_encoder_create().\n  * @param st <tt>OpusProjectionEncoder*</tt>: Projection encoder state to be freed.\n  */\nOPUS_EXPORT void opus_projection_encoder_destroy(OpusProjectionEncoder *st);\n\n\n/** Perform a CTL function on a projection Opus encoder.\n  *\n  * Generally the request and subsequent arguments are generated by a\n  * convenience macro.\n  * @param st <tt>OpusProjectionEncoder*</tt>: Projection encoder state.\n  * @param request This and all remaining parameters should be replaced by one\n  *                of the convenience macros in @ref opus_genericctls,\n  *                @ref opus_encoderctls, @ref opus_multistream_ctls, or\n  *                @ref opus_projection_ctls\n  * @see opus_genericctls\n  * @see opus_encoderctls\n  * @see opus_multistream_ctls\n  * @see opus_projection_ctls\n  */\nOPUS_EXPORT int opus_projection_encoder_ctl(OpusProjectionEncoder *st, int request, ...) OPUS_ARG_NONNULL(1);\n\n\n/**@}*/\n\n/**\\name Projection decoder functions */\n/**@{*/\n\n/** Gets the size of an <code>OpusProjectionDecoder</code> structure.\n  * @param channels <tt>int</tt>: The total number of output channels.\n  *                               This must be no more than 255.\n  * @param streams <tt>int</tt>: The total number of streams coded in the\n  *                              input.\n  *                              This must be no more than 255.\n  * @param coupled_streams <tt>int</tt>: Number streams to decode as coupled\n  *                                      (2 channel) streams.\n  *                                      This must be no larger than the total\n  *                                      number of streams.\n  *                                      Additionally, The total number of\n  *                                      coded channels (<code>streams +\n  *                                      coupled_streams</code>) must be no\n  *                                      more than 255.\n  * @returns The size in bytes on success, or a negative error code\n  *          (see @ref opus_errorcodes) on error.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_projection_decoder_get_size(\n    int channels,\n    int streams,\n    int coupled_streams\n);\n\n\n/** Allocates and initializes a projection decoder state.\n  * Call opus_projection_decoder_destroy() to release\n  * this object when finished.\n  * @param Fs <tt>opus_int32</tt>: Sampling rate to decode at (in Hz).\n  *                                This must be one of 8000, 12000, 16000,\n  *                                24000, or 48000.\n  * @param channels <tt>int</tt>: Number of channels to output.\n  *                               This must be at most 255.\n  *                               It may be different from the number of coded\n  *                               channels (<code>streams +\n  *                               coupled_streams</code>).\n  * @param streams <tt>int</tt>: The total number of streams coded in the\n  *                              input.\n  *                              This must be no more than 255.\n  * @param coupled_streams <tt>int</tt>: Number of streams to decode as coupled\n  *                                      (2 channel) streams.\n  *                                      This must be no larger than the total\n  *                                      number of streams.\n  *                                      Additionally, The total number of\n  *                                      coded channels (<code>streams +\n  *                                      coupled_streams</code>) must be no\n  *                                      more than 255.\n  * @param[in] demixing_matrix <tt>const unsigned char[demixing_matrix_size]</tt>: Demixing matrix\n  *                         that mapping from coded channels to output channels,\n  *                         as described in @ref opus_projection and\n  *                         @ref opus_projection_ctls.\n  * @param demixing_matrix_size <tt>opus_int32</tt>: The size in bytes of the\n  *                                                  demixing matrix, as\n  *                                                  described in @ref\n  *                                                  opus_projection_ctls.\n  * @param[out] error <tt>int *</tt>: Returns #OPUS_OK on success, or an error\n  *                                   code (see @ref opus_errorcodes) on\n  *                                   failure.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusProjectionDecoder *opus_projection_decoder_create(\n    opus_int32 Fs,\n    int channels,\n    int streams,\n    int coupled_streams,\n    unsigned char *demixing_matrix,\n    opus_int32 demixing_matrix_size,\n    int *error\n) OPUS_ARG_NONNULL(5);\n\n\n/** Intialize a previously allocated projection decoder state object.\n  * The memory pointed to by \\a st must be at least the size returned by\n  * opus_projection_decoder_get_size().\n  * This is intended for applications which use their own allocator instead of\n  * malloc.\n  * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.\n  * @see opus_projection_decoder_create\n  * @see opus_projection_deocder_get_size\n  * @param st <tt>OpusProjectionDecoder*</tt>: Projection encoder state to initialize.\n  * @param Fs <tt>opus_int32</tt>: Sampling rate to decode at (in Hz).\n  *                                This must be one of 8000, 12000, 16000,\n  *                                24000, or 48000.\n  * @param channels <tt>int</tt>: Number of channels to output.\n  *                               This must be at most 255.\n  *                               It may be different from the number of coded\n  *                               channels (<code>streams +\n  *                               coupled_streams</code>).\n  * @param streams <tt>int</tt>: The total number of streams coded in the\n  *                              input.\n  *                              This must be no more than 255.\n  * @param coupled_streams <tt>int</tt>: Number of streams to decode as coupled\n  *                                      (2 channel) streams.\n  *                                      This must be no larger than the total\n  *                                      number of streams.\n  *                                      Additionally, The total number of\n  *                                      coded channels (<code>streams +\n  *                                      coupled_streams</code>) must be no\n  *                                      more than 255.\n  * @param[in] demixing_matrix <tt>const unsigned char[demixing_matrix_size]</tt>: Demixing matrix\n  *                         that mapping from coded channels to output channels,\n  *                         as described in @ref opus_projection and\n  *                         @ref opus_projection_ctls.\n  * @param demixing_matrix_size <tt>opus_int32</tt>: The size in bytes of the\n  *                                                  demixing matrix, as\n  *                                                  described in @ref\n  *                                                  opus_projection_ctls.\n  * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes)\n  *          on failure.\n  */\nOPUS_EXPORT int opus_projection_decoder_init(\n    OpusProjectionDecoder *st,\n    opus_int32 Fs,\n    int channels,\n    int streams,\n    int coupled_streams,\n    unsigned char *demixing_matrix,\n    opus_int32 demixing_matrix_size\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6);\n\n\n/** Decode a projection Opus packet.\n  * @param st <tt>OpusProjectionDecoder*</tt>: Projection decoder state.\n  * @param[in] data <tt>const unsigned char*</tt>: Input payload.\n  *                                                Use a <code>NULL</code>\n  *                                                pointer to indicate packet\n  *                                                loss.\n  * @param len <tt>opus_int32</tt>: Number of bytes in payload.\n  * @param[out] pcm <tt>opus_int16*</tt>: Output signal, with interleaved\n  *                                       samples.\n  *                                       This must contain room for\n  *                                       <code>frame_size*channels</code>\n  *                                       samples.\n  * @param frame_size <tt>int</tt>: The number of samples per channel of\n  *                                 available space in \\a pcm.\n  *                                 If this is less than the maximum packet duration\n  *                                 (120 ms; 5760 for 48kHz), this function will not be capable\n  *                                 of decoding some packets. In the case of PLC (data==NULL)\n  *                                 or FEC (decode_fec=1), then frame_size needs to be exactly\n  *                                 the duration of audio that is missing, otherwise the\n  *                                 decoder will not be in the optimal state to decode the\n  *                                 next incoming packet. For the PLC and FEC cases, frame_size\n  *                                 <b>must</b> be a multiple of 2.5 ms.\n  * @param decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band\n  *                                 forward error correction data be decoded.\n  *                                 If no such data is available, the frame is\n  *                                 decoded as if it were lost.\n  * @returns Number of samples decoded on success or a negative error code\n  *          (see @ref opus_errorcodes) on failure.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_decode(\n    OpusProjectionDecoder *st,\n    const unsigned char *data,\n    opus_int32 len,\n    opus_int16 *pcm,\n    int frame_size,\n    int decode_fec\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);\n\n\n/** Decode a projection Opus packet with floating point output.\n  * @param st <tt>OpusProjectionDecoder*</tt>: Projection decoder state.\n  * @param[in] data <tt>const unsigned char*</tt>: Input payload.\n  *                                                Use a <code>NULL</code>\n  *                                                pointer to indicate packet\n  *                                                loss.\n  * @param len <tt>opus_int32</tt>: Number of bytes in payload.\n  * @param[out] pcm <tt>opus_int16*</tt>: Output signal, with interleaved\n  *                                       samples.\n  *                                       This must contain room for\n  *                                       <code>frame_size*channels</code>\n  *                                       samples.\n  * @param frame_size <tt>int</tt>: The number of samples per channel of\n  *                                 available space in \\a pcm.\n  *                                 If this is less than the maximum packet duration\n  *                                 (120 ms; 5760 for 48kHz), this function will not be capable\n  *                                 of decoding some packets. In the case of PLC (data==NULL)\n  *                                 or FEC (decode_fec=1), then frame_size needs to be exactly\n  *                                 the duration of audio that is missing, otherwise the\n  *                                 decoder will not be in the optimal state to decode the\n  *                                 next incoming packet. For the PLC and FEC cases, frame_size\n  *                                 <b>must</b> be a multiple of 2.5 ms.\n  * @param decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band\n  *                                 forward error correction data be decoded.\n  *                                 If no such data is available, the frame is\n  *                                 decoded as if it were lost.\n  * @returns Number of samples decoded on success or a negative error code\n  *          (see @ref opus_errorcodes) on failure.\n  */\nOPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_decode_float(\n    OpusProjectionDecoder *st,\n    const unsigned char *data,\n    opus_int32 len,\n    float *pcm,\n    int frame_size,\n    int decode_fec\n) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);\n\n\n/** Perform a CTL function on a projection Opus decoder.\n  *\n  * Generally the request and subsequent arguments are generated by a\n  * convenience macro.\n  * @param st <tt>OpusProjectionDecoder*</tt>: Projection decoder state.\n  * @param request This and all remaining parameters should be replaced by one\n  *                of the convenience macros in @ref opus_genericctls,\n  *                @ref opus_decoderctls, @ref opus_multistream_ctls, or\n  *                @ref opus_projection_ctls.\n  * @see opus_genericctls\n  * @see opus_decoderctls\n  * @see opus_multistream_ctls\n  * @see opus_projection_ctls\n  */\nOPUS_EXPORT int opus_projection_decoder_ctl(OpusProjectionDecoder *st, int request, ...) OPUS_ARG_NONNULL(1);\n\n\n/** Frees an <code>OpusProjectionDecoder</code> allocated by\n  * opus_projection_decoder_create().\n  * @param st <tt>OpusProjectionDecoder</tt>: Projection decoder state to be freed.\n  */\nOPUS_EXPORT void opus_projection_decoder_destroy(OpusProjectionDecoder *st);\n\n\n/**@}*/\n\n/**@}*/\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* OPUS_PROJECTION_H */\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/cpp/libopus/opus_types.h",
    "content": "/* (C) COPYRIGHT 1994-2002 Xiph.Org Foundation */\n/* Modified by Jean-Marc Valin */\n/*\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n\n   - Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n   - Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER\n   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n/* opus_types.h based on ogg_types.h from libogg */\n\n/**\n   @file opus_types.h\n   @brief Opus reference implementation types\n*/\n#ifndef OPUS_TYPES_H\n#define OPUS_TYPES_H\n\n#define opus_int         int                     /* used for counters etc; at least 16 bits */\n#define opus_int64       long long\n#define opus_int8        signed char\n\n#define opus_uint        unsigned int            /* used for counters etc; at least 16 bits */\n#define opus_uint64      unsigned long long\n#define opus_uint8       unsigned char\n\n/* Use the real stdint.h if it's there (taken from Paul Hsieh's pstdint.h) */\n#if (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) || defined (HAVE_STDINT_H))\n#include <stdint.h>\n#  undef opus_int64\n#  undef opus_int8\n#  undef opus_uint64\n#  undef opus_uint8\n   typedef int8_t opus_int8;\n   typedef uint8_t opus_uint8;\n   typedef int16_t opus_int16;\n   typedef uint16_t opus_uint16;\n   typedef int32_t opus_int32;\n   typedef uint32_t opus_uint32;\n   typedef int64_t opus_int64;\n   typedef uint64_t opus_uint64;\n#elif defined(_WIN32)\n\n#  if defined(__CYGWIN__)\n#    include <_G_config.h>\n     typedef _G_int32_t opus_int32;\n     typedef _G_uint32_t opus_uint32;\n     typedef _G_int16 opus_int16;\n     typedef _G_uint16 opus_uint16;\n#  elif defined(__MINGW32__)\n     typedef short opus_int16;\n     typedef unsigned short opus_uint16;\n     typedef int opus_int32;\n     typedef unsigned int opus_uint32;\n#  elif defined(__MWERKS__)\n     typedef int opus_int32;\n     typedef unsigned int opus_uint32;\n     typedef short opus_int16;\n     typedef unsigned short opus_uint16;\n#  else\n     /* MSVC/Borland */\n     typedef __int32 opus_int32;\n     typedef unsigned __int32 opus_uint32;\n     typedef __int16 opus_int16;\n     typedef unsigned __int16 opus_uint16;\n#  endif\n\n#elif defined(__MACOS__)\n\n#  include <sys/types.h>\n   typedef SInt16 opus_int16;\n   typedef UInt16 opus_uint16;\n   typedef SInt32 opus_int32;\n   typedef UInt32 opus_uint32;\n\n#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */\n\n#  include <sys/types.h>\n   typedef int16_t opus_int16;\n   typedef u_int16_t opus_uint16;\n   typedef int32_t opus_int32;\n   typedef u_int32_t opus_uint32;\n\n#elif defined(__BEOS__)\n\n   /* Be */\n#  include <inttypes.h>\n   typedef int16 opus_int16;\n   typedef u_int16 opus_uint16;\n   typedef int32_t opus_int32;\n   typedef u_int32_t opus_uint32;\n\n#elif defined (__EMX__)\n\n   /* OS/2 GCC */\n   typedef short opus_int16;\n   typedef unsigned short opus_uint16;\n   typedef int opus_int32;\n   typedef unsigned int opus_uint32;\n\n#elif defined (DJGPP)\n\n   /* DJGPP */\n   typedef short opus_int16;\n   typedef unsigned short opus_uint16;\n   typedef int opus_int32;\n   typedef unsigned int opus_uint32;\n\n#elif defined(R5900)\n\n   /* PS2 EE */\n   typedef int opus_int32;\n   typedef unsigned opus_uint32;\n   typedef short opus_int16;\n   typedef unsigned short opus_uint16;\n\n#elif defined(__SYMBIAN32__)\n\n   /* Symbian GCC */\n   typedef signed short opus_int16;\n   typedef unsigned short opus_uint16;\n   typedef signed int opus_int32;\n   typedef unsigned int opus_uint32;\n\n#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X)\n\n   typedef short opus_int16;\n   typedef unsigned short opus_uint16;\n   typedef long opus_int32;\n   typedef unsigned long opus_uint32;\n\n#elif defined(CONFIG_TI_C6X)\n\n   typedef short opus_int16;\n   typedef unsigned short opus_uint16;\n   typedef int opus_int32;\n   typedef unsigned int opus_uint32;\n\n#else\n\n   /* Give up, take a reasonable guess */\n   typedef short opus_int16;\n   typedef unsigned short opus_uint16;\n   typedef int opus_int32;\n   typedef unsigned int opus_uint32;\n\n#endif\n\n#endif  /* OPUS_TYPES_H */\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/cpp/ogg_opus_encoder.cc",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"ogg_opus_encoder.h\"\n\n#include <cassert>\n#include <endian.h>\n#include <memory>\n#include <string>\n#include <cstdint>\n#include \"opus_tools/opus_header.h\"\n\n// Ogg Opus information comes from the standard here:\n// https://tools.ietf.org/html/draft-ietf-codec-oggopus-14\n// This was also a useful reference:\n// https://github.com/krad-radio/butt-krad-opus/blob/302a4b6a6a596be6632f30cfb567a6a6d8fcb3f9/src/opus_encode.cpp\n\nnamespace audio_util {\nnamespace {\n\nstatic constexpr float kEncodingBufferSizeSeconds = 0.02f;\n\nstd::string SerializeUint32(uint32_t value) {\n  std::string result(4, '\\0');\n#if __BYTE_ORDER == __BIG_ENDIAN\n#error The following line assumes that the byte order is little endian.\n#endif\n  memcpy(&result[0], &value, sizeof(value));\n  return result;\n}\n\n}  // namespace\n\nOggOpusEncoder::OggOpusEncoder(int num_channels, int sample_rate_hz,\n                               int bitrate_bps, bool use_vbr,\n                               bool low_latency_mode)\n    : num_channels_(num_channels),\n      sample_rate_hz_(sample_rate_hz),\n      frame_size_(kEncodingBufferSizeSeconds * sample_rate_hz_),\n      encoder_(OpusUniquePtr(\n          opus_encoder_create(sample_rate_hz_, num_channels_,\n                              OPUS_APPLICATION_AUDIO, &error_code_),\n          opus_encoder_destroy)),\n      flushed_(false),\n      low_latency_mode_(low_latency_mode),\n      elements_in_pcm_frame_(0),\n      pcm_frame_(num_channels_ * frame_size_) {\n  assert(num_channels <= 2);  // Only mono and stereo are supported).\n  std::vector<int> valid_sample_rates = {8000, 12000, 16000, 24000, 48000};\n  assert(std::find(valid_sample_rates.begin(), valid_sample_rates.end(),\n                   sample_rate_hz) != valid_sample_rates.end());\n  assert(bitrate_bps >= 500);\n  assert(bitrate_bps <= 512000);\n\n  opus_encoder_ctl(encoder_.get(), OPUS_SET_BITRATE(bitrate_bps));\n  if (!use_vbr) {\n    opus_encoder_ctl(encoder_.get(), OPUS_SET_VBR(0));\n  }\n  constexpr int kComplexity = 4;\n  opus_encoder_ctl(encoder_.get(), OPUS_SET_COMPLEXITY(kComplexity));\n\n  // We will always pass exactly one frame at a time to the encoder.\n  opus_frame_.resize(kBytesPerSample * pcm_frame_.size());\n\n  // Start generating Ogg packets (though they don't get sent out until the\n  // first call to Encode()).\n  packet_count_ = 0;\n  granule_position_ = 0;\n  ogg_stream_init(&stream_, 0 /* serial number */);\n  GenerateOggPacketsForHeader();\n}\n\nOggOpusEncoder::~OggOpusEncoder() {\n  ogg_stream_clear(&stream_);\n}\n\n// Encodes 16-bit PCM data in OggOpus format.\nconst std::vector<unsigned char>& OggOpusEncoder::Process(\n    const std::vector<int16_t>& pcm) {\n  assert(!flushed_);\n  assert((pcm.size() % num_channels_) == 0);\n  if (!header_) {\n    ogg_bytes_.resize(0);\n  } else {\n    header_ = false;\n  }\n  int num_samples_processed = 0;\n\n  // Process the first block, handling any leftovers from a previous round.\n  if (elements_in_pcm_frame_ > 0) {\n    int entries_to_write =\n        std::min(pcm_frame_.size() - elements_in_pcm_frame_, pcm.size());\n    std::copy(pcm.begin(), pcm.begin() + entries_to_write,\n              pcm_frame_.begin() + elements_in_pcm_frame_);\n    elements_in_pcm_frame_ += entries_to_write;\n    if (elements_in_pcm_frame_ == pcm_frame_.size()) {\n      // pcm_frame_ is full, encode it.\n      int num_opus_frame_bytes =\n          opus_encode(encoder_.get(), pcm_frame_.data(), frame_size_,\n                      opus_frame_.data(), opus_frame_.size());\n\n      assert(num_opus_frame_bytes >= 0);\n      GenerateOggPacketsForOpusFrame(opus_frame_.data(), num_opus_frame_bytes,\n                                     &ogg_bytes_, false);\n      num_samples_processed += entries_to_write;\n      pcm_frame_.assign(pcm_frame_.size(), 0);\n      elements_in_pcm_frame_ = 0;\n    } else {\n      // There's nothing to encode. We've put all of pcm data into pcm_frame_\n      // for later processing.\n      ogg_bytes_.resize(0);\n      return ogg_bytes_;\n    }\n  }\n\n  // Process whole frames directly from pcm.\n  while (num_samples_processed + frame_size_ * num_channels_ <= pcm.size()) {\n    int num_opus_frame_bytes =\n        opus_encode(encoder_.get(), pcm.data() + num_samples_processed,\n                    frame_size_, opus_frame_.data(), opus_frame_.size());\n\n    assert(num_opus_frame_bytes >= 0);\n    GenerateOggPacketsForOpusFrame(opus_frame_.data(), num_opus_frame_bytes,\n                                   &ogg_bytes_, false);\n    num_samples_processed += frame_size_ * num_channels_;\n  }\n\n  if (low_latency_mode_) {\n    // Force the codec to produce samples for every input buffer.\n    AppendOggStateToBuffer(&ogg_bytes_, true);\n  }\n\n  // Place any remaining samples in pcm_frame_.\n  elements_in_pcm_frame_ = pcm.size() - num_samples_processed;\n  std::copy(pcm.begin() + num_samples_processed, pcm.end(), pcm_frame_.begin());\n  return ogg_bytes_;\n}\n\n// Returns any remaining samples from the codec.\nconst std::vector<unsigned char>& OggOpusEncoder::Flush() {\n  assert(!flushed_);\n  ogg_bytes_.resize(0);\n  int num_opus_frame_bytes =\n      opus_encode(encoder_.get(), pcm_frame_.data(), frame_size_,\n                  opus_frame_.data(), opus_frame_.size());\n  assert(num_opus_frame_bytes >= 0);\n  GenerateOggPacketsForOpusFrame(opus_frame_.data(), num_opus_frame_bytes,\n                                 &ogg_bytes_, true);\n  flushed_ = true;\n  return ogg_bytes_;\n}\n\nvoid OggOpusEncoder::GenerateOggPacketsForHeader() {\n  // Both header packets must have granule position of zero.\n  assert(granule_position_ == 0);\n  OpusHeader header;\n  header.version = 1;\n  header.channels = num_channels_;\n  opus_encoder_ctl(encoder_.get(), OPUS_GET_LOOKAHEAD(&header.preskip));\n  header.input_sample_rate = sample_rate_hz_;\n  header.gain = 0;\n  header.channel_mapping = 0;\n\n  // Write the ID header.\n  ogg_packet id_packet;\n  id_packet.b_o_s = 1;  // The first packet.\n  id_packet.e_o_s = 0;\n  id_packet.granulepos = granule_position_;\n  id_packet.packetno = packet_count_;\n  constexpr int kHeaderSizeUpperBound = 64;\n  id_packet.packet = new unsigned char[kHeaderSizeUpperBound];\n  // opus_header_to_packet fills id_packet.packet with header data and returns\n  // the number of bytes.\n  id_packet.bytes =\n      opus_header_to_packet(&header, id_packet.packet, kHeaderSizeUpperBound);\n  // Add the ID packet into the stream.\n  packet_count_++;\n  ogg_stream_packetin(&stream_, &id_packet);\n\n  // Write the comment header.\n  ogg_packet comment_packet;\n  comment_packet.b_o_s = 0;\n  comment_packet.e_o_s = 0;\n  comment_packet.granulepos = granule_position_;\n  comment_packet.packetno = packet_count_;\n  const std::string kVendor = \"Google using libopus\";\n  std::string packet = \"\";\n  packet.append(\"OpusTags\");\n  packet.append(SerializeUint32(kVendor.size()));\n  packet.append(kVendor);\n  packet.append(SerializeUint32(0));\n  comment_packet.packet = const_cast<unsigned char*>(\n      reinterpret_cast<const unsigned char*>(packet.c_str()));\n  comment_packet.bytes = packet.length();\n\n  // Add the comment header into the stream.\n  packet_count_++;\n  ogg_stream_packetin(&stream_, &comment_packet);\n  // Force a page break after the comment header.\n  // According to\n  // https://tools.ietf.org/html/draft-ietf-codec-oggopus-14#section-3 there is\n  // a mandatory page break after the comment header.\n  AppendOggStateToBuffer(&ogg_bytes_, true);\n  header_ = true;\n\n  delete[] id_packet.packet;\n}\n\nvoid OggOpusEncoder::GenerateOggPacketsForOpusFrame(\n    unsigned char* opus_frame_bytes, int opus_bytes_length,\n    std::vector<unsigned char>* ogg_bytes, bool flush) {\n  // Flush data from the ogg object into the outgoing stream.\n  AppendOggStateToBuffer(ogg_bytes, flush);\n\n  // Write the most recent buffer of Opus data into an Ogg packet.\n  ogg_packet frame_packet;\n  frame_packet.b_o_s = 0;\n  frame_packet.e_o_s = flush ? 1 : 0;\n  // According to\n  // https://tools.ietf.org/html/draft-ietf-codec-oggopus-14#section-4 the\n  // granule position should include all samples up to the last packet completed\n  // on the page, so we need to update granule_position_ before assigning it to\n  // the packet.  If we're closing the stream, we don't assume that the last\n  // packet includes a full frame.\n  if (flush) {\n    granule_position_ += (elements_in_pcm_frame_ / num_channels_);\n  } else {\n    granule_position_ += frame_size_;\n  }\n  frame_packet.granulepos = granule_position_;\n  frame_packet.packetno = packet_count_;\n  frame_packet.packet = opus_frame_bytes;\n  frame_packet.bytes = opus_bytes_length;\n  // Add the data packet into the stream.\n  packet_count_++;\n  ogg_stream_packetin(&stream_, &frame_packet);\n\n  // Try flushing again after data packet.\n  AppendOggStateToBuffer(ogg_bytes, flush);\n}\n\nvoid OggOpusEncoder::AppendOggStateToBuffer(std::vector<unsigned char>* buffer,\n                                            bool flush_ogg_stream) {\n  int (*write_fun)(ogg_stream_state*, ogg_page*) =\n      flush_ogg_stream ? &ogg_stream_flush : &ogg_stream_pageout;\n  while (write_fun(&stream_, &page_) != 0) {\n    const int initial_size = buffer->size();\n    buffer->resize(buffer->size() + page_.header_len + page_.body_len);\n    memcpy(buffer->data() + initial_size, page_.header, page_.header_len);\n    memcpy(buffer->data() + initial_size + page_.header_len, page_.body,\n           page_.body_len);\n  }\n}\n\n}  // namespace audio_util\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/cpp/ogg_opus_encoder.h",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef AUDIO_UTIL_OGG_OPUS_ENCODER_H_\n#define AUDIO_UTIL_OGG_OPUS_ENCODER_H_\n\n#include <cstdint>\n#include <memory>\n#include <string>\n#include <vector>\n#include \"libogg/ogg.h\"\n#include \"libopus/opus.h\"\n\nnamespace audio_util {\n\n// This class is meant to be a dependency-light streaming encoder.\n//\n// Encoding is done internally on a block size of 20ms, which seems to be the\n// recommended size for Opus encoding.\nclass OggOpusEncoder {\n public:\n  // Input is int16 data.\n  constexpr static int kBytesPerSample = 2;\n  constexpr static int kBitsPerSample = 16;\n\n  // num_channels must be 1 or 2.\n  // sample rate must be one of {8000, 12000, 16000, 24000, 48000}\n  // Note that low_latency_mode will increase the total number of Ogg packets,\n  // but will reduce overall latency of the codec. This does not impact the\n  // quality of audio compression, only how the data is packaged in the Ogg\n  // container. Low latency mode is only recommended for realtime streaming\n  // applications. See test for actual bitrate increases.\n  OggOpusEncoder(int num_channels, int sample_rate_hz, int bitrate_bps,\n                 bool use_vbr, bool low_latency_mode);\n\n  ~OggOpusEncoder();\n\n  // Encodes 16-bit PCM data in OggOpus format. There is no restriction on the\n  // size of the input vector.\n  // Note that it is very common for the returned vector to be empty. Keep\n  // calling this function with new samples until they become available.\n  const std::vector<unsigned char>& Process(const std::vector<int16_t>& pcm);\n\n  // Returns any remaining samples from the codec. This should be called last,\n  // and never more than once.\n  const std::vector<unsigned char>& Flush();\n\n private:\n  using OpusUniquePtr =\n      std::unique_ptr<OpusEncoder, decltype(&opus_encoder_destroy)>;\n\n  std::string GetOpusErrorMessage() const;\n\n  // Push the Opus header details into the ogg stream.\n  void GenerateOggPacketsForHeader();\n\n  // Push data from a single Opus frame into an Ogg stream.\n  void GenerateOggPacketsForOpusFrame(unsigned char* opus_frame_bytes,\n                                     int opus_bytes_length,\n                                     std::vector<unsigned char>* ogg_bytes,\n                                     bool flush);\n\n  // Moves data from the stream_ object into buffer.\n  void AppendOggStateToBuffer(std::vector<unsigned char>* buffer, bool flush);\n\n  int num_channels_;\n  int sample_rate_hz_;\n  int bitrate_bps_;\n\n  // Number of samples in an Opus 20ms frame for a single channel.\n  int frame_size_;\n  OpusUniquePtr encoder_;\n\n  // Stores the status of Opus codec initialization.\n  int error_code_;\n\n  // Checks that Flush() isn't called multiple times.\n  bool flushed_;\n  bool header_;\n\n  // When true, flushing of the Ogg stream after every call to Process().\n  bool low_latency_mode_;\n\n  // A preallocated buffer to store the temporary OGG result.\n  std::vector<unsigned char> opus_frame_;\n\n  std::vector<unsigned char> ogg_bytes_;\n\n  // A stored buffer for a single frame of PCM data to be processed.\n  int elements_in_pcm_frame_;\n  std::vector<opus_int16> pcm_frame_;\n\n  // Ogg objects.\n  ogg_stream_state stream_;\n  ogg_page page_;\n  int packet_count_;      // Count of packets pushed to the stream.\n  int granule_position_;  // Position in the ogg stream.\n};\n\n}  // namespace audio_util\n\n#endif  // AUDIO_UTIL_OGG_OPUS_ENCODER_H_\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/cpp/opus_tools/opus_header.h",
    "content": "/* Copyright (C)2012 Xiph.Org Foundation\n   File: opus_header.h\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n\n   - Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n   - Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR\n   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifndef OPUS_HEADER_H\n#define OPUS_HEADER_H\n\n#include \"../libogg/ogg.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct {\n   int version;\n   int channels; /* Number of channels: 1..255 */\n   int preskip;\n   ogg_uint32_t input_sample_rate;\n   int gain; /* in dB S7.8 should be zero whenever possible */\n   int channel_mapping;\n   /* The rest is only used if channel_mapping != 0 */\n   int nb_streams;\n   int nb_coupled;\n   unsigned char stream_map[255];\n} OpusHeader;\n\nint opus_header_parse(const unsigned char *header, int len, OpusHeader *h);\nint opus_header_to_packet(const OpusHeader *h, unsigned char *packet, int len);\n\nextern const int wav_permute_matrix[8][8];\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/SmartGlassesAndroidService.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager;\n\nimport android.app.Notification;\nimport android.app.NotificationChannel;\nimport android.app.NotificationManager;\nimport android.app.PendingIntent;\nimport android.app.Service;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.graphics.Bitmap;\nimport android.os.Binder;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.IBinder;\nimport android.util.Log;\nimport android.widget.Toast;\n\nimport androidx.core.app.NotificationCompat;\nimport androidx.lifecycle.LifecycleService;\nimport androidx.preference.PreferenceManager;\n\nimport com.teamopensmartglasses.smartglassesmanager.eventbusmessages.PostGenericGlobalMessageEvent;\nimport com.teamopensmartglasses.augmentoslib.events.SmartGlassesConnectedEvent;\nimport com.teamopensmartglasses.smartglassesmanager.smartglassescommunicators.SmartGlassesFontSize;\nimport com.teamopensmartglasses.smartglassesmanager.comms.MessageTypes;\nimport com.teamopensmartglasses.augmentoslib.events.BulletPointListViewRequestEvent;\nimport com.teamopensmartglasses.augmentoslib.events.CenteredTextViewRequestEvent;\nimport com.teamopensmartglasses.augmentoslib.events.DoubleTextWallViewRequestEvent;\nimport com.teamopensmartglasses.augmentoslib.events.FinalScrollingTextRequestEvent;\nimport com.teamopensmartglasses.augmentoslib.events.HomeScreenEvent;\nimport com.teamopensmartglasses.augmentoslib.events.ReferenceCardImageViewRequestEvent;\nimport com.teamopensmartglasses.augmentoslib.events.ReferenceCardSimpleViewRequestEvent;\nimport com.teamopensmartglasses.augmentoslib.events.RowsCardViewRequestEvent;\nimport com.teamopensmartglasses.augmentoslib.events.SendBitmapViewRequestEvent;\nimport com.teamopensmartglasses.smartglassesmanager.eventbusmessages.SetFontSizeEvent;\nimport com.teamopensmartglasses.augmentoslib.events.TextWallViewRequestEvent;\nimport com.teamopensmartglasses.augmentoslib.events.ScrollingTextViewStartRequestEvent;\nimport com.teamopensmartglasses.augmentoslib.events.ScrollingTextViewStopRequestEvent;\nimport com.teamopensmartglasses.smartglassesmanager.eventbusmessages.SmartGlassesConnectionEvent;\nimport com.teamopensmartglasses.augmentoslib.events.TextLineViewRequestEvent;\nimport com.teamopensmartglasses.smartglassesmanager.eventbusmessages.TextToSpeechEvent;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.ASR_FRAMEWORKS;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.SpeechRecSwitchSystem;\nimport com.teamopensmartglasses.smartglassesmanager.supportedglasses.AudioWearable;\nimport com.teamopensmartglasses.smartglassesmanager.supportedglasses.InmoAirOne;\nimport com.teamopensmartglasses.smartglassesmanager.supportedglasses.SmartGlassesDevice;\nimport com.teamopensmartglasses.smartglassesmanager.supportedglasses.SmartGlassesOperatingSystem;\nimport com.teamopensmartglasses.smartglassesmanager.supportedglasses.TCLRayNeoXTwo;\nimport com.teamopensmartglasses.smartglassesmanager.supportedglasses.VuzixShield;\nimport com.teamopensmartglasses.smartglassesmanager.supportedglasses.VuzixUltralite;\nimport com.teamopensmartglasses.smartglassesmanager.texttospeech.TextToSpeechSystem;\n\nimport org.greenrobot.eventbus.EventBus;\nimport org.greenrobot.eventbus.EventBusException;\nimport org.greenrobot.eventbus.Subscribe;\nimport org.json.JSONObject;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\n\nimport io.reactivex.rxjava3.subjects.PublishSubject;\n\n/** Main service of Smart Glasses Manager, that starts connections to smart glasses and talks to third party apps (3PAs) */\npublic abstract class SmartGlassesAndroidService extends LifecycleService {\n    private static final String TAG = \"SGM_ASP_Service\";\n\n    // Service Binder given to clients\n    private final IBinder binder = new LocalBinder();\n    public static final String ACTION_START_FOREGROUND_SERVICE = \"MY_ACTION_START_FOREGROUND_SERVICE\";\n    public static final String ACTION_STOP_FOREGROUND_SERVICE = \"MY_ACTION_STOP_FOREGROUND_SERVICE\";\n    private int myNotificationId;\n    private Class mainActivityClass;\n    private String myChannelId;\n    private String notificationAppName;\n    private String notificationDescription;\n    private int notificationDrawable;\n\n    //Text to Speech\n    private TextToSpeechSystem textToSpeechSystem;\n\n    //observables to send data around app\n    PublishSubject<JSONObject> dataObservable;\n\n    //representatives of the other pieces of the system\n    SmartGlassesRepresentative smartGlassesRepresentative;\n\n    //speech rec\n    SpeechRecSwitchSystem speechRecSwitchSystem;\n\n    //connection handler\n    public Handler connectHandler;\n\n    public SmartGlassesAndroidService(Class mainActivityClass, String myChannelId, int myNotificationId, String notificationAppName, String notificationDescription, int notificationDrawable){\n        this.myNotificationId = myNotificationId;\n        this.mainActivityClass = mainActivityClass;\n        this.myChannelId = myChannelId;\n        this.notificationAppName = notificationAppName;\n        this.notificationDescription = notificationDescription;\n        this.notificationDrawable = notificationDrawable;\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n\n        //setup connection handler\n        connectHandler = new Handler();\n\n        //start speech rec\n        speechRecSwitchSystem = new SpeechRecSwitchSystem(this.getApplicationContext());\n        ASR_FRAMEWORKS asrFramework = getChosenAsrFramework(this.getApplicationContext());\n        String transcribeLanguage = getChosenTranscribeLanguage(this.getApplicationContext());\n        String targetLanguage = getChosenTargetLanguage(this.getApplicationContext());\n        String sourceLanguage = getChosenSourceLanguage(this.getApplicationContext());\n        int selectedLiveCaptionsTranslation = getSelectedLiveCaptionsTranslation(this.getApplicationContext());\n        if (selectedLiveCaptionsTranslation != 2) speechRecSwitchSystem.startAsrFramework(asrFramework, transcribeLanguage);\n        else {\n            if (transcribeLanguage.equals(sourceLanguage)) speechRecSwitchSystem.startAsrFramework(asrFramework, transcribeLanguage, targetLanguage); // If transcribe language and source language are the same translate to the target language\n            else speechRecSwitchSystem.startAsrFramework(asrFramework, transcribeLanguage, sourceLanguage);\n        }\n//        speechRecSwitchSystem.startAsrFramework(asrFramework, \"Chinese (Hanzi)\", \"English\");\n\n        //setup data observable which passes information (transcripts, commands, etc. around our app using mutlicasting\n        dataObservable = PublishSubject.create();\n\n        //start text to speech\n        textToSpeechSystem = new TextToSpeechSystem(this);\n        textToSpeechSystem.setup();\n    }\n\n    protected void setupEventBusSubscribers() {\n        try {\n            EventBus.getDefault().register(this);\n        }\n        catch(EventBusException e){\n            e.printStackTrace();\n        }\n    }\n\n    @Subscribe\n    public void handleConnectionEvent(SmartGlassesConnectionEvent event) {\n        sendUiUpdate();\n    }\n\n    protected abstract void onGlassesConnected(SmartGlassesDevice device);\n\n    public void connectToSmartGlasses(SmartGlassesDevice device) {\n        //this represents the smart glasses - it handles the connection, sending data to them, etc\n        LifecycleService currContext = this;\n        connectHandler.post(new Runnable() {\n            @Override\n            public void run() {\n                 Log.d(TAG, \"CONNECTING TO SMART GLASSES\");\n                smartGlassesRepresentative = new SmartGlassesRepresentative(currContext, device, currContext, dataObservable);\n                smartGlassesRepresentative.connectToSmartGlasses();\n            }\n        });\n    }\n\n    @Override\n    public void onDestroy() {\n        Log.d(TAG, \"WearableAiAspService killing itself and all its children\");\n\n        EventBus.getDefault().unregister(this);\n\n        //kill speech rec\n        if (speechRecSwitchSystem != null){\n            speechRecSwitchSystem.destroy();\n        }\n\n        //kill asg connection\n        if (smartGlassesRepresentative != null) {\n            smartGlassesRepresentative.destroy();\n            smartGlassesRepresentative = null;\n        }\n\n        //kill data transmitters\n        if (dataObservable != null) {\n            dataObservable.onComplete();\n        }\n\n        //kill textToSpeech\n        textToSpeechSystem.destroy();\n\n        //kill aioConnect\n        aioRetryHandler.removeCallbacks(aioRetryConnectionTask);\n\n        //call parent destroy\n        super.onDestroy();\n        Log.d(TAG, \"WearableAiAspService destroy complete\");\n    }\n\n    public void sendTestCard(String title, String body, String img) {\n        Log.d(TAG, \"SENDING TEST CARD FROM WAIService\");\n        EventBus.getDefault().post(new ReferenceCardSimpleViewRequestEvent(title, body));\n    }\n\n    public int getSmartGlassesConnectState() {\n        if (smartGlassesRepresentative != null) {\n            return smartGlassesRepresentative.getConnectionState();\n        } else {\n            return 0;\n        }\n    }\n\n    public SmartGlassesDevice getConnectedSmartGlasses() {\n        if (smartGlassesRepresentative == null) return null;\n        if(smartGlassesRepresentative.getConnectionState() != 2) return null;\n        return smartGlassesRepresentative.smartGlassesDevice;\n    }\n\n    public SmartGlassesOperatingSystem getConnectedDeviceModelOs(){\n        if (smartGlassesRepresentative == null) return null;\n        if(smartGlassesRepresentative.getConnectionState() != 2) return null;\n        return smartGlassesRepresentative.smartGlassesDevice.glassesOs;\n    }\n\n    public void sendUiUpdate() {\n        //connectionState = 2 means connected\n        Intent intent = new Intent();\n        intent.setAction(MessageTypes.GLASSES_STATUS_UPDATE);\n        // Set the optional additional information in extra field.\n        int connectionState;\n        if (smartGlassesRepresentative != null) {\n            connectionState = smartGlassesRepresentative.getConnectionState();\n            intent.putExtra(MessageTypes.CONNECTION_GLASSES_GLASSES_OBJECT, smartGlassesRepresentative.smartGlassesDevice);\n\n            // Update preferred wearable if connected\n            if(connectionState == 2){\n                savePreferredWearable(this, smartGlassesRepresentative.smartGlassesDevice.deviceModelName);\n                onGlassesConnected(smartGlassesRepresentative.smartGlassesDevice);\n                EventBus.getDefault().post(new SmartGlassesConnectedEvent(smartGlassesRepresentative.smartGlassesDevice));\n            }\n        } else {\n            connectionState = 0;\n        }\n        intent.putExtra(MessageTypes.CONNECTION_GLASSES_STATUS_UPDATE, connectionState);\n        sendBroadcast(intent);\n    }\n\n    /** Saves the chosen ASR framework in user shared preference. */\n    public static void saveChosenAsrFramework(Context context, ASR_FRAMEWORKS asrFramework) {\n        PreferenceManager.getDefaultSharedPreferences(context)\n                .edit()\n                .putString(context.getResources().getString(R.string.SHARED_PREF_ASR_KEY), asrFramework.name())\n                .apply();\n    }\n\n    /** Gets the chosen ASR framework from shared preference. */\n    public static ASR_FRAMEWORKS getChosenAsrFramework(Context context) {\n        String asrString = PreferenceManager.getDefaultSharedPreferences(context).getString(context.getResources().getString(R.string.SHARED_PREF_ASR_KEY), \"\");\n        if (asrString.equals(\"\")){\n            saveChosenAsrFramework(context, ASR_FRAMEWORKS.AZURE_ASR_FRAMEWORK);\n            asrString = ASR_FRAMEWORKS.AZURE_ASR_FRAMEWORK.name();\n        }\n        return ASR_FRAMEWORKS.valueOf(asrString);\n    }\n\n    public void changeChosenAsrFramework(ASR_FRAMEWORKS asrFramework){\n        saveChosenAsrFramework(getApplicationContext(), asrFramework);\n        if (speechRecSwitchSystem != null) {\n            speechRecSwitchSystem.startAsrFramework(asrFramework);\n        }\n    }\n\n    /** Gets the API key from shared preference. */\n    public static String getApiKey(Context context) {\n        return PreferenceManager.getDefaultSharedPreferences(context).getString(context.getResources().getString(R.string.SHARED_PREF_KEY), \"\");\n    }\n\n    /** Saves the API Key in user shared preference. */\n    public static void saveApiKey(Context context, String key) {\n        PreferenceManager.getDefaultSharedPreferences(context)\n                .edit()\n                .putString(context.getResources().getString(R.string.SHARED_PREF_KEY), key)\n                .apply();\n    }\n\n    /** Gets the preferred wearable from shared preference. */\n    public static String getPreferredWearable(Context context) {\n        return PreferenceManager.getDefaultSharedPreferences(context).getString(context.getResources().getString(R.string.PREFERRED_WEARABLE), \"\");\n    }\n\n    /** Saves the preferred wearable in user shared preference. */\n    public static void savePreferredWearable(Context context, String wearableName) {\n        PreferenceManager.getDefaultSharedPreferences(context)\n                .edit()\n                .putString(context.getResources().getString(R.string.PREFERRED_WEARABLE), wearableName)\n                .apply();\n    }\n\n    public static void saveChosenTranscribeLanguage(Context context, String transcribeLanguageString) {\n        PreferenceManager.getDefaultSharedPreferences(context)\n                .edit()\n                .putString(context.getResources().getString(R.string.SHARED_PREF_TRANSCRIBE_LANGUAGE), transcribeLanguageString)\n                .apply();\n    }\n\n    public static String getChosenTranscribeLanguage(Context context) {\n        String transcribeLanguageString = PreferenceManager.getDefaultSharedPreferences(context).getString(context.getResources().getString(R.string.SHARED_PREF_TRANSCRIBE_LANGUAGE), \"\");\n        if (transcribeLanguageString.equals(\"\")){\n            saveChosenTranscribeLanguage(context, \"English\");\n            transcribeLanguageString = \"English\";\n        }\n        return transcribeLanguageString;\n    }\n\n    public static void saveChosenTargetLanguage(Context context, String targetLanguageString) {\n        PreferenceManager.getDefaultSharedPreferences(context)\n                .edit()\n                .putString(context.getResources().getString(R.string.SHARED_PREF_TARGET_LANGUAGE), targetLanguageString)\n                .apply();\n    }\n\n    public static String getChosenTargetLanguage(Context context) {\n        String targetLanguageString = PreferenceManager.getDefaultSharedPreferences(context).getString(context.getResources().getString(R.string.SHARED_PREF_TARGET_LANGUAGE), \"\");\n        if (targetLanguageString.equals(\"\")){\n            saveChosenTargetLanguage(context, \"English\");\n            targetLanguageString = \"English\";\n        }\n        return targetLanguageString;\n    }\n\n    public static void saveChosenSourceLanguage(Context context, String sourceLanguageString) {\n        PreferenceManager.getDefaultSharedPreferences(context)\n                .edit()\n                .putString(context.getResources().getString(R.string.SHARED_PREF_SOURCE_LANGUAGE), sourceLanguageString)\n                .apply();\n    }\n\n    public static String getChosenSourceLanguage(Context context) {\n        String sourceLanguageString = PreferenceManager.getDefaultSharedPreferences(context).getString(context.getResources().getString(R.string.SHARED_PREF_SOURCE_LANGUAGE), \"\");\n        if (sourceLanguageString.equals(\"\")){\n            saveChosenSourceLanguage(context, \"English\");\n            sourceLanguageString = \"English\";\n        }\n        return sourceLanguageString;\n    }\n\n    public static void saveSelectedLiveCaptionsTranslationChecked(Context context, int liveCaptionsTranslationSelected) {\n        PreferenceManager.getDefaultSharedPreferences(context)\n                .edit()\n                .putInt(context.getResources().getString(R.string.SHARED_PREF_LIVE_CAPTIONS_TRANSLATION), liveCaptionsTranslationSelected)\n                .apply();\n    }\n\n    public static int getSelectedLiveCaptionsTranslation(Context context) {\n        return PreferenceManager.getDefaultSharedPreferences(context).getInt(context.getResources().getString(R.string.SHARED_PREF_LIVE_CAPTIONS_TRANSLATION), 0);\n    }\n\n    //switches the currently running transcribe language without changing the default/saved language\n    public void switchRunningTranscribeLanguage(String language){\n        if (speechRecSwitchSystem.currentLanguage.equals(language)){\n            return;\n        }\n\n        //kill previous speech rec\n        speechRecSwitchSystem.destroy();\n        speechRecSwitchSystem = null;\n\n        //start speech rec after small delay\n        Handler speechRecHandler = new Handler();\n        Context context = this;\n        speechRecHandler.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                speechRecSwitchSystem = new SpeechRecSwitchSystem(context);\n                ASR_FRAMEWORKS asrFramework = getChosenAsrFramework(context);\n                speechRecSwitchSystem.startAsrFramework(asrFramework, language);\n            }\n        }, 250);\n    }\n\n    //service stuff\n    private Notification updateNotification() {\n        Context context = getApplicationContext();\n\n        PendingIntent action = PendingIntent.getActivity(context,\n                0, new Intent(context, mainActivityClass),\n                PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE); // Flag indicating that if the described PendingIntent already exists, the current one should be canceled before generating a new one.\n\n        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);\n        NotificationCompat.Builder builder;\n\n        String CHANNEL_ID = myChannelId;\n\n        NotificationChannel channel = new NotificationChannel(CHANNEL_ID, notificationAppName,\n                NotificationManager.IMPORTANCE_HIGH);\n        channel.setDescription(notificationDescription);\n        manager.createNotificationChannel(channel);\n\n        builder = new NotificationCompat.Builder(this, CHANNEL_ID);\n\n        return builder.setContentIntent(action)\n                .setContentTitle(notificationAppName)\n                .setContentText(notificationDescription)\n                .setSmallIcon(notificationDrawable)\n                .setTicker(\"...\")\n                .setContentIntent(action)\n                .setOngoing(true).build();\n    }\n\n    public class LocalBinder extends Binder {\n        public SmartGlassesAndroidService getService() {\n            // Return this instance of LocalService so clients can call public methods\n            return SmartGlassesAndroidService.this;\n        }\n    }\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        super.onBind(intent);\n        return binder;\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        super.onStartCommand(intent, flags, startId);\n        if (intent != null) {\n            String action = intent.getAction();\n            Bundle extras = intent.getExtras();\n\n            switch (action) {\n                case ACTION_START_FOREGROUND_SERVICE:\n                    // start the service in the foreground\n                    Log.d(\"TEST\", \"starting foreground\");\n                    startForeground(myNotificationId, updateNotification());\n                    break;\n                case ACTION_STOP_FOREGROUND_SERVICE:\n                    stopForeground(true);\n                    stopSelf();\n                    break;\n            }\n        }\n        return Service.START_STICKY;\n    }\n\n\n    // Setup for aioConnectSmartGlasses\n    ArrayList<SmartGlassesDevice> smartGlassesDevices = new ArrayList<>();\n    Handler aioRetryHandler = new Handler();\n    Runnable aioRetryConnectionTask = new Runnable() {\n        @Override\n        public void run() {\n            if (smartGlassesRepresentative == null || smartGlassesRepresentative.getConnectionState() != 2) { // If still disconnected\n                if(!smartGlassesDevices.isEmpty()){\n                    Toast.makeText(getApplicationContext(), \"Searching for glasses...\", Toast.LENGTH_LONG).show();\n                    // EventBus.getDefault().post(new PostGenericGlobalMessageEvent(\"Searching for glasses...\"));\n                    Log.d(TAG, \"TRYING TO CONNECT TO: \" + smartGlassesDevices.get(0).deviceModelName);\n\n                    if (smartGlassesRepresentative != null) {\n                        smartGlassesRepresentative.destroy();\n                        smartGlassesRepresentative = null;\n                    }\n\n                    connectToSmartGlasses(smartGlassesDevices.get(0));\n                    smartGlassesDevices.add(smartGlassesDevices.remove(0));\n                    aioRetryHandler.postDelayed(this, 5000); // Schedule another retry if needed\n                }\n                else\n                {\n                    aioRetryHandler.removeCallbacks(this);\n                    Toast.makeText(getApplicationContext(), \"No glasses found\", Toast.LENGTH_LONG).show();\n                    // EventBus.getDefault().post(new PostGenericGlobalMessageEvent(\"No glasses found\"));\n                }\n            }\n            else {\n                Toast.makeText(getApplicationContext(), \"Connected to \" + smartGlassesRepresentative.smartGlassesDevice.deviceModelName, Toast.LENGTH_LONG).show();\n                // EventBus.getDefault().post(new PostGenericGlobalMessageEvent(\"Connected to \" + smartGlassesRepresentative.smartGlassesDevice.deviceModelName));\n            }\n        }\n    };\n    public void aioConnectSmartGlasses(){\n        if (getChosenAsrFramework(this) == ASR_FRAMEWORKS.GOOGLE_ASR_FRAMEWORK) {\n            String apiKey = getApiKey(getApplicationContext());\n            if (apiKey == null || apiKey.equals(\"\")) {\n                showNoGoogleAsrDialog();\n                return;\n            }\n        }\n\n        String preferred = getPreferredWearable(this.getApplicationContext());\n        smartGlassesDevices = new ArrayList<SmartGlassesDevice>(Arrays.asList(new VuzixUltralite(), new VuzixShield(),  new InmoAirOne(), new TCLRayNeoXTwo()));\n        for (int i = 0; i < smartGlassesDevices.size(); i++){\n            if (smartGlassesDevices.get(i).deviceModelName.equals(preferred)){\n                // Move to start for earliest search priority\n                smartGlassesDevices.add(0, smartGlassesDevices.remove(i));\n                break;\n            }\n        }\n\n        // Check for Audio Wearable\n        if (preferred.equals(new AudioWearable().deviceModelName))\n            smartGlassesDevices.add(0, new AudioWearable());\n\n        //start loop\n        aioRetryConnectionTask.run();\n    }\n\n    public void showNoGoogleAsrDialog(){\n        new android.app.AlertDialog.Builder(getApplicationContext()).setIcon(android.R.drawable.ic_dialog_alert)\n                .setTitle(\"No Google API Key Provided\")\n                .setMessage(\"You have Google ASR enabled without an API key. Please turn off Google ASR or enter a valid API key.\")\n                .setPositiveButton(\"Ok\", new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                    }\n                }).show();\n    }\n\n    //show a reference card on the smart glasses with title and body text\n    public static void sendReferenceCard(String title, String body) {\n        EventBus.getDefault().post(new ReferenceCardSimpleViewRequestEvent(title, body));\n    }\n\n    //show a text wall card on the smart glasses\n    public static void sendTextWall(String text) {\n        EventBus.getDefault().post(new TextWallViewRequestEvent(text));\n    }\n\n    //show a double text wall card on the smart glasses\n    public static void sendDoubleTextWall(String textTop, String textBottom) {\n        EventBus.getDefault().post(new DoubleTextWallViewRequestEvent(textTop, textBottom));\n    }\n\n    //show a reference card on the smart glasses with title and body text\n    public static void sendRowsCard(String[] rowStrings) {\n        EventBus.getDefault().post(new RowsCardViewRequestEvent(rowStrings));\n    }\n\n    //show a bullet point list card on the smart glasses with title and bullet points\n    public void sendBulletPointList(String title, String [] bullets) {\n        EventBus.getDefault().post(new BulletPointListViewRequestEvent(title, bullets));\n    }\n\n    //show a list of up to 4 rows of text. Only put a few characters per line!\n    public void sendBulletPointList(String[] rowStrings) {\n        EventBus.getDefault().post(new RowsCardViewRequestEvent(rowStrings));\n    }\n\n    public void sendReferenceCard(String title, String body, String imgUrl) {\n        EventBus.getDefault().post(new ReferenceCardImageViewRequestEvent(title, body, imgUrl));\n    }\n\n    public void sendBitmap(Bitmap bitmap) {\n        EventBus.getDefault().post(new SendBitmapViewRequestEvent(bitmap));\n    }\n\n    public void startScrollingText(String title){\n        EventBus.getDefault().post(new ScrollingTextViewStartRequestEvent(title));\n    }\n\n    public void pushScrollingText(String text){\n        EventBus.getDefault().post(new FinalScrollingTextRequestEvent(text));\n    }\n\n    public void stopScrollingText(){\n        EventBus.getDefault().post(new ScrollingTextViewStopRequestEvent());\n    }\n\n    public void sendTextLine(String text) {\n        EventBus.getDefault().post(new TextLineViewRequestEvent(text));\n    }\n\n    public void sendTextToSpeech(String text, String languageString) {\n        EventBus.getDefault().post(new TextToSpeechEvent(text, languageString));\n    }\n\n    public void sendCenteredText(String text){\n        EventBus.getDefault().post(new CenteredTextViewRequestEvent(text));\n    }\n\n    public void sendCustomContent(String json){\n        EventBus.getDefault().post(new CenteredTextViewRequestEvent(json));\n    }\n\n    public void sendHomeScreen(){\n        EventBus.getDefault().post(new HomeScreenEvent());\n    }\n\n    public void setFontSize(SmartGlassesFontSize fontSize) { EventBus.getDefault().post(new SetFontSizeEvent(fontSize)); }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/SmartGlassesRepresentative.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager;\n\nimport android.content.Context;\n\nimport org.greenrobot.eventbus.EventBus;\nimport org.greenrobot.eventbus.Subscribe;\nimport org.json.JSONObject;\n\nimport android.os.Handler;\nimport android.util.Log;\n\n//custom, our code\nimport androidx.lifecycle.LifecycleOwner;\n\nimport com.teamopensmartglasses.augmentoslib.events.AudioChunkNewEvent;\nimport com.teamopensmartglasses.smartglassesmanager.eventbusmessages.DisableBleScoAudioEvent;\nimport com.teamopensmartglasses.augmentoslib.events.DisplayCustomContentRequestEvent;\nimport com.teamopensmartglasses.augmentoslib.events.DoubleTextWallViewRequestEvent;\nimport com.teamopensmartglasses.augmentoslib.events.HomeScreenEvent;\nimport com.teamopensmartglasses.augmentoslib.events.SendBitmapViewRequestEvent;\nimport com.teamopensmartglasses.smartglassesmanager.eventbusmessages.SetFontSizeEvent;\nimport com.teamopensmartglasses.augmentoslib.events.TextWallViewRequestEvent;\nimport com.teamopensmartglasses.smartglassesmanager.smartglassescommunicators.AudioWearableSGC;\nimport com.teamopensmartglasses.smartglassesmanager.smartglassescommunicators.UltraliteSGC;\nimport com.teamopensmartglasses.augmentoslib.events.BulletPointListViewRequestEvent;\nimport com.teamopensmartglasses.augmentoslib.events.CenteredTextViewRequestEvent;\nimport com.teamopensmartglasses.augmentoslib.events.FinalScrollingTextRequestEvent;\nimport com.teamopensmartglasses.augmentoslib.events.IntermediateScrollingTextRequestEvent;\nimport com.teamopensmartglasses.augmentoslib.events.ReferenceCardImageViewRequestEvent;\nimport com.teamopensmartglasses.augmentoslib.events.ReferenceCardSimpleViewRequestEvent;\nimport com.teamopensmartglasses.augmentoslib.events.RowsCardViewRequestEvent;\nimport com.teamopensmartglasses.augmentoslib.events.PromptViewRequestEvent;\nimport com.teamopensmartglasses.augmentoslib.events.ScrollingTextViewStartRequestEvent;\nimport com.teamopensmartglasses.augmentoslib.events.ScrollingTextViewStopRequestEvent;\nimport com.teamopensmartglasses.smartglassesmanager.hci.AudioChunkCallback;\nimport com.teamopensmartglasses.smartglassesmanager.hci.MicrophoneLocalAndBluetooth;\n//import com.teamopensmartglasses.smartglassesmanager.smartglassescommunicators.ActiveLookSGC;\nimport com.teamopensmartglasses.smartglassesmanager.smartglassescommunicators.AndroidSGC;\nimport com.teamopensmartglasses.smartglassesmanager.smartglassescommunicators.SmartGlassesCommunicator;\nimport com.teamopensmartglasses.smartglassesmanager.supportedglasses.SmartGlassesDevice;\nimport com.teamopensmartglasses.augmentoslib.events.TextLineViewRequestEvent;\n\n//rxjava\nimport java.nio.ByteBuffer;\n\nimport io.reactivex.rxjava3.subjects.PublishSubject;\n\nclass SmartGlassesRepresentative {\n    private static final String TAG = \"WearableAi_ASGRepresentative\";\n\n    //receive/send data stream\n    PublishSubject<JSONObject> dataObservable;\n\n    Context context;\n\n    public SmartGlassesDevice smartGlassesDevice;\n    SmartGlassesCommunicator smartGlassesCommunicator;\n    MicrophoneLocalAndBluetooth bluetoothAudio;\n\n    //timing settings\n    long referenceCardDelayTime = 10000;\n\n    LifecycleOwner lifecycleOwner;\n\n    //handler to handle delayed UI events\n    Handler uiHandler;\n    Handler micHandler;\n\n    SmartGlassesRepresentative(Context context, SmartGlassesDevice smartGlassesDevice, LifecycleOwner lifecycleOwner, PublishSubject<JSONObject> dataObservable){\n        this.context = context;\n        this.smartGlassesDevice = smartGlassesDevice;\n        this.lifecycleOwner = lifecycleOwner;\n\n        //receive/send data\n        this.dataObservable = dataObservable;\n\n        uiHandler = new Handler();\n        micHandler = new Handler();\n\n        //register event bus subscribers\n        EventBus.getDefault().register(this);\n    }\n\n    public void connectToSmartGlasses(){\n        switch (smartGlassesDevice.getGlassesOs()){\n            case ANDROID_OS_GLASSES:\n                smartGlassesCommunicator = new AndroidSGC(context, dataObservable);\n                break;\n//            case ACTIVELOOK_OS_GLASSES:\n//                smartGlassesCommunicator = new ActiveLookSGC(context);\n//                break;\n            case AUDIO_WEARABLE_GLASSES:\n                smartGlassesCommunicator = new AudioWearableSGC(context);\n                break;\n            case ULTRALITE_MCU_OS_GLASSES:\n                smartGlassesCommunicator = new UltraliteSGC(context, lifecycleOwner);\n                break;\n            case EVENREALITIES_G1_MCU_OS_GLASSES:\n                // smartGlassesCommunicator = new EvenRealitiesG1SGC(context, lifecycleOwner);\n                break;\n        }\n\n        smartGlassesCommunicator.connectToSmartGlasses();\n\n        //if the glasses don't support a microphone, this Representative handles local microphone\n        if (smartGlassesDevice.useScoMic) {\n            connectAndStreamLocalMicrophone(true);\n        } else if (!smartGlassesDevice.getHasInMic() && !smartGlassesDevice.getHasOutMic()) {\n            connectAndStreamLocalMicrophone(false);\n        }\n    }\n\n\n    @Subscribe\n    public void onDisableBleScoEvent(DisableBleScoAudioEvent receivedEvent) {\n        Log.d(TAG, \"onDisableBleScoEvent called\");\n        restartAudioWithNoBleSco();\n    }\n\n    public void restartAudioWithNoBleSco(){\n        //kill current audio\n        if (bluetoothAudio != null) {\n            bluetoothAudio.destroy();\n        }\n\n        //start new audio, with no bluetooth\n        connectAndStreamLocalMicrophone(false);\n    }\n\n    private void connectAndStreamLocalMicrophone(boolean useBluetoothSco){\n        //follow this order for speed\n        //start audio from bluetooth headset\n        uiHandler.post(new Runnable() {\n            @Override\n            public void run() {\n                bluetoothAudio = new MicrophoneLocalAndBluetooth(context, useBluetoothSco, new AudioChunkCallback(){\n                    @Override\n                    public void onSuccess(ByteBuffer chunk){\n                        receiveChunk(chunk);\n                    }\n                });\n            }\n        });\n    }\n\n    private void receiveChunk(ByteBuffer chunk){\n        byte[] audio_bytes = chunk.array();\n        //throw off new audio chunk event\n        EventBus.getDefault().post(new AudioChunkNewEvent(audio_bytes));\n    }\n\n    public void destroy(){\n        Log.d(TAG, \"SG rep destroying\");\n\n        EventBus.getDefault().unregister(this);\n\n        if (bluetoothAudio != null) {\n            bluetoothAudio.destroy();\n        }\n\n        if (smartGlassesCommunicator != null){\n            smartGlassesCommunicator.destroy();\n            smartGlassesCommunicator = null;\n        }\n\n        Log.d(TAG, \"SG rep destroy complete\");\n    }\n\n    //are our smart glasses currently connected?\n    public int getConnectionState(){\n        if (smartGlassesCommunicator == null){\n            return 0;\n        } else {\n            return smartGlassesCommunicator.getConnectionState();\n        }\n    }\n\n    public void showReferenceCard(String title, String body){\n        if (smartGlassesCommunicator != null) {\n            smartGlassesCommunicator.displayReferenceCardSimple(title, body);\n        }\n    }\n\n    public void showRowsCard(String[] rowStrings){\n        if (smartGlassesCommunicator != null) {\n            smartGlassesCommunicator.displayRowsCard(rowStrings);\n        }\n    }\n\n    public void startScrollingTextViewModeTest(){\n        //pass for now\n        if (smartGlassesCommunicator != null) {\n            smartGlassesCommunicator.startScrollingTextViewMode(\"ScrollingTextView\");\n            smartGlassesCommunicator.scrollingTextViewFinalText(\"test line 1\");\n            smartGlassesCommunicator.scrollingTextViewFinalText(\"line 2 testy boi\");\n            smartGlassesCommunicator.scrollingTextViewFinalText(\"how's this?\");\n            smartGlassesCommunicator.scrollingTextViewFinalText(\"this is a line of text that is going to be long enough to wrap around, it would be good to see if it doesn so, that would be super cool\");\n            smartGlassesCommunicator.scrollingTextViewFinalText(\"test line n\");\n            smartGlassesCommunicator.scrollingTextViewFinalText(\"line n + 1 testy boi\");\n            smartGlassesCommunicator.scrollingTextViewFinalText(\"seconnndd how's this?\");\n        }\n    }\n\n    private void homeUiAfterDelay(long delayTime){\n        uiHandler.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                homeScreen();\n            }\n        }, delayTime);\n    }\n\n    public void homeScreen(){\n        if (smartGlassesCommunicator != null) {\n            smartGlassesCommunicator.showHomeScreen();\n        }\n    }\n\n    @Subscribe\n    public void onHomeScreenEvent(HomeScreenEvent receivedEvent){\n        homeScreen();\n    }\n\n    @Subscribe\n    public void onTextWallViewEvent(TextWallViewRequestEvent receivedEvent){\n        if (smartGlassesCommunicator != null) {\n            smartGlassesCommunicator.displayTextWall(receivedEvent.text);\n        }\n    }\n\n    @Subscribe\n    public void onDoubleTextWallViewEvent(DoubleTextWallViewRequestEvent receivedEvent){\n        if (smartGlassesCommunicator != null) {\n            smartGlassesCommunicator.displayDoubleTextWall(receivedEvent.textTop, receivedEvent.textBottom);\n        }\n    }\n\n    @Subscribe\n    public void onReferenceCardSimpleViewEvent(ReferenceCardSimpleViewRequestEvent receivedEvent){\n        if (smartGlassesCommunicator != null) {\n            smartGlassesCommunicator.displayReferenceCardSimple(receivedEvent.title, receivedEvent.body);\n//            homeUiAfterDelay(referenceCardDelayTime);\n        }\n    }\n\n\n    @Subscribe\n    public void onRowsCardViewEvent(RowsCardViewRequestEvent receivedEvent){\n        if (smartGlassesCommunicator != null) {\n            smartGlassesCommunicator.displayRowsCard(receivedEvent.rowStrings);\n//            homeUiAfterDelay(referenceCardDelayTime);\n        }\n    }\n\n    @Subscribe\n    public void onBulletPointListViewEvent(BulletPointListViewRequestEvent receivedEvent){\n        if (smartGlassesCommunicator != null) {\n            smartGlassesCommunicator.displayBulletList(receivedEvent.title, receivedEvent.bullets);\n//            homeUiAfterDelay(referenceCardDelayTime);\n        }\n    }\n\n    @Subscribe\n    public void onReferenceCardImageViewEvent(ReferenceCardImageViewRequestEvent receivedEvent){\n        Log.d(TAG, \"sending reference card image view event\");\n        if (smartGlassesCommunicator != null) {\n            smartGlassesCommunicator.displayReferenceCardImage(receivedEvent.title, receivedEvent.body, receivedEvent.imgUrl);\n//            homeUiAfterDelay(referenceCardDelayTime);\n        }\n    }\n\n    @Subscribe\n    public void onSendBitmapViewRequestEvent(SendBitmapViewRequestEvent receievedEvent){\n        Log.d(TAG, \"Sending a bitmap event\");\n        if (smartGlassesCommunicator != null) {\n            smartGlassesCommunicator.displayBitmap(receievedEvent.bmp);\n        }\n    }\n\n    @Subscribe\n    public void onDisplayCustomContentRequestEvent(DisplayCustomContentRequestEvent receivedEvent){\n        Log.d(TAG, \"Got display custom content event: \" + receivedEvent.json);\n        if (smartGlassesCommunicator != null) {\n            smartGlassesCommunicator.displayCustomContent(receivedEvent.json);\n        }\n    }\n\n    @Subscribe\n    public void onTextLineViewRequestEvent(TextLineViewRequestEvent receivedEvent){\n        Log.d(TAG, \"Got text line event: \" + receivedEvent.text);\n        if (smartGlassesCommunicator != null) {\n            smartGlassesCommunicator.displayTextLine(receivedEvent.text);\n        }\n    }\n\n    @Subscribe\n    public void onDisplayCenteredTextRequestEvent(CenteredTextViewRequestEvent receivedEvent){\n        if(smartGlassesCommunicator != null){\n            smartGlassesCommunicator.displayCenteredText(receivedEvent.text);\n        }\n    }\n\n    @Subscribe\n    public void onStartScrollingTextViewEvent(ScrollingTextViewStartRequestEvent receivedEvent){\n        if (smartGlassesCommunicator != null) {\n            smartGlassesCommunicator.startScrollingTextViewMode(receivedEvent.title);\n        }\n    }\n\n    @Subscribe\n    public void onStopScrollingTextViewEvent(ScrollingTextViewStopRequestEvent receivedEvent){\n        if (smartGlassesCommunicator != null) {\n            smartGlassesCommunicator.stopScrollingTextViewMode();\n        }\n    }\n\n    @Subscribe\n    public void onFinalScrollingTextEvent(FinalScrollingTextRequestEvent receivedEvent) {\n        Log.d(TAG, \"onFinalScrollingTextEvent\");\n        if (smartGlassesCommunicator != null) {\n            smartGlassesCommunicator.scrollingTextViewFinalText(receivedEvent.text);\n        }\n    }\n\n    @Subscribe\n    public void onIntermediateScrollingTextEvent(IntermediateScrollingTextRequestEvent receivedEvent) {\n        if (smartGlassesCommunicator != null) {\n            smartGlassesCommunicator.scrollingTextViewIntermediateText(receivedEvent.text);\n        }\n    }\n\n    @Subscribe\n    public void onPromptViewRequestEvent(PromptViewRequestEvent receivedEvent) {\n        Log.d(TAG, \"onPromptViewRequestEvent called\");\n        if (smartGlassesCommunicator != null) {\n            smartGlassesCommunicator.displayPromptView(receivedEvent.prompt, receivedEvent.options);\n        }\n    }\n\n    @Subscribe\n    public void onSetFontSizeEvent(SetFontSizeEvent receivedEvent) {\n        if (smartGlassesCommunicator != null) {\n            smartGlassesCommunicator.setFontSize(receivedEvent.fontSize);\n        }\n    }\n\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/comms/AspWebsocketServer.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.comms;\n\nimport java.net.InetSocketAddress;\n\nimport org.java_websocket.WebSocket;\nimport org.java_websocket.exceptions.WebsocketNotConnectedException;\nimport org.java_websocket.handshake.ClientHandshake;\nimport org.java_websocket.server.WebSocketServer;\nimport java.util.Map;\nimport java.util.UUID;\nimport java.nio.ByteBuffer;\nimport java.util.concurrent.ConcurrentHashMap;\nimport android.util.Log;\nimport org.json.JSONObject;\nimport org.json.JSONException;\n\nimport io.reactivex.rxjava3.disposables.Disposable;\nimport io.reactivex.rxjava3.subjects.PublishSubject;\n\npublic class AspWebsocketServer extends WebSocketServer {\n    //data observable we can send data through\n    private static PublishSubject<JSONObject> dataObservable;\n    private static Disposable dataSub;\n\n    private static int connected = 0;\n\n    private final String TAG = \"WearableAI_AspWebsocketServer\";\n\n    private Map<String, WebSocket> clients = new ConcurrentHashMap<>();\n    private WebSocket asgConn;\n\n    public AspWebsocketServer(int port)\n    {\n        super(new InetSocketAddress(port));\n        setReuseAddr(true);\n    }\n\n    public AspWebsocketServer(InetSocketAddress address)\n    {\n        super(address);\n    }\n\n    @Override\n    public void onOpen(WebSocket conn, ClientHandshake handshake) {\n        connected = 2;\n        String uniqueID = UUID.randomUUID().toString();\n        Log.d(TAG, \"Got new connection at address: \" + conn.getRemoteSocketAddress());\n        clients.put(uniqueID, conn);\n        asgConn = conn;\n    }\n\n    @Override\n    public void onClose(WebSocket conn, int code, String reason, boolean remote) {\n        Log.d(TAG, \"onClose called\");\n        Log.d(TAG, \"WebSocketServer currently has this many conns: \" + clients.size());\n        for (WebSocket connToCheck : clients.values()){ // there was a race condition where the ASG would recconnect before the socket was marked as closed, so the ASP thought their was no connection (connected = 1), but there actually was a connection, so now we check to see if any of the sockets in the clients hashmap is still open\n            Log.d(TAG, \"Checking conn with remoteSocketAddress: \" + connToCheck.getRemoteSocketAddress());\n            if (connToCheck.isOpen()){ //exit, because we have a live connection to the ASG\n                Log.d(TAG, \"onClose found open connection, so not setting connected=1\");\n                return;\n            }\n        }\n        Log.d(TAG, \"onClose set connected=1\");\n        clients.clear();\n        connected = 1;\n    }\n\n    @Override\n    public void onMessage(WebSocket conn, String message) {\n        try {\n//            Log.d(TAG, message);\n            JSONObject json_obj = new JSONObject(message);\n            dataObservable.onNext(json_obj);\n        } catch (JSONException e){\n            //if we send a string, this will get thrown, all messages should be JSON or byte []\n//            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public void onMessage(WebSocket conn, ByteBuffer message) {\n        Log.d(TAG, \"GOT MESSAGE BYTES\");\n    }\n\n    @Override\n    public void onError(WebSocket conn, Exception ex)\n    {\n        ex.printStackTrace();\n        if (conn != null) {\n            // some errors like port binding failed may not be assignable to a specific websocket\n        }\n    }\n\n    @Override\n    public void onStart()\n    {\n        //LogHelper.e(TAG, \"Server started!\");\n        connected = 1;\n        setConnectionLostTimeout(2);\n        startConnectionLostTimer();\n    }\n\n    public void sendJson(JSONObject data){\n        if (connected == 2){\n            try {\n                asgConn.send(data.toString());\n            } catch (WebsocketNotConnectedException e){\n                e.printStackTrace();\n                Log.d(TAG, \"Not connected, close should be running now.\");\n            }\n        } else {\n            Log.d(TAG, \"CANNOT SEND JSON, NOT CONNECTED\");\n        }\n\n    }\n\n    //receive observable to send and receive data\n    public void setObservable(PublishSubject<JSONObject> observable){\n        Log.d(TAG, \"called setObservable\");\n        dataObservable = observable;\n        dataSub = dataObservable.subscribe(i -> handleDataStream(i));\n    }\n\n    //this receives data from the data observable. For now, this class decides what to send and what not to send to the ASG\n    private void handleDataStream(JSONObject data){\n        //first check if it's a type we should handle\n        try{\n            String type = data.getString(MessageTypes.MESSAGE_TYPE_LOCAL);\n//            if (type.equals(MessageTypes.INTERMEDIATE_TRANSCRIPT)){\n////                Log.d(TAG, \"AspWebsocketServer got INTERMEDIATE_TRANSCRIPT, sending to ASG\");\n//                //data.put(MessageTypes.MESSAGE_TYPE_LOCAL, data.getString(MessageTypes.MESSAGE_TYPE_ASG)); //change the type to the type for ASG\n//                //data.remove(MessageTypes.MESSAGE_TYPE_ASG);\n//                sendJson(data);\n//            } else if (type.equals(MessageTypes.FINAL_TRANSCRIPT)){\n////                Log.d(TAG, \"AspWebsocketServer got FINAL_TRANSCRIPT, sending to ASG\");\n//                sendJson(data);\n            if (type.equals(MessageTypes.VOICE_COMMAND_RESPONSE)){\n//                Log.d(TAG, \"AspWebsocketServer got VOICE_COMMAND_RESPONSE, sending to ASG\");\n                sendJson(data);\n            } else if (type.equals(MessageTypes.REFERENCE_CARD_SIMPLE_VIEW)){\n//                Log.d(TAG, \"AspWebsocketServer got REFERENCE_CARD_SIMPLE_VIEW, sending to ASG\");\n                sendJson(data);\n            } else if (type.equals(MessageTypes.REFERENCE_CARD_TEXT_WALL_VIEW)){\n//                Log.d(TAG, \"AspWebsocketServer got REFERENCE_CARD_SIMPLE_VIEW, sending to ASG\");\n                sendJson(data);\n            } else if (type.equals(MessageTypes.REFERENCE_CARD_IMAGE_VIEW)){\n                sendJson(data);\n            } else if (type.equals(MessageTypes.ACTION_SWITCH_MODES)){\n//                Log.d(TAG, \"AspWebsocketServer got ACTION_SWITCH_MODES, sending to ASG\");\n                sendJson(data);\n            } else if (type.equals(MessageTypes.SCROLLING_TEXT_VIEW_START)){\n//                Log.d(TAG, \"AspWebsocketServer sending STV start\");\n                sendJson(data);\n            } else if (type.equals(MessageTypes.SCROLLING_TEXT_VIEW_STOP)){\n//                Log.d(TAG, \"AspWebsocketServer sending STV start\");\n                sendJson(data);\n            } else if (type.equals(MessageTypes.SCROLLING_TEXT_VIEW_FINAL)){\n//                Log.d(TAG, \"AspWebsocketServer sending STV final\");\n                sendJson(data);\n            } else if (type.equals(MessageTypes.SCROLLING_TEXT_VIEW_INTERMEDIATE)){\n//                Log.d(TAG, \"AspWebsocketServer sending STV intermediate\");\n                sendJson(data);\n            } else if (type.equals(MessageTypes.VOICE_COMMAND_STREAM_EVENT)) {\n//                Log.d(TAG, \"AspWebsocketServer got VOICE_COMMAND_STREAM_EVENT, sending to ASG\");\n                sendJson(data);\n            }\n    } catch (JSONException e){\n            e.printStackTrace();\n        }\n    }\n\n\n    //need to call this so if we get \"Force Stop\"ped, we will clean up sockets so we can connect on restart\n    public void destroy(){\n        Log.d(TAG, \"destroying\");\n        connected = 0;\n        dataSub.dispose();\n        dataSub = null;\n\n        try{\n            stop(400);\n        } catch (InterruptedException e){\n            e.printStackTrace();\n        }\n        Log.d(TAG, \"destroy complete\");\n    }\n\n\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/comms/AudioSystem.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.comms;\n\nimport android.media.AudioFormat;\n\nimport android.util.Base64;\n\nimport io.reactivex.rxjava3.disposables.Disposable;\nimport io.reactivex.rxjava3.subjects.PublishSubject;\n\nimport java.io.IOException;\n\nimport org.greenrobot.eventbus.EventBus;\nimport org.json.JSONObject;\nimport org.json.JSONException;\n\nimport android.content.Context;\n\nimport java.util.Random;\nimport java.nio.ByteOrder;\n\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingQueue;\nimport java.io.DataOutputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.nio.ByteBuffer;\nimport java.io.DataInputStream;\nimport java.net.ServerSocket;\nimport java.net.Socket;\n\nimport com.teamopensmartglasses.augmentoslib.events.AudioChunkNewEvent;\nimport com.teamopensmartglasses.smartglassesmanager.utils.AES;\n\nimport android.util.Log;\n\nimport com.teamopensmartglasses.smartglassesmanager.R;\n\npublic class AudioSystem {\n    private static String TAG = \"WearableAi_AudioSystem\";\n\n    private boolean shouldDie;\n\n    private String secretKey;\n\n    // the audio recording options - same on ASG\n    private static final int RECORDING_RATE = 16000;\n    private static final int CHANNEL = AudioFormat.CHANNEL_IN_MONO;\n    private static final int FORMAT = AudioFormat.ENCODING_PCM_16BIT;\n\n    //Thread to receive audio from ASG\n    //socket info\n    static int PORT = 4449;\n    private static int mConnectState = 0;\n    final byte [] ack_id = {0x13, 0x37};\n    final byte [] heart_beat_id = {0x19, 0x20};\n    final byte [] img_id = {0x01, 0x10}; //id for images\n\n    //handle heart beat stuff\n    private static long lastHeartbeatTime;\n    private static int heartbeatInterval = 3000; //milliseconds\n    private static int heartbeatPanicX = 3; // number of intervals before we reset connection\n    static Thread HeartbeatThread = null;\n    private  int outbound_heart_beats = 0;\n\n    //socket data\n    static Thread SocketThread = null;\n    static Thread ReceiveThread = null;\n    static Thread SendThread = null;\n    //i/o\n    private  DataOutputStream output;\n    private  DataInputStream input;\n\n    //our actual socket connection object\n    ServerSocket serverSocket;\n    private static Socket socket;\n\n    //send audio to to other services in the app\n    PublishSubject<JSONObject> dataObservable;\n    Disposable dataSubscriber;\n\n    Context context;\n\n    public AudioSystem(Context context, PublishSubject<JSONObject> dataObservable){\n        this.context = context;\n\n        //set the key for encryption\n        secretKey = context.getResources().getString(R.string.key);\n\n        this.dataObservable = dataObservable;\n        dataSubscriber = dataObservable.subscribe(i -> handleDataStream(i));\n    }\n\n\n    //send_queue of data to send through the socket\n    private  BlockingQueue<byte []> send_queue;\n\n    public void startAudio(){\n        //make a new queue to hold data to send\n        send_queue = new ArrayBlockingQueue<byte[]>(50);\n\n        //start the socket thread which will send the raw audio data\n        startSocket();\n    }\n\n    public void startSocket(){\n        //start first socketThread\n        if (socket == null) {\n            mConnectState = 1;\n            SocketThread = new Thread(new SocketThread());\n            SocketThread.start();\n\n            //setup handler to handle keeping connection alive, all subsequent start of SocketThread\n            //start a new handler thread to send heartbeats\n            HandlerThread thread = new HandlerThread(\"HeartBeater\");\n            thread.start();\n            Handler heart_beat_handler = new Handler(thread.getLooper());\n            final int hb_delay = 3000;\n            final int min_hb_delay = 1000;\n            final int max_hb_delay = 2000;\n            Random rand = new Random();\n            heart_beat_handler.postDelayed(new Runnable() {\n                public void run() {\n                    heartBeat();\n                    //random hb_delay for heart beat so as to disallow synchronized failure between client and server\n                    int random_hb_delay = rand.nextInt((max_hb_delay - min_hb_delay) + 1) + min_hb_delay;\n                    heart_beat_handler.postDelayed(this, random_hb_delay);\n                }\n            }, hb_delay);\n        }\n    }\n\n\n        //heart beat checker - check if we have received a heart rate\n//    private void heartBeat(){\n//        //check if we are still connected.\n//        //if not , reconnect,\n//        //we don't need to actively send heart beats from the client, as it's assumed that we are ALWAYS streaming data. Later, if we have periods of time where no data is sent, we will want to send a heart beat perhaps. but the client doesn't really need to, we just need to check if we are still connected\n//        if (mConnectState == 0) {\n//            restartSocket();\n//        }\n//\n//        //or, if haven't been receiving heart beats, restart socket\n//        if (mConnectState == 2) {\n//            if ((System.currentTimeMillis() - lastHeartbeatTime) > (heartbeatInterval * heartbeatPanicX)) {\n//                Log.d(TAG, \"DIDN'T RECEIVE HEART BEATS, RESTARTING SOCKET\");\n//                mConnectState = 0;\n//                restartSocket();\n//            }\n//        }\n//    }\n//\n    private void heartBeat(){\n        //check if we are still connected.\n        //if not , reconnect,\n        //if we are connected, send a heart beat to make sure we are still connected\n        if ((mConnectState == 0) && (shouldDie == false)) {\n            restartSocket();\n        } else if (mConnectState == 2){\n            //make sure we don't have a ton of outbound heart beats unresponded to\n            //reimplement this later -- ASG needs to receive heart beats\n//            if (outbound_heart_beats > 5) {\n//                restartSocket();\n//                return;\n//            }\n//\n//            //increment counter\n//            outbound_heart_beats++;\n//\n//            //send heart beat\n//            sendBytes(heart_beat_id, null);\n        }\n    }\n\n\n\n//    public static void restartSocket() {\n//        Log.d(TAG, \"Restarting socket\");\n//        mConnectState = 1;\n//        if (socket != null && (!socket.isClosed())){\n//            try {\n//                output.close();\n//                input.close();\n//                socket.close();\n//            } catch (IOException e) {\n//                System.out.println(\"FAILED TO CLOSE SOCKET, SOMETHING IS WRONG\");\n//            }\n//        }\n//\n//\n//        //restart socket thread\n//        Log.d(TAG, \"starting socket\");\n//        SocketThread = new Thread(new SocketThread());\n//        SocketThread.start();\n//    }\n//\n    private void restartSocket(){\n        Log.d(TAG, \"Running restart socket\");\n        mConnectState = 1;\n\n        outbound_heart_beats = 0;\n\n        //close the previous socket now that it's broken/being restarted\n        killSocket();\n\n        //make sure socket thread has joined before throwing off a new one\n        try {\n            Log.d(TAG, \"Waiting socket thread join\");\n            SocketThread.join();\n            Log.d(TAG, \"Socket thread joined\");\n        } catch (InterruptedException e){\n            e.printStackTrace();\n        }\n\n        //start a new socket thread\n        SocketThread = new Thread(new SocketThread());\n        SocketThread.start();\n    }\n\n    private void killSocket(){\n        try {\n            if (serverSocket != null && (!serverSocket.isClosed())) {\n                Log.d(TAG, \"Closing socket, input, serverSocket, etc.\");\n                serverSocket.close();\n            }\n            if (socket != null){\n                socket.close();\n            }\n            if (output != null){\n                output.close();\n            }\n            if (input != null){\n                input.close();\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n\n\n//    static class SocketThread implements Runnable {\n//        public void run() {\n//            try {\n//                serverSocket = new ServerSocket(PORT);\n//                try {\n//                    socket = serverSocket.accept();\n//    //                System.out.println(\"TRYING TO CONNECT AUDIO STREAM ASG\");\n//    //                socket = new Socket(SERVER_IP, SERVER_PORT);\n//                    lastHeartbeatTime = System.currentTimeMillis();\n//                    System.out.println(\"GLBOX CONNECTED!\");\n//                    //output = new DataOutputStream(socket.getOutputStream());\n//                    //input = new BufferedReader(new InputStreamReader(socket.getInputStream()));\n//                    input = new DataInputStream(new DataInputStream(socket.getInputStream()));\n//                    mConnectState = 2;\n//                    //make the threads that will send and receive\n//                    if (ReceiveThread == null) { //if the thread is null, make a new one (the first one)\n//                        ReceiveThread = new Thread(new ReceiveThread());\n//                        ReceiveThread.start();\n//                    } else if (!ReceiveThread.isAlive()) { //if the thread is not null but it's dead, let it join then start a new one\n//                        Log.d(TAG, \"IN SocketThread, WAITING FOR receive THREAD JOING\");\n//                        try {\n//                            ReceiveThread.join(); //make sure socket thread has joined before throwing off a new one\n//                        } catch (InterruptedException e) {\n//                            e.printStackTrace();\n//                        }\n//                        Log.d(TAG, \"receive JOINED\");\n//                        ReceiveThread = new Thread(new ReceiveThread());\n//                        ReceiveThread.start();\n//                    }\n//                } catch(IOException e){\n//                    e.printStackTrace();\n//                    mConnectState = 0;\n//                }\n//            } catch (IOException e) {\n//                Log.d(TAG, \"Connection Refused on socket\");\n//                e.printStackTrace();\n//                mConnectState = 0;\n//            }\n//        }\n//    }\n//\n    class SocketThread implements Runnable {\n        @Override\n        public void run() {\n            try {\n                Log.d(TAG, \"Starting new socket, waiting for connection...\");\n                serverSocket = new ServerSocket(PORT);\n                try {\n                    socket = serverSocket.accept();\n                    socket.setSoTimeout(3000);\n                    Log.d(TAG, \"Got socket connection.\");\n                    //output = new PrintWriter(socket.getOutputStream(), true);\n                    output = new DataOutputStream(socket.getOutputStream());\n                    input = new DataInputStream(new DataInputStream(socket.getInputStream()));\n                    mConnectState = 2;\n                    if (ReceiveThread == null) { //if the thread is null, make a new one (the first one)\n                        ReceiveThread = new Thread(new ReceiveThread());\n                        ReceiveThread.start();\n                    } else if (!ReceiveThread.isAlive()) { //if the thread is not null but it's dead, let it join then start a new one\n                        try {\n                            ReceiveThread.join(); //make sure socket thread has joined before throwing off a new one\n                        } catch (InterruptedException e) {\n                            e.printStackTrace();\n                        }\n                        ReceiveThread = new Thread(new ReceiveThread());\n                        ReceiveThread.start();\n                    }\n                    if (SendThread == null) { //if the thread is null, make a new one (the first one)\n                    SendThread = new Thread(new SendThread());\n                    SendThread.start();\n                } else if (!SendThread.isAlive()) { //if the thread is not null but it's dead, let it join then start a new one\n                    try {\n                        SendThread.join(); //make sure socket thread has joined before throwing off a new one\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                    SendThread =  new Thread(new SendThread());\n                    SendThread.start();\n                }\n                } catch (IOException e) {\n                    e.printStackTrace();\n                    mConnectState = 0;\n                }\n            } catch (IOException e) {\n                e.printStackTrace();\n                mConnectState = 0;\n            }\n        }\n    }\n\n\n    public void sendBytes(byte[] id, byte [] data){\n        //first, send hello\n        byte [] hello = {0x01, 0x02, 0x03};\n        //then send length of body\n        byte[] len;\n        if (data != null) {\n             len = my_int_to_bb_be(data.length);\n        } else {\n            len = my_int_to_bb_be(0);\n        }\n        //then send id of message type\n        byte [] msg_id = id;\n        //then send data\n        byte [] body = data;\n        //then send end tag - eventually make this unique to the image\n        byte [] goodbye = {0x3, 0x2, 0x1};\n        //combine those into a payload\n        ByteArrayOutputStream outputStream;\n        try {\n            outputStream = new ByteArrayOutputStream();\n            outputStream.write(hello);\n            outputStream.write(len);\n            outputStream.write(msg_id);\n            if (body != null) {\n                outputStream.write(body);\n            }\n            outputStream.write(goodbye);\n        } catch (IOException e){\n            mConnectState = 0;\n            return;\n        }\n        byte [] payload = outputStream.toByteArray();\n\n        //send it in a background thread\n        //new Thread(new SendThread(payload)).start();\n        send_queue.add(payload);\n    }\n\n    //this sends messages\n     class SendThread implements Runnable {\n        SendThread() {\n        }\n        @Override\n        public void run() {\n            send_queue.clear();\n            while (true){\n                if (mConnectState != 2){\n                    break;\n                }\n                if (send_queue.size() > 10){\n                    break;\n                }\n                byte [] data;\n                try {\n                    data = send_queue.take(); //block until there is something we can pull out to send\n                } catch (InterruptedException e){\n                    e.printStackTrace();\n                    break;\n                }\n                try {\n                    output.write(data);           // write the message\n                } catch (java.io.IOException e) {\n                    e.printStackTrace();\n                    break;\n                }\n            }\n            throwBrokenSocket();\n        }\n    }\n\n    //receives messages\n    private class ReceiveThread implements Runnable {\n        @Override\n        public void run() {\n            //System.out.println(\"Receive Started, mconnect: \" + mConnectState);\n            while (true) {\n                if (mConnectState != 2){\n                    break;\n                }\n                try {\n                    int chunk_len = 6416; //until we use a better protocol to specify start and end of packet, we need to to match the number in asg\n                    byte [] raw_data = new byte[chunk_len];\n                    input.readFully(raw_data, 0, chunk_len); // read the body\n                    EventBus.getDefault().post(new AudioChunkNewEvent(raw_data));\n                    //byte [] plain_audio_bytes = decryptBytes(raw_data);\n                    //dataObservable.onNext(plain_audio_bytes);\n                } catch (IOException e) {\n                    Log.d(TAG, \"Audio service receive thread broken.\");\n                    e.printStackTrace();\n                    break;\n                }\n            }\n            throwBrokenSocket();\n        }\n    }\n\n    public byte[] my_int_to_bb_be(int myInteger){\n        return ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(myInteger).array();\n    }\n\n\n    private  void throwBrokenSocket(){\n        if (mConnectState == 2){\n            mConnectState = 0;\n        }\n    }\n\n    public byte [] decryptBytes(byte [] input) {\n        byte [] decryptedBytes = AES.decrypt(input, secretKey);\n        return decryptedBytes;\n    }\n\n    public void destroy(){\n        shouldDie = true;\n        dataSubscriber.dispose();\n        killSocket();\n    }\n\n    private void handleDataStream(JSONObject data){\n        try {\n            String dataType = data.getString(MessageTypes.MESSAGE_TYPE_LOCAL);\n            if (dataType.equals(MessageTypes.AUDIO_CHUNK_ENCRYPTED)) {\n                handleEncryptedData(data);\n            } else if (dataType.equals(MessageTypes.AUDIO_CHUNK_DECRYPTED)){\n                String encodedPlainData = data.getString(MessageTypes.AUDIO_DATA);\n                byte [] decodedPlainData = Base64.decode(encodedPlainData, Base64.DEFAULT);\n                EventBus.getDefault().post(new AudioChunkNewEvent(decodedPlainData));\n            }\n        } catch (JSONException e){\n            e.printStackTrace();\n        }\n    }\n\n    //here we decode, decrypt, the encode again. It's not pretty, but it allows us to use a JSON event bus, which makes things way more manageable and modular\n    private void handleEncryptedData(JSONObject data){\n        try{\n            String encodedData = data.getString(MessageTypes.AUDIO_DATA);\n            byte [] decodedData = Base64.decode(encodedData, Base64.DEFAULT);\n            byte [] plainData = decryptBytes(decodedData);\n            String encodedPlainData = Base64.encodeToString(plainData, Base64.DEFAULT);\n\n            //make new object and send as decrypted data\n//            JSONObject decryptedData = new JSONObject();\n//            decryptedData.put(MessageTypes.MESSAGE_TYPE_LOCAL, MessageTypes.AUDIO_CHUNK_DECRYPTED);\n//            decryptedData.put(MessageTypes.AUDIO_DATA, encodedPlainData);\n//            dataObservable.onNext(decryptedData);\n\n            //throw new audio event\n            EventBus.getDefault().post(new AudioChunkNewEvent(plainData));\n        } catch (JSONException e){\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/comms/MessageTypes.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.comms;\n\npublic class MessageTypes {\n    //top level\n    public static final String MESSAGE_TYPE_LOCAL = \"MESSAGE_TYPE_LOCAL\";\n\n    //SERVICE TO ACTIVITY\n    public static final String GLASSES_STATUS_UPDATE = \"GLASSES_STATUS_UPDATE\";\n    public static final String CONNECTION_GLASSES_STATUS_UPDATE = \"CONNECTION_GLASSES_STATUS_UPDATE\";\n    public static final String CONNECTION_GLASSES_GLASSES_OBJECT = \"CONNECTION_GLASSES_GLASSES_OBJECT\";\n\n    //REFERENCE CARD VIEW\n    public static final String REFERENCE_CARD_SIMPLE_VIEW = \"REFERENCE_CARD_SIMPLE_VIEW\";\n    public static final String REFERENCE_CARD_TEXT_WALL_VIEW = \"REFERENCE_CARD_TEXT_WALL_VIEW\";\n    public static final String REFERENCE_CARD_SIMPLE_VIEW_TITLE = \"REFERENCE_CARD_SIMPLE_VIEW_TITLE\";\n    public static final String REFERENCE_CARD_SIMPLE_VIEW_BODY = \"REFERENCE_CARD_SIMPLE_VIEW_BODY\";\n\n    public static final String REFERENCE_CARD_IMAGE_VIEW = \"REFERENCE_CARD_IMAGE_VIEW\";\n    public static final String REFERENCE_CARD_IMAGE_VIEW_TITLE = \"REFERENCE_CARD_IMAGE_VIEW_TITLE\";\n    public static final String REFERENCE_CARD_IMAGE_VIEW_BODY = \"REFERENCE_CARD_IMAGE_VIEW_BODY\";\n    public static final String REFERENCE_CARD_TEXT_WALL_TEXT = \"REFERENCE_CARD_TEXT_WALL_TEXT\";\n    public static final String REFERENCE_CARD_IMAGE_VIEW_IMG_URL = \"REFERENCE_CARD_IMAGE_VIEW_IMG_URL\";\n\n    //SCROLLING TEXT VIEW\n    public static final String SCROLLING_TEXT_VIEW_START = \"SCROLLING_TEXT_VIEW_START\";\n    public static final String SCROLLING_TEXT_VIEW_FINAL = \"SCROLLING_TEXT_VIEW_FINAL\";\n    public static final String SCROLLING_TEXT_VIEW_INTERMEDIATE = \"SCROLLING_TEXT_VIEW_INTERMEDIATE\";\n    public static final String SCROLLING_TEXT_VIEW_TEXT = \"SCROLLING_TEXT_VIEW_TEXT\";\n    public static final String SCROLLING_TEXT_VIEW_TITLE = \"SCROLLING_TEXT_VIEW_TITLE\";\n    public static final String SCROLLING_TEXT_VIEW_STOP = \"SCROLLING_TEXT_VIEW_STOP\";\n\n    //GLASSES CONNECTION EVENT/STATE\n    public static final int CONNECTED_GLASSES = 2;\n    public static final int DISCONNECTED_GLASSES = 0;\n    public static final int TRYNA_CONNECT_GLASSES = 1;\n    public static final int FAILED_CONNECTING_GLASSES = 3;\n\n\n\n\n\n\n\n\n    //DATA TYPES\n    public static final String POV_IMAGE = \"POV_IMAGE\";\n    public static final String JPG_BYTES_BASE64 = \"JPG_BYTES_BASE64\";\n    public static final String IMAGE_ID = \"IMAGE_ID\";\n\n    //specific message types (after MESSAGE_TYPE_*)\n    //TRANSCRIPTS\n    public static final String FINAL_TRANSCRIPT = \"FINAL_TRANSCRIPT\";\n    public static final String INTERMEDIATE_TRANSCRIPT = \"INTERMEDIATE_TRANSCRIPT\";\n    public static final String FINAL_TRANSCRIPT_FOREIGN = \"FINAL_TRANSCRIPT_FOREIGN\";\n    public static final String INTERMEDIATE_TRANSCRIPT_FOREIGN = \"INTERMEDIATE_TRANSCRIPT_FOREIGN\";\n    public static final String TRANSCRIPT_TEXT = \"TRANSCRIPT_TEXT\";\n    public static final String TRANSCRIPT_ID = \"TRANSCRIPT_ID\";\n    public static final String TIMESTAMP = \"TIMESTAMP\";\n\n    //VOICE COMMANDS\n    public static final String VOICE_COMMAND_RESPONSE = \"VOICE_COMMAND_RESPONSE\";\n    public static final String COMMAND_RESULT = \"COMMAND_RESULT\";\n    public static final String COMMAND_NAME = \"COMMAND_NAME\";\n    public static final String COMMAND_RESPONSE_DISPLAY_STRING = \"COMMAND_RESPONSE_DISPLAY_STRING\";\n\n    //voice command event\n    public static final String VOICE_COMMAND_STREAM_EVENT = \"VOICE_COMMAND_STREAM_EVENT\";\n    public static final String VOICE_COMMAND_STREAM_EVENT_TYPE = \"VOICE_COMMAND_STREAM_EVENT_TYPE\";\n    public static final String WAKE_WORD_EVENT_TYPE = \"WAKE_WORD_EVENT_TYPE\";\n    public static final String COMMAND_EVENT_TYPE = \"COMMAND_EVENT_TYPE\";\n    public static final String CANCEL_EVENT_TYPE = \"CANCEL_EVENT_TYPE\";\n    public static final String RESOLVE_EVENT_TYPE = \"RESOLVE_EVENT_TYPE\";\n    public static final String TEXT_RESPONSE_EVENT_TYPE = \"TEXT_RESPONSE_EVENT_TYPE\";\n    public static final String COMMAND_ARGS_EVENT_TYPE = \"COMMAND_ARGS_EVENT_TYPE\";\n    public static final String REQUIRED_ARG_EVENT_TYPE = \"REQUIRED_ARG_EVENT_TYPE\";\n    public static final String ARG_NAME = \"ARG_NAME\";\n    public static final String ARG_OPTIONS = \"ARG_OPTIONS\";\n    public static final String INPUT_VOICE_STRING = \"INPUT_VOICE_STRING\";\n    public static final String VOICE_ARG_EXPECT_TYPE = \"VOICE_ARG_EXPECT_TYPE\";\n    public static final String VOICE_ARG_EXPECT_NATURAL_LANGUAGE = \"VOICE_ARG_EXPECT_NATURAL_LANGUAGE\";\n    public static final String VOICE_COMMAND_LIST = \"VOICE_COMMAND_LIST\";\n    public static final String INPUT_WAKE_WORD = \"INPUT_WAKE_WORD\";\n    public static final String INPUT_VOICE_COMMAND_NAME = \"INPUT_VOICE_COMMAND_NAME\";\n\n    //FACE/PERSON SIGHTING\n    public static final String FACE_SIGHTING_EVENT = \"FACE_SIGHTING_EVENT\";\n    public static final String FACE_NAME = \"FACE_NAME\";\n\n    //SMS\n    public static final String SMS_REQUEST_SEND = \"SMS_REQUEST_SEND\";\n    public static final String SMS_MESSAGE_TEXT = \"SMS_MESSAGE_TEXT\";\n    public static final String SMS_PHONE_NUMBER = \"SMS_PHONE_NUMBER\";\n\n    //AUDIO\n    public static final String AUDIO_CHUNK_ENCRYPTED = \"AUDIO_CHUNK_ENCRYPTED\";\n    public static final String AUDIO_CHUNK_DECRYPTED = \"AUDIO_CHUNK_DECRYPTED\";\n    public static final String AUDIO_DATA = \"AUDIO_DATA\";\n\n    //AUTOCITER/WEARABLE-REFERENCER\n    public static final String AUTOCITER_START = \"AUTOCITER_START\";\n    public static final String AUTOCITER_STOP = \"AUTOCITER_STOP\";\n    public static final String AUTOCITER_PHONE_NUMBER = \"AUTOCITER_PHONE_NUMBER\";\n    public static final String AUTOCITER_POTENTIAL_REFERENCES = \"AUTOCITER_POTENTIAL_REFERENCES\";\n    public static final String AUTOCITER_REFERENCE_DATA = \"AUTOCITER_REFERENCE_DATA\";\n\n    //request user UI to display a list of possible choices to dipslay\n    public static final String REFERENCE_SELECT_REQUEST = \"REFERENCE_SELECT_REQUEST\";\n    public static final String REFERENCES = \"REFERENCES\";\n\n    //command responses to show\n    //Natural language\n    public final static String NATURAL_LANGUAGE_QUERY = \"NATURAL_LANGUAGE_QUERY\";\n    public final static String TEXT_QUERY = \"TEXT_QUERY\";\n    //visual search\n    public final static String VISUAL_SEARCH_RESULT = \"VISUAL_SEARCH_RESULT\"; //this is the ASG facing term\n    public final static String VISUAL_SEARCH_IMAGE= \"VISUAL_SEARCH_IMAGE\";\n    public final static String VISUAL_SEARCH_QUERY = \"VISUAL_SEARCH_QUERY\"; //this is the glbox facing term\n    public final static String VISUAL_SEARCH_DATA = \"VISUAL_SEARCH_DATA\"; //this is the payload\n    //search engine\n    public final static String SEARCH_ENGINE_QUERY = \"SEARCH_ENGINE_QUERY\";\n    public final static String SEARCH_ENGINE_RESULT = \"SEARCH_ENGINE_RESULT\";\n    public final static String SEARCH_ENGINE_RESULT_DATA = \"SEARCH_ENGINE_RESULT_DATA\";\n    public final static String SEARCH_ENGINE_RESULT_TITLE = \"SEARCH_ENGINE_RESULT_TITLE\";\n    public final static String SEARCH_ENGINE_RESULT_BODY = \"SEARCH_ENGINE_RESULT_BODY\";\n    public final static String SEARCH_ENGINE_RESULT_IMAGE = \"SEARCH_ENGINE_RESULT_IMAGE\";\n\n    //translation\n    public final static String TRANSLATE_TEXT_QUERY = \"TRANSLATE_TEXT_QUERY\";\n    public final static String TRANSLATE_TEXT_DATA = \"TRANSLATE_TEXT_DATA\";\n    public final static String TRANSLATE_TEXT_RESULT = \"TRANSLATE_TEXT_RESULT\";\n    public final static String TRANSLATE_TEXT_RESULT_DATA = \"TRANSLATION_RESULT_DATA\";\n    public final static String START_FOREIGN_LANGUAGE_ASR = \"START_FOREIGN_LANGUAGE_ASR\";\n    public final static String STOP_FOREIGN_LANGUAGE_ASR = \"STOP_FOREIGN_LANGUAGE_ASR\";\n    public final static String START_FOREIGN_LANGUAGE_SOURCE_LANGUAGE_NAME = \"START_FOREIGN_LANGUAGE_SOURCE_LANGUAGE_NAME\";\n\n    //contextual/semantic search\n    public final static String START_CONTEXTUAL_SEARCH = \"START_CONTEXTUAL_SEARCH\";\n    public final static String STOP_CONTEXTUAL_SEARCH = \"STOP_CONTEXTUAL_SEARCH\";\n    public final static String CONTEXTUAL_SEARCH_REQUEST = \"CONTEXTUAL_SEARCH_REQUEST\";\n    public final static String CONTEXTUAL_SEARCH_RESULT = \"CONTEXTUAL_SEARCH_RESULT\";\n    public final static String CONTEXTUAL_SEARCH_RESULT_DATA = \"CONTEXTUAL_SEARCH_RESULT_DATA\";\n\n    //object translation\n    public final static String START_OBJECT_DETECTION = \"START_OBJECT_DETECTION\";\n    public final static String STOP_OBJECT_DETECTION = \"STOP_OBJECT_DETECTION\";\n    public final static String OBJECT_TRANSLATION_REQUEST = \"OBJECT_TRANSLATION_REQUEST\";\n    public final static String OBJECT_TRANSLATION_RESULT = \"OBJECT_TRANSLATION_RESULT\";\n    public final static String OBJECT_TRANSLATION_RESULT_DATA = \"OBJECT_TRANSLATION_RESULT_DATA\";\n\n    public final static String AFFECTIVE_SUMMARY_RESULT = \"AFFECTIVE_SUMMARY_RESULT\";\n    public final static String COMMAND_SWITCH_MODE = \"COMMAND_SWITCH_MODE\";\n    //select command\n    public final static String ACTION_SELECT_COMMAND = \"ACTION_SELECT_COMMAND\";\n    public final static String SELECTION = \"SELECTION\";\n\n\n    //translate\n    public static final String REFERENCE_TRANSLATE_SEARCH_QUERY = \"REFERENCE_TRANSLATE_SEARCH_QUERY\";\n    public static final String REFERENCE_TRANSLATE_DATA = \"REFERENCE_TRANSLATE_DATA\";\n    public static final String REFERENCE_TRANSLATE_TARGET_LANGUAGE_CODE = \"REFERENCE_TRANSLATE_TARGET_LANGUAGE_CODE\";\n    public static final String REFERENCE_TRANSLATE_RESULT = \"REFERENCE_TRANSLATE_RESULT\";\n    public static final String REFERENCE_TRANSLATE_RESULT_DATA = \"REFERENCE_TRANSLATE_RESULT_DATA\";\n\n    //text to speech\n    public static final String TEXT_TO_SPEECH_SPEAK = \"TEXT_TO_SPEECH_SPEAK\";\n    public static final String TEXT_TO_SPEECH_SPEAK_DATA = \"TEXT_TO_SPEECH_SPEAK_DATA\";\n    public static final String TEXT_TO_SPEECH_TARGET_LANGUAGE_CODE = \"TEXT_TO_SPEECH_TARGET_LANGUAGE_CODE\";\n\n    //control the current mode of the ASG\n    public final static String ACTION_SWITCH_MODES = \"ACTION_SWITCH_MODES\";\n    public final static String NEW_MODE = \"NEW_MODE\";\n    public final static String MODE_HOME = \"MODE_HOME\";\n    public final static String MODE_VISUAL_SEARCH = \"MODE_VISUAL_SEARCH\";\n    public final static String MODE_LIVE_LIFE_CAPTIONS = \"MODE_LIVE_LIFE_CAPTIONS\";\n    public final static String MODE_SOCIAL_MODE = \"MODE_SOCIAL_MODE\";\n    public final static String MODE_CONVERSATION_MODE = \"MODE_CONVERSATION_MODE\";\n    public final static String MODE_CONTEXTUAL_SEARCH = \"MODE_CONTEXTUAL_SEARCH\";\n    public final static String MODE_REFERENCE_GRID = \"MODE_REFERENCE_GRID\";\n    public final static String MODE_WEARABLE_FACE_RECOGNIZER = \"MODE_WEARABLE_FACE_RECOGNIZER\";\n    public final static String MODE_LANGUAGE_TRANSLATE = \"MODE_LANGUAGE_TRANSLATE\";\n    public final static String MODE_OBJECT_TRANSLATE = \"MODE_OBJECT_TRANSLATE\";\n    public final static String MODE_TEXT_LIST = \"MODE_TEXT_LIST\";\n    public final static String MODE_TEXT_BLOCK = \"MODE_TEXT_BLOCK\";\n    public final static String MODE_BLANK = \"MODE_BLANK\";\n}\n\n\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/comms/VolleyCallback.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.comms;\n\nimport org.json.JSONObject;\n\npublic interface VolleyCallback {\n    void onSuccess(JSONObject result);\n    void onFailure();\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/eventbusmessages/AudioChunkNewEvent.java",
    "content": "package com.teamopensmartglasses.augmentoslib.events;\n\npublic class AudioChunkNewEvent {\n    public byte [] thisChunk;\n\n    public AudioChunkNewEvent(byte [] thisChunk){\n        this.thisChunk = thisChunk;\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/eventbusmessages/DisableBleScoAudioEvent.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.eventbusmessages;\n\npublic class DisableBleScoAudioEvent {\n    public boolean disableBleScoAudio;\n\n    public DisableBleScoAudioEvent(boolean disableBleScoAudio){\n        this.disableBleScoAudio = disableBleScoAudio;\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/eventbusmessages/GoogleAudioChunkNewEvent.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.eventbusmessages;\n\npublic class GoogleAudioChunkNewEvent {\n    public byte [] thisChunk;\n\n    public GoogleAudioChunkNewEvent(byte [] thisChunk){\n        this.thisChunk = thisChunk;\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/eventbusmessages/PauseAsrEvent.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.eventbusmessages;\n\npublic class PauseAsrEvent {\n    public boolean pauseAsr;\n\n    public PauseAsrEvent(boolean pauseAsr){\n        this.pauseAsr = pauseAsr;\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/eventbusmessages/PostGenericGlobalMessageEvent.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.eventbusmessages;\n\npublic class PostGenericGlobalMessageEvent {\n    public String message;\n\n    public PostGenericGlobalMessageEvent(String newMessage){\n        this.message = newMessage;\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/eventbusmessages/ScoStartEvent.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.eventbusmessages;\n\npublic class ScoStartEvent {\n    public boolean scoStart;\n\n    public ScoStartEvent(boolean scoStart){\n        this.scoStart = scoStart;\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/eventbusmessages/SetFontSizeEvent.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.eventbusmessages;\n\nimport com.teamopensmartglasses.smartglassesmanager.smartglassescommunicators.SmartGlassesFontSize;\n\npublic class SetFontSizeEvent {\n\n    public SmartGlassesFontSize fontSize;\n\n    public SetFontSizeEvent(SmartGlassesFontSize newFontSize){\n        this.fontSize = newFontSize;\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/eventbusmessages/SmartGlassesConnectedEvent.java",
    "content": "package com.teamopensmartglasses.augmentoslib.events;\n\nimport com.teamopensmartglasses.smartglassesmanager.supportedglasses.SmartGlassesDevice;\n\npublic class SmartGlassesConnectedEvent {\n    public final SmartGlassesDevice device;\n\n    public SmartGlassesConnectedEvent(SmartGlassesDevice newDevice) {\n        this.device = newDevice;\n    }\n}"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/eventbusmessages/SmartGlassesConnectionEvent.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.eventbusmessages;\n\npublic class SmartGlassesConnectionEvent {\n    public final int connectionStatus;\n\n    public SmartGlassesConnectionEvent(int connectionStatus) {\n        this.connectionStatus = connectionStatus;\n    }\n}"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/eventbusmessages/TextToSpeechEvent.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.eventbusmessages;\n\npublic class TextToSpeechEvent {\n    public String text;\n    public String language; //the name of the language, fully spelled out, ll lowercase\n\n    public TextToSpeechEvent(String text, String language){\n        this.text = text;\n        this.language = language;\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/eventbusmessages/VoskAudioChunkNewEvent.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.eventbusmessages;\n\npublic class VoskAudioChunkNewEvent {\n    public byte [] thisChunk;\n\n    public VoskAudioChunkNewEvent(byte [] thisChunk){\n        this.thisChunk = thisChunk;\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/hci/AudioChunkCallback.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.hci;\n\nimport java.nio.ByteBuffer;\n\npublic interface AudioChunkCallback{\n    void onSuccess(ByteBuffer chunk);\n}"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/hci/HearItBleMicrophone.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.hci;\n\nimport android.bluetooth.BluetoothAdapter;\nimport android.bluetooth.BluetoothDevice;\nimport android.bluetooth.BluetoothGatt;\nimport android.bluetooth.BluetoothGattCallback;\nimport android.bluetooth.BluetoothGattCharacteristic;\nimport android.bluetooth.BluetoothGattService;\nimport android.bluetooth.BluetoothProfile;\nimport android.content.Context;\nimport android.util.Log;\n\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\npublic class HearItBleMicrophone {\n    private static final String TAG = \"HearItBleMicrophone\";\n\n    private static final UUID VOICE_SERVICE_UUID = UUID.fromString(\"00001853-0000-1000-8000-00805f9b34fb\");\n    private static final UUID VOICE_DATA_CHARACTERISTIC_UUID = UUID.fromString(\"00002bcd-0000-1000-8000-00805f9b34fb\");\n\n    private BluetoothAdapter bluetoothAdapter;\n    private BluetoothGatt bluetoothGatt;\n    private BluetoothGattCharacteristic voiceDataCharacteristic;\n    private Context context;\n    private AtomicBoolean isConnected = new AtomicBoolean(false);\n    private boolean foundHearIt = false;\n\n    private final int[] idxtbl = {-1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8};\n    private final int[] steptbl = {\n            7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,\n            50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,\n            337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,\n            2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,\n            15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767\n    };\n\n    private int lastPacketNumber = -1;\n\n    public interface HearItBleMicCallback {\n        void onConnected();\n        void onPcmDataAvailable(byte[] pcmData);\n    }\n\n    private HearItBleMicCallback hearItBleMicCallback;\n\n    public void setHearItBleMicCallback(HearItBleMicCallback hearItBleMicCallback) {\n        this.hearItBleMicCallback = hearItBleMicCallback;\n    }\n\n    public boolean isConnected(){\n        return isConnected.get();\n    }\n\n    public HearItBleMicrophone(Context context) {\n        this.context = context;\n        this.bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();\n    }\n\n    public void startScanning() {\n        if (!bluetoothAdapter.isEnabled()) {\n            Log.e(TAG, \"Bluetooth is not enabled. Cannot start scanning.\");\n            return;\n        }\n        bluetoothAdapter.startLeScan(leScanCallback);\n    }\n\n    private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {\n        @Override\n        public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {\n            if (!foundHearIt && device.getName() != null && device.getName().startsWith(\"GMIC\")) {\n                foundHearIt = true;\n                bluetoothAdapter.stopLeScan(leScanCallback);\n                connectToDevice(device);\n            }\n        }\n    };\n\n    private void connectToDevice(BluetoothDevice device) {\n        if (!bluetoothAdapter.isEnabled()) {\n            Log.e(TAG, \"Bluetooth is not enabled. Cannot connect to device.\");\n            return;\n        }\n        bluetoothGatt = device.connectGatt(context, false, gattCallback);\n    }\n\n    private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {\n        @Override\n        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {\n            if (newState == BluetoothProfile.STATE_CONNECTED) {\n                Log.i(TAG, \"Connected to GATT server.\");\n                bluetoothGatt.discoverServices();\n            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {\n                Log.i(TAG, \"Disconnected from GATT server.\");\n                isConnected.set(false);\n            }\n        }\n\n        @Override\n        public void onServicesDiscovered(BluetoothGatt gatt, int status) {\n            if (status == BluetoothGatt.GATT_SUCCESS) {\n                List<BluetoothGattService> services = bluetoothGatt.getServices();\n                for (BluetoothGattService service : services) {\n                    if (VOICE_SERVICE_UUID.equals(service.getUuid())) {\n                        voiceDataCharacteristic = service.getCharacteristic(VOICE_DATA_CHARACTERISTIC_UUID);\n                        if (voiceDataCharacteristic != null) {\n                            bluetoothGatt.setCharacteristicNotification(voiceDataCharacteristic, true);\n                            isConnected.set(true);\n                            if (hearItBleMicCallback != null) {\n                                hearItBleMicCallback.onConnected();\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        @Override\n        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {\n            if (VOICE_DATA_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {\n                byte[] adpcmData = characteristic.getValue();\n                int sampleCount = adpcmData[3] * 2;\n                ByteBuffer pcmDataBuffer = ByteBuffer.allocate(sampleCount * 2).order(ByteOrder.LITTLE_ENDIAN); // Dynamically allocate buffer\n                adpcmToPcm(adpcmData, pcmDataBuffer);\n                byte[] pcmData = pcmDataBuffer.array();\n                if (hearItBleMicCallback != null) {\n                    hearItBleMicCallback.onPcmDataAvailable(pcmData);\n                }\n            }\n        }\n    };\n\n    private void adpcmToPcm(byte[] adpcmData, ByteBuffer pcmDataBuffer) {\n        int sampleCount = adpcmData[3] * 2;\n        int currentPacketNumber = -1;\n\n        // Check and set currentPacketNumber\n        if (adpcmData.length == sampleCount / 2 + 6) {\n            currentPacketNumber = (adpcmData[adpcmData.length - 1] << 8) + adpcmData[adpcmData.length - 2];\n\n            if (lastPacketNumber != -1 && currentPacketNumber != lastPacketNumber + 1) {\n                int lostPackets = currentPacketNumber - lastPacketNumber - 1;\n                Log.w(TAG, \"Warning: Packet loss detected, number of lost packets: \" + lostPackets);\n            }\n\n            lastPacketNumber = currentPacketNumber;\n        }\n\n        int predict = (adpcmData[0] | (adpcmData[1] << 8)) << 16 >> 16;\n        int predict_idx = adpcmData[2];\n        byte[] pcode = new byte[adpcmData.length - 4];\n        System.arraycopy(adpcmData, 4, pcode, 0, pcode.length);\n\n        int code = pcode[0];\n\n        for (int i = 0; i < sampleCount; i++) {\n            int step = steptbl[predict_idx];\n            int diffq = step >> 3;\n\n            if ((code & 4) != 0) diffq += step;\n            step >>= 1;\n            if ((code & 2) != 0) diffq += step;\n            step >>= 1;\n            if ((code & 1) != 0) diffq += step;\n\n            if ((code & 8) != 0) predict -= diffq;\n            else predict += diffq;\n\n            predict = Math.max(-32768, Math.min(32767, predict));\n            predict_idx = Math.max(0, Math.min(88, predict_idx + idxtbl[code & 15]));\n\n            if (i % 2 == 0) code = pcode[i / 2];\n            else code >>= 4;\n\n            pcmDataBuffer.putShort((short) predict);\n        }\n    }\n\n    public void destroy() {\n        if (bluetoothGatt != null) {\n            bluetoothGatt.disconnect();\n            bluetoothGatt.close();\n            bluetoothGatt = null;\n        }\n        hearItBleMicCallback = null;\n        isConnected.set(false);\n        Log.i(TAG, \"Bluetooth connection closed and callback turned off.\");\n    }\n\n}"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/hci/MicrophoneLocalAndBluetooth.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.hci;\n\n//thanks to https://github.com/aahlenst/android-audiorecord-sample/blob/master/src/main/java/com/example/audiorecord/BluetoothRecordActivity.java\n\nimport android.bluetooth.BluetoothDevice;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.media.AudioFormat;\nimport android.media.AudioManager;\nimport android.media.AudioRecord;\nimport android.media.MediaRecorder;\nimport android.os.CountDownTimer;\nimport android.os.Handler;\nimport android.util.Log;\n\nimport com.teamopensmartglasses.smartglassesmanager.eventbusmessages.ScoStartEvent;\n\nimport org.greenrobot.eventbus.EventBus;\nimport org.greenrobot.eventbus.Subscribe;\n\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.util.concurrent.atomic.AtomicBoolean;\npublic class MicrophoneLocalAndBluetooth {\n    private static final String TAG = \"WearableAi_MicrophoneLocalAndBluetooth\";\n\n    private static final int SAMPLING_RATE_IN_HZ = 16000;\n    private static final int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO;\n    private static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;\n    private final static float BUFFER_SIZE_SECONDS = 0.192f; // gives us 1024*3 = 3072 samples\n    private static final int BUFFER_SIZE_FACTOR = 2;\n    private final int bufferSize;\n    private boolean bluetoothAudio = false; // are we using local audio or bluetooth audio?\n    private boolean shouldUseHearItBleMicrophone = false; // should we use HearIt BLE microphone?\n    private int retries = 0;\n    private int retryLimit = 3;\n\n    private Handler mHandler;\n\n    private final AtomicBoolean recordingInProgress = new AtomicBoolean(false);\n\n    private HearItBleMicrophone hearItBleMicrophone;\n\n    private final BroadcastReceiver bluetoothStateReceiver = new BroadcastReceiver() {\n        private BluetoothState bluetoothState = BluetoothState.UNAVAILABLE;\n\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            String action = intent.getAction();\n            if (action.equals(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED)) {\n                int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1);\n                switch (state) {\n                    case AudioManager.SCO_AUDIO_STATE_CONNECTED:\n                        if (mIsStarting) {\n                            mIsStarting = false;\n                        }\n                        if (mIsCountDownOn) {\n                            mIsCountDownOn = false;\n                            mCountDown.cancel();\n                        }\n                        bluetoothAudio = true;\n                        startRecording();\n                        break;\n                    case AudioManager.SCO_AUDIO_STATE_CONNECTING:\n                        handleBluetoothStateChange(BluetoothState.UNAVAILABLE);\n                    case AudioManager.SCO_AUDIO_STATE_DISCONNECTED:\n                        handleBluetoothStateChange(BluetoothState.UNAVAILABLE);\n                        break;\n                    case AudioManager.SCO_AUDIO_STATE_ERROR:\n                        handleBluetoothStateChange(BluetoothState.UNAVAILABLE);\n                        break;\n                }\n            } else if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {\n                handleNewBluetoothDevice();\n            } else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {\n                handleDisconnectBluetoothDevice();\n            }\n        }\n\n        private void handleBluetoothStateChange(BluetoothState state) {\n            if (bluetoothState == state) {\n                return;\n            }\n            bluetoothState = state;\n            bluetoothStateChanged(state);\n        }\n\n        private void handleNewBluetoothDevice() {\n            retries = 0;\n            mIsCountDownOn = true;\n            mCountDown.start();\n        }\n\n        private void handleDisconnectBluetoothDevice() {\n            if (mIsCountDownOn) {\n                mIsCountDownOn = false;\n                mCountDown.cancel();\n            }\n            bluetoothAudio = false;\n            deactivateBluetoothSco();\n            startRecording();\n        }\n    };\n\n    private AudioRecord recorder = null;\n\n    private AudioManager audioManager;\n    private boolean mIsCountDownOn = false;\n    private boolean mIsStarting = false;\n\n    private Thread recordingThread = null;\n\n    private Context mContext;\n\n    private AudioChunkCallback mChunkCallback;\n\n    public MicrophoneLocalAndBluetooth(Context context, boolean useBluetoothSco, AudioChunkCallback chunkCallback) {\n        this(context, chunkCallback);\n        this.shouldUseHearItBleMicrophone = true;\n        useBluetoothMic(useBluetoothSco);\n    }\n\n    public MicrophoneLocalAndBluetooth(Context context, AudioChunkCallback chunkCallback) {\n        bufferSize = Math.round(SAMPLING_RATE_IN_HZ * BUFFER_SIZE_SECONDS);\n\n        mIsStarting = true;\n\n        mContext = context;\n\n        audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);\n\n        mChunkCallback = chunkCallback;\n\n        mHandler = new Handler();\n\n        startRecording();\n    }\n\n    private void useBluetoothMic(boolean shouldUseBluetoothSco) {\n        bluetoothAudio = shouldUseBluetoothSco;\n\n        if (shouldUseBluetoothSco) {\n            startBluetoothSco();\n        } else {\n            stopBluetoothSco();\n        }\n\n        if (recordingInProgress.get()) {\n            startRecording();\n        }\n    }\n\n    private void startBluetoothSco() {\n        mContext.registerReceiver(bluetoothStateReceiver, new IntentFilter(\n                AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED));\n        mContext.registerReceiver(bluetoothStateReceiver,\n                new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED));\n        mContext.registerReceiver(bluetoothStateReceiver,\n                new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED));\n\n        mIsCountDownOn = true;\n        mCountDown.start();\n    }\n\n    private void stopBluetoothSco() {\n        mIsCountDownOn = false;\n        mCountDown.cancel();\n        try {\n            mContext.unregisterReceiver(bluetoothStateReceiver);\n        } catch (IllegalArgumentException e) {\n            e.printStackTrace();\n        }\n    }\n\n    private void startRecording() {\n        if (recorder != null) {\n            stopRecording();\n        }\n        if (bluetoothAudio) {\n            audioManager.setMode(AudioManager.MODE_IN_CALL);\n            EventBus.getDefault().post(new ScoStartEvent(true));\n        } else {\n            audioManager.setMode(AudioManager.MODE_NORMAL);\n            EventBus.getDefault().post(new ScoStartEvent(false));\n        }\n\n        recorder = new AudioRecord(MediaRecorder.AudioSource.UNPROCESSED,\n                SAMPLING_RATE_IN_HZ, CHANNEL_CONFIG, AUDIO_FORMAT, bufferSize * 2);\n\n        recorder.startRecording();\n\n        recordingInProgress.set(true);\n\n        recordingThread = new Thread(new RecordingRunnable(), \"Recording Thread\");\n        recordingThread.start();\n\n        if (bluetoothAudio && shouldUseHearItBleMicrophone) {\n            Log.d(TAG, \"Connecting HearItBle... \");\n            hearItBleMicrophone = new HearItBleMicrophone(mContext);\n            hearItBleMicrophone.setHearItBleMicCallback(new HearItBleMicrophone.HearItBleMicCallback() {\n                @Override\n                public void onConnected() {\n                    Log.d(TAG, \"--- HearItBle connected!\");\n                    stopAndroidMics();\n                }\n\n                @Override\n                public void onPcmDataAvailable(byte[] pcmData) {\n                    ByteBuffer b_buffer = ByteBuffer.allocate(pcmData.length);\n                    b_buffer.put(pcmData);\n                    mChunkCallback.onSuccess(b_buffer);\n                }\n            });\n            hearItBleMicrophone.startScanning();\n        }\n    }\n\n    private void stopAndroidMics(){\n        mIsCountDownOn = false;\n        mCountDown.cancel();\n        deactivateBluetoothSco();\n        audioManager.setMode(AudioManager.MODE_NORMAL);\n\n        stopRecording();\n    }\n\n    private void stopRecording() {\n        Log.d(TAG, \"Running stopRecording...\");\n\n        if (recorder == null) {\n            Log.d(TAG, \"--- Recorder null, exiting.\");\n            return;\n        }\n\n        recordingInProgress.set(false);\n        recorder.stop();\n        recorder.release();\n        recorder = null;\n        recordingThread = null;\n    }\n\n    private void activateBluetoothSco() {\n        retries += 1;\n\n        if (!audioManager.isBluetoothScoAvailableOffCall()) {\n            Log.e(TAG, \"SCO is not available, recording is not possible\");\n            return;\n        }\n\n        if (audioManager.isBluetoothScoOn()) {\n            audioManager.stopBluetoothSco();\n        }\n        audioManager.startBluetoothSco();\n    }\n\n    private void deactivateBluetoothSco() {\n        audioManager.stopBluetoothSco();\n    }\n\n    private void bluetoothStateChanged(BluetoothState state) {\n        if (BluetoothState.UNAVAILABLE == state && recordingInProgress.get()) {\n            bluetoothAudio = false;\n            stopRecording();\n            deactivateBluetoothSco();\n        } else if (BluetoothState.AVAILABLE == state && !recordingInProgress.get()) {\n            bluetoothAudio = true;\n            startRecording();\n        } else if (BluetoothState.AVAILABLE == state && !bluetoothAudio) {\n            bluetoothAudio = true;\n            startRecording();\n        }\n    }\n\n    private class RecordingRunnable implements Runnable {\n        @Override\n        public void run() {\n            short[] short_buffer = new short[bufferSize];\n            ByteBuffer b_buffer = ByteBuffer.allocate(short_buffer.length * 2);\n\n            while (recordingInProgress.get()) {\n                int result = recorder.read(short_buffer, 0, short_buffer.length);\n                if (result < 0) {\n                    Log.d(TAG, \"ERROR\");\n                }\n                b_buffer.order(ByteOrder.LITTLE_ENDIAN);\n                b_buffer.asShortBuffer().put(short_buffer);\n                if (hearItBleMicrophone != null && !hearItBleMicrophone.isConnected()) {\n                    mChunkCallback.onSuccess(b_buffer);\n                }\n                b_buffer.clear();\n            }\n        }\n\n        private String getBufferReadFailureReason(int errorCode) {\n            switch (errorCode) {\n                case AudioRecord.ERROR_INVALID_OPERATION:\n                    return \"ERROR_INVALID_OPERATION\";\n                case AudioRecord.ERROR_BAD_VALUE:\n                    return \"ERROR_BAD_VALUE\";\n                case AudioRecord.ERROR_DEAD_OBJECT:\n                    return \"ERROR_DEAD_OBJECT\";\n                case AudioRecord.ERROR:\n                    return \"ERROR\";\n                default:\n                    return \"Unknown (\" + errorCode + \")\";\n            }\n        }\n    }\n\n    enum BluetoothState {\n        AVAILABLE, UNAVAILABLE\n    }\n\n    private CountDownTimer mCountDown = new CountDownTimer(1201, 400) {\n        @SuppressWarnings(\"synthetic-access\")\n        @Override\n        public void onTick(long millisUntilFinished) {\n            audioManager.startBluetoothSco();\n        }\n\n        @SuppressWarnings(\"synthetic-access\")\n        @Override\n        public void onFinish() {\n            mIsCountDownOn = false;\n            bluetoothAudio = false;\n            startRecording();\n        }\n    };\n\n    public void destroy() {\n        stopRecording();\n\n        if (hearItBleMicrophone != null) {\n            hearItBleMicrophone.destroy();\n        }\n\n        mIsCountDownOn = false;\n        mCountDown.cancel();\n        deactivateBluetoothSco();\n        audioManager.setMode(AudioManager.MODE_NORMAL);\n        if (mContext != null) {\n            try {\n                mContext.unregisterReceiver(bluetoothStateReceiver);\n            } catch (IllegalArgumentException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n}"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/smartglassescommunicators/AndroidSGC.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.smartglassescommunicators;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport android.os.StrictMode;\nimport android.util.Base64;\nimport android.util.Log;\n\nimport com.teamopensmartglasses.smartglassesmanager.comms.AspWebsocketServer;\nimport com.teamopensmartglasses.smartglassesmanager.comms.AudioSystem;\nimport com.teamopensmartglasses.smartglassesmanager.comms.MessageTypes;\nimport com.teamopensmartglasses.augmentoslib.events.GlassesPovImageEvent;\nimport com.teamopensmartglasses.smartglassesmanager.utils.NetworkUtils;\n\nimport org.greenrobot.eventbus.EventBus;\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.net.DatagramSocket;\nimport java.net.ServerSocket;\nimport java.net.Socket;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.util.Random;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.TimeUnit;\n\nimport io.reactivex.rxjava3.subjects.PublishSubject;\n\npublic class AndroidSGC extends SmartGlassesCommunicator {\n    private static final String TAG = \"WearableAi_AndroidSGC\";\n\n    PublishSubject<JSONObject> dataObservable;\n\n    private static boolean killme;\n\n    private static Handler heart_beat_handler;\n\n    //handler for advertising\n    private Handler adv_handler;\n\n    //network details\n    public int PORT_NUM = 8891;\n    public DatagramSocket adv_socket;\n    public String adv_key = \"WearableAiCyborg\";\n\n    //SOCKET STUFF\n    //socket\n    public AspWebsocketServer asgWebSocket;\n\n    public void displayRowsCard(String[] rowStrings){\n\n    }\n\n    //acutal socket\n    ServerSocket serverSocket;\n    Socket socket;\n    boolean shouldDie = false;\n\n    //socket threads\n    Thread SocketThread = null;\n    Thread ReceiveThread = null;\n    Thread SendThread = null;\n    //queue of data to send through the socket\n    public BlockingQueue<byte []> queue;\n    //address info\n    public  final int SERVER_PORT = 4567;\n    //i/o\n    public DataOutputStream output;\n    public DataInputStream input;\n    public  int outbound_heart_beats = 0;\n\n    //other\n    final byte [] ack_id = {0x13, 0x37};\n    final byte [] heart_beat_id = {0x19, 0x20};\n    final byte [] img_id = {0x01, 0x10}; //id for images\n\n    //audio streaming system\n    AudioSystem audioSystem;\n\n    Context context;\n\n    public AndroidSGC(Context context, PublishSubject<JSONObject> dataObservable){\n        super();\n        this.dataObservable = dataObservable;\n        this.context = context;\n\n        //create a new queue to hold outbound message\n        queue = new ArrayBlockingQueue<byte[]>(50);\n\n        killme = false;\n\n        //state information\n        mConnectState = 0;\n    }\n\n    //not used/valid yet\n    @Override\n    protected void setFontSizes(){\n        LARGE_FONT = 3;\n        MEDIUM_FONT = 2;\n        SMALL_FONT = 0;\n    }\n\n    public void connectToSmartGlasses(){\n        //open the UDP socket to broadcast our IP address\n        openSocket();\n\n        //send broadcast over UDP that tells smart glasses they can find us\n        adv_handler = new Handler();\n        final int delay = 1000; // 1000 milliseconds == 1 second\n        adv_handler.postDelayed(new Runnable() {\n            public void run() {\n                new Thread(new SendAdvThread()).start();\n                adv_handler.postDelayed(this, delay);\n            }\n        }, 5);\n\n        startAsgWebSocketConnection();\n\n        audioSystem = new AudioSystem(context, dataObservable);\n\n        //start first socketThread\n        Log.d(TAG, \"running start socket\");\n        startSocket();\n    }\n\n    class SendAdvThread extends Thread {\n        public void run() {\n            //send broadcast so smart glasses know our address\n            NetworkUtils.sendBroadcast(adv_key, adv_socket, PORT_NUM, context);\n        }\n    }\n\n    public void blankScreen(){\n//        try{\n//            //build json object to send command result\n//            JSONObject commandResponseObject = new JSONObject();\n//            commandResponseObject.put(MessageTypes.MESSAGE_TYPE_LOCAL, MessageTypes.ACTION_SWITCH_MODES);\n//            commandResponseObject.put(MessageTypes.NEW_MODE, MessageTypes.MODE_BLANK);\n//\n//            //send the command result to web socket, to send to asg\n//            dataObservable.onNext(commandResponseObject);\n//        } catch (JSONException e){\n//            e.printStackTrace();\n//        }\n    }\n\n    public void startAsgWebSocketConnection(){\n        Log.d(TAG, \"Starting WebSocket Server\");\n        //String address = \"localhost:8887\";\n        //InetSocketAddress inetSockAddress = new InetSocketAddress(address);\n        int port = 8887;\n        asgWebSocket = new AspWebsocketServer(port);\n        asgWebSocket.setObservable(dataObservable);\n        asgWebSocket.start();\n        Log.d(TAG, \"WebSocket Server STARTED\");\n    }\n\n    //SOCKET STUFF\n    public void startSocket(){\n        //start first socketThread\n        Log.d(TAG, \"socket val in startSocket: \" + socket);\n        if (socket == null) {\n            Log.d(TAG, \"starting new SocketThread\" + socket);\n            connectionEvent(1);\n            SocketThread = new Thread(new SocketThread());\n            SocketThread.start();\n\n            //setup handler to handle keeping connection alive, all subsequent start of SocketThread\n            //start a new handler thread to send heartbeats\n            HandlerThread thread = new HandlerThread(\"HeartBeater\");\n            thread.start();\n            heart_beat_handler = new Handler(thread.getLooper());\n            final int hb_delay = 3000;\n            final int min_hb_delay = 1000;\n            final int max_hb_delay = 2000;\n            Random rand = new Random();\n            heart_beat_handler.postDelayed(new Runnable() {\n                public void run() {\n                    heartBeat();\n                    //random hb_delay for heart beat so as to disallow synchronized failure between client and server\n                    int random_hb_delay = rand.nextInt((max_hb_delay - min_hb_delay) + 1) + min_hb_delay;\n                    heart_beat_handler.postDelayed(this, random_hb_delay);\n                }\n            }, hb_delay);\n\n        } else {\n            Log.d(TAG, \"socket wasn't null, so not starting\");\n        }\n\n    }\n\n    public void openSocket() {\n        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();\n        StrictMode.setThreadPolicy(policy);\n\n        try {\n            //Open a random port to send the package\n            adv_socket = new DatagramSocket();\n            adv_socket.setBroadcast(true);\n        } catch (IOException e) {\n            Log.e(TAG, \"IOException: \" + e.getMessage());\n        }\n    }\n\n    class SocketThread implements Runnable {\n        @Override\n        public void run() {\n            Log.d(TAG, \"I have started SOCKETTHREAD\");\n            try {\n                if (killme){\n                    Log.d(TAG, \"I have killed myself\");\n                    return;\n                }\n                Log.d(TAG, \"Starting new socket, waiting for connection...\");\n                serverSocket = new ServerSocket(SERVER_PORT);\n                //serverSocket.setSoTimeout(2000);\n                try {\n                    socket = serverSocket.accept();\n                    if (killme){\n                        return;\n                    }\n                    socket.setSoTimeout(5000);\n                    Log.d(TAG, \"Got socket connection.\");\n                    //output = new PrintWriter(socket.getOutputStream(), true);\n                    output = new DataOutputStream(socket.getOutputStream());\n                    input = new DataInputStream(new DataInputStream(socket.getInputStream()));\n                    connectionEvent(2);\n                    if (ReceiveThread == null) { //if the thread is null, make a new one (the first one)\n                        ReceiveThread = new Thread(new ReceiveThread());\n                        ReceiveThread.start();\n                    } else if (!ReceiveThread.isAlive()) { //if the thread is not null but it's dead, let it join then start a new one\n                        try {\n                            ReceiveThread.join(); //make sure socket thread has joined before throwing off a new one\n                        } catch (InterruptedException e) {\n                            e.printStackTrace();\n                        }\n                        ReceiveThread = new Thread(new ReceiveThread());\n                        ReceiveThread.start();\n                    }\n                    if (SendThread == null) { //if the thread is null, make a new one (the first one)\n                        SendThread = new Thread(new SendThread());\n                        SendThread.start();\n                    } else if (!SendThread.isAlive()) { //if the thread is not null but it's dead, let it join then start a new one\n                        try {\n                            SendThread.join(); //make sure socket thread has joined before throwing off a new one\n                        } catch (InterruptedException e) {\n                            e.printStackTrace();\n                        }\n                        SendThread =  new Thread(new SendThread());\n                        SendThread.start();\n                    }\n                } catch (IOException e) {\n                    e.printStackTrace();\n                    connectionEvent(0);\n                }\n            } catch (IOException e) {\n                e.printStackTrace();\n                connectionEvent(0);\n            }\n        }\n    }\n\n    //receives messages\n    public void heartBeat(){\n        //check if we are still connected.\n        //if not , reconnect,\n        //if we are connected, send a heart beat to make sure we are still connected\n        if (mConnectState == 0 && !killme) {\n            Log.d(TAG, \"heartBeat failing\");\n            restartSocket();\n        } else if (mConnectState == 2){\n            //make sure we don't have a ton of outbound heart beats unresponded to\n            if (outbound_heart_beats > 5) {\n                Log.d(TAG, \"heartBeat outbounds failing\");\n                restartSocket();\n                return;\n            }\n\n            //increment counter\n            outbound_heart_beats++;\n\n            //send heart beat\n            sendBytes(heart_beat_id, null);\n        }\n    }\n\n    //receives messages\n    public class ReceiveThread implements Runnable {\n        @Override\n        public void run() {\n            //System.out.println(\"Receive Started, mconnect: \" + mConnectState);\n            while (true) {\n                if (killme){\n                    return;\n                }\n                if (mConnectState != 2){\n                    break;\n                }\n                byte b1, b2;\n                byte [] raw_data = null;\n                byte goodbye1, goodbye2, goodbye3;\n                try {\n                    byte hello1 = input.readByte(); // read hello of incoming message\n                    byte hello2 = input.readByte(); // read hello of incoming message\n                    byte hello3 = input.readByte(); // read hello of incoming message\n\n                    //make sure header is verified\n                    if (hello1 != 0x01 || hello2 != 0x02 || hello3 != 0x03){\n                        Log.d(TAG, \"Receive thread: broken intro fail\");\n                        break;\n                    }\n                    //length of body\n                    int body_len = input.readInt();\n\n                    //read in message id bytes\n                    b1 = input.readByte();\n                    b2 = input.readByte();\n\n                    //read in message body (if there is one)\n                    if (body_len > 0){\n                        raw_data = new byte[body_len];\n                        input.readFully(raw_data, 0, body_len); // read the body\n                    }\n                    goodbye1 = input.readByte(); // read goodbye of incoming message\n                    goodbye2 = input.readByte(); // read goodbye of incoming message\n                    goodbye3 = input.readByte(); // read goodbye of incoming message\n                } catch (IOException e) {\n                    if (killme){\n                        Log.d(TAG, \"Socket closed (by us), cleaning up.\");\n                    } else {\n                        Log.d(TAG, \"Socket closed.\");\n                        e.printStackTrace();\n                    }\n                    break;\n                }\n\n                //make sure footer is verified\n                if (goodbye1 != 0x03 || goodbye2 != 0x02 || goodbye3 != 0x01) {\n                    Log.d(TAG, \"Receive thread: broken footer fail\");\n                    break;\n                }\n\n                //now process the data that was sent to us\n                if ((b1 == heart_beat_id[0]) && (b2 == heart_beat_id[1])){ //heart beat id tag\n                    outbound_heart_beats--;\n                } else if ((b1 == ack_id[0]) && (b2 == ack_id[1])){ //an ack id\n                } else if ((b1 == img_id[0]) && (b2 == img_id[1])){ //an ack id\n                    Log.d(TAG, \"Got IMAGE\");\n                    if (raw_data != null) {\n                        //remember the time we received it\n                        long imageTime = System.currentTimeMillis();\n\n                        //ping back the client to let it know we received the message\n                        sendBytes(ack_id, null);\n\n                        handleImage(raw_data, imageTime);\n                    }\n                } else {\n                    Log.d(TAG, \"Killing cuz corrupted data\");\n                    break;\n                }\n            }\n            Log.d(TAG, \"Receive thread throw broken socket\");\n            throwBrokenSocket();\n        }\n    }\n\n    public void restartSocket(){\n        Log.d(TAG, \"Restarting socket.\");\n        connectionEvent(1);\n\n        outbound_heart_beats = 0;\n\n        //close the previous socket now that it's broken/being restarted\n        killSocket();\n\n        //make sure socket thread has joined before throwing off a new one\n        try {\n            SocketThread.join();\n        } catch (InterruptedException e){\n            e.printStackTrace();\n        }\n\n        //start a new socket thread\n        SocketThread = new Thread(new SocketThread());\n        SocketThread.start();\n    }\n\n    public void killSocket(){\n        try {\n            Log.d(TAG, \"Closing socket, input, serverSocket, etc.\");\n            if (serverSocket != null && (!serverSocket.isClosed())) {\n                serverSocket.close();\n                serverSocket = null;\n            }\n            if (socket != null){\n                socket.close();\n                socket = null;\n            }\n            if (output != null){\n                output.close();\n                output = null;\n            }\n            if (input != null){\n                input.close();\n                input = null;\n            }\n        } catch (IOException e) {\n            Log.d(TAG, \"killSocket failed\");\n            e.printStackTrace();\n        }\n    }\n\n\n    public byte[] my_int_to_bb_be(int myInteger){\n        return ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(myInteger).array();\n    }\n\n    public void sendBytes(byte[] id, byte [] data){\n        //first, send hello\n        byte [] hello = {0x01, 0x02, 0x03};\n        //then send length of body\n        byte[] len;\n        if (data != null) {\n            len = my_int_to_bb_be(data.length);\n        } else {\n            len = my_int_to_bb_be(0);\n        }\n        //then send id of message type\n        byte [] msg_id = id;\n        //then send data\n        byte [] body = data;\n        //then send end tag - eventually make this unique to the image\n        byte [] goodbye = {0x3, 0x2, 0x1};\n        //combine those into a payload\n        ByteArrayOutputStream outputStream;\n        try {\n            outputStream = new ByteArrayOutputStream();\n            outputStream.write(hello);\n            outputStream.write(len);\n            outputStream.write(msg_id);\n            if (body != null) {\n                outputStream.write(body);\n            }\n            outputStream.write(goodbye);\n        } catch (IOException e){\n            connectionEvent(0);\n            return;\n        }\n        byte [] payload = outputStream.toByteArray();\n\n        //send it in a background thread\n        //new Thread(new SendThread(payload)).start();\n        queue.add(payload);\n    }\n\n    //this sends messages\n    class SendThread implements Runnable {\n        SendThread() {\n        }\n        @Override\n        public void run() {\n            queue.clear();\n            while (true){\n                if (killme){\n                    return;\n                }\n                if (mConnectState != 2){\n                    break;\n                }\n                if (queue.size() > 10){\n                    break;\n                }\n                byte [] data;\n                try {\n                    data = queue.poll(100, TimeUnit.MILLISECONDS); //block until there is something we can pull out to send\n                    if (data == null){\n                        continue;\n                    }\n                } catch (InterruptedException e){\n                    e.printStackTrace();\n                    break;\n                }\n                try {\n                    output.write(data);           // write the message\n                } catch (java.io.IOException e) {\n                    e.printStackTrace();\n                    break;\n                }\n            }\n            Log.d(TAG, \"Send thread throw broken socket\");\n            throwBrokenSocket();\n        }\n    }\n\n    public  void throwBrokenSocket(){\n        if (mConnectState == 2){\n            Log.d(TAG, \"Throwing broken socket\");\n            connectionEvent(0);\n        }\n    }\n    //^^^ SOCKET STUFF\n\n    public int getConnectionState(){\n        return mConnectState;\n    }\n\n    public void destroy(){\n        Log.d(TAG, \"Destroying AndroidSGC\");\n        killme = true;\n\n        //kill AudioSystem\n        audioSystem.destroy();\n\n        //kill asgWebSocket\n        asgWebSocket.destroy();\n\n        //stop sending heart beats\n        heart_beat_handler.removeCallbacksAndMessages(null);\n\n        //stop advertising broadcasting IP\n        if (adv_handler != null) {\n            adv_handler.removeCallbacksAndMessages(null);\n        }\n\n        //stop sockets\n        killSocket();\n\n        //kill this socket\n        try {\n            Log.i(TAG, \"SOCKETTHREAD TRYNA JOIN\");\n            if (SocketThread != null) {\n                SocketThread.join();\n            }\n            Log.i(TAG, \"SOCKETTHREAD JOINED\");\n            Log.i(TAG, \"SENDTTHREAD TRYNA JOIN\");\n            if (SendThread != null) {\n                SendThread.join();\n            }\n            Log.i(TAG, \"SENDTTHREAD JOINED\");\n            Log.i(TAG, \"RECEIVE THREAD TRYNA JOIN\");\n            if (ReceiveThread != null) {\n                ReceiveThread.join();\n            }\n            Log.i(TAG, \"RECEIVE THREAD JOINED\");\n        } catch (InterruptedException e){\n            e.printStackTrace();\n            Log.d(TAG, \"Error waiting for threads to joing\");\n        }\n    }\n\n    public void displayReferenceCardSimple(String title, String body){\n        try{\n            //build json object to send command result\n            JSONObject commandResponseObject = new JSONObject();\n            commandResponseObject.put(MessageTypes.MESSAGE_TYPE_LOCAL, MessageTypes.REFERENCE_CARD_SIMPLE_VIEW);\n            commandResponseObject.put(MessageTypes.REFERENCE_CARD_SIMPLE_VIEW_TITLE, title);\n            commandResponseObject.put(MessageTypes.REFERENCE_CARD_SIMPLE_VIEW_BODY, body);\n\n            //send the command result to web socket, to send to asg\n            dataObservable.onNext(commandResponseObject);\n        } catch (JSONException e){\n            e.printStackTrace();\n        }\n    }\n\n    public void displayTextWall(String text){\n        Log.d(TAG, \"SHOWING TEXT WALL\");\n        try{\n            //build json object to send command result\n            JSONObject commandResponseObject = new JSONObject();\n            commandResponseObject.put(MessageTypes.MESSAGE_TYPE_LOCAL, MessageTypes.REFERENCE_CARD_TEXT_WALL_VIEW);\n            commandResponseObject.put(MessageTypes.REFERENCE_CARD_TEXT_WALL_TEXT, text);\n\n            //send the command result to web socket, to send to asg\n            dataObservable.onNext(commandResponseObject);\n        } catch (JSONException e){\n            e.printStackTrace();\n        }\n    }\n\n\n    public void displayDoubleTextWall(String textTop, String textBottom){\n        Log.d(TAG, \"TODO: SHOWING DOUBLE TEXT WALL\");\n        displayTextWall(textTop + textBottom);\n    }\n\n    public void displayReferenceCardImage(String title, String body, String imgUrl){\n        try{\n            //build json object to send command result\n            JSONObject commandResponseObject = new JSONObject();\n            commandResponseObject.put(MessageTypes.MESSAGE_TYPE_LOCAL, MessageTypes.REFERENCE_CARD_IMAGE_VIEW);\n            commandResponseObject.put(MessageTypes.REFERENCE_CARD_IMAGE_VIEW_TITLE, title);\n            commandResponseObject.put(MessageTypes.REFERENCE_CARD_IMAGE_VIEW_BODY, body);\n            commandResponseObject.put(MessageTypes.REFERENCE_CARD_IMAGE_VIEW_IMG_URL, imgUrl);\n\n            //send the command result to web socket, to send to asg\n            dataObservable.onNext(commandResponseObject);\n        } catch (JSONException e){\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public void displayBitmap(Bitmap bmp) {\n\n    }\n\n    public void displayBulletList(String title, String [] bullets){\n        displayBulletList(title, bullets, 0);\n    }\n\n    public void displayBulletList(String title, String [] bullets, int lingerTime){\n\n    }\n\n    public void stopScrollingTextViewMode() {\n        Log.d(TAG, \"STOP SCROLLING TEXT VIEW\");\n        try{\n            //build json object to send command result\n            JSONObject commandResponseObject = new JSONObject();\n            commandResponseObject.put(MessageTypes.MESSAGE_TYPE_LOCAL, MessageTypes.SCROLLING_TEXT_VIEW_STOP);\n\n            //send the command result to web socket, to send to asg\n            dataObservable.onNext(commandResponseObject);\n        } catch (JSONException e){\n            e.printStackTrace();\n        }\n    }\n\n    public void startScrollingTextViewMode(String title){\n        super.startScrollingTextViewMode(title);\n        Log.d(TAG, \"START SCROLLING TEXT VIEW\");\n        try{\n            //build json object to send command result\n            JSONObject commandResponseObject = new JSONObject();\n            commandResponseObject.put(MessageTypes.MESSAGE_TYPE_LOCAL, MessageTypes.SCROLLING_TEXT_VIEW_START);\n            commandResponseObject.put(MessageTypes.SCROLLING_TEXT_VIEW_TITLE, title);\n\n            //send the command result to web socket, to send to asg\n            dataObservable.onNext(commandResponseObject);\n        } catch (JSONException e){\n            e.printStackTrace();\n        }\n    }\n\n    public void scrollingTextViewIntermediateText(String text){\n        try{\n            //build json object to send command result\n            JSONObject commandResponseObject = new JSONObject();\n            commandResponseObject.put(MessageTypes.MESSAGE_TYPE_LOCAL, MessageTypes.SCROLLING_TEXT_VIEW_INTERMEDIATE);\n            commandResponseObject.put(MessageTypes.SCROLLING_TEXT_VIEW_TEXT, text);\n\n            //send the command result to web socket, to send to asg\n            dataObservable.onNext(commandResponseObject);\n        } catch (JSONException e){\n            e.printStackTrace();\n        }\n\n    }\n\n    public void scrollingTextViewFinalText(String text){\n        try{\n            //build json object to send command result\n            JSONObject commandResponseObject = new JSONObject();\n            commandResponseObject.put(MessageTypes.MESSAGE_TYPE_LOCAL, MessageTypes.SCROLLING_TEXT_VIEW_FINAL);\n            commandResponseObject.put(MessageTypes.SCROLLING_TEXT_VIEW_TEXT, text);\n\n            //send the command result to web socket, to send to asg\n            dataObservable.onNext(commandResponseObject);\n        } catch (JSONException e){\n            e.printStackTrace();\n        }\n    }\n\n    public void showHomeScreen(){\n        try{\n            //build json object to send command result\n            JSONObject commandResponseObject = new JSONObject();\n            commandResponseObject.put(MessageTypes.MESSAGE_TYPE_LOCAL, MessageTypes.ACTION_SWITCH_MODES);\n            commandResponseObject.put(MessageTypes.NEW_MODE, MessageTypes.MODE_HOME);\n\n            //send the command result to web socket, to send to asg\n            dataObservable.onNext(commandResponseObject);\n        } catch (JSONException e){\n            e.printStackTrace();\n        }\n    }\n\n    public void displayPromptView(String prompt, String [] options){\n        //generate args list\n        if (options != null) {\n\n            //required args\n//            try{\n//                JSONArray argsList = new JSONArray();\n//                for (String s : options) {\n//                    argsList.put(s);\n//                }\n//                JSONObject wakeWordFoundEvent = new JSONObject();\n//                wakeWordFoundEvent.put(MessageTypes.MESSAGE_TYPE_LOCAL, MessageTypes.VOICE_COMMAND_STREAM_EVENT);\n//                wakeWordFoundEvent.put(MessageTypes.VOICE_COMMAND_STREAM_EVENT_TYPE, MessageTypes.REQUIRED_ARG_EVENT_TYPE);\n//                wakeWordFoundEvent.put(MessageTypes.ARG_NAME, prompt);\n//                wakeWordFoundEvent.put(MessageTypes.ARG_OPTIONS, argsList);\n//                dataObservable.onNext(wakeWordFoundEvent);\n//            } catch (JSONException e){\n//                e.printStackTrace();\n//            }\n\n\n            //natural language arg\n//            try {\n//                JSONObject commandFoundEvent = new JSONObject();\n//                commandFoundEvent.put(MessageTypes.MESSAGE_TYPE_LOCAL, MessageTypes.VOICE_COMMAND_STREAM_EVENT);\n//                commandFoundEvent.put(MessageTypes.VOICE_COMMAND_STREAM_EVENT_TYPE, MessageTypes.COMMAND_EVENT_TYPE);\n//                commandFoundEvent.put(MessageTypes.INPUT_VOICE_COMMAND_NAME, command);\n//                commandFoundEvent.put(MessageTypes.INPUT_WAKE_WORD, this.wakeWordGiven);\n//                commandFoundEvent.put(MessageTypes.VOICE_ARG_EXPECT_TYPE, MessageTypes.VOICE_ARG_EXPECT_NATURAL_LANGUAGE);\n//                dataObservable.onNext(commandFoundEvent);\n//            } catch (JSONException e){\n//                e.printStackTrace();\n//            }\n\n            //found wake word\n            JSONArray argsList = new JSONArray();\n            for (String s : options) {\n                argsList.put(s);\n            }\n            try {\n                JSONObject wakeWordFoundEvent = new JSONObject();\n                wakeWordFoundEvent.put(MessageTypes.MESSAGE_TYPE_LOCAL, MessageTypes.VOICE_COMMAND_STREAM_EVENT);\n                wakeWordFoundEvent.put(MessageTypes.VOICE_COMMAND_STREAM_EVENT_TYPE, MessageTypes.WAKE_WORD_EVENT_TYPE);\n                wakeWordFoundEvent.put(MessageTypes.VOICE_COMMAND_LIST, argsList.toString());\n                wakeWordFoundEvent.put(MessageTypes.INPUT_WAKE_WORD, prompt);\n                dataObservable.onNext(wakeWordFoundEvent);\n            } catch (JSONException e){\n                e.printStackTrace();\n            }\n        }\n    }\n\n    public void displayTextLine(String text){\n        displayReferenceCardSimple(\"\", text);\n    }\n\n    public void displayCenteredText(String text){\n        //TODO: Complete this\n        displayTextLine(text);\n    }\n\n    public void displayCustomContent(String json) {\n        displayReferenceCardSimple(\"CustomDisplayNotImplemented\", json);\n    }\n\n\n    public void showNaturalLanguageCommandScreen(String prompt, String naturalLanguageArgs){\n        try {\n            JSONObject commandFoundEvent = new JSONObject();\n            commandFoundEvent.put(MessageTypes.MESSAGE_TYPE_LOCAL, MessageTypes.VOICE_COMMAND_STREAM_EVENT);\n            commandFoundEvent.put(MessageTypes.VOICE_COMMAND_STREAM_EVENT_TYPE, MessageTypes.COMMAND_EVENT_TYPE);\n            commandFoundEvent.put(MessageTypes.INPUT_VOICE_COMMAND_NAME, \"myCommand\");\n            commandFoundEvent.put(MessageTypes.INPUT_WAKE_WORD, \"myWakeWord\");\n            commandFoundEvent.put(MessageTypes.VOICE_ARG_EXPECT_TYPE, MessageTypes.VOICE_ARG_EXPECT_NATURAL_LANGUAGE);\n            dataObservable.onNext(commandFoundEvent);\n        } catch (JSONException e){\n            e.printStackTrace();\n        }\n    }\n\n    public void updateNaturalLanguageCommandScreen(String naturalLanguageArgs){\n        try {\n                JSONObject commandFoundEvent = new JSONObject();\n                commandFoundEvent.put(MessageTypes.MESSAGE_TYPE_LOCAL, MessageTypes.VOICE_COMMAND_STREAM_EVENT);\n                commandFoundEvent.put(MessageTypes.VOICE_COMMAND_STREAM_EVENT_TYPE, MessageTypes.COMMAND_ARGS_EVENT_TYPE);\n                commandFoundEvent.put(MessageTypes.INPUT_VOICE_STRING, naturalLanguageArgs);\n                dataObservable.onNext(commandFoundEvent);\n        } catch (JSONException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void handleImage(byte [] raw_data, long imageTime){\n        //convert to bitmap\n        Bitmap bitmap = BitmapFactory.decodeByteArray(raw_data, 0, raw_data.length);\n\n        //save and process 1 image at set frequency\n        sendPovImage(raw_data, imageTime);\n    }\n\n    public void sendPovImage(byte [] img, long imageTime){\n        String encodedImage = Base64.encodeToString(img, Base64.DEFAULT);\n        EventBus.getDefault().post(new GlassesPovImageEvent(encodedImage, imageTime));\n    }\n\n    public void setFontSize(SmartGlassesFontSize fontSize){}\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/smartglassescommunicators/AudioWearableSGC.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.smartglassescommunicators;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.util.Log;\n\nimport com.teamopensmartglasses.smartglassesmanager.eventbusmessages.TextToSpeechEvent;\n\nimport org.greenrobot.eventbus.EventBus;\n\npublic class AudioWearableSGC extends SmartGlassesCommunicator {\n    private static final String TAG = \"WearableAi_AndroidWearableSGC\";\n\n    private static boolean killme;\n\n    Context context;\n\n    public AudioWearableSGC(Context context){\n        super();\n\n        //state information\n        killme = false;\n        mConnectState = 0;\n    }\n\n    public void setFontSizes(){\n    }\n\n    public void connectToSmartGlasses(){\n        connectionEvent(2);\n    }\n\n    public void blankScreen(){\n    }\n\n    public void displayRowsCard(String[] rowStrings){\n\n    }\n\n    public void destroy(){\n        killme = true;\n    }\n\n    public void displayReferenceCardSimple(String title, String body){\n        Log.d(TAG, \"TTS reference card\");\n        EventBus.getDefault().post(new TextToSpeechEvent(title + \", \" + body, \"english\"));\n    }\n\n    public void displayReferenceCardImage(String title, String body, String imgUrl){\n        Log.d(TAG, \"TTS reference card\");\n        EventBus.getDefault().post(new TextToSpeechEvent(title + \", \" + body, \"english\"));\n    }\n\n    public void displayBulletList(String title, String [] bullets){\n        displayBulletList(title, bullets, 0);\n    }\n\n    public void displayBulletList(String title, String [] bullets, int lingerTime){\n\n    }\n\n    public void displayTextWall(String text){}\n    public void displayDoubleTextWall(String textTop, String textBottom){}\n\n    public void stopScrollingTextViewMode() {\n    }\n\n    public void startScrollingTextViewMode(String title){\n    }\n\n    public void scrollingTextViewIntermediateText(String text){\n    }\n\n    public void scrollingTextViewFinalText(String text){\n    }\n\n    public void showHomeScreen(){\n    }\n\n    public void displayPromptView(String prompt, String [] options){\n    }\n\n    public void displayTextLine(String text){\n        Log.d(TAG, \"displayTextLine: \" + text);\n        EventBus.getDefault().post(new TextToSpeechEvent(text, \"english\"));\n    }\n\n    @Override\n    public void displayBitmap(Bitmap bmp) {\n\n    }\n\n    public void displayCenteredText(String text){\n        //TODO: Find a way to add (optional) pauses between lines?\n        displayTextLine(text);\n    }\n\n    @Override\n    public void displayCustomContent(String json) {\n        displayTextLine(json);\n    }\n\n\n    public void showNaturalLanguageCommandScreen(String prompt, String naturalLanguageArgs){\n    }\n\n    public void updateNaturalLanguageCommandScreen(String naturalLanguageArgs){\n    }\n\n    public void setFontSize(SmartGlassesFontSize fontSize){}\n}"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/smartglassescommunicators/SmartGlassesCommunicator.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.smartglassescommunicators;\n\nimport android.graphics.Bitmap;\n\nimport com.teamopensmartglasses.augmentoslib.events.GlassesTapOutputEvent;\nimport com.teamopensmartglasses.smartglassesmanager.eventbusmessages.SmartGlassesConnectionEvent;\n\nimport org.greenrobot.eventbus.EventBus;\n\npublic abstract class SmartGlassesCommunicator {\n    //basic glasses utils/settings\n    public int mConnectState = 0;\n    protected SmartGlassesModes currentMode;\n    public abstract void connectToSmartGlasses();\n    public abstract void blankScreen();\n    public abstract void destroy();\n    public final String commandNaturalLanguageString = \"Command: \";\n    public final String finishNaturalLanguageString = \"'finish command' when done\";\n\n    //reference card\n    public abstract void displayReferenceCardSimple(String title, String body);\n\n    //display text wall\n    public abstract void displayTextWall(String text);\n    public abstract void displayDoubleTextWall(String textTop, String textBottom);\n\n    public abstract void displayReferenceCardImage(String title, String body, String imgUrl);\n    public abstract void displayBulletList(String title, String [] bullets);\n    public abstract void displayRowsCard(String[] rowStrings);\n\n    //voice command UI\n    public abstract void showNaturalLanguageCommandScreen(String prompt, String naturalLanguageArgs);\n    public abstract void updateNaturalLanguageCommandScreen(String naturalLanguageArgs);\n\n    //scrolling text view\n    public void startScrollingTextViewMode(String title){\n        setMode(SmartGlassesModes.SCROLLING_TEXT_VIEW);\n    }\n\n    public abstract void scrollingTextViewIntermediateText(String text);\n    public abstract void scrollingTextViewFinalText(String text);\n    public abstract void stopScrollingTextViewMode();\n\n    //prompt view card\n    public abstract void displayPromptView(String title, String [] options);\n\n    //display text line\n    public abstract void displayTextLine(String text);\n\n    public abstract void displayBitmap(Bitmap bmp);\n\n    //display centered text\n    public abstract void displayCenteredText(String text);\n\n    public abstract void displayCustomContent(String json);\n\n    //home screen\n    public abstract void showHomeScreen();\n\n    public abstract void setFontSize(SmartGlassesFontSize fontSize);\n\n    //fonts\n    public int LARGE_FONT;\n    public int MEDIUM_FONT;\n    public int SMALL_FONT;\n\n    public SmartGlassesCommunicator(){\n        setFontSizes();\n    }\n\n    //must be run and set font sizes\n    protected abstract void setFontSizes();\n\n    public int getConnectionState(){\n        return mConnectState;\n    }\n\n    protected boolean isConnected(){\n        return (mConnectState == 2);\n    }\n\n    public void connectionEvent(int connectState){\n        mConnectState = connectState;\n        EventBus.getDefault().post(new SmartGlassesConnectionEvent(mConnectState));\n        if (isConnected()) {\n            showHomeScreen();\n        }\n    }\n\n    public void tapEvent(int num){\n        EventBus.getDefault().post(new GlassesTapOutputEvent(num, false, System.currentTimeMillis()));\n    }\n\n    public void setMode(SmartGlassesModes mode){\n        currentMode = mode;\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/smartglassescommunicators/SmartGlassesFontSize.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.smartglassescommunicators;\n\npublic enum SmartGlassesFontSize {\n    SMALL,\n    MEDIUM,\n    LARGE\n\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/smartglassescommunicators/SmartGlassesModes.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.smartglassescommunicators;\n\npublic enum SmartGlassesModes {\n    SCROLLING_TEXT_VIEW,\n    SCREEN_OFF\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/smartglassescommunicators/TextLineSG.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.smartglassescommunicators;\n\npublic class TextLineSG {\n    private String text;\n    private int fontSize;\n\n    public TextLineSG(String text, int fontSize){\n        this.text = text;\n        this.fontSize = fontSize;\n    }\n\n    public String getText() {\n        return text;\n    }\n\n    public void setText(String text) {\n        this.text = text;\n    }\n\n    public int getFontSizeCode() {\n        return fontSize;\n    }\n\n    public void setFontSize(int fontSize) {\n        this.fontSize = fontSize;\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/smartglassescommunicators/UltraliteLayoutHelper.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.smartglassescommunicators;\n\nimport com.vuzix.ultralite.Layout;\n\npublic class UltraliteLayoutHelper {\n    public static String getJsonTag(Layout layout) {\n        return layout.getJsonTag();\n    }\n\n    public static String getCustomJsonTag(String layout) {\n        switch (layout) {\n            case \"TEXT_TOP_LEFT_ALIGN\":\n                return \"ttla\";\n            default:\n                return \"\";\n        }\n    }\n}"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/smartglassescommunicators/UltraliteSGC.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.smartglassescommunicators;\n\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Typeface;\nimport android.graphics.drawable.Drawable;\nimport android.os.Handler;\nimport android.util.Log;\n\nimport androidx.lifecycle.LifecycleOwner;\nimport androidx.lifecycle.LiveData;\n\nimport com.teamopensmartglasses.smartglassesmanager.R;\nimport com.squareup.picasso.Picasso;\nimport com.squareup.picasso.Target;\nimport com.vuzix.ultralite.Anchor;\nimport com.vuzix.ultralite.EventListener;\nimport com.vuzix.ultralite.Layout;\nimport com.vuzix.ultralite.TextAlignment;\nimport com.vuzix.ultralite.TextWrapMode;\nimport com.vuzix.ultralite.UltraliteColor;\nimport com.vuzix.ultralite.UltraliteSDK;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\n\n\n//communicate with ActiveLook smart glasses\npublic class UltraliteSGC extends SmartGlassesCommunicator {\n    private static final String TAG = \"WearableAi_UltraliteSGC\";\n\n    UltraliteSDK ultraliteSdk;\n    UltraliteSDK.Canvas ultraliteCanvas;\n    UltraliteListener ultraliteListener;\n    Layout currentUltraliteLayout;\n    boolean screenToggleOff = false; //should we keep the screen off?\n    LifecycleOwner lifecycleOwner;\n    Context context;\n    public static final int cardLingerTime = 15;\n\n    private ArrayList rowTextsLiveNow;\n\n    //ultralite pixel buffer on left side of screen\n    int ultraliteLeftSidePixelBuffer = 40;\n\n    // Constants for maximum lines and characters per line //depends on size of pixel buffer! //for MEDIUM text!\n    private int maxLines = 12; // Adjusted from 11.5 for practical use\n    private int maxCharsPerLine = 38; // Assuming max 27 characters fit per line on your display\n\n    //handler to turn off screen\n    Handler goHomeHandler;\n    Runnable goHomeRunnable;\n\n    //handler to turn off screen/toggle\n    Handler screenOffHandler;\n    Runnable screenOffRunnable;\n\n    //handler to disconnect\n    Handler killHandler;\n\n    boolean hasUltraliteControl;\n    boolean screenIsClear;\n\n    public class UltraliteListener implements EventListener{\n        @Override\n        public void onTap(int tapCount) {\n            Log.d(TAG, \"Ultralite go tap n times: \" + tapCount);\n            tapEvent(tapCount);\n        }\n\n        @Override\n        public void onDisplayTimeout() {\n            Log.d(TAG, \"Ultralite display timeout.\");\n        }\n\n        @Override\n        public void onPowerButtonPress(boolean turningOn) {\n            //since we implement our own state for the power turn on/off, we ignore what the ultralite thinks ('turningOn') and use our own state\n            Log.d(TAG, \"Ultralites power button pressed: \" + turningOn);\n\n            //flip value of screen toggle\n            screenToggleOff = !turningOn;\n\n            if (!screenToggleOff) {\n                Log.d(TAG, \"screen toggle off NOT on, showing turn ON message\");\n                displayReferenceCardSimple(\"SGM Connected.\", \"Screen back on...\", 4);\n            } else {\n                Log.d(TAG, \"screen toggle off IS on, showing turn OFF message\");\n//                ultraliteCanvas.clear();\n//                displayReferenceCardSimple(\"Toggling off....\", \"Toggling off...\", -1);\n//                screenOffHandler.removeCallbacksAndMessages(this);\n//                screenOffHandler.removeCallbacksAndMessages(screenOffRunnable);\n//                screenOffRunnable = new Runnable() {\n//                    @Override\n//                    public void run() {\n//                        ultraliteSdk.screenOff();\n//                    }\n//                };\n//                screenOffHandler.postDelayed(screenOffRunnable, 2200);\n            }\n        }\n    }\n\n    public UltraliteSGC(Context context, LifecycleOwner lifecycleOwner) {\n        super();\n        this.lifecycleOwner = lifecycleOwner;\n        this.context = context;\n\n        mConnectState = 0;\n        hasUltraliteControl = false;\n        screenIsClear = true;\n        goHomeHandler = new Handler();\n        screenOffHandler = new Handler();\n        killHandler = new Handler();\n\n        rowTextsLiveNow = new ArrayList<Integer>();\n\n        ultraliteSdk = UltraliteSDK.get(context);\n        ultraliteListener = new UltraliteListener();\n        ultraliteSdk.addEventListener(ultraliteListener);\n\n        LiveData<Boolean> ultraliteConnectedLive = ultraliteSdk.getConnected();\n        ultraliteConnectedLive.observe(lifecycleOwner, isConnected -> {\n            onUltraliteConnectedChange(isConnected);\n        });\n\n        LiveData<Boolean> ultraliteControlled = ultraliteSdk.getControlledByMe();\n        ultraliteControlled.observe(lifecycleOwner, isControlled -> {\n            onUltraliteControlChanged(isControlled);\n        });\n\n//        if (ultraliteSdk.isAvailable()){\n//            Log.d(TAG, \"Ultralite SDK is available.\");\n//        } else {\n//            Log.d(TAG, \"Ultralite SDK is NOT available.\");\n//        }\n    }\n\n    private void onUltraliteConnectedChange(boolean isConnected) {\n        Log.d(TAG, \"Ultralite CONNECT changed to: \" + isConnected);\n        if (isConnected) {\n            Log.d(TAG, \"Ultralite requesting control...\");\n            boolean isControlled = ultraliteSdk.requestControl();\n            if (isControlled){\n//                setupUltraliteCanvas();\n                changeUltraliteLayout(Layout.CANVAS);\n            } else {\n                return;\n            }\n            Log.d(TAG, \"Ultralite RESULT control request: \" + isControlled);\n            connectionEvent(2);\n        } else {\n            Log.d(TAG, \"Ultralite not connected.\");\n            connectionEvent(0);\n        }\n    }\n\n    private void onUltraliteControlChanged(boolean isControlledByMe) {\n        Log.d(TAG, \"Ultralite CONTROL changed to: \" + isControlledByMe);\n        if(isControlledByMe) {\n            hasUltraliteControl = true;\n            setupUltraliteCanvas();\n            connectionEvent(2);\n            displayReferenceCardSimple(\"Connected to SGM\", \"by TeamOpenSmartGlasses\", 5);\n        } else {\n            hasUltraliteControl = false;\n        }\n//        mUltraliteControlledByMe = isControlledByMe;\n    }\n\n    @Override\n    protected void setFontSizes(){\n    }\n\n    @Override\n    public void connectToSmartGlasses(){\n        Log.d(TAG, \"connectToSmartGlasses running...\");\n//        int mCount = 10;\n//        while ((mConnectState != 2) && (!hasUltraliteControl) && (mCount > 0)){\n//            mCount--;\n//            try {\n//                Log.d(TAG, \"Don't have Ultralite yet, let's wait for it...\");\n//                Thread.sleep(200);\n//            } catch (InterruptedException e) {\n//                e.printStackTrace();\n//            }\n//        }\n//        Log.d(TAG, \"Connected to Ultralites.\");\n//        Log.d(TAG, \"mCOnnectestate: \" + mConnectState);\n//        Log.d(TAG, \"mCOunt: \" + mCount);\n//        displayReferenceCardSimple(\"Connected to SGM.\", \"Authors: TeamOpenSmartGlasses\");\n//        connectionEvent(mConnectState);\n        Log.d(TAG, \"connectToSmartGlasses finished\");\n    }\n\n    public void displayTextLine(String text){\n        displayReferenceCardSimple(\"\", text);\n    }\n\n    private static final int MAX_LINES = 7;\n    public void displayTextWall(String text) {\n        String cleanedText = cleanText(text);\n\n        if (screenToggleOff) {\n            return;\n        }\n\n        goHomeHandler.removeCallbacksAndMessages(null);\n        goHomeHandler.removeCallbacksAndMessages(goHomeRunnable);\n\n        Log.d(TAG, \"Ultralite is doing text wall\");\n\n        // Cut text wall down to the largest number of lines possible to display\n        String[] lines = cleanedText.split(\"\\n\");\n        StringBuilder truncatedText = new StringBuilder();\n        for (int i = 0; i < Math.min(lines.length, MAX_LINES); i++) {\n            truncatedText.append(lines[i]).append(\"\\n\");\n        }\n\n//        changeUltraliteLayout(Layout.TEXT_BOTTOM_LEFT_ALIGN);\n        changeUltraliteLayout(Layout.TEXT_BOTTOM_LEFT_ALIGN);\n        ultraliteSdk.sendText(truncatedText.toString().trim());\n\n//        changeUltraliteLayout(Layout.CANVAS);\n//        ultraliteCanvas.removeText(0); //remove last text we added\n//        Anchor ultraliteAnchor = Anchor.TOP_LEFT;\n//        TextAlignment ultraliteAlignment = TextAlignment.LEFT;\n//        int textId = ultraliteCanvas.createText(text, ultraliteAlignment, UltraliteColor.WHITE, ultraliteAnchor, ultraliteLeftSidePixelBuffer, 0, 640 - ultraliteLeftSidePixelBuffer, -1, TextWrapMode.WRAP, true);\n////        ultraliteCanvas.createText(title, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.TOP_LEFT, ultraliteLeftSidePixelBuffer, 120, 640 - ultraliteLeftSidePixelBuffer, -1, TextWrapMode.WRAP, true);\n//        Log.d(TAG, \"VUZIX TEXT ID: \" + textId);\n        ultraliteCanvas.commit();\n        screenIsClear = false;\n    }\n\n    private String cleanText(String input) {\n        // Replace Chinese punctuation with English equivalents\n        String cleaned = input.replace(\" ，\", \", \")\n                .replace(\"，\", \", \")\n                .replace(\" 。\", \".\")\n                .replace(\"。\", \".\")\n                .replace(\" ！\", \"!\")\n                .replace(\" ？\", \"?\")\n                .replace(\"？\", \"?\")\n                .replace(\"：\", \":\")\n                .replace(\"；\", \";\")\n                .replace(\"（\", \"(\")\n                .replace(\"）\", \")\")\n                .replace(\"【\", \"[\")\n                .replace(\"】\", \"]\")\n                .replace(\"“\", \"\\\"\")\n                .replace(\"”\", \"\\\"\")\n                .replace(\"、\", \",\") // No quotes around this one\n                .replace(\"‘\", \"'\")\n                .replace(\"’\", \"'\");\n\n        // Fix contractions: handle spaces around apostrophes\n        cleaned = cleaned.replaceAll(\"\\\\s+'\\\\s*\", \"'\");\n\n        // Remove any non-breaking spaces and trim leading/trailing spaces\n//        cleaned = cleaned.replace(\"\\u00A0\", \" \").trim();\n\n        return cleaned;\n    }\n\n    public static int countNewLines(String str) {\n        int count = 0;\n        for (int i = 0; i < str.length(); i++) {\n            if (str.charAt(i) == '\\n') {\n                count++;\n            }\n        }\n        return count;\n    }\n\n    public void displayDoubleTextWall(String textTop, String textBottom) {\n        if (screenToggleOff) {\n            return;\n        }\n\n        textTop = cleanText(textTop);\n        textBottom = cleanText(textBottom);\n\n//        if (textBottom.endsWith(\"\\n\")) {\n//            textBottom = textBottom.substring(0, textBottom.length() - 1);\n//        }\n\n        goHomeHandler.removeCallbacksAndMessages(null);\n        goHomeHandler.removeCallbacksAndMessages(goHomeRunnable);\n\n//        int rowsTop = 5;\n        int rowsTop = 5 - countNewLines(textTop);\n\n        StringBuilder combinedText = new StringBuilder();\n        combinedText.append(textTop);\n\n        for (int i = 0; i < rowsTop; i++) {\n            combinedText.append(\"\\n\");\n        }\n\n        StringBuilder bottomBuilder = new StringBuilder(textBottom);\n\n        combinedText.append(bottomBuilder);\n\n        // Display the combined text using TEXT_BOTTOM_LEFT_ALIGN layout\n        changeUltraliteLayout(Layout.TEXT_BOTTOM_LEFT_ALIGN);\n        // ultraliteSdk.sendText(combinedText.toString().trim());\n        ultraliteSdk.sendText(combinedText.toString());\n        ultraliteCanvas.commit();\n        screenIsClear = false;\n    }\n\n    public void displayCenteredText(String text){\n    }\n\n    public void displayCustomContent(String json) {\n        displayReferenceCardSimple(\"CustomDisplayNotImplemented\", json);\n    }\n\n\n    public void showNaturalLanguageCommandScreen(String prompt, String naturalLanguageInput){\n//        int boxDelta = 3;\n//\n//        if (connectedGlasses != null) {\n//            connectedGlasses.clear();\n//            showPromptCircle();\n//\n//            //show the prompt\n//            lastLocNaturalLanguageArgsTextView = displayText(new TextLineSG(prompt, SMALL_FONT), new Point(0, 11), true);\n//            lastLocNaturalLanguageArgsTextView = new Point(lastLocNaturalLanguageArgsTextView.x, lastLocNaturalLanguageArgsTextView.y + boxDelta); //margin down a tad\n//\n//            //show the final \"finish command\" prompt\n//            int finishY = 90;\n//            displayLine(new Point(0, finishY), new Point(100, finishY));\n//            displayText(new TextLineSG(finishNaturalLanguageString, SMALL_FONT), new Point(0, finishY + 2), true);\n//\n//            //show the natural language args in a scroll box\n////            ArrayList<TextLineSG> nli = new ArrayList<>();\n////            nli.add(new TextLineSG(naturalLanguageInput, SMALL_FONT));\n////            lastLocNaturalLanguageArgsTextView = scrollTextShow(nli, startScrollBoxY.y + boxDelta, finishY - boxDelta);\n//        }\n    }\n\n    public void updateNaturalLanguageCommandScreen(String naturalLanguageArgs){\n//        Log.d(TAG, \"Displaynig: \" + naturalLanguageArgs);\n//        displayText(new TextLineSG(naturalLanguageArgs, SMALL_FONT), new Point(0, lastLocNaturalLanguageArgsTextView.y));\n    }\n\n    public void blankScreen(){\n//        if (connectedGlasses != null){\n//            connectedGlasses.clear();\n//        }\n    }\n\n    @Override\n    public void destroy(){\n       if (ultraliteSdk != null){\n//           displayReferenceCardSimple(\"Disconnecting...\", \"Disconnecting Smart Glasses from SGM\");\n//\n//           //disconnect after slight delay, so our above text gets a chance to show up\n//           killHandler.postDelayed(new Runnable() {\n//               @Override\n//               public void run() {\n//                   ultraliteSdk.releaseControl();\n//               }\n//           }, 800);\n           ultraliteSdk.removeEventListener(ultraliteListener);\n           ultraliteSdk.releaseControl();\n       }\n    }\n\n    public void showHomeScreen(){\n        changeUltraliteLayout(Layout.CANVAS);\n        ultraliteCanvas.clear();\n        screenIsClear = true;\n    }\n\n    public void setupUltraliteCanvas(){\n        Log.d(TAG, \"Setting up ultralite canvas\");\n        if (ultraliteSdk != null) {\n            ultraliteCanvas = ultraliteSdk.getCanvas();\n        }\n    }\n\n    public void changeUltraliteLayout(Layout chosenLayout) {\n        //don't update layout if it's already setup\n        if (currentUltraliteLayout != null && currentUltraliteLayout == chosenLayout){\n            return;\n        }\n\n        currentUltraliteLayout = chosenLayout;\n        ultraliteSdk.setLayout(chosenLayout, 0, true);\n\n        if (chosenLayout.equals(Layout.CANVAS)){\n            if (ultraliteCanvas == null){\n                setupUltraliteCanvas();\n            }\n        }\n    }\n\n    public void startScrollingTextViewMode(String title){\n        super.startScrollingTextViewMode(title);\n\n        if (ultraliteSdk == null) {\n            return;\n        }\n\n        //clear the screen\n        ultraliteCanvas.clear();\n        drawTextOnUltralite(title);\n    }\n\n    public String addNewlineEveryNWords(String input, int n) {\n        String[] words = input.split(\"\\\\s+\");\n        StringBuilder result = new StringBuilder();\n\n        for (int i = 0; i < words.length; i++) {\n            result.append(words[i]);\n            if ((i + 1) % n == 0 && i != words.length - 1) {\n                result.append(\"\\n\");\n            } else if (i != words.length - 1) {\n                result.append(\" \");\n            }\n        }\n\n        return result.toString();\n    }\n\n    public void drawTextOnUltralite(String text){\n        //edit the text to add new lines to it because ultralite wrapping doesn't work\n        String wrappedText = addNewlineEveryNWords(text, 6);\n\n        //display the title at the top of the screen\n        UltraliteColor ultraliteColor = UltraliteColor.WHITE;\n        Anchor ultraliteAnchor = Anchor.TOP_LEFT;\n        TextAlignment ultraliteAlignment = TextAlignment.LEFT;\n        changeUltraliteLayout(Layout.CANVAS);\n        ultraliteCanvas.clear();\n        ultraliteCanvas.clearBackground(UltraliteColor.DIM);\n//        ultraliteCanvas.createText(text, ultraliteAlignment, ultraliteColor, ultraliteAnchor, true);\n//        ultraliteCanvas.createText(text, ultraliteAlignment, ultraliteColor, Anchor.BOTTOM_LEFT, 0, 0, -1, 80, TextWrapMode.WRAP, true);\n        ultraliteCanvas.createText(wrappedText, ultraliteAlignment, ultraliteColor, ultraliteAnchor, true); //, 0, 0, -1, -1, TextWrapMode.WRAP, true);\n        ultraliteCanvas.commit();\n        screenIsClear = false;\n    }\n\n    public Bitmap getBitmapFromDrawable(Resources res) {\n        return BitmapFactory.decodeResource(res, R.drawable.vuzix_shield);\n    }\n\n    public void displayReferenceCardSimple(String title, String body){\n       displayReferenceCardSimple(title, body, cardLingerTime);\n    }\n\n//    public void displayReferenceCardSimple(String title, String body, int lingerTime){\n//        if (!isConnected()) {\n//            Log.d(TAG, \"Not showing reference card because not connected to Ultralites...\");\n//            return;\n//        }\n//\n////        String [] bulletPoints = {\"first one\", \"second one\", \"dogs and cats\"};\n////        displayBulletList(\"Cool Bullets:\", bulletPoints, 15);\n//\n//            Log.d(TAG, \"Sending text to Ultralite SDK: \\n\" + body);\n////            ultraliteSdk.sendText(\"hello world\"); //this is BROKEN in Vuzix ultralite 0.4.2 SDK - crashes Vuzix OEM Platform android app\n//\n//        //edit the text to add new lines to it because ultralite wrapping doesn't work\n////        String titleWrapped = addNewlineEveryNWords(title, 6);\n////        String bodyWrapped = addNewlineEveryNWords(body, 6);\n//\n//        //display the title at the top of the screen\n//        UltraliteColor ultraliteColor = UltraliteColor.WHITE;\n//        Anchor ultraliteAnchor = Anchor.TOP_LEFT;\n//        TextAlignment ultraliteAlignment = TextAlignment.LEFT;\n//        changeUltraliteLayout(Layout.CANVAS);\n//        ultraliteCanvas.clear();\n//        ultraliteCanvas.createText(title, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.TOP_LEFT, ultraliteLeftSidePixelBuffer, 120, 640 - ultraliteLeftSidePixelBuffer, -1, TextWrapMode.WRAP, true);\n//        ultraliteCanvas.createText(body, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.MIDDLE_LEFT, ultraliteLeftSidePixelBuffer, 0, 640 - ultraliteLeftSidePixelBuffer, -1, TextWrapMode.WRAP, true);\n//        ultraliteCanvas.commit();\n//        screenIsClear = false;\n//\n//        homeScreenInNSeconds(lingerTime);\n//    }\n\n    public void setFontSize(SmartGlassesFontSize fontSize){\n        int textSize;\n        switch (fontSize){\n            case SMALL:\n                textSize = 24;\n                maxLines = 14;\n                maxCharsPerLine = 42;\n                break;\n            case MEDIUM:\n                textSize = 29;\n                maxLines = 12; // Adjusted from 11.5 for practical use\n                maxCharsPerLine = 38; // Assuming max 27 characters fit per line on your display\n                break;\n            case LARGE:\n                textSize = 40;\n                maxLines = 7;\n                maxCharsPerLine = 28;\n                break;\n            default:\n                throw new IllegalArgumentException(\"Unknown font size: \" + fontSize);\n        }\n        ultraliteSdk.setFont(null, 0, textSize);\n    }\n\n    public void displayReferenceCardSimple(String titleStr, String bodyStr, int lingerTime){\n        if (screenToggleOff){\n            return;\n        }\n\n        String title = maybeReverseRTLString(titleStr);\n        String body = maybeReverseRTLString(bodyStr);\n        if (!isConnected()) {\n            Log.d(TAG, \"Not showing reference card because not connected to Ultralites...\");\n            return;\n        }\n\n        changeUltraliteLayout(Layout.CANVAS);\n        ultraliteCanvas.clear();\n\n//        String [] bulletPoints = {\"first one\", \"second one\", \"dogs and cats\"};\n//        displayBulletList(\"Cool Bullets:\", bulletPoints, 15);\n\n            Log.d(TAG, \"Sending text to Ultralite SDK: \\n\" + body);\n//            ultraliteSdk.sendText(\"hello world\"); //this is BROKEN in Vuzix ultralite 0.4.2 SDK - crashes Vuzix OEM Platform android app\n\n        //edit the text to add new lines to it because ultralite wrapping doesn't work\n//        String titleWrapped = addNewlineEveryNWords(title, 6);\n//        String bodyWrapped = addNewlineEveryNWords(body, 6);\n\n        //display title top of scren adn text middle of screen\n//        UltraliteColor ultraliteColor = UltraliteColor.WHITE;\n//        Anchor ultraliteAnchor = Anchor.TOP_LEFT;\n//        TextAlignment ultraliteAlignment = TextAlignment.LEFT;\n//        ultraliteCanvas.createText(title, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.TOP_LEFT, ultraliteLeftSidePixelBuffer, 120, 640 - ultraliteLeftSidePixelBuffer, -1, TextWrapMode.WRAP, true);\n//        ultraliteCanvas.createText(body, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.MIDDLE_LEFT, ultraliteLeftSidePixelBuffer, 0, 640 - ultraliteLeftSidePixelBuffer, -1, TextWrapMode.WRAP, true);\n\n        //concat body and title, put text on top right of screen (to not block main view)\n        UltraliteColor ultraliteColor = UltraliteColor.WHITE;\n        Anchor ultraliteAnchor = Anchor.TOP_CENTER;\n        TextAlignment ultraliteAlignment = TextAlignment.LEFT;\n        //ultraliteCanvas.createText(body, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.TOP_RIGHT, 0, 0, (640 / 2) - ultraliteLeftSidePixelBuffer, -1, TextWrapMode.WRAP, true);\n        if (!title.isEmpty() && !title.equals(\"\")){\n            ultraliteCanvas.createText(title + \": \" + body, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.TOP_RIGHT, 0, 0, 640 / 2, -1, TextWrapMode.WRAP, true);\n        } else {\n            ultraliteCanvas.createText(body, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.TOP_RIGHT, 0, 0, 640 / 2, -1, TextWrapMode.WRAP, true);\n        }\n\n        //NOTE:\n//        int createText(@NonNull\n//                String text,\n//                @NonNull\n//                        TextAlignment alignment,\n//                @NonNull\n//                        UltraliteColor color,\n//                @NonNull\n//                        Anchor anchor,\n//        int offsetX,\n//        int offsetY,\n//        int width,\n//        int height,\n//        @Nullable\n//        TextWrapMode wrap,\n//        boolean visible)\n\n        ultraliteCanvas.commit();\n        screenIsClear = false;\n\n        homeScreenInNSeconds(lingerTime);\n    }\n\n\n    public void displayBulletList(String title, String [] bullets){\n        displayBulletList(title, bullets, 14);\n    }\n\n    public void displayRowsCard(String[] rowStrings){\n        displayRowsCard(rowStrings, cardLingerTime);\n    }\n\n    public void displayRowsCard(String[] rowStringList, int lingerTime){\n        if (screenToggleOff){\n            return;\n        }\n\n        String[] rowStrings = maybeReverseRTLStringList(rowStringList);\n        if (!isConnected()) {\n            Log.d(TAG, \"Not showing rows card because not connected to Ultralites...\");\n            return;\n        }\n\n//        changeUltraliteLayout(Layout.CANVAS);\n//        ultraliteCanvas.clear();\n\n        //make lines to draw on screen to delineate rows\n        int line_thickness = 3;\n        for (int y = 120; y < 480; y += 120) {\n            ultraliteCanvas.clearBackgroundRect(0, y, 640, line_thickness, UltraliteColor.DIM);\n        }\n\n        //clear old text\n        for (int i = 0; i < rowTextsLiveNow.size(); i++){\n            ultraliteCanvas.removeText(i);\n        }\n        //old way to clear old text - vuzix ultralite sdk bug that clear background doesn't clear text?\n//        for (int y = 0; y < 480; y += 120) {\n//            //clear previous text\n//            ultraliteCanvas.clearBackgroundRect(0, y + line_thickness, 640, 120 - line_thickness, UltraliteColor.DIM);\n//            ultraliteCanvas.clearBackgroundRect(0, y + line_thickness, 640, 120 - line_thickness, UltraliteColor.BLACK);\n//        }\n//        ultraliteCanvas.commit();\n\n        //display the title at the top of the screen\n        UltraliteColor ultraliteColor = UltraliteColor.WHITE;\n        Anchor ultraliteAnchor = Anchor.TOP_LEFT;\n        TextAlignment ultraliteAlignment = TextAlignment.LEFT;\n\n        //if no input, just show the lines\n        if (rowStrings.length == 0){\n            ultraliteCanvas.commit();\n            screenIsClear = false;\n//            homeScreenInNSeconds(lingerTime);\n            return;\n        }\n\n        //go throw rows, draw the text, don't do more than 4\n        int y_start_height = 55;\n        // Reverse rowStrings array\n        Collections.reverse(Arrays.asList(rowStrings));\n        int numRows = 4;\n        int actualRows = Math.min(rowStrings.length, numRows);\n        for (int i = 0; i < actualRows; i++) {\n            // Calculate the offset to start from the bottom for 1, 2, or 3 values\n            int yOffset = (numRows - actualRows) * 112;\n            int textId = ultraliteCanvas.createText(rowStrings[i], TextAlignment.CENTER, UltraliteColor.WHITE, Anchor.TOP_LEFT, ultraliteLeftSidePixelBuffer, y_start_height + yOffset + (i * 112), 640 - ultraliteLeftSidePixelBuffer, -1, TextWrapMode.WRAP, true);\n            rowTextsLiveNow.add(textId);\n        }\n\n        ultraliteCanvas.commit();\n        screenIsClear = false;\n//        homeScreenInNSeconds(cardLingerTime);\n    }\n\n    public void displayBulletList(String title, String [] bulletList, int lingerTime){\n        if (screenToggleOff){\n            return;\n        }\n\n        String[] bullets = maybeReverseRTLStringList(bulletList);\n        if (!isConnected()) {\n            Log.d(TAG, \"Not showing bullet point list because not connected to Ultralites...\");\n            return;\n        }\n\n        Log.d(TAG, \"Sending bullets to Ultralite SDK: \" + title);\n\n        //display the title at the top of the screen\n        UltraliteColor ultraliteColor = UltraliteColor.WHITE;\n        Anchor ultraliteAnchor = Anchor.TOP_LEFT;\n        TextAlignment ultraliteAlignment = TextAlignment.LEFT;\n        changeUltraliteLayout(Layout.CANVAS);\n        ultraliteCanvas.clear();\n\n        ultraliteCanvas.createText(title, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.TOP_LEFT, 0, 0, 640, -1, TextWrapMode.WRAP, true);\n        int displaceY = 25;\n        int displaceX = 25;\n        for (String bullet : bullets){\n            ultraliteCanvas.createText(\"⬤ \" + bullet, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.TOP_LEFT, displaceX, displaceY, 640 - displaceX, -1, TextWrapMode.WRAP, true);\n            displaceY += 125;\n        }\n\n        ultraliteCanvas.commit();\n        screenIsClear = false;\n\n//        if (lingerTime > 0){\n//            homeScreenInNSeconds(lingerTime);\n//        }\n    }\n\n    public void homeScreenInNSeconds(int n){\n        if (n == -1){\n            return;\n        }\n\n       //disconnect after slight delay, so our above text gets a chance to show up\n       goHomeHandler.removeCallbacksAndMessages(null);\n       goHomeHandler.removeCallbacksAndMessages(goHomeRunnable);\n       goHomeRunnable = new Runnable() {\n           @Override\n           public void run() {\n               showHomeScreen();\n        }};\n       goHomeHandler.postDelayed(goHomeRunnable, n * 1000);\n    }\n\n    public void displayBitmap(Bitmap bmp) {\n        Bitmap resizedBmp = Bitmap.createScaledBitmap(bmp, 620, 460, true); // 640 x 480\n\n        changeUltraliteLayout(Layout.CANVAS);\n        screenIsClear = false;\n\n        Log.d(TAG, \"Sending bitmap to Ultralite\");\n        ultraliteCanvas.drawBackground(resizedBmp, 50, 80);\n        ultraliteCanvas.commit();\n    }\n\n    //don't show images on activelook (screen is too low res)\n    public void displayReferenceCardImage(String title, String body, String imgUrl){\n        if (screenToggleOff){\n            return;\n        }\n\n        changeUltraliteLayout(Layout.CANVAS);\n        ultraliteCanvas.clear();\n\n        //make image\n        //below works, but only for very, very low res/size images\n        Anchor ultraliteImageAnchor = Anchor.CENTER;\n        Picasso.get()\n                .load(imgUrl)\n                .into(new Target() {\n                    @Override\n                    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {\n                        // Use the bitmap\n//                        LVGLImage ultraliteImage = LVGLImage.fromBitmap(getBitmapFromDrawable(context.getResources()), CF_INDEXED_2_BIT);\n//                        LVGLImage ultraliteImage = LVGLImage.fromBitmap(bitmap, CF_INDEXED_2_BIT);\n                        changeUltraliteLayout(Layout.CANVAS);\n\n                        //send text first, cuz this is fast\n                        ultraliteCanvas.createText(title, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.TOP_LEFT, 0, 0, 640, -1, TextWrapMode.WRAP, true);\n                        ultraliteCanvas.createText(body, TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.BOTTOM_LEFT, 0, 0, 640, -1, TextWrapMode.WRAP, true);\n                        ultraliteCanvas.commit();\n                        screenIsClear = false;\n\n                        Log.d(TAG, \"Sending image to Ultralite\");\n//                        ultraliteCanvas.createImage(ultraliteImage, ultraliteImageAnchor, 0, 0, true);\n                        ultraliteCanvas.drawBackground(bitmap, 0, 0);\n\n                        //sending text again to ultralite in case image overwrote it\n//                        ultraliteCanvas.createText(title + \"2\", TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.BOTTOM_LEFT, 0, 0, 640, -1, TextWrapMode.WRAP, true);\n//                        ultraliteCanvas.createText(body + \"2\", TextAlignment.AUTO, UltraliteColor.WHITE, Anchor.MIDDLE_LEFT, 0, 0, 640, -1, TextWrapMode.WRAP, true);\n//                        ultraliteCanvas.commit();\n\n//                        //display the title at the top of the screen\n//                        UltraliteColor ultraliteColor = UltraliteColor.WHITE;\n//                        TextAlignment ultraliteAlignment = TextAlignment.LEFT;\n//                //        ultraliteCanvas.clearBackground(UltraliteColor.DIM);\n//                        ultraliteCanvas.createText(titleWrapped, ultraliteAlignment, ultraliteColor, Anchor.TOP_LEFT, true); //, 0, 0, -1, -1, TextWrapMode.WRAP, true);\n//                        ultraliteCanvas.createText(bodyWrapped, ultraliteAlignment, ultraliteColor, Anchor.BOTTOM_LEFT, true); //, 0, 0, -1, -1, TextWrapMode.WRAP, true);\n//                        ultraliteCanvas.commit();\n\n\n\n//                        homeScreenInNSeconds(cardLingerTime);\n                    }\n\n                    @Override\n                    public void onBitmapFailed(Exception e, Drawable errorDrawable) {\n                        // Handle the error\n                        Log.d(TAG, \"Bitmap failed\");\n                        e.printStackTrace();\n                    }\n\n                    @Override\n                    public void onPrepareLoad(Drawable placeHolderDrawable) {\n                        // Called before the image is loaded. You can set a placeholder if needed.\n                    }\n                });\n\n            //edit the text to add new lines to it because ultralite wrapping doesn't work\n//            String titleWrapped = addNewlineEveryNWords(title, 6);\n//            String bodyWrapped = addNewlineEveryNWords(body, 6);\n//\n//            //display the title at the top of the screen\n//            UltraliteColor ultraliteColor = UltraliteColor.WHITE;\n//            TextAlignment ultraliteAlignment = TextAlignment.LEFT;\n//            //ultraliteCanvas.clearBackground(UltraliteColor.DIM);\n//            ultraliteCanvas.createText(titleWrapped, ultraliteAlignment, ultraliteColor, Anchor.TOP_LEFT, true); //, 0, 0, -1, -1, TextWrapMode.WRAP, true);\n//            ultraliteCanvas.createText(bodyWrapped, ultraliteAlignment, ultraliteColor, Anchor.BOTTOM_LEFT, true); //, 0, 0, -1, -1, TextWrapMode.WRAP, true);\n//            ultraliteCanvas.commit();\n//            screenIsClear = false;\n    }\n\n    //handles text wrapping, returns final position of last line printed\n//    private Point displayText(TextLineSG textLine, Point percentLoc, boolean centered){\n//        if (!isConnected()){\n//            return null;\n//        }\n//\n//        //get info about the wrapping\n//        Pair wrapInfo = computeStringWrapInfo(textLine);\n//        int numWraps = (int)wrapInfo.first;\n//        int wrapLenNumChars = (int)wrapInfo.second;\n//\n//        //loop through the text, writing out individual lines to the glasses\n//        ArrayList<String> chunkedText = new ArrayList<>();\n//        Point textPoint = percentLoc;\n//        int textMarginY = computeMarginPercent(textLine.getFontSizeCode()); //(fontToSize.get(textLine.getFontSize()) * 1.3)\n//        for (int i = 0; i <= numWraps; i++){\n//            int startIdx = wrapLenNumChars * i;\n//            int endIdx = Math.min(startIdx + wrapLenNumChars, textLine.getText().length());\n//            String subText = textLine.getText().substring(startIdx, endIdx).trim();\n//            chunkedText.add(subText);\n//            TextLineSG thisTextLine = new TextLineSG(subText, textLine.getFontSizeCode());\n//            if (!centered) {\n//                sendTextToGlasses(thisTextLine, textPoint);\n//            } else {\n//                int xPercentLoc = computeStringCenterInfo(thisTextLine);\n//                sendTextToGlasses(thisTextLine, new Point(xPercentLoc, textPoint.y));\n//            }\n//            textPoint = new Point(textPoint.x, textPoint.y + pixelToPercent(displayHeightPixels, fontToSize.get(textLine.getFontSizeCode())) + textMarginY); //lower our text for the next loop\n//        }\n//\n//        return textPoint;\n//    }\n\n    public void stopScrollingTextViewMode() {\n//        if (connectedGlasses == null) {\n//            return;\n//        }\n//\n//        //clear the screen\n//        connectedGlasses.clear();\n    }\n\n    public void scrollingTextViewIntermediateText(String text){\n    }\n\n    public void scrollingTextViewFinalText(String text){\n        if (!isConnected()){\n            return;\n        }\n\n//        //save to our saved list of final scrolling text strings\n//        finalScrollingTextStrings.add(text);\n//\n//        //get the max number of wraps allows\n//        float allowedTextRows = computeAllowedTextRows(fontToSize.get(scrollingTextTitleFontSize), fontToSize.get(scrollingTextTextFontSize), percentToPixel(displayHeightPixels, computeMarginPercent(scrollingTextTextFontSize)));\n//\n//        //figure out the maximum we can display\n//        int totalRows = 0;\n//        ArrayList<String> finalTextToDisplay = new ArrayList<>();\n//        boolean hitBottom = false;\n//        for (int i = finalScrollingTextStrings.toArray().length - 1; i >= 0; i--){\n//            String finalText = finalScrollingTextStrings.get(i);\n//            //convert to a TextLine type with small font\n//            TextLineSG tlString = new TextLineSG(finalText, SMALL_FONT);\n//            //get info about the wrapping of this string\n//            Pair wrapInfo = computeStringWrapInfo(tlString);\n//            int numWraps = (int)wrapInfo.first;\n//            int wrapLenNumChars = (int)wrapInfo.second;\n//            totalRows += numWraps + 1;\n//\n//            if (totalRows > allowedTextRows){\n//                finalScrollingTextStrings = finalTextToDisplay;\n//                lastLocScrollingTextView = belowTitleLocScrollingTextView;\n//                //clear the glasses as we hit our limit and need to redraw\n//                connectedGlasses.color((byte)0x00);\n//                connectedGlasses.rectf(percentScreenToPixelsLocation(belowTitleLocScrollingTextView.x, belowTitleLocScrollingTextView.y), percentScreenToPixelsLocation(100, 100));\n//                //stop looping, as we've ran out of room\n//                hitBottom = true;\n//            } else {\n//                finalTextToDisplay.add(0, finalText);\n//            }\n//        }\n//\n//        //display all of the text that we can\n//        if (hitBottom) { //if we ran out of room, we need to redraw all the text\n//            for (String finalString : finalTextToDisplay) {\n//                TextLineSG tlString = new TextLineSG(finalString, scrollingTextTextFontSize);\n//                //write this text at the last location + margin\n//                Log.d(TAG, \"Writing string: \" + tlString.getText() + finalTextToDisplay.size());\n//                lastLocScrollingTextView = displayText(tlString, new Point(0, lastLocScrollingTextView.y));\n//            }\n//        } else { //if we didn't hit the bottom, and there's room, we can just display the next line\n//            TextLineSG tlString = new TextLineSG(text, scrollingTextTextFontSize);\n//            lastLocScrollingTextView = displayText(tlString, new Point(0, lastLocScrollingTextView.y));\n//        }\n\n    }\n\n    public static String maybeReverseRTLString(String text) {\n        StringBuilder result = new StringBuilder();\n        StringBuilder rtlBuffer = new StringBuilder();\n\n        for (char c : text.toCharArray()) {\n            if (isRTLCharacter(c)) {\n                rtlBuffer.append(c); // Append RTL characters to a buffer\n            } else {\n                if (rtlBuffer.length() > 0) {\n                    result.append(rtlBuffer.reverse()); // Reverse and append RTL text when a non-RTL character is found\n                    rtlBuffer.setLength(0); // Clear the buffer\n                }\n                result.append(c); // Append non-RTL characters directly to the result\n            }\n        }\n\n        if (rtlBuffer.length() > 0) {\n            result.append(rtlBuffer.reverse()); // Append any remaining RTL text in reverse\n        }\n\n        return result.toString();\n    }\n\n    private static boolean isRTLCharacter(char c) {\n        Character.UnicodeBlock block = Character.UnicodeBlock.of(c);\n        return block == Character.UnicodeBlock.ARABIC ||\n                block == Character.UnicodeBlock.HEBREW ||\n                block == Character.UnicodeBlock.SYRIAC ||\n                block == Character.UnicodeBlock.ARABIC_SUPPLEMENT ||\n                block == Character.UnicodeBlock.THAANA ||\n                block == Character.UnicodeBlock.NKO ||\n                block == Character.UnicodeBlock.SAMARITAN ||\n                block == Character.UnicodeBlock.MANDAIC ||\n                block == Character.UnicodeBlock.ARABIC_EXTENDED_A;\n        // Add other RTL blocks as needed\n    }\n    public String[] maybeReverseRTLStringList(String[] in){\n        String[] out = new String[in.length];\n        for(int i = 0; i < in.length; i++)\n            out[i] = maybeReverseRTLString(in[i]);\n        return out;\n    }\n\n    public void displayPromptView(String prompt, String [] options){\n        if (!isConnected()){\n            return;\n        }\n\n//        ultraliteCanvas.clear();\n//        connectedGlasses.clear();\n//        showPromptCircle();\n//\n//        //show the prompt and options, if any\n//        ArrayList<Object> promptPageElements = new ArrayList<>();\n//        promptPageElements.add(new TextLineSG(prompt, LARGE_FONT));\n//        if (options != null) {\n//            //make an array list of options\n//            for (String s : options){\n//               promptPageElements.add(new TextLineSG(s, SMALL_FONT));\n//            }\n//        }\n//        displayLinearStuff(promptPageElements, new Point(0, 11), true);\n    }\n\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/ASR_FRAMEWORKS.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.speechrecognition;\n\npublic enum ASR_FRAMEWORKS {\n    GOOGLE_ASR_FRAMEWORK,\n    DEEPGRAM_ASR_FRAMEWORK,\n    AZURE_ASR_FRAMEWORK\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/SpeechRecFramework.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.speechrecognition;\n\nimport android.content.Context;\n\npublic abstract class SpeechRecFramework {\n    private ASR_FRAMEWORKS asrFramework;\n    private Context mContext;\n    public boolean pauseAsrFlag = false;\n\n    public abstract void start();\n    public abstract void destroy();\n    public abstract void ingestAudioChunk(byte [] audioChunk);\n\n    public void pauseAsr(boolean pauseAsrFlag){\n        this.pauseAsrFlag = pauseAsrFlag;\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/SpeechRecSwitchSystem.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.speechrecognition;\n\nimport android.content.Context;\nimport android.util.Log;\n\nimport com.teamopensmartglasses.augmentoslib.events.AudioChunkNewEvent;\nimport com.teamopensmartglasses.smartglassesmanager.eventbusmessages.PauseAsrEvent;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.azure.SpeechRecAzure;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.deepgram.SpeechRecDeepgram;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.SpeechRecGoogle;\n\nimport org.greenrobot.eventbus.EventBus;\nimport org.greenrobot.eventbus.Subscribe;\n\n//send audio to one of the built in ASR frameworks.\npublic class SpeechRecSwitchSystem {\n    private final String TAG = \"WearableAi_SpeechRecSwitchSystem\";\n    private ASR_FRAMEWORKS asrFramework;\n    private SpeechRecFramework speechRecFramework;\n    private SpeechRecGoogle speechRecGoogle;\n    private Context mContext;\n    public String currentLanguage;\n\n    public SpeechRecSwitchSystem(Context mContext) {\n        this.mContext = mContext;\n    }\n\n    public void startAsrFramework(ASR_FRAMEWORKS asrFramework) {\n        startAsrFramework(asrFramework, \"English\");\n    }\n\n    public void startAsrFramework(ASR_FRAMEWORKS asrFramework, String language) {\n        //kill old asr\n        EventBus.getDefault().unregister(this);\n        if (speechRecFramework != null){\n            speechRecFramework.destroy();\n        }\n\n        //set language\n        this.currentLanguage = language;\n\n        //set new asr\n        this.asrFramework = asrFramework;\n\n        //create new asr\n        if (this.asrFramework == ASR_FRAMEWORKS.GOOGLE_ASR_FRAMEWORK){\n            speechRecFramework = new SpeechRecGoogle(mContext, language);\n        } else if (this.asrFramework == ASR_FRAMEWORKS.DEEPGRAM_ASR_FRAMEWORK){\n            speechRecFramework = new SpeechRecDeepgram(mContext, language);\n        } else if (this.asrFramework == ASR_FRAMEWORKS.AZURE_ASR_FRAMEWORK){\n            speechRecFramework = new SpeechRecAzure(mContext, language);\n        }\n\n        //start asr\n        speechRecFramework.start();\n        EventBus.getDefault().register(this);\n    }\n\n    public void startAsrFramework(ASR_FRAMEWORKS asrFramework, String transcribeLanguage, String sourceLanguage) {\n        //kill old asr\n        EventBus.getDefault().unregister(this);\n        if (speechRecFramework != null){\n            speechRecFramework.destroy();\n        }\n\n//        if (!(this.asrFramework == ASR_FRAMEWORKS.AZURE_ASR_FRAMEWORK)) {\n//            Log.e(TAG, \"startAsrFramework: This function is only for Azure ASR\");\n//            return;\n//        }\n\n\n        //set language\n        this.currentLanguage = transcribeLanguage;\n\n        //set new asr\n        this.asrFramework = asrFramework;\n\n        //create new asr\n        speechRecFramework = new SpeechRecAzure(mContext, transcribeLanguage, sourceLanguage);\n\n        //start asr\n        speechRecFramework.start();\n        EventBus.getDefault().register(this);\n    }\n\n    @Subscribe\n    public void onAudioChunkNewEvent(AudioChunkNewEvent receivedEvent){\n        //redirect audio to the currently in use ASR framework, if it's not paused\n        if (!speechRecFramework.pauseAsrFlag) {\n            speechRecFramework.ingestAudioChunk(receivedEvent.thisChunk);\n        }\n    }\n\n    @Subscribe\n    public void onPauseAsrEvent(PauseAsrEvent receivedEvent){\n        //redirect audio to the currently in use ASR framework\n        speechRecFramework.pauseAsr(receivedEvent.pauseAsr);\n    }\n\n    public void destroy(){\n        if (speechRecFramework != null){\n            speechRecFramework.destroy();\n        }\n        EventBus.getDefault().unregister(this);\n    }\n}\n\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/azure/AzureAudioInputStream.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.speechrecognition.azure;\n\nimport com.microsoft.cognitiveservices.speech.audio.AudioStreamFormat;\nimport com.microsoft.cognitiveservices.speech.audio.PullAudioInputStreamCallback;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.LinkedBlockingQueue;\n\npublic class AzureAudioInputStream extends PullAudioInputStreamCallback {\n\n    private static final int SAMPLE_RATE = 16000;\n    private static final short BITS_PER_SAMPLE = 16;\n    private static final short CHANNELS = 1;\n\n    private final AudioStreamFormat format;\n    private final BlockingQueue<byte[]> audioQueue;\n    private byte[] leftoverChunk;\n    private int leftoverOffset;\n\n    private static AzureAudioInputStream instance;\n\n    private AzureAudioInputStream() {\n        this.format = AudioStreamFormat.getWaveFormatPCM(SAMPLE_RATE, BITS_PER_SAMPLE, CHANNELS);\n        this.audioQueue = new LinkedBlockingQueue<>();\n        this.leftoverChunk = null;\n        this.leftoverOffset = 0;\n    }\n\n    public static synchronized AzureAudioInputStream getInstance() {\n        if (instance == null) {\n            instance = new AzureAudioInputStream();\n        }\n        return instance;\n    }\n\n    public void push(byte[] audioChunk) {\n        audioQueue.add(audioChunk);\n    }\n\n    @Override\n    public int read(byte[] dataBuffer) {\n        int bytesRead = 0;\n\n        try {\n            if (leftoverChunk != null) {\n                int length = Math.min(leftoverChunk.length - leftoverOffset, dataBuffer.length);\n                System.arraycopy(leftoverChunk, leftoverOffset, dataBuffer, 0, length);\n                leftoverOffset += length;\n                bytesRead = length;\n\n                if (leftoverOffset >= leftoverChunk.length) {\n                    leftoverChunk = null;\n                    leftoverOffset = 0;\n                }\n            }\n\n            while (bytesRead < dataBuffer.length) {\n                byte[] chunk = audioQueue.take(); // Blocks if queue is empty\n                int length = Math.min(chunk.length, dataBuffer.length - bytesRead);\n                System.arraycopy(chunk, 0, dataBuffer, bytesRead, length);\n                bytesRead += length;\n\n                if (length < chunk.length) {\n                    leftoverChunk = chunk;\n                    leftoverOffset = length;\n                    break;\n                }\n            }\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            return 0;\n        }\n\n        return bytesRead;\n    }\n\n    @Override\n    public void close() {\n        audioQueue.clear();\n    }\n\n    public AudioStreamFormat getFormat() {\n        return this.format;\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/azure/SpeechRecAzure.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.speechrecognition.azure;\n\nimport android.content.Context;\nimport android.util.Log;\n\nimport com.microsoft.cognitiveservices.speech.Connection;\nimport com.microsoft.cognitiveservices.speech.PhraseListGrammar;\nimport com.microsoft.cognitiveservices.speech.ProfanityOption;\nimport com.microsoft.cognitiveservices.speech.SpeechConfig;\nimport com.microsoft.cognitiveservices.speech.SpeechRecognizer;\nimport com.microsoft.cognitiveservices.speech.audio.AudioConfig;\nimport com.microsoft.cognitiveservices.speech.translation.SpeechTranslationConfig;\nimport com.microsoft.cognitiveservices.speech.translation.TranslationRecognizer;\nimport com.teamopensmartglasses.augmentoslib.events.SpeechRecOutputEvent;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.SpeechRecFramework;\nimport org.greenrobot.eventbus.EventBus;\n\nimport java.math.BigInteger;\nimport java.util.Map;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\npublic class SpeechRecAzure extends SpeechRecFramework {\n    private static final String API_KEY = \"0a2244c410664011bbf33fdb2cdc0f30\";\n    private static final String REGION = \"eastasia\";\n    private static final String TAG = \"WearableAi_SpeechRecAzure\";\n\n    private SpeechConfig speechConfig;\n    private SpeechRecognizer speechRecognizer;\n\n    private SpeechTranslationConfig speechTranslationConfig;\n    private TranslationRecognizer translationRecognizer;\n\n    private ExecutorService executorService = Executors.newCachedThreadPool();\n    private Context mContext;\n    private String currentLanguageCode;\n    private String targetLanguageCode;\n    private boolean isTranslation;\n\n    public SpeechRecAzure(Context context, String languageLocale) {\n        this.mContext = context;\n        this.currentLanguageCode = initLanguageLocale(languageLocale);\n        this.isTranslation = false;\n    }\n\n    public SpeechRecAzure(Context context, String currentLanguageLocale, String targetLanguageLocale) {\n        this.mContext = context;\n        this.currentLanguageCode = initLanguageLocale(currentLanguageLocale);\n        this.targetLanguageCode = initLanguageLocale(targetLanguageLocale);\n        this.isTranslation = true;\n    }\n\n    @Override\n    public void start() {\n        Log.d(TAG, \"Starting Azure Speech Service\");\n        if (isTranslation) {\n            initializeTranslationRecognizer();\n        } else {\n            initializeSpeechRecognizer();\n        }\n    }\n\n    private void stopReco() {\n        Log.d(TAG, \"Attempting to stop continuous recognition.\");\n        if (isTranslation && translationRecognizer != null) {\n            executorService.submit(() -> {\n                try {\n                    translationRecognizer.stopContinuousRecognitionAsync().get();\n                    Log.i(TAG, \"Continuous translation stopped.\");\n                } catch (Exception e) {\n                    Log.e(TAG, \"Failed to stop continuous translation: \" + e.getMessage());\n                } finally {\n                    translationRecognizer.close();\n                    translationRecognizer = null;\n                    Log.i(TAG, \"TranslationRecognizer instance closed and set to null.\");\n                    AzureAudioInputStream.getInstance().close();\n                }\n            });\n        } else if (!isTranslation && speechRecognizer != null) {\n            executorService.submit(() -> {\n                try {\n                    speechRecognizer.stopContinuousRecognitionAsync().get();\n                    Log.i(TAG, \"Continuous recognition stopped.\");\n                } catch (Exception e) {\n                    Log.e(TAG, \"Failed to stop continuous recognition: \" + e.getMessage());\n                } finally {\n                    speechRecognizer.close();\n                    speechRecognizer = null;\n                    Log.i(TAG, \"SpeechRecognizer instance closed and set to null.\");\n                    AzureAudioInputStream.getInstance().close();\n                }\n            });\n        }\n    }\n\n    @Override\n    public void destroy() {\n        stopReco();\n        Log.d(TAG, \"--- Azure speech service destroyed.\");\n    }\n\n    @Override\n    public void ingestAudioChunk(byte[] audioChunk) {\n        if (isTranslation && translationRecognizer != null) {\n            AzureAudioInputStream.getInstance().push(audioChunk);\n        } else if (!isTranslation && speechRecognizer != null) {\n            AzureAudioInputStream.getInstance().push(audioChunk);\n        }\n    }\n\n    private void initializeSpeechRecognizer() {\n        speechConfig = SpeechConfig.fromSubscription(API_KEY, REGION);\n        speechConfig.setSpeechRecognitionLanguage(currentLanguageCode);\n        speechConfig.requestWordLevelTimestamps();\n        speechConfig.setProfanity(ProfanityOption.Raw);\n\n        AudioConfig audioConfig = AudioConfig.fromStreamInput(AzureAudioInputStream.getInstance());\n\n        speechRecognizer = new SpeechRecognizer(speechConfig, audioConfig);\n\n        setupPhraseList(speechRecognizer);\n\n        speechRecognizer.recognizing.addEventListener((o, e) -> {\n            String intermediateResult = e.getResult().getText();\n            BigInteger offset = e.getResult().getOffset();\n            if (intermediateResult != null && !intermediateResult.trim().isEmpty()) {\n                EventBus.getDefault().post(new SpeechRecOutputEvent(intermediateResult, offset.longValue(), false));\n            }\n        });\n\n        speechRecognizer.recognized.addEventListener((o, e) -> {\n            String finalResult = e.getResult().getText();\n            BigInteger offset = e.getResult().getOffset();\n            if (finalResult != null && !finalResult.trim().isEmpty()) {\n                EventBus.getDefault().post(new SpeechRecOutputEvent(finalResult, offset.longValue(), true));\n            }\n        });\n\n        Connection connection = Connection.fromRecognizer(speechRecognizer);\n        connection.disconnected.addEventListener((s, connectionEventArgs) -> {\n            Log.e(TAG, \"Disconnected from Azure Speech Service, sessionId: \" + connectionEventArgs.getSessionId());\n            handleDisconnect();\n        });\n\n        executorService.submit(() -> {\n            try {\n                speechRecognizer.startContinuousRecognitionAsync().get();\n                Log.i(TAG, \"Continuous recognition started.\");\n            } catch (Exception e) {\n                Log.e(TAG, \"Error starting continuous recognition: \" + e.getMessage());\n                handleDisconnect();\n            }\n        });\n    }\n\n    private void initializeTranslationRecognizer() {\n        speechTranslationConfig = SpeechTranslationConfig.fromSubscription(API_KEY, REGION);\n        speechTranslationConfig.setSpeechRecognitionLanguage(currentLanguageCode);\n        speechTranslationConfig.addTargetLanguage(targetLanguageCode);\n\n        AudioConfig audioConfig = AudioConfig.fromStreamInput(AzureAudioInputStream.getInstance());\n\n        translationRecognizer = new TranslationRecognizer(speechTranslationConfig, audioConfig);\n\n        translationRecognizer.recognizing.addEventListener((o, e) -> {\n            String intermediateResult = e.getResult().getText();\n            BigInteger offset = e.getResult().getOffset();\n            if (intermediateResult != null && !intermediateResult.trim().isEmpty()) {\n                // Get the single entry from the map\n                Map.Entry<String, String> translation = e.getResult().getTranslations().entrySet().iterator().next();\n                String translatedText = translation.getValue();\n                String targetLanguage = translation.getKey();\n                Log.d(TAG, \"Translated into \" + targetLanguage + \": \" + translatedText);\n                EventBus.getDefault().post(new SpeechRecOutputEvent(intermediateResult, offset.longValue(), false, false));\n                EventBus.getDefault().post(new SpeechRecOutputEvent(translatedText, offset.longValue(), false, true));\n            }\n        });\n\n        translationRecognizer.recognized.addEventListener((o, e) -> {\n            String finalResult = e.getResult().getText();\n            BigInteger offset = e.getResult().getOffset();\n            if (finalResult != null && !finalResult.trim().isEmpty()) {\n                // Get the single entry from the map\n                Map.Entry<String, String> translation = e.getResult().getTranslations().entrySet().iterator().next();\n                String translatedText = translation.getValue();\n                String targetLanguage = translation.getKey();\n                Log.d(TAG, \"Translated into \" + targetLanguage + \": \" + translatedText);\n                EventBus.getDefault().post(new SpeechRecOutputEvent(finalResult, offset.longValue(), true, false));\n                EventBus.getDefault().post(new SpeechRecOutputEvent(translatedText, offset.longValue(), true, true));\n            }\n        });\n\n        Connection connection = Connection.fromRecognizer(translationRecognizer);\n        connection.disconnected.addEventListener((s, connectionEventArgs) -> {\n            Log.e(TAG, \"Disconnected from Azure Speech Service, sessionId: \" + connectionEventArgs.getSessionId());\n            handleDisconnect();\n        });\n\n        executorService.submit(() -> {\n            try {\n                translationRecognizer.startContinuousRecognitionAsync().get();\n                Log.i(TAG, \"Continuous recognition started.\");\n            } catch (Exception e) {\n                Log.e(TAG, \"Error starting continuous recognition: \" + e.getMessage());\n                handleDisconnect();\n            }\n        });\n    }\n\n    private void handleDisconnect() {\n        executorService.submit(() -> {\n            boolean connected = false;\n            while (!connected) {\n                try {\n                    Thread.sleep(1000);\n                    if (speechRecognizer == null){\n                        return;\n                    }\n                    if (isTranslation) {\n                        if (translationRecognizer == null){\n                            return;\n                        }\n                        translationRecognizer.startContinuousRecognitionAsync().get();\n                    } else {\n                        if (speechRecognizer == null){\n                            return;\n                        }\n                        speechRecognizer.startContinuousRecognitionAsync().get();\n                    }\n\n                    connected = true;\n                    Log.i(TAG, \"Reconnected and continuous recognition started.\");\n                } catch (Exception e) {\n                    Log.e(TAG, \"Error reconnecting: \" + e.getMessage());\n                }\n            }\n        });\n    }\n\n    private void setupPhraseList(SpeechRecognizer speechRecognizer) {\n        PhraseListGrammar phraseListGrammar = PhraseListGrammar.fromRecognizer(speechRecognizer);\n        phraseListGrammar.addPhrase(\"Hey Mira\");\n        phraseListGrammar.addPhrase(\"Convoscope\");\n        phraseListGrammar.addPhrase(\"Team Open Smart Glasses\");\n        phraseListGrammar.addPhrase(\"smart glasses\");\n    }\n\n    //below is long list of languages\n    private String initLanguageLocale(String localeString) {\n        switch (localeString) {\n            case \"Afrikaans (South Africa)\":\n                return \"af-ZA\";\n            case \"Amharic (Ethiopia)\":\n                return \"am-ET\";\n            case \"Arabic (United Arab Emirates)\":\n                return \"ar-AE\";\n            case \"Arabic (Bahrain)\":\n                return \"ar-BH\";\n            case \"Arabic (Algeria)\":\n                return \"ar-DZ\";\n            case \"Arabic (Egypt)\":\n                return \"ar-EG\";\n            case \"Arabic (Israel)\":\n                return \"ar-IL\";\n            case \"Arabic (Iraq)\":\n                return \"ar-IQ\";\n            case \"Arabic (Jordan)\":\n                return \"ar-JO\";\n            case \"Arabic (Kuwait)\":\n                return \"ar-KW\";\n            case \"Arabic (Lebanon)\":\n                return \"ar-LB\";\n            case \"Arabic (Libya)\":\n                return \"ar-LY\";\n            case \"Arabic (Morocco)\":\n                return \"ar-MA\";\n            case \"Arabic (Oman)\":\n                return \"ar-OM\";\n            case \"Arabic (Palestinian Authority)\":\n                return \"ar-PS\";\n            case \"Arabic (Qatar)\":\n                return \"ar-QA\";\n            case \"Arabic (Saudi Arabia)\":\n                return \"ar-SA\";\n            case \"Arabic (Syria)\":\n                return \"ar-SY\";\n            case \"Arabic (Tunisia)\":\n                return \"ar-TN\";\n            case \"Arabic (Yemen)\":\n                return \"ar-YE\";\n            case \"Azerbaijani (Latin, Azerbaijan)\":\n                return \"az-AZ\";\n            case \"Bulgarian (Bulgaria)\":\n                return \"bg-BG\";\n            case \"Bengali (India)\":\n                return \"bn-IN\";\n            case \"Bosnian (Bosnia and Herzegovina)\":\n                return \"bs-BA\";\n            case \"Catalan\":\n                return \"ca-ES\";\n            case \"Czech (Czechia)\":\n                return \"cs-CZ\";\n            case \"Welsh (United Kingdom)\":\n                return \"cy-GB\";\n            case \"Danish (Denmark)\":\n                return \"da-DK\";\n            case \"German (Austria)\":\n                return \"de-AT\";\n            case \"German (Switzerland)\":\n                return \"de-CH\";\n            case \"German\":\n            case \"German (Germany)\":\n                return \"de-DE\";\n            case \"Greek (Greece)\":\n                return \"el-GR\";\n            case \"English (Australia)\":\n                return \"en-AU\";\n            case \"English (Canada)\":\n                return \"en-CA\";\n            case \"English (United Kingdom)\":\n                return \"en-GB\";\n            case \"English (Ghana)\":\n                return \"en-GH\";\n            case \"English (Hong Kong SAR)\":\n                return \"en-HK\";\n            case \"English (Ireland)\":\n                return \"en-IE\";\n            case \"English (India)\":\n                return \"en-IN\";\n            case \"English (Kenya)\":\n                return \"en-KE\";\n            case \"English (Nigeria)\":\n                return \"en-NG\";\n            case \"English (New Zealand)\":\n                return \"en-NZ\";\n            case \"English (Philippines)\":\n                return \"en-PH\";\n            case \"English (Singapore)\":\n                return \"en-SG\";\n            case \"English (Tanzania)\":\n                return \"en-TZ\";\n            case \"English\":\n            case \"English (United States)\":\n                return \"en-US\";\n            case \"English (South Africa)\":\n                return \"en-ZA\";\n            case \"Spanish (Argentina)\":\n                return \"es-AR\";\n            case \"Spanish (Bolivia)\":\n                return \"es-BO\";\n            case \"Spanish (Chile)\":\n                return \"es-CL\";\n            case \"Spanish (Colombia)\":\n                return \"es-CO\";\n            case \"Spanish (Costa Rica)\":\n                return \"es-CR\";\n            case \"Spanish (Cuba)\":\n                return \"es-CU\";\n            case \"Spanish (Dominican Republic)\":\n                return \"es-DO\";\n            case \"Spanish (Ecuador)\":\n                return \"es-EC\";\n            case \"Spanish (Spain)\":\n                return \"es-ES\";\n            case \"Spanish (Equatorial Guinea)\":\n                return \"es-GQ\";\n            case \"Spanish (Guatemala)\":\n                return \"es-GT\";\n            case \"Spanish (Honduras)\":\n                return \"es-HN\";\n            case \"Spanish\":\n            case \"Spanish (Mexico)\":\n                return \"es-MX\";\n            case \"Spanish (Nicaragua)\":\n                return \"es-NI\";\n            case \"Spanish (Panama)\":\n                return \"es-PA\";\n            case \"Spanish (Peru)\":\n                return \"es-PE\";\n            case \"Spanish (Puerto Rico)\":\n                return \"es-PR\";\n            case \"Spanish (Paraguay)\":\n                return \"es-PY\";\n            case \"Spanish (El Salvador)\":\n                return \"es-SV\";\n            case \"Spanish (United States)\":\n                return \"es-US\";\n            case \"Spanish (Uruguay)\":\n                return \"es-UY\";\n            case \"Spanish (Venezuela)\":\n                return \"es-VE\";\n            case \"Estonian (Estonia)\":\n                return \"et-EE\";\n            case \"Basque\":\n                return \"eu-ES\";\n            case \"Persian (Iran)\":\n                return \"fa-IR\";\n            case \"Finnish (Finland)\":\n                return \"fi-FI\";\n            case \"Filipino (Philippines)\":\n                return \"fil-PH\";\n            case \"French (Belgium)\":\n                return \"fr-BE\";\n            case \"French (Canada)\":\n                return \"fr-CA\";\n            case \"French (Switzerland)\":\n                return \"fr-CH\";\n            case \"French\":\n            case \"French (France)\":\n                return \"fr-FR\";\n            case \"Irish (Ireland)\":\n                return \"ga-IE\";\n            case \"Galician\":\n                return \"gl-ES\";\n            case \"Gujarati (India)\":\n                return \"gu-IN\";\n            case \"Hebrew\":\n            case \"Hebrew (Israel)\":\n                return \"he-IL\";\n            case \"Hindi (India)\":\n                return \"hi-IN\";\n            case \"Croatian (Croatia)\":\n                return \"hr-HR\";\n            case \"Hungarian (Hungary)\":\n                return \"hu-HU\";\n            case \"Armenian (Armenia)\":\n                return \"hy-AM\";\n            case \"Indonesian (Indonesia)\":\n                return \"id-ID\";\n            case \"Icelandic (Iceland)\":\n                return \"is-IS\";\n            case \"Italian (Switzerland)\":\n                return \"it-CH\";\n            case \"Italian\":\n            case \"Italian (Italy)\":\n                return \"it-IT\";\n            case \"Japanese\":\n            case \"Japanese (Japan)\":\n                return \"ja-JP\";\n            case \"Javanese (Latin, Indonesia)\":\n                return \"jv-ID\";\n            case \"Georgian (Georgia)\":\n                return \"ka-GE\";\n            case \"Kazakh (Kazakhstan)\":\n                return \"kk-KZ\";\n            case \"Khmer (Cambodia)\":\n                return \"km-KH\";\n            case \"Kannada (India)\":\n                return \"kn-IN\";\n            case \"Korean\":\n            case \"Korean (Korea)\":\n                return \"ko-KR\";\n            case \"Lao (Laos)\":\n                return \"lo-LA\";\n            case \"Lithuanian (Lithuania)\":\n                return \"lt-LT\";\n            case \"Latvian (Latvia)\":\n                return \"lv-LV\";\n            case \"Macedonian (North Macedonia)\":\n                return \"mk-MK\";\n            case \"Malayalam (India)\":\n                return \"ml-IN\";\n            case \"Mongolian (Mongolia)\":\n                return \"mn-MN\";\n            case \"Marathi (India)\":\n                return \"mr-IN\";\n            case \"Malay (Malaysia)\":\n                return \"ms-MY\";\n            case \"Maltese (Malta)\":\n                return \"mt-MT\";\n            case \"Burmese (Myanmar)\":\n                return \"my-MM\";\n            case \"Norwegian Bokmål (Norway)\":\n                return \"nb-NO\";\n            case \"Nepali (Nepal)\":\n                return \"ne-NP\";\n            case \"Dutch\":\n            case \"Dutch (Belgium)\":\n                return \"nl-BE\";\n            case \"Dutch (Netherlands)\":\n                return \"nl-NL\";\n            case \"Punjabi (India)\":\n                return \"pa-IN\";\n            case \"Polish (Poland)\":\n                return \"pl-PL\";\n            case \"Pashto (Afghanistan)\":\n                return \"ps-AF\";\n            case \"Portuguese\":\n            case \"Portuguese (Brazil)\":\n                return \"pt-BR\";\n            case \"Portuguese (Portugal)\":\n                return \"pt-PT\";\n            case \"Romanian (Romania)\":\n                return \"ro-RO\";\n            case \"Russian\":\n            case \"Russian (Russia)\":\n                return \"ru-RU\";\n            case \"Sinhala (Sri Lanka)\":\n                return \"si-LK\";\n            case \"Slovak (Slovakia)\":\n                return \"sk-SK\";\n            case \"Slovenian (Slovenia)\":\n                return \"sl-SI\";\n            case \"Somali (Somalia)\":\n                return \"so-SO\";\n            case \"Albanian (Albania)\":\n                return \"sq-AL\";\n            case \"Serbian (Cyrillic, Serbia)\":\n                return \"sr-RS\";\n            case \"Swedish (Sweden)\":\n                return \"sv-SE\";\n            case \"Swahili (Kenya)\":\n                return \"sw-KE\";\n            case \"Swahili (Tanzania)\":\n                return \"sw-TZ\";\n            case \"Tamil (India)\":\n                return \"ta-IN\";\n            case \"Telugu (India)\":\n                return \"te-IN\";\n            case \"Thai (Thailand)\":\n                return \"th-TH\";\n            case \"Turkish\":\n            case \"Turkish (Türkiye)\":\n                return \"tr-TR\";\n            case \"Ukrainian (Ukraine)\":\n                return \"uk-UA\";\n            case \"Urdu (India)\":\n                return \"ur-IN\";\n            case \"Uzbek (Latin, Uzbekistan)\":\n                return \"uz-UZ\";\n            case \"Vietnamese (Vietnam)\":\n                return \"vi-VN\";\n            case \"Chinese (Wu, Simplified)\":\n                return \"wuu-CN\";\n            case \"Chinese (Cantonese, Simplified)\":\n                return \"yue-CN\";\n            case \"Chinese\":\n            case \"Chinese (Pinyin)\":\n            case \"Chinese (Hanzi)\":\n            case \"Chinese (Mandarin, Simplified)\":\n                return \"zh-CN\";\n            case \"Chinese (Jilu Mandarin, Simplified)\":\n                return \"zh-CN-shandong\";\n            case \"Chinese (Southwestern Mandarin, Simplified)\":\n                return \"zh-CN-sichuan\";\n            case \"Chinese (Cantonese, Traditional)\":\n                return \"zh-HK\";\n            case \"Chinese (Taiwanese Mandarin, Traditional)\":\n                return \"zh-TW\";\n            case \"Zulu (South Africa)\":\n                return \"zu-ZA\";\n            default:\n                return \"en-US\";\n        }\n    }\n}"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/deepgram/SpeechRecDeepgram.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.speechrecognition.deepgram;\n\nimport android.content.Context;\nimport android.util.Log;\n\nimport com.teamopensmartglasses.augmentoslib.events.SpeechRecOutputEvent;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.SpeechRecFramework;\n\nimport org.greenrobot.eventbus.EventBus;\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport okhttp3.OkHttpClient;\nimport okhttp3.Request;\nimport okhttp3.Response;\nimport okhttp3.WebSocket;\nimport okhttp3.WebSocketListener;\nimport okio.ByteString;\n\npublic class SpeechRecDeepgram extends SpeechRecFramework {\n//    private static final String BASE_URL = \"wss://api.deepgram.com/v1/listen?encoding=linear16&sample_rate=16000&diarize=false&interim_results=true&smart_format=true&utterance_end_ms=1200&punctuate=true\"; //&filler_words=true\";\n    private static final String BASE_URL = \"wss://api.deepgram.com/v1/listen?encoding=linear16&sample_rate=16000&diarize=false&interim_results=true\"; //&filler_words=true\";\n    private static final String API_KEY = \"3d445184e814ba545ad508c24f08b0f5e2645c09\";\n    private WebSocket webSocket;\n    public String TAG = \"WearableAi_SpeechRecDeepgram\";\n\n    private Context mContext;\n    private String currentLanguageCode;\n\n    public SpeechRecDeepgram(Context context, String languageLocale) {\n        this.mContext = context;\n        initLanguageLocale(languageLocale);\n    }\n\n    @Override\n    public void start() {\n        Log.d(TAG, \"starting Deepgram\");\n        initializeWebSocket();\n    }\n\n    @Override\n    public void destroy() {\n        Log.d(TAG, \"destroying Deepgram\");\n        if (webSocket != null) {\n            webSocket.close(1000, \"Closing Connection\");\n        }\n    }\n\n    @Override\n    public void ingestAudioChunk(byte[] audioChunk) {\n        if (webSocket != null) {\n            webSocket.send(ByteString.of(audioChunk));\n        }\n    }\n\n    private void initializeWebSocket() {\n        Log.d(TAG, \"init socket Deepgram\");\n        OkHttpClient client = new OkHttpClient();\n        String url = BASE_URL + \"&language=\" + currentLanguageCode;\n        Request request = new Request.Builder()\n                .url(url)\n                .addHeader(\"Authorization\", \"Token \" + API_KEY)\n                .build();\n\n        webSocket = client.newWebSocket(request, new WebSocketListener() {\n            @Override\n            public void onOpen(WebSocket webSocket, Response response) {\n                Log.d(TAG, \"opened Deepgram\");\n            }\n\n            @Override\n            public void onMessage(WebSocket webSocket, String text) {\n                parseDeepgramMessage(text);\n            }\n\n            @Override\n            public void onClosing(WebSocket webSocket, int code, String reason) {\n                webSocket.close(1000, null);\n                Log.d(TAG, \"got closing Deepgram\");\n            }\n\n            @Override\n            public void onFailure(WebSocket webSocket, Throwable t, Response response) {\n                Log.d(TAG, \"failure in Deepgram\");\n            }\n        });\n\n        client.dispatcher().executorService().shutdown();\n    }\n\n    public void parseDeepgramMessage(String jsonString) {\n        try {\n            JSONObject obj = new JSONObject(jsonString);\n\n            String type = obj.getString(\"type\");\n            JSONArray channelIndex = obj.getJSONArray(\"channel_index\");\n            double duration = obj.getDouble(\"duration\");\n            double start = obj.getDouble(\"start\");\n            boolean isFinal = obj.getBoolean(\"is_final\");\n            boolean speechFinal = obj.getBoolean(\"speech_final\");\n\n            JSONObject channel = obj.getJSONObject(\"channel\");\n            JSONArray alternatives = channel.getJSONArray(\"alternatives\");\n            JSONObject firstAlternative = alternatives.getJSONObject(0);\n            String transcript = firstAlternative.getString(\"transcript\");\n            double confidence = firstAlternative.getDouble(\"confidence\");\n\n            JSONObject metadata = obj.getJSONObject(\"metadata\");\n            String requestId = metadata.getString(\"request_id\");\n            JSONObject modelInfo = metadata.getJSONObject(\"model_info\");\n            String modelName = modelInfo.getString(\"name\");\n            String modelVersion = modelInfo.getString(\"version\");\n            String modelArch = modelInfo.getString(\"arch\");\n            String modelUuid = metadata.getString(\"model_uuid\");\n\n            boolean fromFinalize = obj.getBoolean(\"from_finalize\");\n\n            if (!transcript.equals(\"\") && !transcript.equals(\" \") && transcript != null) {\n                EventBus.getDefault().post(new SpeechRecOutputEvent(transcript, (long) start, isFinal));\n            }\n        } catch (JSONException e) {\n            e.printStackTrace();\n        }\n    }\n\n    private void initLanguageLocaleDefault() {\n        currentLanguageCode = \"en-US\";\n    }\n\n    private void initLanguageLocale(String localeString) {\n        switch (localeString) {\n            case \"Bulgarian\":\n                currentLanguageCode = \"bg\";\n                break;\n            case \"Catalan\":\n                currentLanguageCode = \"ca\";\n                break;\n            case \"Chinese (Pinyin)\":\n            case \"Chinese (Hanzi)\":\n            case \"Chinese (Simplified)\":\n            case \"Mandarin Simplified\":\n                currentLanguageCode = \"zh\";\n                break;\n            case \"Czech\":\n                currentLanguageCode = \"cs\";\n                break;\n            case \"Danish\":\n                currentLanguageCode = \"da\";\n                break;\n            case \"Dutch\":\n                currentLanguageCode = \"nl\";\n                break;\n            case \"English\":\n                currentLanguageCode = \"en\";\n                break;\n            case \"Estonian\":\n                currentLanguageCode = \"et\";\n                break;\n            case \"Finnish\":\n                currentLanguageCode = \"fi\";\n                break;\n            case \"French\":\n                currentLanguageCode = \"fr\";\n                break;\n            case \"German\":\n                currentLanguageCode = \"de\";\n                break;\n            case \"Greek\":\n                currentLanguageCode = \"el\";\n                break;\n            case \"Hindi\":\n                currentLanguageCode = \"hi\";\n                break;\n            case \"Hungarian\":\n                currentLanguageCode = \"hu\";\n                break;\n            case \"Indonesian\":\n                currentLanguageCode = \"id\";\n                break;\n            case \"Italian\":\n                currentLanguageCode = \"it\";\n                break;\n            case \"Japanese\":\n                currentLanguageCode = \"ja\";\n                break;\n            case \"Korean\":\n                currentLanguageCode = \"ko\";\n                break;\n            case \"Latvian\":\n                currentLanguageCode = \"lv\";\n                break;\n            case \"Lithuanian\":\n                currentLanguageCode = \"lt\";\n                break;\n            case \"Malay\":\n                currentLanguageCode = \"ms\";\n                break;\n            case \"Norwegian\":\n                currentLanguageCode = \"no\";\n                break;\n            case \"Polish\":\n                currentLanguageCode = \"pl\";\n                break;\n            case \"Portuguese\":\n                currentLanguageCode = \"pt\";\n                break;\n            case \"Romanian\":\n                currentLanguageCode = \"ro\";\n                break;\n            case \"Russian\":\n                currentLanguageCode = \"ru\";\n                break;\n            case \"Slovak\":\n                currentLanguageCode = \"sk\";\n                break;\n            case \"Spanish\":\n                currentLanguageCode = \"es\";\n                break;\n            case \"Swedish\":\n                currentLanguageCode = \"sv\";\n                break;\n            case \"Thai\":\n                currentLanguageCode = \"th\";\n                break;\n            case \"Turkish\":\n                currentLanguageCode = \"tr\";\n                break;\n            case \"Ukrainian\":\n                currentLanguageCode = \"uk\";\n                break;\n            case \"Vietnamese\":\n                currentLanguageCode = \"vi\";\n                break;\n            default:\n                currentLanguageCode = \"en\";\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/SpeechRecGoogle.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.speechrecognition.google;\n\nimport static com.google.audio.asr.SpeechRecognitionModelOptions.SpecificModel.DICTATION_DEFAULT;\nimport static com.google.audio.asr.SpeechRecognitionModelOptions.SpecificModel.VIDEO;\nimport static com.google.audio.asr.TranscriptionResultFormatterOptions.TranscriptColoringStyle.NO_COLORING;\n\nimport android.content.Context;\nimport android.util.Log;\n\nimport com.google.audio.CodecAndBitrate;\nimport com.google.audio.asr.CloudSpeechSessionParams;\nimport com.google.audio.asr.CloudSpeechStreamObserverParams;\nimport com.google.audio.asr.SpeechRecognitionModelOptions;\nimport com.google.audio.asr.TranscriptionResultFormatterOptions;\nimport com.teamopensmartglasses.smartglassesmanager.SmartGlassesAndroidService;\nimport com.teamopensmartglasses.augmentoslib.events.SpeechRecOutputEvent;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.SpeechRecFramework;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.RepeatingRecognitionSession;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.SafeTranscriptionResultFormatter;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.TranscriptionResultUpdatePublisher;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.asrhelpers.NetworkConnectionChecker;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.gcloudspeech.CloudSpeechSessionFactory;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.vad.VadGateSpeechPolicy;\n\nimport org.greenrobot.eventbus.EventBus;\n\npublic class SpeechRecGoogle extends SpeechRecFramework {\n    public String TAG = \"WearableAi_SpeechRecGoogle\";\n\n    private Context mContext;\n\n    public SpeechRecGoogle(Context mContext) {\n        this.mContext = mContext;\n\n        initLanguageLocaleDefault();\n\n//        EventBus.getDefault().register(this);\n    }\n    public SpeechRecGoogle(Context mContext, String languageLocale) {\n        this.mContext = mContext;\n\n        initLanguageLocale(languageLocale);\n\n//        EventBus.getDefault().register(this);\n    }\n\n//    @Subscribe\n//    public void onGoogleAudioChunkNewEvent(GoogleAudioChunkNewEvent receivedEvent) {\n//    }\n\n    @Override\n    public void ingestAudioChunk(byte[] audioChunk) {\n        recognizer.processAudioBytes(audioChunk);\n    }\n\n    @Override\n    public void start(){\n        //start text to speech\n        constructRepeatingRecognitionSession();\n        recognizer.init(1024*3);\n    }\n\n    @Override\n    public void destroy(){\n        if (recognizer != null) {\n            recognizer.unregisterCallback(transcriptUpdater);\n            networkChecker.unregisterNetworkCallback();\n            recognizer.stop();\n        }\n    }\n\n    private int currentLanguageCodePosition;\n    private String currentLanguageCode;\n\n    // This class was intended to be used from a thread where timing is not critical (i.e. do not\n    // call this in a system audio callback). Network calls will be made during all of the functions\n    // that RepeatingRecognitionSession inherits from SampleProcessorInterface.\n    private RepeatingRecognitionSession recognizer;\n    private NetworkConnectionChecker networkChecker;\n\n    private final TranscriptionResultUpdatePublisher transcriptUpdater =\n            (formattedTranscript, updateType) -> {\n                //post the event bus event\n                if (updateType == TranscriptionResultUpdatePublisher.UpdateType.TRANSCRIPT_FINALIZED){\n//                    Log.d(TAG, \"GOT FINAL TRANSCRIPT: \" + formattedTranscript.toString());\n                    EventBus.getDefault().post(new SpeechRecOutputEvent(formattedTranscript.toString(), System.currentTimeMillis(), true));\n                } else {\n                    EventBus.getDefault().post(new SpeechRecOutputEvent(formattedTranscript.toString(), System.currentTimeMillis(), false));\n                }\n            };\n\n    private void initLanguageLocaleDefault() {\n        // The default locale is en-US.\n        currentLanguageCode = \"en-US\";\n    }\n\n    private void initLanguageLocale(String localeString) {\n        if (localeString.equals(\"English\")) {\n            currentLanguageCode = \"en-US\";\n        } else if (localeString.equals(\"Russian\")) {\n            currentLanguageCode = \"ru-RU\";\n        } else if (localeString.equals(\"Japanese\")) {\n            currentLanguageCode = \"ja-JP\";\n        } else if (localeString.contains(\"Chinese\")) {\n            currentLanguageCode = \"zh\";\n        } else if (localeString.equals(\"Spanish\")) {\n            currentLanguageCode = \"es-MX\";\n        } else if (localeString.equals(\"Hebrew\")) {\n            currentLanguageCode = \"iw-IL\";\n        } else if (localeString.equals(\"Dutch\")) {\n            currentLanguageCode = \"nl-NL\";\n        } else if(localeString.equals(\"French\")){\n            currentLanguageCode = \"fr-FR\";\n        }else if (localeString.equals(\"German\")) {\n            currentLanguageCode = \"de-DE\";\n        } else if (localeString.equals(\"Arabic\")) {\n            currentLanguageCode = \"ar-AR\";\n        } else if (localeString.equals(\"Korean\")) {\n            currentLanguageCode = \"ko-KR\";\n        } else if (localeString.equals(\"Italian\")) {\n            currentLanguageCode = \"it-IT\";\n        } else if (localeString.equals(\"Turkish\")) {\n            currentLanguageCode = \"tr-TR\";\n        } else if (localeString.equals(\"Portuguese\")) {\n            currentLanguageCode = \"pt-PT\";\n        } else {\n            currentLanguageCode = \"en-US\";\n        }\n    }\n\n    private void constructRepeatingRecognitionSession() {\n        SpeechRecognitionModelOptions options =\n                SpeechRecognitionModelOptions.newBuilder()\n                        .setLocale(currentLanguageCode)\n                        // As of 7/18/19, Cloud Speech's video model supports en-US only.\n                        .setModel(currentLanguageCode.equals(\"en-US\") ? VIDEO : DICTATION_DEFAULT) //this is overwritten to use 'latest_long' in cloud/CloudSpeechSession.java\n                        .build();\n        CloudSpeechSessionParams cloudParams =\n                CloudSpeechSessionParams.newBuilder()\n                        .setObserverParams(\n                                CloudSpeechStreamObserverParams.newBuilder().setRejectUnstableHypotheses(false))\n                        .setFilterProfanity(false)\n                        .setEncoderParams(\n                                CloudSpeechSessionParams.EncoderParams.newBuilder()\n                                        .setEnableEncoder(true)\n                                        .setAllowVbr(true)\n                                        .setCodec(CodecAndBitrate.OGG_OPUS_BITRATE_32KBPS))\n                        .build();\n        networkChecker = new NetworkConnectionChecker(mContext);\n        networkChecker.registerNetworkCallback();\n\n        // There are lots of options for formatting the text. These can be useful for debugging\n        // and visualization, but it increases the effort of reading the transcripts.\n        TranscriptionResultFormatterOptions formatterOptions =\n                TranscriptionResultFormatterOptions.newBuilder()\n                        .setTranscriptColoringStyle(NO_COLORING)\n                        .build();\n        RepeatingRecognitionSession.Builder recognizerBuilder =\n                RepeatingRecognitionSession.newBuilder()\n                        .setSpeechSessionFactory(new CloudSpeechSessionFactory(cloudParams, SmartGlassesAndroidService.getApiKey(mContext)))\n                        .setSampleRateHz(16000)\n                        .setTranscriptionResultFormatter(new SafeTranscriptionResultFormatter(formatterOptions))\n                        .setSpeechRecognitionModelOptions(options)\n                        .setSpeechDetectionPolicy(new VadGateSpeechPolicy(mContext))\n                        .setNetworkConnectionChecker(networkChecker);\n        recognizer = recognizerBuilder.build();\n        recognizer.registerCallback(transcriptUpdater, TranscriptionResultUpdatePublisher.ResultSource.MOST_RECENT_SEGMENT);\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/asr/AlwaysSameSpeakerIDLabeler.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr;\n\nimport com.google.audio.SpeakerIdInfo;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.asrhelpers.SpeakerIDLabeler;\n\nimport org.joda.time.Instant;\n\n/** A diarizer that always reports the same speaker. */\npublic class AlwaysSameSpeakerIDLabeler implements SpeakerIDLabeler {\n  private final SpeakerIdInfo fixedInfo;\n\n  public AlwaysSameSpeakerIDLabeler(SpeakerIdInfo fixedInfo) {\n    this.fixedInfo = fixedInfo;\n  }\n\n  @Override\n  public void setReferenceTimestamp(Instant now) {}\n\n  @Override\n  public SpeakerIdInfo getSpeakerIDForTimeInterval(Instant start, Instant end) {\n    return fixedInfo;\n  }\n\n  @Override\n  public void init(int blockSizeSamples) {}\n\n  @Override\n  public void clearSpeakerIDTimestamps() {}\n\n  @Override\n  public void reset() {}\n\n  @Override\n  public void processAudioBytes(byte[] bytes, int offset, int length) {}\n\n  @Override\n  public void stop() {}\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/asr/AlwaysSpeechPolicy.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr;\n\n/** A speech detector that always reports hearing speech. */\npublic class AlwaysSpeechPolicy implements SpeechDetectionPolicy {\n  public AlwaysSpeechPolicy() {}\n\n  @Override\n  public boolean shouldPassAudioToRecognizer() {\n    return true;\n  }\n\n  @Override\n  public void init(int blockSizeSamples) {}\n\n  @Override\n  public void reset() {}\n\n  @Override\n  public void processAudioBytes(byte[] bytes, int offset, int length) {}\n\n  @Override\n  public void stop() {}\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/asr/RepeatingRecognitionSession.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr;\n\nimport static com.google.common.base.Preconditions.checkArgument;\nimport static com.google.common.base.Preconditions.checkNotNull;\n\nimport android.text.Spanned;\n\nimport com.google.audio.SpeakerIdInfo;\nimport com.google.audio.asr.SpeechRecognitionModelOptions;\nimport com.google.audio.asr.TranscriptionResult;\nimport com.google.common.base.Optional;\nimport com.google.common.flogger.FluentLogger;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.asrhelpers.CircularByteBuffer;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.asrhelpers.NetworkConnectionChecker;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.asrhelpers.SampleProcessorInterface;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.asrhelpers.SpeakerIDLabeler;\n\nimport org.joda.time.Duration;\nimport org.joda.time.Instant;\n\nimport java.lang.ref.WeakReference;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.concurrent.ConcurrentLinkedQueue;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.stream.Collectors;\nimport java.util.stream.IntStream;\n\n/**\n * Repeatedly runs recognition sessions, starting a new session whenever one terminates, until\n * stopped.\n *\n * <p>Incoming is speech is timestamped as time since epoch in milliseconds.\n *\n * <p>In between sessions, some buffering is done, but if the internal session is closed for more\n * than SECONDS_TO_STORE_BETWEEN_SESSIONS, audio will be lost.\n *\n * <p>This class was intended to be used from a thread where timing is not critical (i.e. do not\n * call this in a system audio callback). Network calls may be made during all of the functions\n * inherited from SampleProcessorInterface.\n *\n * <p>Results delivered via a TranscriptionResultUpdatePublisher are done so asynchronously. All\n * public functions that are not a part of the SampleProcessorInterface API may be called from any\n * thread at any time.\n *\n * <p>TranscriptionResultUpdatePublisher callbacks are delivered from a thread on a separate thread\n * pool. You will never get two callbacks to the same TranscriptionResultUpdatePublisher instance at\n * the same time.\n */\n\n// Threading notes:\n//\n// Recognition thread:\n// This thread is owned by whatever system is providing the class with audio (one that treats this\n// generically as a SampleProcessorInterface, interacting only with the init(), processAudioBytes(),\n// and stop() methods). This is the thread that is doing most of the work of the class (session\n// management, audio buffering and processing, network checks, etc.). Be aware that it can make\n// network calls and do other expensive actions that should not be placed in a system audio\n// callback.\n//\n// Note that your audio engine should never call init(), processAudioBytes(), and stop()\n// concurrently.\n//\n// Results thread:\n// This thread is not exposed outside of this class. It is controlled by the CloudSpeechSession and\n// alerts the TranscriptionResultReceiver when the recognition has a result from the server. It\n// posts requests to the recognition thread via that 'requests' member below. If the speech session\n// implementation is single threaded, this thread and the recognition thread are the same thread.\n//\n// Other threads:\n// Public methods other than init(), processAudioBytes(), and stop() may be called from threads\n// other than the recognition thread. They are thread-safe.\n\npublic class RepeatingRecognitionSession implements SampleProcessorInterface {\n  /* ---------------- BEGIN: MEMBERS THAT ARE SHARED ACROSS MULTIPLE THREADS ------------------ */\n  private static final FluentLogger logger = FluentLogger.forEnclosingClass();\n\n  // All threads but the recognition thread may post to this queue, only the recognition thread\n  // will read from it.\n  private final ConcurrentLinkedQueue<RequestForRecognitionThread> requests =\n      new ConcurrentLinkedQueue<>();\n\n  // Shared between client threads and recognizer thread.\n  private final AtomicBoolean repeatedSessionIsInitialized = new AtomicBoolean(false);\n  private final AtomicReference<SpeechRecognitionModelOptions> modelOptions =\n      new AtomicReference<>();\n  private final ConcurrentLinkedQueue<TranscriptionResultPublisherReference> callbackRefs;\n  private final TranscriptionErrorPublisher transcriptionErrorPublisher;\n  // The client may have retained a reference to the formatter, so it is assumed to be accessible\n  // from multiple threads. However, it is a thread-safe object.\n  private final SafeTranscriptionResultFormatter resultFormatter;\n  /* ----------------- END: MEMBERS THAT ARE SHARED ACROSS MULTIPLE THREADS ------------------- */\n\n  /* --------------- BEGIN: MEMBERS THAT ARE ACCESSED ONLY FROM RESULTS THREAD ---------------- */\n  /** An interface for posting requests to the RepeatingRecognitionSession. */\n  public interface PostHandler {\n    void post(RequestForRecognitionThread request);\n  }\n\n  private final PostHandler postHandler;\n  private final SpeechSessionListener speechSessionListener;\n  /* ---------------- END: MEMBERS THAT ARE ACCESSED ONLY FROM RESULTS THREAD ----------------- */\n\n  /* ------------- BEGIN: MEMBERS THAT ARE ACCESSED ONLY FROM RECOGNITION THREAD -------------- */\n  /**\n   * Used to keep track of the current session. This is not only used for numbering incoming\n   * sessions, but also to prevent old sessions from updating the state of this object. Old sessions\n   * may persist and send results back to RepeatingRecognitionSession after a call to reset() or\n   * after stop() and init() are called in quick succession. Sessions IDs will be monotonically\n   * increasing, but are not guaranteed to be contiguous.\n   */\n  private int currentSessionID = -1;\n\n  public static final Duration SECONDS_TO_STORE_BETWEEN_SESSIONS = Duration.standardSeconds(10);\n  private static final int BYTES_PER_SAMPLE = 2;\n\n  // Members related to session management.\n  private SpeechSession currentSession;\n  private final SpeechSessionFactory sessionFactory;\n  private final int sampleRateHz;\n  private int chunkSizeSamples;\n\n  private boolean isStopped = false;\n  private boolean okToTerminateSession = false;\n\n  // Some variables to facilitate buffering between sessions.\n  private static int maxNumSamplesToStoreBetweenSessions;\n  private CircularByteBuffer leftoverBytes;\n  private byte[] leftoverBytesAllocation; // Exists to avoid repeated allocations.\n  private CircularByteBuffer.Reader leftoverBytesReader;\n\n  /**\n   * Allows the RepeatingRecognitionSession to stall session creation when there is a network error\n   * until connection is regained. If not provided, a short delay will happen after connection loss\n   * to prevent a rapid recreation of sessions.\n   */\n  private final NetworkConnectionChecker networkCheck;\n\n  private boolean hadNetworkConnectionError = false;\n  private Instant lastInitSessionTimestampWithoutNetworkChecker = new Instant(0);\n  static final Duration RECREATE_SESSION_IF_NO_NETWORKCHECKER_DURATION =\n      Duration.standardSeconds(1);\n\n  private final SpeechDetectionPolicy speechDetector;\n  private final SpeakerIDLabeler diarizer;\n\n  /** Passes results back to registered listeners. */\n  private final ExecutorService resultsDeliveryService;\n\n  /**\n   * Keeps track of time that the last session ended. This will be used to log how long reconnection\n   * takes.\n   */\n  private Optional<Instant> endSessionRequestTime = Optional.absent();\n  /* -------------- END: MEMBERS THAT ARE ACCESSED ONLY FROM RECOGNITION THREAD --------------- */\n\n  /*\n   * A specialized reference for {@link TranscriptionResultUpdatePublisher} that allows us to fix\n   * the {@link TranscriptionResultUpdatePublisher.ResultSource} which the callback expect to\n   * handle.\n   */\n  private static class TranscriptionResultPublisherReference\n      extends WeakReference<TranscriptionResultUpdatePublisher> {\n    final TranscriptionResultUpdatePublisher.ResultSource source;\n\n    public TranscriptionResultPublisherReference(\n        TranscriptionResultUpdatePublisher referent,\n        TranscriptionResultUpdatePublisher.ResultSource source) {\n      super(referent);\n      this.source = source;\n    }\n  }\n\n  private RepeatingRecognitionSession(Builder builder) {\n    this.postHandler = (request) -> requests.add(request);\n    this.speechSessionListener = new TranscriptionResultReceiver(postHandler);\n    this.resultFormatter = builder.resultFormatter;\n    this.sampleRateHz = builder.sampleRateHz;\n    this.sessionFactory = builder.sessionFactory;\n    this.modelOptions.set(builder.modelOptions);\n    this.networkCheck = builder.networkCheck;\n    this.speechDetector = builder.speechDetector;\n    this.diarizer = builder.diarizer;\n    this.callbackRefs = builder.callbackRefs;\n    this.resultsDeliveryService = builder.resultsDeliveryService;\n    this.transcriptionErrorPublisher = builder.transcriptionErrorPublisher;\n\n    maxNumSamplesToStoreBetweenSessions =\n        (int) Math.ceil(SECONDS_TO_STORE_BETWEEN_SESSIONS.getStandardSeconds() * sampleRateHz);\n  }\n\n  public static Builder newBuilder() {\n    return new Builder();\n  }\n\n  // Should only be called on the recognition thread. See threading notes above.\n  @Override\n  public void init(int chunkSizeSamples) {\n    checkArgument(chunkSizeSamples > 0);\n    this.chunkSizeSamples = chunkSizeSamples;\n    speechDetector.init(chunkSizeSamples);\n    diarizer.init(chunkSizeSamples);\n    diarizer.setReferenceTimestamp(Instant.now());\n    this.leftoverBytes =\n        new CircularByteBuffer(maxNumSamplesToStoreBetweenSessions * BYTES_PER_SAMPLE);\n    this.leftoverBytesAllocation = new byte[leftoverBytes.getCapacity()];\n    this.leftoverBytesReader = leftoverBytes.newReader();\n    isStopped = false;\n    okToTerminateSession = false;\n    // Create the first session.\n    currentSession = sessionFactory.create(speechSessionListener, sampleRateHz);\n    repeatedSessionIsInitialized.set(true);\n  }\n\n  // Should only be called on the recognition thread. See threading notes above.\n  @Override\n  public void processAudioBytes(byte[] samples, int offset, int length) {\n    if (!repeatedSessionIsInitialized.get()) {\n      throw new IllegalStateException(\"processAudioBytes() called prior to initialization!\");\n    }\n    if (isStopped) {\n      throw new IllegalStateException(\"processAudioBytes() called while stopped!\");\n    }\n    // Ignoring thread safety issues, it would be ideal to run handlePostedActions() endlessly in\n    // another thread. To keep everything on the same thread, we run it in this function first\n    // at the beginning to process reset events as soon as possible and again at the end to process\n    // results as soon as their generated (in practice, this is mostly useful during testing).\n    handlePostedActions();\n    speechDetector.processAudioBytes(samples, offset, length);\n    diarizer.processAudioBytes(samples, offset, length);\n\n    // Restart the session when necessary.\n    if (okToTerminateSession) {\n      logger.atInfo().log(\n          \"Creating a new session. Reconnection timer: %s\", getReconnectionTimerValue());\n      currentSession = sessionFactory.create(speechSessionListener, sampleRateHz);\n      okToTerminateSession = false;\n    }\n\n    // If we need network, but it is unavailable, put the samples in leftovers.\n    boolean networkRequirementsMet =\n        !currentSession.requiresNetworkConnection() || isNetworkAvailable();\n    if (!networkRequirementsMet) {\n      storeSamplesInLeftovers(samples, offset, length, false);\n      // Stop the session when network is lost.\n      if (currentSession.isInitialized()) {\n        logger.atInfo().log(\n            \"Online Session #%d abandoned due to lack of network connection.\",\n            currentSession.sessionID());\n        requestCurrentSessionEnd();\n      }\n      return;\n    }\n    hadNetworkConnectionError = false;\n\n    // If there is no speech, end the session, and don't try to process data.\n    if (!speechDetector.shouldPassAudioToRecognizer()) {\n      // Buffer the speech so that when we reconnect, even a late speech detection will cause some\n      // of the buffered audio to get to the server. If we drop samples we don't need to log because\n      // we know it does not contain speech.\n      storeSamplesInLeftovers(samples, offset, length, true);\n      if (currentSession.isInitialized()) {\n//        logger.atInfo().log(\n//            \"Session #%d ending due to lack of detected speech.\", currentSession.sessionID());\n        requestCurrentSessionEnd();\n      }\n      return;\n    }\n\n    // Initialize the session.\n    if (!currentSession.isInitialized()) {\n      // Get the reference to the model so that the log and the session see the same version.\n      SpeechRecognitionModelOptions model = modelOptions.get();\n      currentSessionID++;\n//      logger.atInfo().log(\n//          \"Starting a Session #%d in language `%s`.\", currentSessionID, model.getLocale());\n      currentSession.init(model, chunkSizeSamples, currentSessionID);\n    }\n\n    tryToProcessLeftovers();\n\n    // If the session can take requests, send samples. Otherwise, put them into the leftover queue.\n    if (currentSession.processAudioBytes(samples, offset, length)) {\n      stopReconnectionTimer();\n    } else {\n      storeSamplesInLeftovers(samples, offset, length, false);\n    }\n\n    handlePostedActions();\n  }\n\n  /**\n   * Terminate the current session. Any results from the server after a call to stop() are not\n   * guaranteed to arrive.\n   */\n  // Should only be called only from the MicManager on the recognition thread as a\n  // SampleProcessorInterface.\n  @Override\n  public void stop() {\n    // Handle any requests that have happened prior to now.\n    handlePostedActions();\n    isStopped = true;\n    speechDetector.stop();\n    diarizer.stop();\n    if (currentSession.isInitialized()) {\n//      logger.atInfo().log(\n//          \"Session #%d abandoned due to repeated session ending.\", currentSession.sessionID());\n      abandonCurrentSession();\n    }\n    repeatedSessionIsInitialized.set(false);\n  }\n\n  /**\n   * Restarts recognition, discarding the state of the currently active session. Request is\n   * performed asynchronously, so this function may be called from any thread at any point during\n   * the session.\n   *\n   * <p>Results generated after the asynchronous reset will not arrive.\n   */\n  // May be called from any thread.\n  public void reset() {\n    reset(false);\n  }\n\n  private void reset(boolean clearTranscript) {\n    if (!repeatedSessionIsInitialized.get()) {\n      return;\n    }\n//    logger.atInfo().log(\n//        \"Session #%d scheduled to be abandoned due to call to reset().\",\n//        currentSession.sessionID());\n    requests.add(\n        RequestForRecognitionThread.newBuilder()\n            .setAction(\n                clearTranscript\n                    ? RequestForRecognitionThread.Action.RESET_SESSION_AND_CLEAR_TRANSCRIPT\n                    : RequestForRecognitionThread.Action.RESET_SESSION)\n            .build());\n  }\n\n  /**\n   * Restarts recognition, discarding the state of the currently active session. Request is\n   * performed asynchronously, so this function may be called from any thread at any point during\n   * the session. Clears returned transcript. The caller will know that\n   * the reset has been completed when a TRANSCRIPT_CLEARED is received through the listener.\n   */\n  // May be called from any thread.\n  public void resetAndClearTranscript() {\n    reset(true);\n  }\n\n  /**\n   * Sets the modelOptions, which may include a language change or usage of a different model.\n   * Session management is performed asynchronously, so this function may be called from any thread\n   * at any point during the session.\n   */\n  // May be called from any thread.\n  public void setModelOptions(SpeechRecognitionModelOptions modelOptions) {\n    this.modelOptions.set(modelOptions);\n//    logger.atInfo().log(\"Session scheduled to be ended due to model options change.\");\n    requests.add(\n        RequestForRecognitionThread.newBuilder()\n            .setAction(RequestForRecognitionThread.Action.REQUEST_TO_END_SESSION)\n            .build());\n  }\n\n  /** Gets the modelOptions, which may include a language change or usage of a different model. */\n  // May be called from any thread.\n  public SpeechRecognitionModelOptions getModelOptions() {\n    return modelOptions.get();\n  }\n\n  // Must be called prior to init() or after stop().\n  public void registerCallback(\n      TranscriptionResultUpdatePublisher callback,\n      TranscriptionResultUpdatePublisher.ResultSource source) {\n    checkNotNull(callback);\n    Iterator<TranscriptionResultPublisherReference> iterator = callbackRefs.iterator();\n    while (iterator.hasNext()) {\n      if (callback.equals(iterator.next().get())) {\n        throw new RuntimeException(\"Listener is already registered.\");\n      }\n    }\n    callbackRefs.add(new TranscriptionResultPublisherReference(callback, source));\n  }\n\n  // Must be called prior to init() or after stop().\n  public void unregisterCallback(TranscriptionResultUpdatePublisher callback) {\n    checkNotNull(callback);\n    Iterator<TranscriptionResultPublisherReference> iterator = callbackRefs.iterator();\n    while (iterator.hasNext()) {\n      if (callback.equals(iterator.next().get())) {\n        iterator.remove();\n      }\n    }\n  }\n\n  /**\n   * Pulls requests off of the queue and performs them. This is only to be called from the thread\n   * that is calling init(), processAudioBytes(), and stop().\n   *\n   * <p>Internal notes: None of the tasks performed while emptying the request queue should make a\n   * call to handlePostedActions() or post new requests, as this may result in results being\n   * processed out of order.\n   */\n  private void handlePostedActions() {\n    RequestForRecognitionThread request = requests.poll();\n\n    while (request != null) {\n      if (request.hasSessionID() && request.sessionID() < currentSessionID) {\n        // Completely ignore results for sessions that have been abandoned.\n//        logger.atInfo().log(\"Old event from Session #%d discarded.\", request.sessionID());\n        request = requests.poll();\n        continue;\n      }\n      switch (request.action()) {\n        case HANDLE_NETWORK_CONNECTION_FATAL_ERROR:\n//          logger.atInfo().log(\"Closing Session #%d due to network error.\", request.sessionID());\n          finalizeLeftoverHypothesis();\n          okToTerminateSession = true;\n          processError(request.getErrorCause());\n          startReconnectionTimer();\n          break;\n        case HANDLE_NON_NETWORK_CONNECTION_FATAL_ERROR:\n//          logger.atInfo().log(\"Closing Session #%d due to non-network error.\", request.sessionID());\n          hadNetworkConnectionError = true;\n          finalizeLeftoverHypothesis();\n          okToTerminateSession = true;\n          processError(request.getErrorCause());\n          startReconnectionTimer();\n          break;\n        case POST_RESULTS:\n//          logger.atInfo().log(\n//              \"Session #%d received result (final = %b).\",\n//              request.sessionID(), request.requestIsFinal());\n          processResult(request.result(), request.requestIsFinal());\n          break;\n        case OK_TO_TERMINATE_SESSION:\n//          logger.atInfo().log(\"Terminating Session #%d cleanly.\", request.sessionID());\n          okToTerminateSession = true;\n          startReconnectionTimer();\n          break;\n        case REQUEST_TO_END_SESSION:\n          requestCurrentSessionEnd();\n          break;\n        case RESET_SESSION:\n          resetInternal();\n          break;\n        case RESET_SESSION_AND_CLEAR_TRANSCRIPT:\n          resetInternal();\n          resultFormatter.reset();\n          sendTranscriptResultUpdated(\n              TranscriptionResultUpdatePublisher.UpdateType.TRANSCRIPT_CLEARED);\n          break;\n        case NO_ACTION:\n          break;\n      }\n      request = requests.poll();\n    }\n  }\n\n  private void processError(Throwable errorCause) {\n    if (transcriptionErrorPublisher != null) {\n      transcriptionErrorPublisher.onError(errorCause);\n    }\n  }\n\n  private void resetInternal() {\n    speechDetector.reset();\n    if (currentSession.isInitialized()) {\n//      logger.atInfo().log(\n//          \"Session #%d abandoned due to call to reset().\", currentSession.sessionID());\n      abandonCurrentSession();\n    }\n  }\n\n  private void requestCurrentSessionEnd() {\n    if (repeatedSessionIsInitialized.get() && currentSession.isInitialized()) {\n      currentSession.requestCloseSession();\n    }\n  }\n\n  private void abandonCurrentSession() {\n    finalizeLeftoverHypothesis();\n    requestCurrentSessionEnd();\n    // By incrementing the session ID here, we are preventing results from the old session from\n    // being processed.\n    currentSessionID++;\n    okToTerminateSession = true;\n  }\n\n  private void tryToProcessLeftovers() {\n    // Process stored samples, if there are any.\n    int numLeftoverBytes = leftoverBytesReader.availableBytes();\n    if (numLeftoverBytes > 0) {\n      leftoverBytesReader.peek(leftoverBytesAllocation, 0, numLeftoverBytes);\n      if (currentSession.processAudioBytes(leftoverBytesAllocation, 0, numLeftoverBytes)) {\n        stopReconnectionTimer();\n        leftoverBytes.reset(); // Readers get reset.\n      }\n    }\n  }\n\n  private void storeSamplesInLeftovers(\n      byte[] samples, int offset, int length, boolean droppingSamplesIsIntended) {\n    // If we fail this, it means we passed many seconds of audio at once. This should never happen\n    // under normal streaming conditions.\n    checkArgument(length < leftoverBytes.getCapacity());\n    int numLeftoverBytes = leftoverBytesReader.availableBytes();\n    if (numLeftoverBytes + length > leftoverBytes.getCapacity()) {\n      if (!droppingSamplesIsIntended) {\n//        logger.atSevere().atMostEvery(5, TimeUnit.SECONDS).log(\n//            \"Dropped audio between sessions. [atMostEvery 5s]\");\n      }\n      leftoverBytesReader.advance((numLeftoverBytes + length) - leftoverBytes.getCapacity());\n    }\n    leftoverBytes.write(samples, offset, length);\n  }\n\n  /**\n   * Check reconnect timeout to prevent connecting fail repeatedly in a short time.\n   *\n   * @return true if establishing connection is allowed.\n   */\n  private boolean isNetworkReconnectionTimeout() {\n    if (RECREATE_SESSION_IF_NO_NETWORKCHECKER_DURATION.isShorterThan(\n        new Duration(lastInitSessionTimestampWithoutNetworkChecker, Instant.now()))) {\n      // Allow to create a new session every second.\n      lastInitSessionTimestampWithoutNetworkChecker = Instant.now();\n      return true;\n    }\n    return false;\n  }\n\n  private boolean isNetworkAvailable() {\n    if (networkCheck != null) {\n      return networkCheck.isConnected();\n    } else if (hadNetworkConnectionError) {\n      return isNetworkReconnectionTimeout();\n    } else {\n      return true;\n    }\n  }\n\n  protected void processResult(TranscriptionResult result, boolean resultIsFinal) {\n    speechDetector.cueEvidenceOfSpeech();\n    result = addSpeakerIDLabels(result);\n    resultFormatter.setCurrentHypothesis(result);\n    if (resultIsFinal) {\n      resultFormatter.finalizeCurrentHypothesis();\n    }\n    sendTranscriptResultUpdated(\n        resultIsFinal\n            ? TranscriptionResultUpdatePublisher.UpdateType.TRANSCRIPT_FINALIZED\n            : TranscriptionResultUpdatePublisher.UpdateType.TRANSCRIPT_UPDATED);\n  }\n\n  private void finalizeLeftoverHypothesis() {\n    if (resultFormatter.finalizeCurrentHypothesis()) {\n      sendTranscriptResultUpdated(\n          TranscriptionResultUpdatePublisher.UpdateType.TRANSCRIPT_FINALIZED);\n    }\n  }\n\n  private void startReconnectionTimer() {\n    endSessionRequestTime = Optional.of(Instant.now());\n  }\n\n  private String getReconnectionTimerValue() {\n    if (endSessionRequestTime.isPresent()) {\n      Duration difference = new Duration(endSessionRequestTime.get(), Instant.now());\n      return \"<\" + difference.getMillis() / 1000.0f + \"s>\";\n    }\n    return \"<Timer not set>\";\n  }\n\n  private void stopReconnectionTimer() {\n    if (endSessionRequestTime.isPresent()) {\n      String endTime = getReconnectionTimerValue();\n//      logger.atInfo().log(\"Reconnection timer stopped: %s.\", endTime);\n    }\n    endSessionRequestTime = Optional.absent();\n  }\n\n  private void sendTranscriptResultUpdated(TranscriptionResultUpdatePublisher.UpdateType type) {\n    final Spanned transcript = resultFormatter.getFormattedTranscript();\n    final Spanned segment = resultFormatter.getMostRecentTranscriptSegment();\n    Iterator<TranscriptionResultPublisherReference> iterator = callbackRefs.iterator();\n\n    while (iterator.hasNext()) {\n      TranscriptionResultPublisherReference ref = iterator.next();\n      final TranscriptionResultUpdatePublisher publisher = ref.get();\n      final TranscriptionResultUpdatePublisher.ResultSource source = ref.source;\n      final TranscriptionResultUpdatePublisher.UpdateType typeToSend = type;\n      if (publisher == null) {\n        iterator.remove();\n      } else {\n        resultsDeliveryService.execute(\n            () -> {\n              synchronized (publisher) {\n                switch (source) {\n                  case MOST_RECENT_SEGMENT:\n                    publisher.onTranscriptionUpdate(segment, typeToSend);\n                    break;\n                  case WHOLE_RESULT:\n                    publisher.onTranscriptionUpdate(transcript, typeToSend);\n                    break;\n                }\n              }\n            });\n      }\n    }\n  }\n\n  /** Returns a new proto that is labeled with speaker ID information. */\n  TranscriptionResult addSpeakerIDLabels(TranscriptionResult result) {\n    // We don't know whether we'll be using word level detail or not downstream, so have the\n    // diarizer process everything.\n    SpeakerIdInfo wholeUtteranceInfo =\n        diarizer.getSpeakerIDForTimeInterval(\n            TimeUtil.toInstant(result.getStartTimestamp()),\n            TimeUtil.toInstant(result.getEndTimestamp()));\n    List<SpeakerIdInfo> wordLevelInfo = new ArrayList<>(result.getWordLevelDetailCount());\n    for (TranscriptionResult.Word word : result.getWordLevelDetailList()) {\n      wordLevelInfo.add(\n          diarizer.getSpeakerIDForTimeInterval(\n              TimeUtil.toInstant(word.getStartTimestamp()),\n              TimeUtil.toInstant(word.getEndTimestamp())));\n    }\n    // Protos are immutable, so to move the diarization info in, we need to make a deep copy and\n    // fill in the word level data.\n    return result.toBuilder()\n        .setSpeakerInfo(wholeUtteranceInfo)\n        .clearWordLevelDetail()\n        .addAllWordLevelDetail(\n            IntStream.range(0, wordLevelInfo.size())\n                .mapToObj(\n                    i ->\n                        result.getWordLevelDetail(i).toBuilder()\n                            .setSpeakerInfo(wordLevelInfo.get(i))\n                            .build())\n                .collect(Collectors.toList()))\n        .build();\n  }\n\n  /** A Builder class for constructing RepeatingRecognitionSessions. */\n  public static class Builder {\n    // Required.\n    private int sampleRateHz;\n    private SpeechSessionFactory sessionFactory;\n    private SpeechRecognitionModelOptions modelOptions;\n    // Optional. Note that if you don't have either a resultFormatter or a callbackRefs there is\n    // no way to get output out of the RepeatingRecognitionSession.\n    private SafeTranscriptionResultFormatter resultFormatter =\n        new SafeTranscriptionResultFormatter();\n    private NetworkConnectionChecker networkCheck;\n    private SpeechDetectionPolicy speechDetector = new AlwaysSpeechPolicy();\n    private SpeakerIDLabeler diarizer =\n        new AlwaysSameSpeakerIDLabeler(SpeakerIdInfo.newBuilder().setSpeakerId(0).build());\n    private final ConcurrentLinkedQueue<TranscriptionResultPublisherReference> callbackRefs =\n        new ConcurrentLinkedQueue<>();\n    private TranscriptionErrorPublisher transcriptionErrorPublisher;\n    private ExecutorService resultsDeliveryService = Executors.newCachedThreadPool();\n\n    private Builder() {}\n\n    public RepeatingRecognitionSession build() {\n      checkArgument(sampleRateHz > 0);\n      checkNotNull(modelOptions);\n      checkNotNull(sessionFactory);\n      return new RepeatingRecognitionSession(this);\n    }\n\n    public Builder setSampleRateHz(int sampleRateHz) {\n      this.sampleRateHz = sampleRateHz;\n      return this;\n    }\n\n    public Builder setSpeechSessionFactory(SpeechSessionFactory factory) {\n      this.sessionFactory = factory;\n      return this;\n    }\n\n    public Builder setSpeechRecognitionModelOptions(SpeechRecognitionModelOptions modelOptions) {\n      this.modelOptions = modelOptions;\n      return this;\n    }\n\n    public Builder setNetworkConnectionChecker(NetworkConnectionChecker networkCheck) {\n      this.networkCheck = networkCheck;\n      return this;\n    }\n\n    public Builder setTranscriptionResultFormatter(SafeTranscriptionResultFormatter formatter) {\n      this.resultFormatter = formatter;\n      return this;\n    }\n\n    public Builder setSpeechDetectionPolicy(SpeechDetectionPolicy speechDetector) {\n      this.speechDetector = speechDetector;\n      return this;\n    }\n\n    public Builder setSpeakerIDLabeler(SpeakerIDLabeler diarizer) {\n      this.diarizer = diarizer;\n      return this;\n    }\n\n    public Builder addTranscriptionResultCallback(\n        TranscriptionResultUpdatePublisher callback,\n        TranscriptionResultUpdatePublisher.ResultSource source) {\n      checkNotNull(callback);\n      Iterator<TranscriptionResultPublisherReference> iterator = callbackRefs.iterator();\n      while (iterator.hasNext()) {\n        if (callback.equals(iterator.next().get())) {\n          throw new RuntimeException(\"Listener is already registered.\");\n        }\n      }\n      callbackRefs.add(new TranscriptionResultPublisherReference(callback, source));\n      return this;\n    }\n\n    public Builder setTranscriptionErrorPublisher(TranscriptionErrorPublisher publisher) {\n      transcriptionErrorPublisher = publisher;\n      return this;\n    }\n  }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/asr/RequestForRecognitionThread.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr;\n\nimport static com.google.common.base.Preconditions.checkArgument;\n\nimport com.google.audio.asr.TranscriptionResult;\n\n/**\n * Actions that may be performed on the session that should be executed in the recognition thread.\n *\n * <p>Most requests come from a session, but they can also come from a client triggering a reset or\n * a model change. If the request comes from a session, it will be marked with a session ID.\n */\npublic class RequestForRecognitionThread {\n  private static final int NO_SESSION = -1;\n  private final Action action;\n  private final TranscriptionResult result;\n  private final boolean requestIsFinal;\n  private final int sessionID;\n  private final Throwable errorCause;\n\n  /** The action that will be executed on the audio thread of the RepeatingRecognitionSession. */\n  public enum Action {\n    NO_ACTION,\n    HANDLE_NETWORK_CONNECTION_FATAL_ERROR,\n    HANDLE_NON_NETWORK_CONNECTION_FATAL_ERROR,\n    OK_TO_TERMINATE_SESSION,\n    POST_RESULTS,\n    REQUEST_TO_END_SESSION,\n    RESET_SESSION,\n    RESET_SESSION_AND_CLEAR_TRANSCRIPT,\n  }\n\n  private RequestForRecognitionThread(Builder builder) {\n    this.action = builder.action;\n    this.result = builder.result;\n    this.requestIsFinal = builder.requestIsFinal;\n    this.sessionID = builder.sessionID;\n    this.errorCause = builder.errorCause;\n  }\n\n  static Builder newBuilder() {\n    return new Builder();\n  }\n\n  Action action() {\n    return action;\n  }\n\n  boolean hasSessionID() {\n    return sessionID != NO_SESSION;\n  }\n\n  // May return NO_SESSION.\n  int sessionID() {\n    return sessionID;\n  }\n\n  boolean requestIsFinal() {\n    return requestIsFinal;\n  }\n\n  TranscriptionResult result() {\n    return result;\n  }\n\n  Throwable getErrorCause() {\n    return errorCause;\n  }\n\n  /** A Builder class for RequestForRecognitionThread objects. */\n  static class Builder {\n    private Action action = Action.NO_ACTION;\n    private int sessionID = NO_SESSION;\n    private TranscriptionResult result = null;\n    private boolean requestIsFinal;\n    private Throwable errorCause = null;\n\n    private Builder() {}\n\n    /** Notes the action to be performed. If you don't call this, no action will be requested. */\n    public Builder setAction(Action action) {\n      this.action = action;\n      return this;\n    }\n\n    /** Tells the audio thread what the corresponding session ID is. Must be non-negative. */\n    public Builder setSessionID(int sessionID) {\n      // We use a negative value to indicate NO_SESSION. Do not assign a negative ID.\n      checkArgument(sessionID >= 0);\n      this.sessionID = sessionID;\n      return this;\n    }\n\n    /** Adds a finalized/nonfinalized result to the request. */\n    public Builder setResult(TranscriptionResult result, boolean requestIsFinal) {\n      this.result = result;\n      this.requestIsFinal = requestIsFinal;\n      return this;\n    }\n\n    public RequestForRecognitionThread build() {\n      return new RequestForRecognitionThread(this);\n    }\n\n    public Builder setErrorCause(Throwable errorCause) {\n      this.errorCause = errorCause;\n      return this;\n    }\n  }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/asr/SafeTranscriptionResultFormatter.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr;\n\nimport android.text.Spanned;\n\nimport com.google.audio.asr.TranscriptionResult;\nimport com.google.audio.asr.TranscriptionResultFormatterOptions;\nimport com.google.common.flogger.FluentLogger;\nimport com.google.common.util.concurrent.SettableFuture;\n\nimport org.joda.time.Duration;\n\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\n\nimport javax.annotation.concurrent.GuardedBy;\n\n/**\n * A thread-safe version of the TranscriptionResultFormatter. Please see\n * TranscriptionResultFormatter.java for notes on how to use the class.\n *\n * <p>Concurrency notes: These functions may be called from any thread. Note that the delay\n * corresponding to any particular function call depends on the length of the request queue.\n *\n * <p>This class implements a confined thread concurrency model where an internal service,\n * TranscriptionResultFormatterService, delegates requests to an instance of\n * TranscriptResultFormatter in an isolated thread. The thread remains open as long as there is work\n * to be done. If the work queue empties, the thread will close and a new one will spawn on the next\n * work request.\n */\npublic class SafeTranscriptionResultFormatter {\n  private static final FluentLogger logger = FluentLogger.forEnclosingClass();\n\n  private final TranscriptionResultFormatterService service;\n\n  /** Protects the member, confinedThread, when the worker thread is being restarted. */\n  private final Object threadRestartLock = new Object();\n  @GuardedBy(\"threadRestartLock\")\n  private Thread confinedThread;\n\n  /**\n   * A request is a single job to be executed on the worker thread, confinedThread. Its members\n   * represent the various inputs/outputs of the TranscriptionResultFormatter.\n   */\n  private static class Request {\n    // Each of these elements is only used for a subset of requests.\n    public TranscriptionResultFormatterOptions inOptions;\n    public TranscriptionResult inTranscriptionResult;\n    public final SettableFuture<Boolean> outBoolean;\n    public final SettableFuture<Spanned> outSpanned;\n    public final SettableFuture<Duration> outDuration;\n\n    private final RequestType type;\n\n    public Request(RequestType type) {\n      this.type = type;\n      outBoolean = SettableFuture.create();\n      outSpanned = SettableFuture.create();\n      outDuration = SettableFuture.create();\n    }\n  }\n\n  // Used to pass requests to TranscriptionResultFormatterService.\n  private final BlockingQueue<Request> requestQueue = new ArrayBlockingQueue<>(100);\n\n  private enum RequestType {\n    SET_OPTIONS,\n    RESET,\n    ADD_FINALIZED_RESULT,\n    CLEAR_CURRENT_HYPOTHESIS,\n    FINALIZE_CURRENT_HYPOTHESIS,\n    SET_CURRENT_HYPOTHESIS,\n    GET_FORMATTED_TRANSCRIPT,\n    GET_MOST_RECENT_TRANSCRIPT_SEGMENT,\n    GET_TRANSCRIPT_DURATION,\n  }\n\n  private static final String EXECUTION_EXCEPTION_MESSAGE = \"request failed.\";\n  private static final String INTERRUPTED_EXCEPTION_MESSAGE = \"was interrupted.\";\n\n  public SafeTranscriptionResultFormatter() {\n    this.service = new TranscriptionResultFormatterService();\n  }\n\n  public SafeTranscriptionResultFormatter(TranscriptionResultFormatterOptions options) {\n    this.service = new TranscriptionResultFormatterService(options);\n  }\n\n  private void ensureThreadIsRunning() {\n    synchronized (threadRestartLock) {\n      if (confinedThread == null) {\n        logger.atInfo().log(\"Restarting formatter request queue. %s\", confinedThread);\n        confinedThread = new Thread(service);\n        confinedThread.start();\n      }\n    }\n  }\n\n  public void setOptions(TranscriptionResultFormatterOptions options) {\n    try {\n      Request request = new Request(RequestType.SET_OPTIONS);\n      request.inOptions = options;\n      requestQueue.put(request);\n      ensureThreadIsRunning();\n    } catch (InterruptedException interrupted) {\n      logger.atSevere().withCause(interrupted).log(\"setOptions %s\", INTERRUPTED_EXCEPTION_MESSAGE);\n    }\n  }\n\n  public void reset() {\n    try {\n      requestQueue.put(new Request(RequestType.RESET));\n      ensureThreadIsRunning();\n    } catch (InterruptedException interrupted) {\n      logger.atSevere().withCause(interrupted).log(\"reset %s\", INTERRUPTED_EXCEPTION_MESSAGE);\n    }\n  }\n\n  public void addFinalizedResult(TranscriptionResult resultSingleUtterance) {\n    try {\n      Request request = new Request(RequestType.ADD_FINALIZED_RESULT);\n      request.inTranscriptionResult = resultSingleUtterance;\n      requestQueue.put(request);\n      ensureThreadIsRunning();\n    } catch (InterruptedException interrupted) {\n      logger.atSevere().withCause(interrupted).log(\n          \"addFinalizedResult %s\", INTERRUPTED_EXCEPTION_MESSAGE);\n    }\n  }\n\n  public void clearCurrentHypothesis() {\n    try {\n      requestQueue.put(new Request(RequestType.CLEAR_CURRENT_HYPOTHESIS));\n      ensureThreadIsRunning();\n    } catch (InterruptedException interrupted) {\n      logger.atSevere().withCause(interrupted).log(\n          \"clearCurrentHypothesis %s\", INTERRUPTED_EXCEPTION_MESSAGE);\n    }\n  }\n\n  public boolean finalizeCurrentHypothesis() {\n    try {\n      Request request = new Request(RequestType.FINALIZE_CURRENT_HYPOTHESIS);\n      requestQueue.put(request);\n      ensureThreadIsRunning();\n      return request.outBoolean.get();\n    } catch (ExecutionException error) {\n      logger.atSevere().withCause(error).log(\n          \"finalizeCurrentHypothesis %s\", EXECUTION_EXCEPTION_MESSAGE);\n    } catch (InterruptedException interrupted) {\n      logger.atSevere().withCause(interrupted).log(\n          \"finalizeCurrentHypothesis %s\", INTERRUPTED_EXCEPTION_MESSAGE);\n    }\n    return false;\n  }\n\n  public void setCurrentHypothesis(TranscriptionResult resultSingleUtterance) {\n    try {\n      Request request = new Request(RequestType.SET_CURRENT_HYPOTHESIS);\n      request.inTranscriptionResult = resultSingleUtterance;\n      requestQueue.put(request);\n      ensureThreadIsRunning();\n    } catch (InterruptedException interrupted) {\n      logger.atSevere().withCause(interrupted).log(\n          \"setCurrentHypothesis %s\", INTERRUPTED_EXCEPTION_MESSAGE);\n    }\n  }\n\n  public Spanned getFormattedTranscript() {\n    try {\n      Request request = new Request(RequestType.GET_FORMATTED_TRANSCRIPT);\n      requestQueue.put(request);\n      ensureThreadIsRunning();\n      return request.outSpanned.get();\n    } catch (ExecutionException error) {\n      logger.atSevere().withCause(error).log(\n          \"getFormattedTranscript %s\", EXECUTION_EXCEPTION_MESSAGE);\n    } catch (InterruptedException interrupted) {\n      logger.atSevere().withCause(interrupted).log(\n          \"getFormattedTranscript %s\", INTERRUPTED_EXCEPTION_MESSAGE);\n    }\n    return null;\n  }\n\n  public Spanned getMostRecentTranscriptSegment() {\n    try {\n      Request request = new Request(RequestType.GET_MOST_RECENT_TRANSCRIPT_SEGMENT);\n      requestQueue.put(request);\n      ensureThreadIsRunning();\n      return request.outSpanned.get();\n    } catch (ExecutionException error) {\n      logger.atSevere().withCause(error).log(\n          \"getMostRecentTranscriptSegment %s\", EXECUTION_EXCEPTION_MESSAGE);\n    } catch (InterruptedException interrupted) {\n      logger.atSevere().withCause(interrupted).log(\n          \"getMostRecentTranscriptSegment %s\", INTERRUPTED_EXCEPTION_MESSAGE);\n    }\n    return null;\n  }\n\n  public Duration getTranscriptDuration() {\n    try {\n      Request request = new Request(RequestType.GET_TRANSCRIPT_DURATION);\n      requestQueue.put(request);\n      ensureThreadIsRunning();\n      return request.outDuration.get();\n    } catch (ExecutionException error) {\n      logger.atSevere().withCause(error).log(\n          \"getTranscriptDuration %s\", EXECUTION_EXCEPTION_MESSAGE);\n    } catch (InterruptedException interrupted) {\n      logger.atSevere().withCause(interrupted).log(\n          \"getTranscriptDuration %s\", INTERRUPTED_EXCEPTION_MESSAGE);\n    }\n    return null;\n  }\n\n  /**\n   * A service to be run on a separate thread that performs the formatting logic. The formatting\n   * logic is controlled by the TranscriptionResultFormatter instance (which is not thread-safe).\n   * Each job is sent to this class by adding a request into requestQueue. Jobs will be executed in\n   * the order that they are placed in the queue.\n   *\n   * <p>If the queue remains empty for longer than 15 seconds, the run() method will complete and\n   * the parent thread will end. However, it may be restarted in a new thread.\n   */\n  private class TranscriptionResultFormatterService implements Runnable {\n    private final TranscriptionResultFormatter impl;\n\n    TranscriptionResultFormatterService() {\n      impl = new TranscriptionResultFormatter();\n    }\n\n    TranscriptionResultFormatterService(TranscriptionResultFormatterOptions options) {\n      impl = new TranscriptionResultFormatter(options);\n    }\n\n    // Concurrency notes: As long as this task does not make callbacks into client code or\n    // spawn additional tasks, there is no risk of it deadlocking. Be very careful in modifying it.\n\n    @Override\n    public void run() {\n      Thread.currentThread().setName(\"SafeTranscriptionResultFormatterThread\");\n      try {\n        while (true) {\n          // Try and pull from the queue. If the queue is empty for more than 15 seconds, complete\n          // the thread. The parent class will start a new thread to process this service again if\n          // another task arrives.\n          Request request = requestQueue.poll(15, TimeUnit.SECONDS);\n          if (request == null) {\n            // We are ready to terminate the thread.\n            synchronized (threadRestartLock) {\n//              logger.atInfo().log(\"Formatter request queue is exhausted. %s\", confinedThread);\n              // Setting confinedThread to null is very important. This is how we signal in a\n              // synchronizable way that this thread is no longer relevant. The parent object\n              // can restart a new thread if more requests come in.\n              confinedThread = null;\n            }\n            return;\n          }\n          switch (request.type) {\n            case SET_OPTIONS:\n              impl.setOptions(request.inOptions);\n              break;\n            case RESET:\n              impl.reset();\n              break;\n            case ADD_FINALIZED_RESULT:\n              impl.addFinalizedResult(request.inTranscriptionResult);\n              break;\n            case CLEAR_CURRENT_HYPOTHESIS:\n              impl.clearCurrentHypothesis();\n              break;\n            case FINALIZE_CURRENT_HYPOTHESIS:\n              request.outBoolean.set(impl.finalizeCurrentHypothesis());\n              break;\n            case SET_CURRENT_HYPOTHESIS:\n              impl.setCurrentHypothesis(request.inTranscriptionResult);\n              break;\n            case GET_FORMATTED_TRANSCRIPT:\n              request.outSpanned.set(impl.getFormattedTranscript());\n              break;\n            case GET_MOST_RECENT_TRANSCRIPT_SEGMENT:\n              request.outSpanned.set(impl.getMostRecentTranscriptSegment());\n              break;\n            case GET_TRANSCRIPT_DURATION:\n              request.outDuration.set(impl.getTranscriptDuration());\n              break;\n          }\n        }\n      } catch (InterruptedException interrupted) {\n        // Interrupting causes the service to stop.\n        logger.atSevere().withCause(interrupted).log(\"Formatter service has been interrupted\");\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/asr/SpeechDetectionPolicy.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr;\n\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.asrhelpers.SampleProcessorInterface;\n\n/**\n * Decides whether audio should be passed to the recognizer. Unlike the SpeechDetector, this\n * is not trying to make a fine-grain estimate about whether there is speech or not, but instead\n * it decides how to manage sessions, possibly based on the output of a SpeechDetector.\n */\npublic interface SpeechDetectionPolicy extends SampleProcessorInterface {\n  boolean shouldPassAudioToRecognizer();\n\n  void reset();\n\n  /**\n   * Tells the detector that there is currently evidence of speech coming from a source that is\n   * external to this class (for example, getting transcription results from an ASR engine).\n   *\n   * <p>Use of this function is certainly not required (implementations may ignore these cues by not\n   * overriding this function), but it can be used to build speech detectors that consume less power\n   * when there is external evidence of speech.\n   */\n  default void cueEvidenceOfSpeech() {};\n}\n\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/asr/SpeechSession.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr;\n\nimport com.google.audio.asr.SpeechRecognitionModelOptions;\n\n/**\n * Speech recognizers must use this interface. Note that any initialization that if *really*\n * expensive should happen in the factory, not the speech session, as the factory will setup once\n * before streaming occurs and persist across all sessions.\n */\npublic abstract class SpeechSession {\n  private boolean initialized = false;\n  private int sessionID;\n  /** Returns true if internet is an initialization requirement. */\n  public abstract boolean requiresNetworkConnection();\n\n  /**\n   * Any setup that requires network connection should happen here.\n   *\n   * <p>This must not be called multiple times.\n   */\n  public void init(\n      SpeechRecognitionModelOptions modelOptions, int bufferSizeSamples, int sessionID) {\n    if (isInitialized()) {\n      throw new IllegalStateException(\"Do not call initialize multiple times!\");\n    }\n    this.sessionID = sessionID;\n    initImpl(modelOptions, bufferSizeSamples);\n    initialized = true;\n  }\n\n  public int sessionID() {\n    return sessionID;\n  }\n\n  protected abstract void initImpl(\n          SpeechRecognitionModelOptions modelOptions, int bufferSizeSamples);\n\n  /** Returns true if init has been called already. */\n  public final boolean isInitialized() {\n    return initialized;\n  }\n\n  /** Passes audio to the session, formatted as int16 samples. */\n  public boolean processAudioBytes(byte[] buffer, int offset, int count) {\n    if (!isInitialized()) {\n      throw new IllegalStateException(\"Do not call processAudioBytes before init()!\");\n    }\n    return processAudioBytesImpl(buffer, offset, count);\n  }\n\n  protected abstract boolean processAudioBytesImpl(byte[] buffer, int offset, int count);\n\n  /**\n   * Begin the process of ending the speech session. The session need not be fully closed by the\n   * time this function returns. To signal that the session is fully closed, use\n   * SpeechSessionListener.onOkToTerminate() (the listener is passed into the session's\n   * constructor).\n   *\n   * <p>This must not cause isInitialized to return false. This may be called multiple times.\n   */\n  public void requestCloseSession() {\n    if (!isInitialized()) {\n      throw new IllegalStateException(\"Do not call requestCloseSession before init()!\");\n    }\n    requestCloseSessionImpl();\n  }\n\n  protected abstract void requestCloseSessionImpl();\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/asr/SpeechSessionFactory.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr;\n\n/** Factory for creating online or offline speech sessions. */\npublic interface SpeechSessionFactory {\n  SpeechSession create(SpeechSessionListener listener, int sampleRateHz);\n\n  /** Cleans up any allocated resources, if there are any. */\n  default void cleanup() {}\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/asr/SpeechSessionListener.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr;\n\nimport com.google.audio.asr.TranscriptionResult;\n\n/** An interface for communicating recognition events to the RepeatingRecognitionSession. */\npublic interface SpeechSessionListener {\n  /**\n   * Tells the client that the recognizer has had an error from which we cannot recover. It is safe\n   * to terminate the session.\n   */\n  void onSessionFatalError(int sessionID, Throwable error);\n\n  /**\n   * Notifies that a new transcription result is available. If resultIsFinal is false, the results\n   * are subject to change.\n   */\n  void onResults(int sessionID, TranscriptionResult result, boolean resultIsFinal);\n\n  /** Signals that no more audio should be sent to the recognizer. */\n  void onDoneListening(int sessionID);\n\n  /**\n   * Notifies that it is safe to kill the session. Called when the recognizer is done returning\n   * results.\n   */\n  void onOkToTerminateSession(int sessionID);\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/asr/TimeUtil.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr;\n\nimport com.google.protobuf.Timestamp;\nimport com.google.protobuf.util.Durations;\nimport com.google.protobuf.util.Timestamps;\n\nimport org.joda.time.Duration;\nimport org.joda.time.Instant;\n\n/**\n * Conversions between the proto and Joda timestamp representations.\n *\n * <p>Note that toInstant() drops from nanosecond to millisecond precision (which shouldn't be\n * needed for ASR applications anyhow).\n */\npublic final class TimeUtil {\n  public static Instant toInstant(Timestamp t) {\n    return new Instant(Timestamps.toMillis(t));\n  }\n\n  public static Timestamp toTimestamp(Instant t) {\n    return Timestamps.fromMillis(t.getMillis());\n  }\n\n  public static Duration convert(com.google.protobuf.Duration d) {\n    return Duration.millis(Durations.toMillis(d));\n  }\n\n  public static com.google.protobuf.Duration convert(Duration d) {\n    return Durations.fromMillis(d.getMillis());\n  }\n  private TimeUtil() {}\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/asr/TranscriptionErrorPublisher.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr;\n\n/** An interface for notifying the client about ASR errors. */\npublic interface TranscriptionErrorPublisher {\n  /** Called when error happens. */\n  void onError(Throwable errorCause);\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/asr/TranscriptionResultFormatter.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr;\n\nimport android.graphics.Color;\nimport android.graphics.Typeface;\nimport android.text.Spannable;\nimport android.text.SpannableString;\nimport android.text.SpannableStringBuilder;\nimport android.text.Spanned;\nimport android.text.SpannedString;\nimport android.text.TextUtils;\nimport android.text.style.ForegroundColorSpan;\nimport android.text.style.StyleSpan;\n\nimport com.google.audio.asr.TranscriptionResult;\nimport com.google.audio.asr.TranscriptionResultFormatterOptions;\nimport com.google.common.base.Strings;\nimport com.google.common.collect.ImmutableList;\nimport com.google.common.collect.Lists;\n\nimport org.joda.time.Duration;\n\nimport java.util.ArrayDeque;\nimport java.util.Deque;\nimport java.util.List;\n\n/**\n * Creates a colored transcript in the format of {@link SpannedString} from {@link\n * TranscriptionResult} according to the configuration of {@link Options}.\n *\n * <p>This class is not thread-safe. If you intend to use this from multiple threads, consider\n * SafeTranscriptionResultFormatter.\n */\npublic class TranscriptionResultFormatter {\n  private static final String WHITE = \"#ffffffff\"; // Alpha: 1\n  private static final String BLACK = \"#de000000\"; // Alpha: .87\n  // Color gradients can be generated using http://www.perbang.dk/rgbgradient/.\n  // In order of ascending confidence.\n  private static final ImmutableList<String> LIGHT_THEME_COLORS =\n      ImmutableList.of(\"#004ffa\", \"#1b55c8\", \"#375b96\", \"#526164\", \"#6e6732\", \"#8a6e00\");\n  private static final ImmutableList<String> DARK_THEME_COLORS =\n      ImmutableList.of(\"#004ffa\", \"#306dc8\", \"#608c69\", \"#90aa64\", \"#c0c932\", \"#ffff00\");\n  private static final ImmutableList<String> SPEAKER_ID_COLORS =\n      ImmutableList.of(\n          \"#4285f4\", // blue\n          \"#ea4335\", // red\n          \"#fbbc04\", // yellow\n          \"#34a853\", // green\n          \"#FA7B17\", // orange\n          \"#F439A0\", // pink\n          \"#A142F4\", // purple\n          \"#24C1E0\" // cyan\n      );\n\n  private static final ImmutableList<Double> UPPER_CONFIDENCE_THRESHOLDS =\n      ImmutableList.of(0.3, 0.55, 0.7, 0.8, 0.9, Double.POSITIVE_INFINITY);\n\n  // The separator regex used to split a concatenated string of word values.\n  private static final String JAPANESE_SPLITTER_REGEX = \"\\\\|\";\n\n  public static TranscriptionResultFormatterOptions noFormattingOptions() {\n    return TranscriptionResultFormatterOptions.newBuilder()\n        .setNumExtendedSilenceLineBreaks(0)\n        .setNumLanguageSwitchLineBreaks(1)\n        .setItalicizeCurrentHypothesis(false)\n        .setTranscriptColoringStyle(TranscriptionResultFormatterOptions.TranscriptColoringStyle.NO_COLORING)\n        .setTextColormap(TranscriptionResultFormatterOptions.TextColormap.DARK_THEME)\n        .build();\n  }\n\n  /** Formatted text and the TranscriptionResult that produced it. */\n  private static class CachedResult {\n    public Spanned text;\n    public TranscriptionResult result;\n    public Spanned leadingWhitespace;\n\n    CachedResult(TranscriptionResult result, Spanned text, Spanned leadingWhitespace) {\n      this.result = result;\n      this.text = text;\n      this.leadingWhitespace = leadingWhitespace;\n    }\n\n    CharSequence getFormattedText() {\n      return TextUtils.concat(leadingWhitespace, text);\n    }\n  }\n\n  private TranscriptionResultFormatterOptions options;\n\n  private Deque<CachedResult> resultsDeque = new ArrayDeque<>();\n\n  private TranscriptionResult currentHypothesis;\n\n  // A stored string of whitespace to add between extended silences.\n  private String silenceLineBreak;\n  // A stored string of whitespace to add between extended language switch.\n  private String languageSwitchLineBreak;\n  // A joda.org.Duration version of the options field of the same name.\n  private Duration extendedSilenceDurationForLineBreaks;\n\n  // The index of the last speaker contained in the most recently finalized result. -1 indicates\n  // that no results have been seen.\n  private int lastSpeakerId = -1;\n\n  public TranscriptionResultFormatter() {\n    setOptions(noFormattingOptions());\n  }\n\n  public TranscriptionResultFormatter(TranscriptionResultFormatterOptions options) {\n    setOptions(options);\n    reset();\n  }\n\n  /**\n   * Sets the formatter options, which may include settings of current hypotheses in italics or\n   * color transcripts by confidence.\n   */\n  public void setOptions(TranscriptionResultFormatterOptions options) {\n    this.options = options.toBuilder().build();\n\n    lastSpeakerId = -1;\n    // Prepare the whitespace string.\n    silenceLineBreak = createLineBreakString(options.getNumExtendedSilenceLineBreaks());\n    languageSwitchLineBreak = createLineBreakString(options.getNumLanguageSwitchLineBreaks());\n    extendedSilenceDurationForLineBreaks =\n        TimeUtil.convert(options.getExtendedSilenceDurationForLineBreaks());\n\n    // Reformat the old list.\n    Deque<CachedResult> oldResultsDeque = resultsDeque;\n    resultsDeque = new ArrayDeque<>();\n    for (CachedResult oldResult : oldResultsDeque) {\n      addFinalizedResult(oldResult.result);\n    }\n  }\n\n  /**\n   * Creates the line break string.\n   *\n   * @param lineBreakCount line break count in the string.\n   * @return the line break string according to the lineBreakCount.\n   */\n  private String createLineBreakString(int lineBreakCount) {\n    return Strings.repeat(\"\\n\", lineBreakCount);\n  }\n\n  /** Reset to initial state, before any calls to addFinalizedResult() or setCurrentHypothesis(). */\n  public void reset() {\n    resultsDeque.clear();\n    lastSpeakerId = -1;\n    clearCurrentHypothesis();\n  }\n\n  /**\n   * Commits a result to the final transcript.\n   *\n   * <p>NOTE: This does not clear the hypothesis. Users who get partial results (hypotheses) should\n   * prefer calling setCurrentHypothesis(...) and then finalizeCurrentHypothesis().\n   */\n  public void addFinalizedResult(TranscriptionResult resultSingleUtterance) {\n    String lineBreak = obtainLineBreaksFromLastFinalizedResult(resultSingleUtterance);\n    resultsDeque.add(\n        new CachedResult(\n            resultSingleUtterance.toBuilder().build(),\n            formatSingleFinalized(resultSingleUtterance, !lineBreak.isEmpty()),\n            SpannedString.valueOf(lineBreak)));\n    lastSpeakerId = getLastSpeakerIdTag(resultSingleUtterance);\n  }\n\n  /**\n   * Removes the current hypothesis so that only the finalized results will be in the transcript.\n   */\n  public void clearCurrentHypothesis() {\n    currentHypothesis = null;\n  }\n\n  /**\n   * Commits the currently stored hypothesis to the finalized text buffer and clears the hypothesis.\n   *\n   * @return true if it has results to finalize, otherwise false.\n   */\n  public boolean finalizeCurrentHypothesis() {\n    if (currentHypothesis == null) {\n      return false;\n    }\n\n    addFinalizedResult(currentHypothesis);\n    clearCurrentHypothesis();\n    return true;\n  }\n\n  /**\n   * Sets the estimate of the current text, this result is expected to change. Once it is done\n   * changing, commit it, by passing it to addFinalizedResult().\n   */\n  public void setCurrentHypothesis(TranscriptionResult resultSingleUtterance) {\n    currentHypothesis = resultSingleUtterance.toBuilder().build();\n  }\n\n  /** Returns the current finalized text with the hypothesis appended to the end. */\n  public Spanned getFormattedTranscript() {\n    SpannableStringBuilder builder = new SpannableStringBuilder();\n    for (CachedResult timestampedAndCachedResult : resultsDeque) {\n      builder.append(timestampedAndCachedResult.getFormattedText());\n    }\n    builder.append(getFormattedHypothesis());\n\n    return new SpannedString(builder);\n  }\n\n  /** Returns the latest sentence from transcription result. */\n  public Spanned getMostRecentTranscriptSegment() {\n    SpannableStringBuilder builder = new SpannableStringBuilder();\n    builder.append(getFormattedHypothesis());\n    if (!TextUtils.isEmpty(builder)) {\n      return new SpannedString(builder);\n    }\n\n    if (!resultsDeque.isEmpty()) {\n      CachedResult timestampedAndCachedResult = resultsDeque.getLast();\n      builder.append(timestampedAndCachedResult.getFormattedText());\n    }\n\n    return new SpannedString(builder);\n  }\n\n  /** Get the transcription's duration time. */\n  public Duration getTranscriptDuration() {\n    if (resultsDeque.isEmpty()) {\n      return Duration.ZERO;\n    }\n    return new Duration(\n        TimeUtil.toInstant(resultsDeque.peekFirst().result.getStartTimestamp()),\n        TimeUtil.toInstant(resultsDeque.peekLast().result.getEndTimestamp()));\n  }\n\n  private Spannable getFormattedHypothesis() {\n    if (currentHypothesis == null) {\n      return new SpannableString(\"\");\n    }\n\n    SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();\n    String lineBreak = obtainLineBreaksFromLastFinalizedResult(currentHypothesis);\n    boolean precededByLineBreak = !lineBreak.isEmpty();\n    if (precededByLineBreak) {\n      spannableStringBuilder.append(lineBreak);\n    }\n    spannableStringBuilder.append(formatHypothesis(currentHypothesis, precededByLineBreak));\n\n    return SpannableString.valueOf(spannableStringBuilder);\n  }\n\n  private Spannable formatHypothesis(TranscriptionResult result, boolean precededByLineBreak) {\n    Spannable spannable = formatSingleFinalized(result, precededByLineBreak);\n    if (options.getItalicizeCurrentHypothesis()) {\n      spannable.setSpan(\n          new StyleSpan(Typeface.ITALIC),\n          0,\n          spannable.length(),\n          Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);\n    }\n    return spannable;\n  }\n\n  /** A function that maps a Word to a six digit hex color (e.g. #a0b341). */\n  private interface ColorByWordFunction {\n    String getColor(TranscriptionResult.Word w);\n  }\n\n  /**\n   * Format a single result. precededByLineBreak is used to determine if a speaker indicator should\n   * be added to reestablish context after a newline.\n   */\n  private Spannable formatSingleFinalized(\n      TranscriptionResult result, boolean precededByLineBreak) {\n    // Trim leading spaces, but ensure that there will be a space before the next word.\n    String normalizedTranscript = result.getText().trim() + \" \";\n    if (result.getWordLevelDetailList().isEmpty()) {\n      // Process the transcript as a whole.\n      String color = \"\";\n      switch (options.getTranscriptColoringStyle()) {\n        case COLOR_BY_SPEAKER_ID:\n          color = getColorFromSpeakerId(result.getSpeakerInfo().getSpeakerId());\n          break;\n        case COLOR_BY_UTTERANCE_LEVEL_CONFIDENCE:\n          color = getColorFromConfidence(result);\n          break;\n        case COLOR_BY_WORD_LEVEL_CONFIDENCE:\n        case NO_COLORING:\n        case UNSPECIFIED_COLORING_STYLE:\n          color = getDefaultColorFromTheme();\n          break;\n      }\n      if (options.getSpeakerIndicationStyle() == TranscriptionResultFormatterOptions.SpeakerIndicationStyle.SHOW_SPEAKER_NUMBER\n          && (precededByLineBreak || result.getSpeakerInfo().getSpeakerId() != lastSpeakerId)) {\n        boolean requiresLineBreak = lastSpeakerId != -1 && !precededByLineBreak;\n        normalizedTranscript =\n            newSpeakerChevron(result.getSpeakerInfo().getSpeakerId(), requiresLineBreak)\n                + normalizedTranscript;\n      }\n      // Make sure the utterance ends in a trailing space so that words don't get merged together.\n      return makeColoredString(normalizedTranscript, color);\n    } else {\n      // Process each word of the transcript separately.\n      ColorByWordFunction colorFunction = w -> getDefaultColorFromTheme();\n      switch (options.getTranscriptColoringStyle()) {\n        case COLOR_BY_WORD_LEVEL_CONFIDENCE:\n          colorFunction = word -> getColorFromConfidence(word.getConfidence());\n          break;\n        case COLOR_BY_UTTERANCE_LEVEL_CONFIDENCE:\n          colorFunction = word -> getColorFromConfidence(result); // Word-independent.\n          break;\n        case COLOR_BY_SPEAKER_ID:\n          colorFunction = word -> getColorFromSpeakerId(word.getSpeakerInfo().getSpeakerId());\n          break;\n        case NO_COLORING:\n        case UNSPECIFIED_COLORING_STYLE:\n          colorFunction = word -> getDefaultColorFromTheme();\n          break;\n      }\n      return addPerWordColoredStringToResult(\n          normalizedTranscript,\n          result.getLanguageCode(),\n          result.getWordLevelDetailList(),\n          precededByLineBreak,\n          colorFunction);\n    }\n  }\n\n  /**\n   * Obtains line breaks between the last finalized result and current result. It would return an\n   * empty string if no finalized transcript result existed. (Current result is he first element.)\n   */\n  private String obtainLineBreaksFromLastFinalizedResult(TranscriptionResult current) {\n    return resultsDeque.isEmpty()\n        ? \"\"\n        : obtainLineBreaksBetweenTwoResults(resultsDeque.getLast(), current);\n  }\n\n  private String obtainLineBreaksBetweenTwoResults(\n      CachedResult previous, TranscriptionResult current) {\n    boolean languageSwitched = !previous.result.getLanguageCode().equals(current.getLanguageCode());\n    if (options.getNumExtendedSilenceLineBreaks() > 0) { // Previous element is not whitespace.\n      Duration timestampDifference =\n          new Duration(\n              TimeUtil.toInstant(previous.result.getEndTimestamp()),\n              TimeUtil.toInstant(current.getStartTimestamp()));\n      if (timestampDifference.isLongerThan(extendedSilenceDurationForLineBreaks)) {\n        // If language switch and silence both happened, return the longer line break.\n        return languageSwitched ? getLineBreaksWhenSilenceAndLanguageSwitch() : silenceLineBreak;\n      }\n    }\n    return languageSwitched ? languageSwitchLineBreak : \"\";\n  }\n\n  /** Returns the String contains more new line breaks between language switch and silence. */\n  private String getLineBreaksWhenSilenceAndLanguageSwitch() {\n    if (options.getNumExtendedSilenceLineBreaks() >= options.getNumLanguageSwitchLineBreaks()) {\n      return silenceLineBreak;\n    }\n    return languageSwitchLineBreak;\n  }\n\n  private static String getLanguageWithoutDialect(String languageCode) {\n    if (TextUtils.isEmpty(languageCode)) {\n      return \"\";\n    }\n    return languageCode.split(\"-\", -1)[0];\n  }\n\n  /**\n   * Returns string with Hiragana only if language is Japanese. Otherwise, returned string is with\n   * any leading and trailing whitespace removed.\n   */\n  private static String formatWord(String languageCode, String word) {\n    String language = getLanguageWithoutDialect(languageCode);\n    if (\"ja\".equalsIgnoreCase(language)) {\n      // Japanese ASR results could contain two parts per word, the former would be one of\n      // Hiragana, Katakana, or Kanji, and the latter would be Katakana or none. Here extract\n      // the former.\n      return word.split(JAPANESE_SPLITTER_REGEX, -1)[0];\n    }\n    return word.trim();\n  }\n\n  /**\n   * If the word occurs as a substring within the rawTranscript, then the substring starting from\n   * the last occurrence of the word and extends to the end is added to intermediateBuilder. We\n   * assume the transcript is formatted perfectly, and then we don't worry about the word divider\n   * between words for all languages if we construct the transcript by words level detail.\n   */\n  private static boolean checkWordExistedThenAdd(\n      StringBuilder rawTranscript, StringBuilder intermediateBuilder, String word) {\n    int index = rawTranscript.lastIndexOf(word);\n    if (index == -1) {\n      return false;\n    }\n    String transcriptToTheEnd = rawTranscript.substring(index);\n    intermediateBuilder.insert(0, transcriptToTheEnd);\n    rawTranscript.delete(index, rawTranscript.length());\n    return true;\n  }\n\n  /**\n   * Generates a Spannable with text formatted at the word level.\n   *\n   * @param wholeStringTranscript the whole transcript, formatted to have no leading spaces and a\n   *     single trailing space\n   * @param languageCode string language code, for example \"en-us\" or \"ja\"\n   * @param words the list of words contained in wholeStringTranscript\n   * @param colorFunction maps a word to a hex color\n   */\n  private Spannable addPerWordColoredStringToResult(\n      String wholeStringTranscript,\n      String languageCode,\n      List<TranscriptionResult.Word> words,\n      boolean precededByLineBreak,\n      ColorByWordFunction colorFunction) {\n    StringBuilder rawTranscript = new StringBuilder(wholeStringTranscript);\n    boolean wordFound = false;\n    String color = \"\";\n    SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();\n    StringBuilder intermediateBuilder = new StringBuilder();\n    // Group adjacent words of the same color within the same span tag.\n    // Traverse in reverse then a space divider will be at the end of word.\n    List<TranscriptionResult.Word> reverseWords = Lists.reverse(words);\n    for (int wordIndex = 0; wordIndex < reverseWords.size(); ++wordIndex) {\n      TranscriptionResult.Word word = reverseWords.get(wordIndex);\n\n      String nextColor = colorFunction.getColor(word);\n      if (wordFound) {\n        if (!color.equals(nextColor)) {\n          spannableStringBuilder.insert(\n              0, makeColoredString(intermediateBuilder.toString(), color));\n          intermediateBuilder = new StringBuilder();\n          wordFound = false;\n        }\n\n        if (options.getSpeakerIndicationStyle() == TranscriptionResultFormatterOptions.SpeakerIndicationStyle.SHOW_SPEAKER_NUMBER) {\n          // If the speaker has changed or if the text was preceded by a space, add a chevron.\n          int previousSpeaker = reverseWords.get(wordIndex - 1).getSpeakerInfo().getSpeakerId();\n          if (word.getSpeakerInfo().getSpeakerId() != previousSpeaker) {\n            boolean needsAdditionalNewline = previousSpeaker != -1 && !precededByLineBreak;\n            intermediateBuilder.insert(\n                0,\n                newSpeakerChevron(\n                    reverseWords.get(wordIndex - 1).getSpeakerInfo().getSpeakerId(),\n                    needsAdditionalNewline));\n\n            spannableStringBuilder.insert(\n                0, makeColoredString(intermediateBuilder.toString(), color));\n            intermediateBuilder = new StringBuilder();\n            wordFound = false;\n          }\n        }\n      }\n      // We'll try to find previous word if we can't find current word in the rawTranscript.\n      // Append the string started from the word to the end if found.\n      wordFound |=\n          checkWordExistedThenAdd(\n              rawTranscript, intermediateBuilder, formatWord(languageCode, word.getText()));\n      color = nextColor;\n    }\n    boolean forceChevron =\n        precededByLineBreak || words.get(0).getSpeakerInfo().getSpeakerId() != lastSpeakerId;\n    intermediateBuilder.insert(0, rawTranscript.toString());\n    if (options.getSpeakerIndicationStyle() == TranscriptionResultFormatterOptions.SpeakerIndicationStyle.SHOW_SPEAKER_NUMBER\n        && intermediateBuilder.length() != 0\n        && forceChevron) {\n      intermediateBuilder.insert(\n          0,\n          newSpeakerChevron(\n              words.get(0).getSpeakerInfo().getSpeakerId(),\n              lastSpeakerId != -1 && !precededByLineBreak));\n    }\n    spannableStringBuilder.insert(0, makeColoredString(intermediateBuilder.toString(), color));\n    return SpannableString.valueOf(spannableStringBuilder);\n  }\n\n  /**\n   * Generates a {@link SpannableString} containing a colored string.\n   *\n   * @param message a string to append to cachedFinalizedResult\n   * @param color a six-character hex string beginning with a pound sign\n   */\n  private SpannableString makeColoredString(String message, String color) {\n    int textColor = Color.parseColor(color);\n    SpannableString spannableString = new SpannableString(message);\n    spannableString.setSpan(\n        new ForegroundColorSpan(textColor),\n        0,\n        spannableString.length(),\n        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);\n    return spannableString;\n  }\n\n  /**\n   * Get a string hex color associated with a confidence value on the range [0, 1] according to the\n   * confidence in {@link TranscriptionResult}.\n   */\n  private String getColorFromConfidence(TranscriptionResult result) {\n    if (result.hasConfidence()) {\n      return getColorFromConfidence(result.getConfidence());\n    }\n    return getDefaultColorFromTheme();\n  }\n\n  /**\n   * Get a string hex color associated with a confidence value on the range [0, 1] according to\n   * specified confidence.\n   */\n  private String getColorFromConfidence(float confidence) {\n    ImmutableList<String> colormap = getColorList(options.getTextColormap());\n    for (int i = 0; i < UPPER_CONFIDENCE_THRESHOLDS.size(); ++i) {\n      if (confidence <= UPPER_CONFIDENCE_THRESHOLDS.get(i)) {\n        return colormap.get(i);\n      }\n    }\n    // Won't happen because upper bound of UPPER_CONFIDENCE_THRESHOLDS is infinity.\n    return getDefaultColorFromTheme();\n  }\n\n  /** Returns the hex code of the default text color according to the theme. */\n  private String getDefaultColorFromTheme() {\n    switch (options.getTextColormap()) {\n      case DARK_THEME:\n        return WHITE;\n      case LIGHT_THEME:\n      case UNSPECIFIED_THEME:\n        return BLACK;\n    }\n    return WHITE;\n  }\n\n  /**\n   * Get a string hex color associated with the speaker number. Currently this supports up to 4\n   * speakers.\n   */\n  private String getColorFromSpeakerId(int speakerID) {\n    return SPEAKER_ID_COLORS.get(speakerID % SPEAKER_ID_COLORS.size());\n  }\n\n  private static ImmutableList<String> getColorList(TranscriptionResultFormatterOptions.TextColormap colormap) {\n    switch (colormap) {\n      case LIGHT_THEME:\n      case UNSPECIFIED_THEME:\n        return LIGHT_THEME_COLORS;\n      case DARK_THEME:\n        return DARK_THEME_COLORS;\n    }\n    return DARK_THEME_COLORS;\n  }\n\n  private static String newSpeakerChevron(int tag, boolean includesNewline) {\n    return (includesNewline ? \"\\n≫ \" : \"≫ \") + Integer.toString(tag) + \": \";\n  }\n\n  private static int getLastSpeakerIdTag(TranscriptionResult result) {\n    if (result.getWordLevelDetailCount() == 0) {\n      return result.getSpeakerInfo().getSpeakerId();\n    } else {\n      return result\n          .getWordLevelDetailList()\n          .get(result.getWordLevelDetailCount() - 1)\n          .getSpeakerInfo()\n          .getSpeakerId();\n    }\n  }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/asr/TranscriptionResultReceiver.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr;\n\nimport com.google.audio.asr.TranscriptionResult;\nimport com.google.common.base.Objects;\nimport com.google.common.flogger.FluentLogger;\n\nimport java.lang.ref.WeakReference;\n\n/**\n * Handles results as they come in from the recognition module and posts them back to the\n * RepeatingRecognitionSession.\n */\nclass TranscriptionResultReceiver implements SpeechSessionListener {\n  private static final FluentLogger logger = FluentLogger.forEnclosingClass();\n\n  private final WeakReference<RepeatingRecognitionSession.PostHandler> postHandlerRef;\n\n  public TranscriptionResultReceiver(RepeatingRecognitionSession.PostHandler postHandler) {\n    this.postHandlerRef = new WeakReference<>(postHandler);\n  }\n\n  @Override\n  public void onSessionFatalError(int sessionID, Throwable error) {\n    logger.atSevere().withCause(error).log(\"Session #%d ended fatally.\", sessionID);\n    post(\n        RequestForRecognitionThread.newBuilder()\n            .setAction(\n                errorIndicatesLossOfConnection(error)\n                    ? RequestForRecognitionThread.Action.HANDLE_NETWORK_CONNECTION_FATAL_ERROR\n                    : RequestForRecognitionThread.Action.HANDLE_NON_NETWORK_CONNECTION_FATAL_ERROR)\n            .setSessionID(sessionID)\n            .setErrorCause(error)\n            .build());\n  }\n\n  @Override\n  public void onResults(int sessionID, TranscriptionResult result, boolean resultsAreFinal) {\n    post(\n        RequestForRecognitionThread.newBuilder()\n            .setSessionID(sessionID)\n            .setAction(RequestForRecognitionThread.Action.POST_RESULTS)\n            .setResult(result, resultsAreFinal)\n            .build());\n  }\n\n  @Override\n  public void onDoneListening(int sessionID) {\n    logger.atInfo().log(\"Session #%d scheduled to be ended gracefully.\", sessionID);\n    post(sessionID, RequestForRecognitionThread.Action.REQUEST_TO_END_SESSION);\n  }\n\n  @Override\n  public void onOkToTerminateSession(int sessionID) {\n    logger.atInfo().log(\"Session #%d scheduled to be terminated.\", sessionID);\n    post(sessionID, RequestForRecognitionThread.Action.OK_TO_TERMINATE_SESSION);\n  }\n\n  private boolean errorIndicatesLossOfConnection(Throwable error) {\n    boolean isGrpcError = error instanceof io.grpc.StatusRuntimeException;\n    if (isGrpcError) {\n      return Objects.equal(io.grpc.Status.fromThrowable(error), io.grpc.Status.UNAVAILABLE);\n    }\n    return false;\n  }\n\n  private void post(int sessionID, RequestForRecognitionThread.Action request) {\n    post(\n        RequestForRecognitionThread.newBuilder()\n            .setAction(request)\n            .setSessionID(sessionID)\n            .build());\n  }\n\n  private void post(RequestForRecognitionThread request) {\n    RepeatingRecognitionSession.PostHandler postHandler = postHandlerRef.get();\n    if (postHandler == null) {\n      return;\n    }\n    postHandler.post(request);\n  }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/asr/TranscriptionResultUpdatePublisher.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr;\n\nimport android.text.Spanned;\n\n/** An interface for notifying the most recent transcription comes from the recognizer. */\npublic interface TranscriptionResultUpdatePublisher {\n  /** A notification about the nature of the update. */\n  enum UpdateType {\n    TRANSCRIPT_UPDATED,\n    TRANSCRIPT_FINALIZED,\n    TRANSCRIPT_CLEARED,\n  }\n\n  /** Enum defining kinds of transcript result the listeners expect to handle. */\n  enum ResultSource {\n    /** Provides the most recent transcript result in current session. */\n    MOST_RECENT_SEGMENT,\n    /** Provides the whole transcript result in current session. */\n    WHOLE_RESULT\n  }\n\n  /**\n   * Called when transcription updates from the server.\n   *\n   * @param formattedResult The formatted result for the transcription.\n   * @param updateType The nature of the update.\n   */\n  void onTranscriptionUpdate(Spanned formattedResult, UpdateType updateType);\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/asr/asrhelpers/CircularByteBuffer.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.asrhelpers;\n\nimport com.google.common.flogger.FluentLogger;\n\nimport java.util.ArrayList;\n\n/**\n * A storage unit for reading chunks of bytes at a time. Only a single writer may populate\n * data in the CircularByteBuffer, but multiple asynchronous reads are supported as long as the\n * write pointer doesn't overlap with any of the read pointers. If this fails to be true, the output\n * bytes may be corrupted.\n */\npublic class CircularByteBuffer {\n  private static final FluentLogger logger = FluentLogger.forEnclosingClass();\n  private final byte[] buffer;\n  private final int capacity;\n  private int writeHead = 0;\n  private int cumulativeWritten = 0;\n  private final ArrayList<Reader> allReaders = new ArrayList<Reader>();\n\n  /** Reads from a CircularBuffer by maintaining its own position. */\n  public static class Reader {\n    private final CircularByteBuffer owner;\n    private int readHead = 0;\n    private long cumulativeRead = 0;\n\n    // Can be used to see if samples were lost prior to most recent read.\n    // If so many samples have been written that the write pointer overlaps one of the\n    // read pointers, samples will be dropped. This is logged in read(), but you can also,\n    // as the caller of read(), check whether samples were lost by checking to see if\n    // droppedSamplesWarning is true. For example, the following lines would fail an assertion if\n    // data were lost:\n    //   reader.read(some_buffer);\n    //   assert reader.droppedSamplesWarning;\n    // This value is set, but never read, by the CircularByteBuffer or its Readers.\n    public boolean droppedSamplesWarning = false;\n\n    /**\n     * Read, updating the read pointer. numBytes must be less than buffer capacity.\n     * @return true on success.\n     */\n    public boolean read(byte[] dst, int offset, int numBytes) {\n      if (owner.read(this, dst, offset, numBytes)) {\n        cumulativeRead += numBytes;\n        return true;\n      }\n      return false;\n    }\n\n    public boolean read(byte[] dst) {\n      return read(dst, 0, dst.length);\n    }\n\n    /**\n     * Read, without updating the read pointer. numBytes must be less than buffer capacity.\n     * @return true on success.\n     */\n    public boolean peek(byte[] dst, int offset, int numBytes) {\n      return owner.peek(this, dst, offset, numBytes);\n    }\n\n    public boolean peek(byte[] dst) {\n      return peek(dst, 0, dst.length);\n    }\n\n    public void advance(int advanceBy) {\n      readHead = (readHead + advanceBy) % owner.getCapacity();\n    }\n\n    public int availableBytes() {\n      return Math.min(owner.getCapacity(), (int) (owner.getCumulativeWritten() - cumulativeRead));\n    }\n\n    private Reader(CircularByteBuffer owner) {\n      this.owner = owner;\n    }\n\n\n    private void reset() {\n      readHead = 0;\n      cumulativeRead = 0;\n    }\n  }\n\n  public CircularByteBuffer(int capacity) {\n    buffer = new byte[capacity];\n    this.capacity = capacity;\n  }\n\n  /**\n   * Get a reader for the circular buffer. You may use several of these independently.\n   * You should call this before the first call to write() occurring after construction or\n   * calling reset(). Otherwise, you may start reading from somewhere in the middle of the stream.\n   */\n  public Reader newReader() {\n    synchronized (allReaders) {\n      Reader reader = new Reader(this);\n      allReaders.add(reader);\n      return reader;\n    }\n  }\n\n  /** Copy data from src into the circular buffer. Returns false when bytesToWrite\n   *  exceeds capacity.\n   */\n  public synchronized boolean write(byte[] src, int offset, int bytesToWrite) {\n    if (bytesToWrite > capacity) {\n      return false;\n    }\n    if (bytesToWrite == 0) {\n      return true;\n    }\n    if (writeHead + bytesToWrite <= capacity) {\n      System.arraycopy(src, offset, buffer, writeHead, bytesToWrite);\n    } else {  // Data wraps around buffer edge.\n      int entriesBeforeWrap = capacity - writeHead;\n      System.arraycopy(src, offset, buffer, writeHead, entriesBeforeWrap);\n      System.arraycopy(\n          src, offset + entriesBeforeWrap, buffer, 0, bytesToWrite - entriesBeforeWrap);\n    }\n    writeHead = (writeHead + bytesToWrite) % capacity;\n    cumulativeWritten += bytesToWrite;\n    return true;\n  }\n\n  public boolean write(byte[] src) {\n    return write(src, 0, src.length);\n  }\n\n  public int getCapacity() {\n    return capacity;\n  }\n\n  /**\n   * Resets the circular buffer and all of the readers that have been issued. The class is reset to\n   * its initial state upon construction. Readers that have been issued do not get removed.\n   */\n  public synchronized void reset() {\n    java.util.Arrays.fill(buffer, (byte) 0);\n    writeHead = 0;\n    cumulativeWritten = 0;\n    synchronized (allReaders) {\n      for (Reader reader : allReaders) {\n        reader.reset();\n      }\n    }\n  }\n\n  /**\n   * Read data from the buffer and update the read pointer. If the reader is far\n   * enough behind (the write pointer passes the read pointer), samples will be dropped to catch up.\n   */\n  private boolean read(Reader reader, byte[] dst, int offset, int numBytes) {\n    reader.droppedSamplesWarning = false;\n    if (cumulativeWritten - reader.cumulativeRead > capacity) {\n      logger.atSevere().log(\"We lost data before this read!\");\n      // Skip ahead to the very end of the buffer.\n      int skipAmount = (int) (cumulativeWritten - reader.cumulativeRead) - numBytes;\n      reader.advance(skipAmount);\n      reader.cumulativeRead += skipAmount;\n      reader.droppedSamplesWarning = true;\n    }\n    if (peek(reader, dst, offset, numBytes)) {\n      reader.advance(numBytes);\n      return true;\n    }\n    return false;\n  }\n\n  /**\n   * Read data from the buffer without modifying the reader. Note that if the\n   * reader is far enough behind, this will return corrupted data.\n   */\n  private boolean peek(Reader reader, byte[] dst, int offset, int numBytes) {\n    int bytesToRead = numBytes;\n    if (bytesToRead == 0) {\n      return true;\n    }\n    if (bytesToRead < 0 || bytesToRead > reader.availableBytes()) {\n      return false;\n    }\n    int endOfReadSection = (reader.readHead + bytesToRead) % capacity;\n    if (reader.readHead < endOfReadSection) {\n      System.arraycopy(buffer, reader.readHead, dst, offset, endOfReadSection - reader.readHead);\n    } else {  // Data wraps around buffer edge.\n      System.arraycopy(buffer, reader.readHead, dst, offset, capacity - reader.readHead);\n      int entriesBeforeWrap = capacity - reader.readHead;\n      System.arraycopy(\n          buffer, 0, dst, offset + capacity - reader.readHead, bytesToRead - entriesBeforeWrap);\n    }\n    return true;\n  }\n\n  public synchronized long getCumulativeWritten() {\n    return cumulativeWritten;\n  }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/asr/asrhelpers/NetworkConnectionChecker.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.asrhelpers;\n\nimport static android.net.ConnectivityManager.CONNECTIVITY_ACTION;\nimport static android.os.Build.VERSION_CODES.N;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.net.ConnectivityManager;\nimport android.net.ConnectivityManager.NetworkCallback;\nimport android.net.Network;\nimport android.net.NetworkInfo;\nimport android.os.Build.VERSION;\n\nimport androidx.lifecycle.LifecycleOwner;\nimport androidx.lifecycle.MutableLiveData;\nimport androidx.lifecycle.Observer;\n\nimport com.google.audio.NetworkState;\nimport com.google.common.base.Preconditions;\nimport com.google.common.flogger.FluentLogger;\n\n/**\n * Checks whether or not there is currently a connection and if that connection is Wifi. Need to\n * call {@link #unregisterNetworkCallback()} before it is destroyed.\n */\npublic class NetworkConnectionChecker {\n  private static final FluentLogger logger = FluentLogger.forEnclosingClass();\n  private final ConnectivityManager connectionManager;\n  private final NetworkCallback networkCallback;\n  private final MutableLiveData<NetworkState> state;\n  private final Context context;\n  private final BroadcastReceiver networkStateReceiver =\n      new BroadcastReceiver() {\n        @Override\n        public void onReceive(Context context, Intent intent) {\n          synchronized (state) {\n            state.postValue(getNetworkState());\n          }\n        }\n      };\n\n  public NetworkConnectionChecker(Context context) {\n    Preconditions.checkNotNull(\n        context, \"You need to pass a context to the NetworkConnectionChecker\");\n    this.context = context;\n    this.connectionManager =\n        (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);\n    this.networkCallback =\n        new NetworkCallback() {\n          @Override\n          public void onAvailable(Network network) {\n            synchronized (state) {\n              logger.atConfig().log(\"Network is available.\");\n              state.postValue(\n                  NetworkState.newBuilder()\n                      .setConnected(true)\n                      .setNetworkMetered(connectionManager.isActiveNetworkMetered())\n                      .build());\n            }\n          }\n\n          @Override\n          public void onLost(Network network) {\n            synchronized (state) {\n              logger.atConfig().log(\"Network is unavailable.\");\n              state.postValue(\n                  NetworkState.newBuilder()\n                      .setConnected(false)\n                      .setNetworkMetered(connectionManager.isActiveNetworkMetered())\n                      .build());\n            }\n          }\n        };\n    state = new MutableLiveData<>();\n    registerNetworkCallback();\n  }\n\n  public void addNetworkStateObserver(LifecycleOwner owner, Observer<NetworkState> observer) {\n    synchronized (state) {\n      state.observe(owner, observer);\n    }\n  }\n\n  protected NetworkState getNetworkState() {\n    NetworkInfo activeNetwork = connectionManager.getActiveNetworkInfo();\n    boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting();\n    NetworkState state =\n        NetworkState.newBuilder()\n            .setConnected(isConnected)\n            .setNetworkMetered(connectionManager.isActiveNetworkMetered())\n            .build();\n    return state;\n  }\n\n  public boolean isConnected() {\n    synchronized (state) {\n      return state.getValue().getConnected();\n    }\n  }\n\n  /**\n   * Applications can skip register if they don't need register/unregister many times. Callback\n   * register is done in the constructor.\n   */\n  public void registerNetworkCallback() {\n    synchronized (state) {\n      state.postValue(getNetworkState());\n    }\n    if (VERSION.SDK_INT >= N) {\n      connectionManager.registerDefaultNetworkCallback(networkCallback);\n    } else {\n      context.registerReceiver(networkStateReceiver, new IntentFilter(CONNECTIVITY_ACTION));\n    }\n  }\n\n  /** Note this must be called if NetworkConnectionChecker is not being used anymore. */\n  public void unregisterNetworkCallback() {\n    try {\n      if (VERSION.SDK_INT >= N) {\n        connectionManager.unregisterNetworkCallback(networkCallback);\n      } else {\n        context.unregisterReceiver(networkStateReceiver);\n      }\n    } catch (IllegalArgumentException unregisteredCallbackException) {\n      logger.atWarning().log(\"Tried to unregister network callback already unregistered.\");\n    }\n  }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/asr/asrhelpers/ResponseTextUiAdapter.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.asrhelpers;\n\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.teamopensmartglasses.smartglassesmanager.R;\n\nimport java.util.List;\n\npublic class ResponseTextUiAdapter extends RecyclerView.Adapter<ResponseTextUiAdapter.ViewHolder> {\n    private List<String> data;\n\n    public ResponseTextUiAdapter(List<String> data) {\n        this.data = data;\n    }\n\n    @NonNull\n    @Override\n    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n        View view = LayoutInflater.from(parent.getContext())\n                .inflate(R.layout.response_text_box, parent, false);\n        return new ViewHolder(view);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n        String text = data.get(position);\n        holder.textView.setText(text);\n    }\n\n    @Override\n    public int getItemCount() {\n        return data.size();\n    }\n\n    static class ViewHolder extends RecyclerView.ViewHolder {\n        TextView textView;\n\n        ViewHolder(@NonNull View itemView) {\n            super(itemView);\n            textView = itemView.findViewById(R.id.textView);\n        }\n    }\n\n    public void addText(String text) {\n        data.add(text);\n        notifyItemInserted(data.size() - 1);\n    }\n\n    public void clearTexts() {\n        data.clear();\n        notifyDataSetChanged();\n    }\n}"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/asr/asrhelpers/SampleProcessorInterface.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.asrhelpers;\n\n/** An interface for sending samples to an object. */\npublic interface SampleProcessorInterface {\n  public void init(int blockSizeSamples);\n  /**\n   *  Samples are PCM, 16-bit samples, formatted as a byte stream.\n   */\n  public void processAudioBytes(byte[] bytes, int offset, int length);\n\n  public default void processAudioBytes(byte[] bytes) {\n    processAudioBytes(bytes, 0, bytes.length);\n  }\n\n  /**\n   * Call when you want the interface to stop playing. Playing may restart, so don't\n   * deallocate resources here.\n   */\n  public void stop();\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/asr/asrhelpers/SpeakerIDLabeler.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.asrhelpers;\n\nimport com.google.audio.SpeakerIdInfo;\n\nimport org.joda.time.Instant;\n\n/**\n * An interface for classes that estimates labels for individual speakers.\n */\npublic interface SpeakerIDLabeler extends SampleProcessorInterface {\n  /**\n   * Tells the diarizer what time it is *now*. The expectation is that time will be incremented\n   * within the calls to processAudioBytes based on the number of samples that are passed.\n   */\n  void setReferenceTimestamp(Instant now);\n\n  /**\n   * Asks the diarizer which speaker was most likely to be active during the time interval (start,\n   * end). The same request may be made several times for the same interval, so this function should\n   * be very inexpensive.\n   */\n  SpeakerIdInfo getSpeakerIDForTimeInterval(Instant start, Instant end);\n\n  /**\n   * Clears the labels currently stored in the diarizer. It is useful to periodically clear the\n   * labels (such as at the start of every new utterance) in order to keep small the data structure\n   * that holds the diarization timestamps.\n   */\n  void clearSpeakerIDTimestamps();\n\n  /** Resets the state of the diarizer as if no audio has been seen. */\n  void reset();\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/asr/asrhelpers/StreamingAudioEncoder.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.asrhelpers;\n\nimport static com.google.common.base.Preconditions.checkArgument;\n\nimport android.media.MediaCodec;\nimport android.media.MediaCodecInfo;\nimport android.media.MediaCodecList;\nimport android.media.MediaFormat;\nimport android.os.Build.VERSION;\nimport android.os.Build.VERSION_CODES;\n\nimport com.google.audio.CodecAndBitrate;\nimport com.google.common.collect.ImmutableList;\nimport com.google.common.flogger.FluentLogger;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\n\n/**\n * Converts from uncompressed 16-bit PCM data to encoded data.\n *\n * <p>You may call the sequence (init, processAudioBytes, ..., processAudioBytes, flush, stop)\n * multiple times.\n *\n * <p>Note that AMR-WB encoding is mandatory for handheld devices and OggOpus is supported\n * regardless of device.\n */\n// Based on examples from https://developer.android.com/reference/android/media/MediaCodec\n// and some reference tests:\n// https://android.googlesource.com/platform/cts/+/jb-mr2-release/tests/tests/media/src/android/media/cts/EncoderTest.java\npublic class StreamingAudioEncoder {\n  private static final FluentLogger logger = FluentLogger.forEnclosingClass();\n  private static final int BYTES_PER_SAMPLE = 2;\n\n  // This is not meaningful for OggOpus, which does not rely on the AndroidSystemEncoder.\n  private boolean useDeprecatedEncoder = false;\n\n  /** State variables for basic control flow management. */\n  private boolean flushed;\n\n  private boolean initialized = false;\n\n  /** An exception for anything that goes wrong with the coder as a result of misuse. */\n  public static class EncoderException extends Exception {\n    public EncoderException(String message) {\n      super(message);\n    }\n  }\n\n  /** Describes the general class of codecs. */\n  public enum CodecType {\n    UNSPECIFIED,\n    AMRWB,\n    FLAC,\n    OGG_OPUS,\n  }\n\n  CodecType codecType = CodecType.UNSPECIFIED;\n\n  private StreamingAudioInternalEncoder impl;\n\n  /** Creates an audio encoder. */\n  public StreamingAudioEncoder(boolean useDeprecatedEncoder) {\n    this.useDeprecatedEncoder = useDeprecatedEncoder;\n  }\n\n  public StreamingAudioEncoder() {\n    this(VERSION.SDK_INT <= VERSION_CODES.KITKAT_WATCH);\n  }\n\n  private interface StreamingAudioInternalEncoder {\n    void init(int sampleRateHz, CodecAndBitrate codecAndBitrate, boolean useVbr)\n        throws EncoderException, IOException;\n\n    byte[] processAudioBytes(byte[] input, int offset, int length);\n\n    byte[] flushAndStop();\n  }\n\n  /**\n   * Prepares a codec to stream. This may be called only if instance is uninitialized (prior to a\n   * call to init() or after a call to stop()).\n   *\n   * @throws IOException if codec cannot be created.\n   * @throws EncoderException if sample rate is not 16kHz or if no suitable encoder exists on device\n   *     for the requested format.\n   */\n  public void init(int sampleRateHz, CodecAndBitrate codecAndBitrate, boolean allowVbr)\n      throws EncoderException, IOException {\n    codecType = lookupCodecType(codecAndBitrate);\n\n    if (codecType == CodecType.OGG_OPUS) {\n      impl = new OggOpusEncoder();\n    } else {\n      impl = new AndroidSystemEncoder(useDeprecatedEncoder);\n    }\n    impl.init(sampleRateHz, codecAndBitrate, allowVbr);\n    initialized = true;\n    flushed = false;\n  }\n\n  /**\n   * Encodes 16-bit PCM audio. This will not always return bytes and will block until the codec has\n   * no output to offer. Must be called after init().\n   *\n   * @param input array of audio samples formatted as raw bytes (i.e., two bytes per sample). buffer\n   *     may be of any size.\n   * @param offset the offset of the first byte to process\n   * @param length the number of bytes to process from input\n   * @return bytes of compressed audio\n   */\n  public byte[] processAudioBytes(byte[] input, int offset, int length) {\n    if (!initialized) {\n      throw new IllegalStateException(\"You forgot to call init()!\");\n    }\n    if (flushed) {\n      throw new IllegalStateException(\"Cannot process more bytes after flushing.\");\n    }\n    return impl.processAudioBytes(input, offset, length);\n  }\n\n  public byte[] processAudioBytes(byte[] input) {\n    return processAudioBytes(input, 0, input.length);\n  }\n\n  /** Stop the codec. Call init() before using again. */\n  public byte[] flushAndStop() {\n    if (!initialized) {\n      throw new IllegalStateException(\"You forgot to call init()!\");\n    }\n    if (flushed) {\n      throw new IllegalStateException(\"Already flushed. You must reinitialize.\");\n    }\n    flushed = true;\n    byte[] flushedBytes = impl.flushAndStop();\n    initialized = false;\n    codecType = CodecType.UNSPECIFIED;\n    return flushedBytes;\n  }\n\n  /**\n   * Can be used to test if codec will work or not on a given device. This will always return the\n   * same value no matter when you call it.\n   */\n  public static boolean isEncoderSupported(CodecAndBitrate encoderInfo) {\n    CodecType type = lookupCodecType(encoderInfo);\n    if (type == CodecType.OGG_OPUS) { // We support Opus directly via the OggOpusEncoder class.\n      return true;\n    }\n    return searchAmongAndroidSupportedCodecs(getMime(type)) != null;\n  }\n\n  public CodecType getCodecType() {\n    return codecType;\n  }\n\n  private static String getMime(CodecType codecAndBitrate) {\n    // MediaFormat.MIMETYPE_AUDIO_AMR_WB requires SDK >= 21.\n    switch (codecAndBitrate) {\n      case AMRWB:\n        return \"audio/amr-wb\";\n      case FLAC:\n        return \"audio/flac\";\n      case OGG_OPUS: // Not supported by android system, so we don't need a MIME.\n      case UNSPECIFIED:\n        return \"\";\n    }\n    return \"\";\n  }\n\n  private static CodecType lookupCodecType(CodecAndBitrate codecAndBitrate) {\n    switch (codecAndBitrate) {\n      case AMRWB_BITRATE_6KBPS:\n      case AMRWB_BITRATE_8KBPS:\n      case AMRWB_BITRATE_12KBPS:\n      case AMRWB_BITRATE_14KBPS:\n      case AMRWB_BITRATE_15KBPS:\n      case AMRWB_BITRATE_18KBPS:\n      case AMRWB_BITRATE_19KBPS:\n      case AMRWB_BITRATE_23KBPS:\n      case AMRWB_BITRATE_24KBPS:\n        return CodecType.AMRWB;\n      case FLAC:\n        return CodecType.FLAC;\n      case OGG_OPUS_BITRATE_12KBPS:\n      case OGG_OPUS_BITRATE_16KBPS:\n      case OGG_OPUS_BITRATE_24KBPS:\n      case OGG_OPUS_BITRATE_32KBPS:\n      case OGG_OPUS_BITRATE_64KBPS:\n      case OGG_OPUS_BITRATE_96KBPS:\n      case OGG_OPUS_BITRATE_128KBPS:\n        return CodecType.OGG_OPUS;\n      case UNDEFINED:\n        return CodecType.UNSPECIFIED;\n    }\n    return CodecType.UNSPECIFIED;\n  }\n\n  /**\n   * Searches for a codec that implements the requested format conversion. Android framework encoder\n   * only.\n   */\n  private static MediaCodecInfo searchAmongAndroidSupportedCodecs(String mimeType) {\n    int numCodecs = MediaCodecList.getCodecCount();\n    for (int i = 0; i < numCodecs; i++) {\n      MediaCodecInfo codecAndBitrate = MediaCodecList.getCodecInfoAt(i);\n      if (!codecAndBitrate.isEncoder()) {\n        continue;\n      }\n      String[] codecTypes = codecAndBitrate.getSupportedTypes();\n      for (int j = 0; j < codecTypes.length; j++) {\n        if (codecTypes[j].equalsIgnoreCase(mimeType)) {\n          return codecAndBitrate;\n        }\n      }\n    }\n    return null;\n  }\n\n  /** An encoder that relies on the Android framework's multimedia encoder. */\n  private static class AndroidSystemEncoder implements StreamingAudioInternalEncoder {\n    // If we can't supply a buffer immediately, we wait until the next one, which is timed at the\n    // microphone & block rate of the audio supplier. Waiting less than that time and getting\n    // samples\n    // before the next input buffer would reduce latency.\n    private static final long WAIT_TIME_MICROSECONDS = 1000; // Joda doesn't support microseconds.\n    /**\n     * Notes when the codec formatting change has occurred. This should happen only once at the\n     * start of streaming. Otherwise, there is an error.\n     */\n    private boolean formatChangeReportedOnce;\n\n    private MediaCodec codec;\n    private boolean useDeprecatedEncoder = false;\n    private CodecType codecType;\n    private int sampleRateHz;\n\n    /** Prevents trying to flush multiple times. */\n    private boolean successfullyFlushed;\n\n    /** Keeps track of whether the header was injected into the stream. */\n    private boolean addedHeader;\n\n    /**\n     * The number of samples that are passed to the underlying codec at once. It's not clear that\n     * one value for this will work better than any other, but powers of two are usually fast, and a\n     * larger CHUNK_SIZE_SAMPLES both reduces the number of buffers we have to wait for and doesn't\n     * prevent sending smaller blocks of samples.\n     */\n    private static final int CHUNK_SIZE_SAMPLES = 2048;\n\n    private static final int CHUNK_SIZE_BYTES = BYTES_PER_SAMPLE * CHUNK_SIZE_SAMPLES;\n\n    // Used only on very old SDKs (pre VERSION_CODES.KITKAT_WATCH).\n    private ByteBuffer[] inputBuffersPreKitKat;\n    private ByteBuffer[] outputBuffersPreKitKat;\n\n    /** Creates an audio encoder. */\n    public AndroidSystemEncoder(boolean useDeprecatedEncoder) {\n      this.useDeprecatedEncoder = useDeprecatedEncoder;\n      this.codecType = CodecType.UNSPECIFIED;\n    }\n\n    // Note that VBR is not currently supported for the AndroidStreamingEncoder.\n    @Override\n    public void init(int sampleRateHz, CodecAndBitrate codecAndBitrate, boolean allowVbr)\n        throws EncoderException, IOException {\n      codecType = lookupCodecType(codecAndBitrate);\n      if (codecType == CodecType.UNSPECIFIED || codecType == CodecType.OGG_OPUS) {\n        throw new EncoderException(\"Codec not set properly.\");\n      }\n      if (codecType == CodecType.AMRWB && sampleRateHz != 16000) {\n        throw new EncoderException(\"AMR-WB encoder requires a sample rate of 16kHz.\");\n      }\n      MediaCodecInfo codecInfo = searchAmongAndroidSupportedCodecs(getMime(codecType));\n      if (codecInfo == null) {\n        throw new EncoderException(\"Encoder not found.\");\n      }\n      this.codec = MediaCodec.createByCodecName(codecInfo.getName());\n\n      MediaFormat format = getMediaFormat(codecAndBitrate, sampleRateHz);\n      codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);\n      codec.start();\n      initBuffers();\n\n      addedHeader = false;\n      successfullyFlushed = false;\n      formatChangeReportedOnce = false;\n    }\n\n    @Override\n    public byte[] processAudioBytes(byte[] input, int offset, int length) {\n      ByteArrayOutputStream outputBytes = new ByteArrayOutputStream();\n      if (!addedHeader) {\n        try {\n          outputBytes.write(getHeaderBytes());\n        } catch (IOException e) {\n          logger.atSevere().log(\"Unable to write bytes into buffer!\");\n        }\n        addedHeader = true;\n      }\n      int startByte = 0;\n      while (startByte < length) {\n        int thisChunkSizeBytes = Math.min(CHUNK_SIZE_BYTES, length - startByte);\n        processAudioBytesInternal(\n            input, offset + startByte, thisChunkSizeBytes, false, outputBytes);\n        startByte += thisChunkSizeBytes;\n      }\n      return outputBytes.toByteArray();\n    }\n\n    @Override\n    public byte[] flushAndStop() {\n      ByteArrayOutputStream outputBytes = new ByteArrayOutputStream();\n      try {\n        processAudioBytesInternal(null, 0, 0, true, outputBytes);  // Flush!\n        codec.stop();\n      } catch (MediaCodec.CodecException e) {\n        logger.atSevere().log(\"Something went wrong in the underlying codec!\");\n      }\n      codec.release();\n      return outputBytes.toByteArray();\n    }\n\n    // length must be less than or equal to CHUNK_SIZE_BYTES.\n    private void processAudioBytesInternal(\n        byte[] input, int offset, int length, boolean flush, ByteArrayOutputStream outputBytes) {\n      checkArgument(\n          length <= CHUNK_SIZE_BYTES, \"length must be less than or equal to CHUNK_SIZE_BYTES!\");\n      boolean processedInput = false;\n      // There are a limited number of buffers allocated in the codec. As long as we're not\n      // holding on to them, they should always be available. Sometimes all buffers will be occupied\n      // by the output and we need to process them before pushing input. Sometimes multiple output\n      // buffers will be available at once. Append them together and return. It is common for\n      // outputBytes to not receive any samples upon returning.\n      MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();\n      // Loop until input is processed and outputs are unavailable.\n      while (!processedInput || flush) {\n        if (!processedInput) {\n          if (flush && successfullyFlushed) {\n            throw new IllegalStateException(\"Already flushed!\");\n          }\n          // Push the input only once.\n          int inputBufferIndex = codec.dequeueInputBuffer(WAIT_TIME_MICROSECONDS);\n          if (inputBufferIndex != MediaCodec.INFO_TRY_AGAIN_LATER) {\n            if (flush) {\n              // Signal that the input stream is complete.\n              codec.queueInputBuffer(\n                  inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);\n              successfullyFlushed = true;\n            } else {\n              // Push audio data into the codec.\n              ByteBuffer inputBuffer = getInputBuffer(inputBufferIndex);\n              inputBuffer.put(input, offset, length);\n              codec.queueInputBuffer(inputBufferIndex, 0, length, 0, 0);\n            }\n            processedInput = true;\n          }\n        }\n        // See if outputs are available.\n        int outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, WAIT_TIME_MICROSECONDS);\n        if (outputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {\n          // There will not be an output buffer for every input buffer.\n        } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {\n          // Shouldn't happen after the very first output.\n          if (formatChangeReportedOnce) {\n            throw new IllegalStateException(\"The codec format was unexpectedly changed.\");\n          }\n          formatChangeReportedOnce = true;\n        } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {\n          // Shouldn't happen for SDK > 21.\n          updateOutputBuffers();\n        } else {\n          // Get an output buffer and add it to the stream.\n          ByteBuffer outputBuffer = getOutputBuffer(outputBufferIndex);\n          byte[] outData = new byte[bufferInfo.size];\n          outputBuffer.get(outData);\n          codec.releaseOutputBuffer(outputBufferIndex, false);\n          try {\n            outputBytes.write(outData);\n          } catch (IOException e) {\n            logger.atSevere().log(\"Unable to write bytes into buffer!\");\n          }\n        }\n\n        boolean processedAllOutput = (bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;\n        if (processedAllOutput) {\n          if (!processedInput) {\n            throw new IllegalStateException(\"Didn't process input yet.\");\n          }\n          break;\n        }\n      }\n    }\n\n    /** Configure the codec at a specified bitrate for a fixed sample block size. */\n    private static MediaFormat getMediaFormat(CodecAndBitrate codecAndBitrate, int sampleRateHz) {\n      MediaFormat format = new MediaFormat();\n      CodecType codecType = lookupCodecType(codecAndBitrate);\n      format.setString(MediaFormat.KEY_MIME, getMime(codecType));\n      format.setInteger(MediaFormat.KEY_SAMPLE_RATE, sampleRateHz);\n      format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);\n      format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, BYTES_PER_SAMPLE * CHUNK_SIZE_SAMPLES);\n      if (codecType != CodecType.FLAC) {\n        // FLAC is lossless, we can't request a bitrate.\n        format.setInteger(MediaFormat.KEY_BIT_RATE, codecAndBitrate.getNumber());\n      }\n      return format;\n    }\n\n    /** The data does not include a header. Some applications will require one anyhow. */\n    private byte[] getHeaderBytes() {\n      switch (this.codecType) {\n        case AMRWB:\n          String amrWbHeader = \"#!AMR-WB\\n\";\n          return amrWbHeader.getBytes();\n        case FLAC:\n          byte[] noHeader = new byte[0];\n          return noHeader;\n        case OGG_OPUS:\n          throw new IllegalStateException(\"Should never happen! Use OggOpusEncoder instead.\");\n        case UNSPECIFIED:\n          throw new IllegalStateException(\"Trying to make header for unspecified codec!\");\n      }\n      return null;\n    }\n\n    // The following methods are used to resolve differences between SDK versions.\n\n    private void initBuffers() {\n      if (useDeprecatedEncoder) {\n        inputBuffersPreKitKat = codec.getInputBuffers();\n        outputBuffersPreKitKat = codec.getOutputBuffers();\n      }\n    }\n\n    private ByteBuffer getInputBuffer(int index) {\n      if (useDeprecatedEncoder) {\n        return inputBuffersPreKitKat[index];\n      } else {\n        return codec.getInputBuffer(index);\n      }\n    }\n\n    private ByteBuffer getOutputBuffer(int index) {\n      if (useDeprecatedEncoder) {\n        return outputBuffersPreKitKat[index];\n      } else {\n        return codec.getOutputBuffer(index);\n      }\n    }\n\n    private void updateOutputBuffers() {\n      if (useDeprecatedEncoder) {\n        outputBuffersPreKitKat = codec.getOutputBuffers();\n      }\n    }\n  }\n\n  private static class OggOpusEncoder implements StreamingAudioInternalEncoder {\n    // This is a pointer to the native object that we're working with. Zero when unallocated.\n    private long instance = 0;\n\n    ImmutableList<Integer> validSampleRates = ImmutableList.of(8000, 12000, 16000, 24000, 48000);\n    public OggOpusEncoder() {}\n\n    @Override\n    public void init(int sampleRateHz, CodecAndBitrate codecAndBitrate, boolean allowVbr)\n        throws EncoderException {\n      if (instance != 0) {\n        flushAndStop();\n      }\n      CodecType codecType = lookupCodecType(codecAndBitrate);\n      if (codecType != CodecType.OGG_OPUS) {\n        throw new RuntimeException(\"Made OggOpusEncoder for non OGG_OPUS encoding type.\");\n      }\n      if (!validSampleRates.contains(sampleRateHz)) {\n        throw new EncoderException(\n            \"Opus encoder requires a sample rate of 8kHz, 12kHz, 16kHz, 24kHz, or 48kHz.\");\n      }\n      this.instance =\n          init(1 /* Mono audio. */, codecAndBitrate.getNumber(), sampleRateHz, allowVbr);\n    }\n\n    private native long init(int channels, int bitrate, int sampleRateHz, boolean allowVbr);\n\n    @Override\n    public byte[] processAudioBytes(byte[] bytes, int offset, int length) {\n      return processAudioBytes(instance, bytes, offset, length);\n    }\n\n    private native byte[] processAudioBytes(long instance, byte[] samples, int offset, int length);\n\n    /**\n     * Complete the input stream, return any remaining bits of the output stream, and stop.\n     * This should only be called once. Must be called after init().\n     *\n     * @return bytes of compressed audio\n     */\n    @Override\n    public byte[] flushAndStop() {\n      if (instance != 0) {\n        byte[] flushedBytes = flush(instance);\n        free(instance);\n        instance = 0;\n        return flushedBytes;\n      } else {\n        logger.atSevere().log(\"stop() called multiple times or without call to init()!\");\n        return new byte[0];\n      }\n    }\n\n    @Override\n    protected void finalize() throws Throwable {\n      super.finalize();\n      if (instance != 0) {\n        logger.atSevere().log(\n            \"Native OggOpusEncoder resources weren't cleaned up. You must call stop()!\");\n        free(instance);\n      }\n    }\n\n    private native byte[] flush(long instance);\n    private native void free(long instance);\n  }\n\n  static {\n    System.loadLibrary(\"ogg_opus_encoder\");\n  }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/gcloudspeech/CloudSpeechSession.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// The CloudSpeechSession streams audio to the server until the endpointer tells it to stop. It\n// therefore must be repeatedly reopened for continuous transcription. The response observer gets\n// data back from the server. Our CloudSpeechStreamObserver extracts the speech and the confidence\n// and passes the data to a SpeechSessionListener, which helps to aggregate\n// TranscriptionResults and manage the repeatedly reopening sessions.\n\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.gcloudspeech;\n\nimport com.google.audio.asr.CloudSpeechSessionParams;\nimport com.google.audio.asr.SpeechRecognitionModelOptions;\nimport com.google.cloud.speech.v1p1beta1.RecognitionConfig;\nimport com.google.cloud.speech.v1p1beta1.SpeechContext;\nimport com.google.cloud.speech.v1p1beta1.SpeechGrpc;\nimport com.google.cloud.speech.v1p1beta1.StreamingRecognitionConfig;\nimport com.google.cloud.speech.v1p1beta1.StreamingRecognizeRequest;\nimport com.google.common.flogger.FluentLogger;\nimport com.google.protobuf.ByteString;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.SpeechSession;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.SpeechSessionListener;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.asrhelpers.StreamingAudioEncoder;\n\nimport org.joda.time.Duration;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\n\nimport io.grpc.ManagedChannel;\nimport io.grpc.stub.StreamObserver;\n\n/**\n * Lightweight wrapper around the GRPC Google Cloud Speech API. It can handle one streaming\n * recognition request at a time.\n */\npublic class CloudSpeechSession extends SpeechSession {\n  private static final FluentLogger logger = FluentLogger.forEnclosingClass();\n  private SpeechGrpc.SpeechStub speechClient;\n\n  // Since the speech session times out after 5 minutes, we should try to avoid sessions reaching\n  // approximately that length. If speech begins 4 mins and 30 seconds into the transcription, it\n  // will likely be cut off. Therefore, we close sessions that haven't received any results in an\n  // extended period of time.\n  public static final Duration CLOSE_SESSION_AFTER_EXTENDED_SILENCE_DURATION =\n      Duration.standardMinutes(4).plus(Duration.standardSeconds(30));\n\n  /**\n   * The stream observer and cloud interaction functions are marked protected so that they may be\n   * replaced with a local server simulation in testing.\n   */\n  private CloudSpeechStreamObserver responseObserver;\n\n  private StreamObserver<StreamingRecognizeRequest> requestObserver;\n\n  private final CloudSpeechSessionParams params;\n  private final SpeechSessionListener speechSessionListener;\n  private int sampleRateHz;\n\n  private boolean stillSendingRequests = false;\n  private final ManagedChannel channel;\n\n  private StreamingAudioEncoder encoder;\n  private boolean encoderIsRequested;\n  private boolean encoderIsSupported;\n\n  /*\n   * @param speechSessionListener Listener for recognition responses.\n   * @param sampleRateHz Sample rate of microphone data.\n   * @param channel The channel to use for cloud communication.\n   */\n  public CloudSpeechSession(\n      CloudSpeechSessionParams params,\n      SpeechSessionListener speechSessionListener,\n      int sampleRateHz,\n      ManagedChannel channel) {\n    this.params = params;\n    this.channel = channel;\n    this.speechSessionListener = speechSessionListener;\n    this.sampleRateHz = sampleRateHz;\n    this.encoder = new StreamingAudioEncoder();\n  }\n\n  /** Starts a streaming speech recognition request. */\n  @Override\n  public synchronized void initImpl(\n          SpeechRecognitionModelOptions modelOptions, int chunkSizeSamples) {\n    if (chunkSizeSamples < 0.050 * sampleRateHz) {\n      logger.atWarning().log(\n          \"Your buffer size is less than 50ms, you may have poor performance getting \"\n              + \"streaming results.\");\n    }\n    responseObserver = makeResponseObserver(speechSessionListener);\n    encoderIsRequested = params.getEncoderParams().getEnableEncoder();\n    encoderIsSupported =\n        StreamingAudioEncoder.isEncoderSupported(params.getEncoderParams().getCodec());\n    if (usingEncoder()) {\n      try {\n        encoder.init(\n            sampleRateHz,\n            params.getEncoderParams().getCodec(),\n            params.getEncoderParams().getAllowVbr());\n      } catch (StreamingAudioEncoder.EncoderException | IOException e) {\n        e.printStackTrace();\n        logger.atSevere().log(\"Encoder could not be created. Using uncompressed audio.\");\n        encoderIsRequested = false;\n      }\n    }\n    initServer(modelOptions);\n\n    stillSendingRequests = true;\n  }\n\n  /** Returns true when the encoder is being used. */\n  public boolean usingEncoder() {\n    return encoderIsRequested && encoderIsSupported;\n  }\n\n  private CloudSpeechStreamObserver makeResponseObserver(\n      SpeechSessionListener speechSessionListener) {\n    return new CloudSpeechStreamObserver(\n        params.getObserverParams(), speechSessionListener, sessionID());\n  }\n\n  /**\n   * Sends an audio buffer to the Cloud Speech Server.\n   *\n   * @param buffer 16 bit LinearPCM byte array.\n   * @param offset first element of buffer to use.\n   * @param count number of elements of buffer to use.\n   * @return true if audio data was processed, false if session was already requested to close. You\n   *     should wait for the recognition listener passed into the constructor to receive\n   *     OK_TO_TERMINATE before destroying the session.\n   */\n  @Override\n  public synchronized boolean processAudioBytesImpl(byte[] buffer, int offset, int count) {\n    if (!isStillSendingRequests()) {\n      return false;\n    }\n\n    if (usingEncoder()) {\n      byte[] encoded = encoder.processAudioBytes(buffer, offset, count);\n      if (encoded.length > 0) {\n        streamToServer(encoded, 0, encoded.length);\n      }\n    } else {\n      streamToServer(buffer, offset, count);\n    }\n\n    if (CLOSE_SESSION_AFTER_EXTENDED_SILENCE_DURATION.isShorterThan(\n        responseObserver.timeSinceLastServerActivity())) {\n      logger.atInfo().log(\n          \"Session #%d scheduled to be ended due to extended silence.\", sessionID());\n      requestCloseSession();\n    }\n    return true;\n  }\n\n  private boolean isStillSendingRequests() {\n    return stillSendingRequests && responseObserver.isStillListening();\n  }\n\n  /**\n   * Closes the current recognition request on the client end. This does not immediately end the\n   * session. Only once the server acknowledges the closing of the session is communication\n   * complete.\n   */\n  @Override\n  public synchronized void requestCloseSessionImpl() {\n    if (stillSendingRequests) {\n      stillSendingRequests = false;\n      if (usingEncoder()) {\n        // Get any remaining output from the codec and stop.\n        byte[] data = encoder.flushAndStop();\n        streamToServer(data, 0, data.length);\n      }\n      closeServer();\n    }\n  }\n\n  @Override\n  public boolean requiresNetworkConnection() {\n    return true;\n  }\n\n  private void initServer(SpeechRecognitionModelOptions modelOptions) {\n    this.speechClient = SpeechGrpc.newStub(channel);\n    requestObserver = speechClient.streamingRecognize(responseObserver);\n\n    // Build and send a StreamingRecognizeRequest containing the parameters for\n    // processing the audio.\n    SpeechContext speechContext = SpeechContext.getDefaultInstance();\n\n    RecognitionConfig.AudioEncoding encodingType = RecognitionConfig.AudioEncoding.LINEAR16;\n    if (usingEncoder()) {\n      switch (encoder.getCodecType()) {\n        case AMRWB:\n          encodingType = RecognitionConfig.AudioEncoding.AMR_WB;\n          break;\n        case FLAC:\n          encodingType = RecognitionConfig.AudioEncoding.FLAC;\n          break;\n        case OGG_OPUS:\n          encodingType = RecognitionConfig.AudioEncoding.OGG_OPUS;\n          break;\n        default:\n      }\n    }\n\n    ArrayList<String> languageList = new ArrayList<>();\n    languageList.add(\"en-US\");\n\n    RecognitionConfig.Builder configBuilder =\n        RecognitionConfig.newBuilder()\n            .setEncoding(encodingType)\n            .setSampleRateHertz(sampleRateHz)\n            .setAudioChannelCount(1)\n            .setEnableAutomaticPunctuation(true)\n            .setEnableWordConfidence(true)\n            .setEnableWordTimeOffsets(true)\n//            .addAllAlternativeLanguageCodes(languageList) //seems to be switching to english too much\n            .addSpeechContexts(speechContext)\n            .setLanguageCode(modelOptions.getLocale())\n            .setProfanityFilter(params.getFilterProfanity())\n            .addSpeechContexts(\n                SpeechContext.newBuilder()\n                    .addAllPhrases(modelOptions.getBiasWordsList()));\n\n    StreamingRecognitionConfig.Builder strbuilder =\n        StreamingRecognitionConfig.newBuilder()\n            .setInterimResults(true)\n            .setSingleUtterance(false);\n    switch (modelOptions.getModel()) {\n      case VIDEO:\n        if (!modelOptions.getLocale().equals(\"en-US\")) {\n          logger.atSevere().log(\"Only en-US is supported by YouTube Livestream model\");\n        }\n//        configBuilder.setModel(\"video\");\n        configBuilder.setModel(\"latest_long\");\n        break;\n      case DICTATION_DEFAULT:\n        configBuilder.setModel(\"default\");\n        break;\n    }\n\n    RecognitionConfig config = configBuilder.build();\n    StreamingRecognitionConfig streamingConfig = strbuilder.setConfig(config).build();\n\n    // First request sends the configuration.\n    StreamingRecognizeRequest initial =\n        StreamingRecognizeRequest.newBuilder().setStreamingConfig(streamingConfig).build();\n\n    requestObserver.onNext(initial);\n  }\n\n  private void streamToServer(byte[] buffer, int offset, int count) {\n    StreamingRecognizeRequest request =\n        StreamingRecognizeRequest.newBuilder()\n            .setAudioContent(ByteString.copyFrom(buffer, offset, count))\n            .build();\n    requestObserver.onNext(request);\n  }\n\n  private void closeServer() {\n    if (requestObserver != null) {\n      // Tell the server we're done sending.\n      requestObserver.onCompleted();\n      requestObserver = null;\n    }\n  }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/gcloudspeech/CloudSpeechSessionFactory.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.gcloudspeech;\n\nimport androidx.annotation.GuardedBy;\n\nimport com.google.audio.asr.CloudSpeechSessionParams;\nimport com.google.common.flogger.FluentLogger;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.SpeechSession;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.SpeechSessionFactory;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.SpeechSessionListener;\n\nimport org.joda.time.Duration;\n\nimport java.util.concurrent.TimeUnit;\n\nimport io.grpc.ConnectivityState;\nimport io.grpc.ManagedChannel;\nimport io.grpc.ManagedChannelBuilder;\nimport io.grpc.Metadata;\nimport io.grpc.stub.MetadataUtils;\n\n/** A factory for creating cloud sessions. */\npublic class CloudSpeechSessionFactory implements SpeechSessionFactory {\n  private static final FluentLogger logger = FluentLogger.forEnclosingClass();\n  private static final String SERVICE_URL = \"speech.googleapis.com\";\n  private static final String HEADER_API_KEY = \"X-Goog-Api-Key\";\n\n  /** Wait 1 second for the preexisting calls to finish. */\n  private static final Duration TERMINATE_CHANNEL_DURATION = Duration.standardSeconds(1);\n\n  /** Lock for handling concurrent accesses to the `params` variable. */\n  private final Object paramsLock = new Object();\n\n  @GuardedBy(\"paramsLock\")\n  private CloudSpeechSessionParams params;\n  private String apiKey;\n\n  private ManagedChannel channel;\n\n  public CloudSpeechSessionFactory(CloudSpeechSessionParams params, String apiKey) {\n    this.params = params;\n    this.apiKey = apiKey;\n  }\n\n  @Override\n  public SpeechSession create(SpeechSessionListener listener, int sampleRateHz) {\n    if (this.channel == null) {\n      this.channel = createManagedChannel(apiKey);\n    } else {\n      ensureManagedChannelConnection();\n    }\n    synchronized (paramsLock) {\n      return new CloudSpeechSession(params, listener, sampleRateHz, channel);\n    }\n  }\n\n  @Override\n  public void cleanup() {\n    if (channel != null) {\n      channel.shutdown();\n      try {\n        if (!channel.awaitTermination(\n            TERMINATE_CHANNEL_DURATION.getStandardSeconds(), TimeUnit.SECONDS)) {\n          channel.shutdownNow();\n        }\n      } catch (InterruptedException e) {\n        logger.atWarning().withCause(e).log(\"Channel termination failed.\");\n      }\n      channel = null;\n    }\n  }\n\n  public void setParams(CloudSpeechSessionParams params) {\n    synchronized (paramsLock) {\n      this.params = params;\n    }\n  }\n\n  protected void ensureManagedChannelConnection() {\n    // The channel may stuck at the TRANSIENT_FAILURE state, if so, enter idle to let channel to\n    // trigger creation of a new connection.\n    if (ConnectivityState.TRANSIENT_FAILURE.equals(channel.getState(false))) {\n      logger.atInfo().log(\"ManagedChannel was in TRANSIENT_FAILURE state.\");\n      channel.enterIdle();\n    }\n  }\n\n  private ManagedChannel createManagedChannel(String apiKey) {\n    Metadata metadata = new Metadata();\n    metadata.put(Metadata.Key.of(HEADER_API_KEY, Metadata.ASCII_STRING_MARSHALLER), apiKey);\n    return ManagedChannelBuilder.forTarget(SERVICE_URL)\n        .intercept(MetadataUtils.newAttachHeadersInterceptor(metadata))\n        .build();\n  }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/gcloudspeech/CloudSpeechStreamObserver.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.gcloudspeech;\n\nimport com.google.audio.asr.CloudSpeechStreamObserverParams;\nimport com.google.audio.asr.TranscriptionResult;\nimport com.google.cloud.speech.v1p1beta1.SpeechRecognitionAlternative;\nimport com.google.cloud.speech.v1p1beta1.StreamingRecognitionResult;\nimport com.google.cloud.speech.v1p1beta1.StreamingRecognizeResponse;\nimport com.google.cloud.speech.v1p1beta1.StreamingRecognizeResponse.SpeechEventType;\nimport com.google.cloud.speech.v1p1beta1.WordInfo;\nimport com.google.common.base.Optional;\nimport com.google.common.flogger.FluentLogger;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.SpeechSessionListener;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.TimeUtil;\n\nimport org.joda.time.Duration;\nimport org.joda.time.Instant;\n\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport io.grpc.stub.StreamObserver;\n\n/**\n * Parses Cloud Speech API GRPC StreamingRecognizeResponse events into CloudSpeechSessionListener\n * events.\n * NOTE: that this object is stateful and needs to be re-instantiated for each streaming\n * request.\n *\n * Threading: All methods that implement the StreamObserver interface are to be called by gRPC. This\n * is the \"results thread\" as documented in the RepeatingRecognitionSession. The other public\n * functions are safe to call from another thread, they are called by CloudSpeechSession in the\n * current implementation.\n */\npublic class CloudSpeechStreamObserver implements StreamObserver<StreamingRecognizeResponse> {\n  private static final FluentLogger logger = FluentLogger.forEnclosingClass();\n\n  // The CloudSpeech API imposes a maximum streaming time of 5 minutes. In order to avoid hitting\n  // this, but still be compatible with singleUtterance = false mode, which is required by some\n  // models, we attempt to close the session after receiving a finalized result after being opened\n  // for MIN_TIME_TO_KEEP_SESSION_OPEN.\n  private static final Duration MIN_TIME_TO_KEEP_SESSION_OPEN =\n      Duration.standardMinutes(4).plus(Duration.standardSeconds(30));\n\n  private final SpeechSessionListener speechSessionListener;\n  private final Instant sessionOkToRequestCloseTime;\n  // Class for computing and returning the timestamps.\n  private final TimestampCalculator timestampCalculator;\n\n  // These variables are accessed through public functions from the recognition thread\n  // (via CloudSpeechSession).\n  private final AtomicBoolean stillListening = new AtomicBoolean(true);\n  private final AtomicReference<Instant> lastActivityTimestamp = new AtomicReference<>();\n\n  /**\n   * Keeps track of time of arrival of first word. Optional.absent() means that the utterance has\n   * not started yet.\n   */\n  private Optional<Instant> utteranceStartTime;\n\n  // Note that only when the results are finalized are the confidences nonzero.\n  private static final float K_CONFIDENCE_NOT_SET = 0.0f;\n\n  private final CloudSpeechStreamObserverParams params;\n  private final int sessionID;\n\n  public CloudSpeechStreamObserver(\n      CloudSpeechStreamObserverParams params,\n      SpeechSessionListener speechSessionListener,\n      int sessionID) {\n    this.sessionID = sessionID;\n    this.speechSessionListener = speechSessionListener;\n    this.params = params;\n    this.sessionOkToRequestCloseTime = Instant.now().plus(MIN_TIME_TO_KEEP_SESSION_OPEN);\n    updateLastActivityTimestamp();\n    this.utteranceStartTime = Optional.absent();\n    // The timestampCalculator keeps track of the session start time because the finalized word\n    // times are relative to the time of the beginning of the session.\n    this.timestampCalculator = new TimestampCalculator(Instant.now());\n  }\n\n  /** Convert the results the speech recognizer gives us into an understandable transcript. */\n  @Override\n  public void onNext(StreamingRecognizeResponse response) {\n    if (response == null) {\n      return;\n    }\n    updateLastActivityTimestamp();\n\n    if (!utteranceStartTime.isPresent()) {\n      utteranceStartTime = Optional.of(Instant.now());\n      timestampCalculator.reset();\n    }\n    StringBuilder transcriptString = new StringBuilder();\n    float highestConfidence = K_CONFIDENCE_NOT_SET;\n\n    boolean endedWithFinalResult = false;\n    String languageCode = \"\";\n    TranscriptionResult.Builder resultBuilder = TranscriptionResult.newBuilder();\n    // Results are for non-overlapping sections of time, each result may have several possible\n    // transcripts, called \"alternatives\".\n    for (StreamingRecognitionResult result : response.getResultsList()) {\n      // We use a threshold of 0.5 for stability. In practice, only 0.9 and 0.01 seem to ever come\n      // up, so this hardly seems like it is worth tuning.\n      final float stableConfidenceThreshold = 0.5f;\n      if (params.getRejectUnstableHypotheses()\n          && !result.getIsFinal()\n          && result.getStability() < stableConfidenceThreshold) {\n        continue;\n      }\n      SpeechRecognitionAlternative bestAlternative = result.getAlternativesList().get(0);\n      highestConfidence = bestAlternative.getConfidence();\n\n      transcriptString.append(bestAlternative.getTranscript());\n      for (WordInfo wordInfo : bestAlternative.getWordsList()) {\n        TranscriptionResult.Word.Builder word =\n            TranscriptionResult.Word.newBuilder()\n                .setText(wordInfo.getWord())\n                .setStartTimestamp(timestampCalculator.getFinalizedStartTimestamp(wordInfo))\n                .setEndTimestamp(timestampCalculator.getFinalizedEndTimestamp(wordInfo));\n        if (wordInfo.getConfidence() != K_CONFIDENCE_NOT_SET) {\n          word.setConfidence(wordInfo.getConfidence());\n        }\n        resultBuilder.addWordLevelDetail(word);\n      }\n      languageCode = result.getLanguageCode();\n      if (result.getIsFinal()) {\n        endedWithFinalResult = true;\n        break;\n      }\n    }\n\n    // If the transcript does not have a word list, generate the list of words and their\n    // timestamps from the partial result utterance.\n    if (resultBuilder.getWordLevelDetailCount() == 0) {\n      List<TranscriptionResult.Word> unfinalizedTimestamps =\n          timestampCalculator.updateUnfinalizedTimestamps(transcriptString);\n      resultBuilder.addAllWordLevelDetail(unfinalizedTimestamps);\n    }\n\n    // If result only contains an endpoint event, we will not call onResults or onPartialResults.\n    if (transcriptString.length() > 0) {\n      speechSessionListener.onResults(\n          sessionID,\n          resultBuilder\n              .setText(transcriptString.toString())\n              .setConfidence(highestConfidence)\n              .setStartTimestamp(TimeUtil.toTimestamp(utteranceStartTime.get()))\n              .setEndTimestamp(TimeUtil.toTimestamp(Instant.now()))\n              .setLanguageCode(languageCode)\n              .build(),\n          endedWithFinalResult);\n      if (endedWithFinalResult) {\n        // Reset the utterance start timer to the uninitialized state.\n        utteranceStartTime = Optional.absent();\n      }\n\n      // Request to stop the session if we see a final result.\n      if (endedWithFinalResult && Instant.now().isAfter(sessionOkToRequestCloseTime)) {\n        logger.atInfo().log(\"Session #%d scheduled to close to avoid timeout.\", sessionID);\n        stopListening();\n        speechSessionListener.onDoneListening(sessionID);\n      }\n    }\n\n    if (response.getSpeechEventType() == SpeechEventType.END_OF_SINGLE_UTTERANCE) {\n      stopListening();\n      speechSessionListener.onDoneListening(sessionID);\n    }\n  }\n\n  @Override\n  public void onError(Throwable t) {\n    updateLastActivityTimestamp();\n    stopListening();\n    speechSessionListener.onSessionFatalError(sessionID, t);\n  }\n\n  @Override\n  public void onCompleted() {\n    updateLastActivityTimestamp();\n    speechSessionListener.onOkToTerminateSession(sessionID);\n  }\n\n\n  // This method is needed to communicate to the CloudSpeechSession that audio should no longer\n  // be sent quickly. Without this, the \"stop listening\" signal has to propagate through the\n  // SpeechSessionListener and the RepeatingRecognitionSession in order to tell the session to\n  // stop accepting audio. Without this, audio buffers can be lost.\n  //\n  // Will be called though CloudSpeechSession (the recognition thread).\n  public boolean isStillListening() {\n    return stillListening.get();\n  }\n\n  // Will be called though CloudSpeechSession (the recognition thread).\n  public Duration timeSinceLastServerActivity() {\n    return new Duration(lastActivityTimestamp.get(), Instant.now());\n  }\n\n  private void stopListening() {\n    stillListening.set(false);\n  }\n\n  /** Update the last activity timestamp. This should be called whenever the session\n   *  changes in any way.\n   */\n  private void updateLastActivityTimestamp() {\n    lastActivityTimestamp.set(Instant.now());\n  }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/google/gcloudspeech/TimestampCalculator.java",
    "content": "/*\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.gcloudspeech;\n\nimport com.google.audio.asr.TranscriptionResult;\nimport com.google.cloud.speech.v1p1beta1.WordInfo;\nimport com.google.common.base.Splitter;\nimport com.google.protobuf.Timestamp;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.TimeUtil;\n\nimport org.joda.time.Duration;\nimport org.joda.time.Instant;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Calculates unfinalized and finalized timestamps and adds them to the word-level details of\n * utterances. Finalized timestamps are simply copied from the corresponding timestamps returned by\n * the cloud. Unfinalized timestamps do not exist in the response returned by the cloud, so they are\n * computed from the returned transcript instead.\n */\npublic class TimestampCalculator {\n\n  /**\n   * Keeps track of the session start time because the finalized word times are relative to the time\n   * of the beginning of the session.\n   */\n  private final Instant sessionStartTime;\n\n  /**\n   * Stores the time instants of each word in the un-finalized utterance. As the utterance is\n   * updated with more words, this array marks the time of the new words.\n   */\n  private final ArrayList<Instant> unfinalizedWordInstants = new ArrayList<>();\n\n  private static final int NANOS_PER_MILLIS = 1_000_000;\n\n  public TimestampCalculator(Instant newSessionStartTime) {\n    this.sessionStartTime = newSessionStartTime;\n  }\n\n  public Timestamp getFinalizedStartTimestamp(WordInfo wordInfo) {\n    Duration startOffset =\n        Duration.standardSeconds(wordInfo.getStartTime().getSeconds())\n            .plus(Duration.millis(wordInfo.getStartTime().getNanos() / NANOS_PER_MILLIS));\n    return TimeUtil.toTimestamp(sessionStartTime.plus(startOffset));\n  }\n\n  public Timestamp getFinalizedEndTimestamp(WordInfo wordInfo) {\n    Duration endOffset =\n        Duration.standardSeconds(wordInfo.getEndTime().getSeconds())\n            .plus(Duration.millis(wordInfo.getEndTime().getNanos() / NANOS_PER_MILLIS));\n    return TimeUtil.toTimestamp(sessionStartTime.plus(endOffset));\n  }\n\n  public void reset() {\n    unfinalizedWordInstants.clear();\n  }\n\n  public List<TranscriptionResult.Word> updateUnfinalizedTimestamps(\n      StringBuilder transcriptString) {\n    // Generate the list of words and their timestamps from the partial result utterance.\n    // This implementation doesn't require every \"word\" to have a timestamp; instead it is\n    // timestamping the smallest logical chunk returned by the ASR.\n    // The algorithm splits by spaces as a convenience to count how many new words have come in.\n\n    // This works for languages that has spaces between logical groups of character (such as words).\n    // For languages that don't have spaces, it treats the group of characters as one timestamp.\n    List<String> wordList =\n        Splitter.onPattern(\"\\\\s+\").splitToList(transcriptString.toString().trim());\n    // Compute time instants for the newly occurring words.\n    // We do not change the times of previously computed words.\n    for (int i = unfinalizedWordInstants.size(); i < wordList.size(); i++) {\n      unfinalizedWordInstants.add(Instant.now());\n    }\n    // Use the computed words and computed time instances to build the word-level detail.\n    // Since the previous loop guaranteed that the size of the word instants array is at least\n    // as long as the list of words, we can safely index into the array.\n    List<TranscriptionResult.Word> wordLevelDetailList = new ArrayList<>();\n    for (int i = 0; i < wordList.size(); i++) {\n      // We set both the start and end timestamps to the same value because we don't know when\n      // the word actually begins and ends because of potential pauses between words.\n      Instant timeInstant = unfinalizedWordInstants.get(i);\n      TranscriptionResult.Word word =\n          TranscriptionResult.Word.newBuilder()\n              .setText(wordList.get(i))\n              .setStartTimestamp(TimeUtil.toTimestamp(timeInstant))\n              .setEndTimestamp(TimeUtil.toTimestamp(timeInstant))\n              .build();\n      wordLevelDetailList.add(word);\n    }\n    return wordLevelDetailList;\n  }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/vad/VadGateSpeechPolicy.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.speechrecognition.vad;\n\nimport android.content.Context;\nimport android.util.Log;\n\nimport com.konovalov.vad.Vad;\nimport com.konovalov.vad.VadListener;\nimport com.konovalov.vad.config.FrameSize;\nimport com.konovalov.vad.config.Mode;\nimport com.konovalov.vad.config.Model;\nimport com.konovalov.vad.config.SampleRate;\nimport com.konovalov.vad.models.VadModel;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.google.asr.SpeechDetectionPolicy;\n\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.util.Arrays;\n\n/** A speech detector that always reports hearing speech. */\npublic class VadGateSpeechPolicy implements SpeechDetectionPolicy {\n    public final String TAG = \"WearLLM_VadGateService\";\n    private Context mContext;\n    private Vad vad;\n    private VadModel vadModel;\n    private boolean isCurrentlySpeech;\n\n    public VadGateSpeechPolicy(Context context){\n       mContext = context;\n       isCurrentlySpeech = false;\n    }\n\n    //custom - divide by 3, gives us best of both worlds - vosk runs best at ~0.2 second buffer, this runs best at 512-1024 size frame, so we run at 0.192second buffer and divide by 3\n    public void startVad(int blockSizeSamples){\n        vad = Vad.builder();\n\n        blockSizeSamples = blockSizeSamples / 3;\n\n        Log.d(TAG, \"VAD looking for block size samples: \" + blockSizeSamples);\n        //find the proper frame size\n        FrameSize fsToUse = null;\n        for (FrameSize fs : FrameSize.values()){\n            if (fs.getValue() == blockSizeSamples){\n                fsToUse = fs;\n                break;\n            }\n        }\n\n        if (fsToUse == null){\n            Log.e(TAG, \"Frame size not supported by VAD, exiting.\");\n            return;\n        }\n\n        vadModel = vad.setModel(Model.SILERO_DNN)\n                .setSampleRate(SampleRate.SAMPLE_RATE_16K)\n                .setFrameSize(fsToUse)\n//                .setMode(Mode.VERY_AGGRESSIVE)\n                .setMode(Mode.AGGRESSIVE)\n                .setSilenceDurationMs(1350)\n                .setSpeechDurationMs(50)\n                .setContext(mContext)\n                .build();\n\n        Log.d(TAG, \"VAD init'ed.\");\n    }\n\n    @Override\n    public boolean shouldPassAudioToRecognizer() {\n        return isCurrentlySpeech;\n    }\n\n    @Override\n    public void init(int blockSizeSamples) {\n        startVad(blockSizeSamples);\n    }\n\n    @Override\n    public void reset() {}\n\n    public short [] bytesToShort(byte[] bytes) {\n        short[] shorts = new short[bytes.length/2];\n        // to turn bytes to shorts as either big endian or little endian.\n        ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);\n        return shorts;\n    }\n\n    @Override\n    public void processAudioBytes(byte[] bytes, int offset, int length) {\n        short [] audioBytesFull = bytesToShort(bytes);\n        int windowLen = audioBytesFull.length / 3;\n        for (int i = 0; i < 3; i++) {\n            int moffset = i * windowLen;\n            short [] audioBytesPartial = Arrays.copyOfRange(audioBytesFull, moffset, moffset + windowLen);\n            vadModel.setContinuousSpeechListener(audioBytesPartial, new VadListener() {\n                @Override\n                public void onSpeechDetected() {\n                    //speech detected!\n//                    Log.d(TAG, \"Speech detected.\");\n                    isCurrentlySpeech = true;\n                }\n\n                @Override\n                public void onNoiseDetected() {\n                    //noise detected!\n//                    Log.d(TAG, \"Noise detected!\");\n                    isCurrentlySpeech = false;\n                }\n            });\n        }\n    }\n\n    @Override\n    public void stop() {\n        vadModel.close();\n    }\n}"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/speechrecognition/vosk/SpeechRecVosk.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.speechrecognition.vosk;\n\n//Vosk ASR\n\nimport android.content.Context;\nimport android.os.Handler;\nimport android.util.Base64;\nimport android.util.Log;\n\nimport com.teamopensmartglasses.smartglassesmanager.comms.MessageTypes;\nimport com.teamopensmartglasses.augmentoslib.events.SpeechRecOutputEvent;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.SpeechRecFramework;\n\nimport org.greenrobot.eventbus.EventBus;\nimport org.json.JSONException;\nimport org.json.JSONObject;\nimport org.vosk.LibVosk;\nimport org.vosk.LogLevel;\nimport org.vosk.Model;\nimport org.vosk.Recognizer;\nimport org.vosk.android.RecognitionListener;\nimport org.vosk.android.StorageService;\n\nimport java.io.InputStream;\nimport java.util.Dictionary;\nimport java.util.Hashtable;\nimport java.util.Locale;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingQueue;\n\nimport io.reactivex.rxjava3.disposables.Disposable;\nimport io.reactivex.rxjava3.subjects.PublishSubject;\n\npublic class SpeechRecVosk extends SpeechRecFramework implements RecognitionListener {\n    public String TAG = \"WearableAi_SpeechRecVosk\";\n\n    private String languageModelPath;\n\n    private boolean isBaseLanguage = true;\n\n    private Context mContext;\n\n    //the current phrase we are receiving\n    private boolean newPhrase = true;\n\n    private Model model;\n    //private SpeechService speechService;\n    //private SpeechStreamService speechStreamService;\n    private SpeechStreamQueueServiceVosk speechStreamService;\n//    private PhraseRepository mPhraseRepository = null;\n\n    private VoskAudioBytesStream voskAudioBytesStream;\n    //private PipedOutputStream audioAdderStreamVosk;\n    //private InputStream audioSenderStreamVosk;\n    private int audioSenderStreamVoskSize;\n    private BlockingQueue<byte []> audioSenderStreamVosk;\n    private Handler main_handler;\n\n    //receive/send data stream\n    PublishSubject<JSONObject> dataObservable;\n    Disposable dataSub;\n    //receive audio stream\n    PublishSubject<byte []> audioObservable;\n    Disposable audioSub;\n\n    //languages\n    String baseLanguage = \"english\";\n    public static Dictionary<String, NaturalLanguage> supportedLanguages = new Hashtable<String, NaturalLanguage>();\n\n    public SpeechRecVosk(Context context){\n        mContext = context;\n        this.isBaseLanguage = true;// isBaseLanguage;\n\n        //setup languages\n        supportedLanguages.put(\"english\", new NaturalLanguage(\"english\", \"en\", \"model-en-us\", Locale.ENGLISH)); //english\n        this.languageModelPath = supportedLanguages.get(baseLanguage).getModelLocation(); //languageModelPath;\n//        supportedLanguages.put(\"french\", new NaturalLanguage(\"french\", \"fr\", \"model-fr-small\", Locale.FRENCH)); //french\n        //supportedLanguages.add(new NaturalLanguage(\"chinese\", \"zh\", \"model-cn-small\", Locale.CHINESE)); //chinese\n        //supportedLanguages.add(new NaturalLanguage(\"italian\", \"it\", \"model-it-small\", Locale.ITALIAN)); //italian\n        //supportedLanguages.add(new NaturalLanguage(\"japanese\", \"ja\", \"model-jp-small\", Locale.JAPANESE)); //japanese\n\n        //to save trancript\n//        this.mPhraseRepository = mPhraseRepository;\n\n        //receive/send data\n//        this.dataObservable = dataObservable;\n//        dataSub = this.dataObservable.subscribe(i -> handleDataStream(i));\n//        setupEventBusSubscribers();\n\n        //receive audio\n        //this.audioObservable = audioObservable;\n        //audioSub = this.audioObservable.subscribe(i -> handleDataStream(i));\n\n        //setup the object which will pass audio bytes to vosk\n//        audioSenderStreamVoskSize = (int) (16000 * 2 * 0.2);\n        audioSenderStreamVoskSize = (int) (16000 * 2 * 0.192);\n//        audioSenderStreamVoskSize = (int) (16000 * 2 * 0.064);\n        audioSenderStreamVosk = new ArrayBlockingQueue(audioSenderStreamVoskSize);\n    }\n\n    @Override\n    public void start(){\n        //start vosk ASR\n        LibVosk.setLogLevel(LogLevel.INFO);\n        initModel();\n\n        //start recognizing audio after delay, must first wait for model to load\n        main_handler = new Handler();\n        final int delay = 500;\n        main_handler.postDelayed(new Runnable() {\n            public void run() {\n                if (model != null){\n                    recognizeSpeech();\n                } else {\n                    main_handler.postDelayed(this, delay);\n                }\n            }\n        }, delay);\n    }\n\n    private void setupEventBusSubscribers(){\n            EventBus.getDefault().register(this);\n    }\n\n        private void initModel() {\n        Log.d(TAG, \"Initing ASR model...\");\n        StorageService.unpack(mContext, languageModelPath, \"model\",\n                (model) -> {\n                    this.model = model;\n                },\n                (exception) -> setErrorState(\"Failed to unpack the model: \" + exception.getMessage()));\n        Log.d(TAG, \"ASR Model loaded.\");\n    }\n\n    private void setErrorState(String message) {\n        Log.d(TAG, \"VOSK error: \" + message);\n    }\n\n    private void recognizeSpeech() {\n        if (speechStreamService != null) {\n            speechStreamService.stop();\n            speechStreamService = null;\n        } else {\n            Log.d(TAG, \"VOSK MAKE RECOGNIZER\");\n            Recognizer rec = new Recognizer(model, 16000.0f);\n            Log.d(TAG, \"VOSK MAKE SPEECH SERVICE\");\n            //speechService = new SpeechService(rec, 16000.0f);\n            //6416 is hard coded - same as chunk_len - size of buffer used on ASG\n            speechStreamService = new SpeechStreamQueueServiceVosk(rec, audioSenderStreamVosk, 16000.0f);\n            Log.d(TAG, \"VOSK START LISTENING\");\n            //speechService.startListening(rec);\n            speechStreamService.start(this);\n        }\n    }\n\n    private void pause(boolean checked) {\n//        if (speechStreamService != null) {\n//            speechStreamService.setPause(checked);\n//        }\n    }\n\n    public void destroy() {\n        Log.d(TAG, \"Destroying VOSK\");\n        EventBus.getDefault().unregister(this);\n        if (speechStreamService != null) {\n            speechStreamService.stop();\n        }\n    }\n\n    //receive audio and send to vosk\n    private void handleDataStream(JSONObject data){\n        try {\n            String dataType = data.getString(MessageTypes.MESSAGE_TYPE_LOCAL);\n            if (dataType.equals(MessageTypes.AUDIO_CHUNK_DECRYPTED)){\n                String encodedPlainData = data.getString(MessageTypes.AUDIO_DATA);\n                byte [] decodedPlainData = Base64.decode(encodedPlainData, Base64.DEFAULT);\n                audioSenderStreamVosk.put(decodedPlainData);\n            }\n        } catch (InterruptedException | JSONException e) {\n            setErrorState(e.getMessage());\n        }\n    }\n\n    //make our own InputStream class we can fill with audio to pass to vosk\n    class VoskAudioBytesStream extends InputStream {\n        public byte [] data;\n\n        public int read() {\n            byte [] tmp = {0x01, 0x01};\n            return 0;\n        }\n\n        public void write(byte [] inputData){\n            data = inputData;\n        }\n    }\n\n    //vosk listener implementation\n    @Override\n    public void onResult(String hypothesis) {\n        //start recognizing audio after delay, must first wait for model to load\n        main_handler.post(new Runnable() {\n            public void run() {\n                handleResult(hypothesis);\n            }\n        });\n    }\n\n    public void handleResult(String hypothesis){\n        long transcriptTime = System.currentTimeMillis();\n        handleTranscript(hypothesis, MessageTypes.FINAL_TRANSCRIPT, transcriptTime);\n    }\n\n    public void handleTranscript(String hypothesis, String transcriptType, long transcriptTime){\n        //save transcript then send to other services in app\n        try {\n            //Below, we do a parsing of Vosk's silly string output\n            //https://github.com/alphacep/vosk-android-demo/issues/81\n            JSONObject voskResponse = new JSONObject(hypothesis);\n            String transcript;\n\n            //to send to other services\n            JSONObject transcriptObj = new JSONObject();\n            //different message types depending on whether or not this is the base language or a foreign language\n\n            if (transcriptType.equals(MessageTypes.FINAL_TRANSCRIPT)){\n                transcript = voskResponse.getString(\"text\");\n                //set event bus type\n                if (isBaseLanguage) {\n                    transcriptObj.put(MessageTypes.MESSAGE_TYPE_LOCAL, transcriptType);\n                } else {\n                    transcriptObj.put(MessageTypes.MESSAGE_TYPE_LOCAL, MessageTypes.FINAL_TRANSCRIPT_FOREIGN);\n                }\n            } else if (transcriptType.equals(MessageTypes.INTERMEDIATE_TRANSCRIPT)) {\n                transcript = voskResponse.getString(\"partial\");\n                if (isBaseLanguage) {\n                    transcriptObj.put(MessageTypes.MESSAGE_TYPE_LOCAL, transcriptType);\n                } else {\n                    transcriptObj.put(MessageTypes.MESSAGE_TYPE_LOCAL, MessageTypes.INTERMEDIATE_TRANSCRIPT_FOREIGN);\n                }\n            } else {\n                return;\n            }\n\n            //don't save null or empty transcripts\n            if (transcript == null || transcript.trim().isEmpty()){\n                return;\n            }\n\n            //don't save transcripts that always appear incorrect\n            String [] badHitWords = {\"huh\", \"her\", \"hit\", \"cut\", \"this\", \"if\", \"but\", \"by\", \"hi\", \"ha\", \"a\", \"the\", \"det\", \"it\", \"you\", \"he\"};\n            for (int i = 0; i < badHitWords.length; i++){\n                if (transcript.equals(badHitWords[i])){\n                    return;\n                }\n            }\n\n            if (isBaseLanguage) {\n                if (newPhrase) {\n//                    currPhrase = PhraseCreator.init(\"transcript_ASG\", mContext, mPhraseRepository);\n                    newPhrase = false;\n                }\n\n                //update the current phrase\n//                PhraseCreator.create(currPhrase, transcript, mContext, mPhraseRepository);\n\n                //save transcript if final\n                if (transcriptType.equals(MessageTypes.FINAL_TRANSCRIPT)) {\n                    newPhrase = true;\n                }\n//                transcriptObj.put(MessageTypes.TRANSCRIPT_ID, currPhrase.getId());\n//                transcriptObj.put(MessageTypes.TIMESTAMP, transcriptTime);\n            }\n//            transcriptObj.put(MessageTypes.TRANSCRIPT_TEXT, transcript);\n//            Log.d(TAG, \"VOSK SENDING: \");\n//            Log.d(TAG, transcriptObj.toString());\n//            dataObservable.onNext(transcriptObj);\n\n//            EventBus.getDefault().post(new SendableIntentEvent(transcriptObj));\n\n            //post the event bus event\n            if (transcriptType.equals(MessageTypes.FINAL_TRANSCRIPT)) {\n                EventBus.getDefault().post(new SpeechRecOutputEvent(transcript, transcriptTime, true));\n            } else {\n                EventBus.getDefault().post(new SpeechRecOutputEvent(transcript, transcriptTime, false));\n            }\n        } catch (JSONException e){\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public void onFinalResult(String hypothesis) {\n        if (speechStreamService != null) {\n            speechStreamService = null;\n        }\n    }\n\n    @Override\n    public void onPartialResult(String hypothesis) {\n        long transcriptTime = System.currentTimeMillis();\n        handleTranscript(hypothesis, MessageTypes.INTERMEDIATE_TRANSCRIPT, transcriptTime);\n    }\n\n    @Override\n    public void onError(Exception e) {\n        setErrorState(e.getMessage());\n    }\n\n    @Override\n    public void onTimeout() {\n        Log.d(TAG, \"VOSK: timeout\");\n    }\n\n//    @Subscribe\n//    public void onVoskAudioChunkNewEvent(VoskAudioChunkNewEvent receivedEvent){\n//        try {\n//            audioSenderStreamVosk.put(receivedEvent.thisChunk);\n//        } catch (InterruptedException e) {\n//            e.printStackTrace();\n//        }\n//    }\n\n    @Override\n    public void ingestAudioChunk(byte[] audioChunk) {\n//        Log.d(TAG, \"Got chunk Vosk\");\n        try {\n            audioSenderStreamVosk.put(audioChunk);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/supportedglasses/AndroidPhoneTestGlasses.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.supportedglasses;\n\n// this is the test device, when someone runs the Android smart glasses thing client on an Android phone\npublic class AndroidPhoneTestGlasses extends SmartGlassesDevice {\n    public AndroidPhoneTestGlasses() {\n        deviceModelName = \"AndroidPhoneTestGlasses\";\n        anySupport = true;\n        fullSupport = true;\n        glassesOs = SmartGlassesOperatingSystem.ANDROID_OS_GLASSES;\n        hasDisplay = true;\n        hasSpeakers = true;\n        hasCamera = true;\n        hasInMic = true;\n        hasOutMic = true;\n        weight = 160;\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/supportedglasses/AudioWearable.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.supportedglasses;\n\npublic class AudioWearable extends SmartGlassesDevice {\n    public AudioWearable() {\n        deviceModelName = \"Audio Wearable\";\n        deviceIconName = \"bluetooth_earpiece\";\n        anySupport = true;\n        fullSupport = true;\n        glassesOs = SmartGlassesOperatingSystem.AUDIO_WEARABLE_GLASSES;\n        hasDisplay = false;\n        hasSpeakers = false; //set as false because we want to do this from ASP\n        hasCamera = false;\n        hasInMic = false; //set as false because we want to do this from ASP\n        hasOutMic = false;\n        useScoMic = true;\n        weight = 14;\n    }\n}"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/supportedglasses/EngoTwo.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.supportedglasses;\n\npublic class EngoTwo extends SmartGlassesDevice {\n    public EngoTwo() {\n        deviceModelName = \"Engo2 by ActiveLook\";\n        deviceIconName = \"engo_two\";\n        anySupport = true;\n        fullSupport = true;\n        glassesOs = SmartGlassesOperatingSystem.ACTIVELOOK_OS_GLASSES;\n        hasDisplay = true;\n        hasSpeakers = false;\n        hasCamera = false;\n        hasInMic = false;\n        hasOutMic = false;\n        weight = 37;\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/supportedglasses/EvenRealitiesG1.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.supportedglasses;\n\npublic class EvenRealitiesG1 extends SmartGlassesDevice {\n    public EvenRealitiesG1() {\n        deviceModelName = \"Even Realities G1\";\n        deviceIconName = \"evenrealities_g1\";\n        anySupport = false;\n        fullSupport = false;\n        glassesOs = SmartGlassesOperatingSystem.EVENREALITIES_G1_MCU_OS_GLASSES;\n        hasDisplay = true;\n        hasSpeakers = false;\n        hasCamera = false;\n        hasInMic = true;\n        hasOutMic = false;\n        useScoMic = false;\n        weight = 38;\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/supportedglasses/InmoAirOne.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.supportedglasses;\n\n// these glasses are pretty bad. There's no home button/gesture... the text/font size is all off android specs. Arms are big. The company has zero customer support. We might drop support for these - cayden\npublic class InmoAirOne extends SmartGlassesDevice {\n    public InmoAirOne() {\n        deviceModelName = \"Inmo Air 1\";\n        deviceIconName = \"inmo_air\";\n        anySupport = true;\n        fullSupport = false;\n        glassesOs = SmartGlassesOperatingSystem.ANDROID_OS_GLASSES;\n        hasDisplay = true;\n        hasSpeakers = true;\n        hasCamera = true;\n        hasInMic = true;\n        hasOutMic = false; //unknown\n        weight = 76;\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/supportedglasses/InmoGo.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.supportedglasses;\n\npublic class InmoGo extends SmartGlassesDevice {\n    public InmoGo() {\n        deviceModelName = \"INMO GO\";\n        deviceIconName = \"inmo_go\";\n        anySupport = false;\n        fullSupport = false;\n        glassesOs = SmartGlassesOperatingSystem.INMO_GO_MCU_OS_GLASSES;\n        hasDisplay = true;\n        hasSpeakers = false;\n        hasCamera = false;\n        hasInMic = true;\n        hasOutMic = false;\n        useScoMic = false;\n        weight = 38;\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/supportedglasses/SmartGlassesDevice.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.supportedglasses;\n\nimport java.io.Serializable;\n\npublic class SmartGlassesDevice implements Serializable {\n    public String deviceModelName;\n    public String deviceIconName;\n    public boolean anySupport;\n    public boolean fullSupport;\n    public SmartGlassesOperatingSystem glassesOs;\n    public boolean hasDisplay;\n    public boolean hasSpeakers;\n    public boolean hasCamera;\n    public boolean hasInMic;\n    public boolean hasOutMic;\n    public boolean useScoMic;\n    public double weight;\n\n    public int connectionState = -1; //0 is not connected, 1 is trying to connect, 2 is connected\n\n    public String getDeviceModelName() {\n        return deviceModelName;\n    }\n\n    public void setDeviceModelName(String deviceModelName) {\n        this.deviceModelName = deviceModelName;\n    }\n\n    public String getDeviceIconName() {\n        return deviceIconName;\n    }\n\n    public void setDeviceIconName(String deviceIconName) {\n        this.deviceIconName = deviceIconName;\n    }\n\n    public boolean getAnySupport() {\n        return anySupport;\n    }\n\n    public void setAnySupport(boolean anySupport) {\n        this.anySupport = anySupport;\n    }\n\n    public boolean getFullSupport() {\n        return fullSupport;\n    }\n\n    public void setFullSupport(boolean fullSupport) {\n        this.fullSupport = fullSupport;\n    }\n\n    public SmartGlassesOperatingSystem getGlassesOs() {\n        return glassesOs;\n    }\n\n    public void setGlassesOs(SmartGlassesOperatingSystem glassesOs) {\n        this.glassesOs = glassesOs;\n    }\n\n    public boolean getHasDisplay() {\n        return hasDisplay;\n    }\n\n    public void setHasDisplay(boolean hasDisplay) {\n        this.hasDisplay = hasDisplay;\n    }\n\n    public boolean getHasSpeakers() {\n        return hasSpeakers;\n    }\n\n    public void setHasSpeakers(boolean hasSpeakers) {\n        this.hasSpeakers = hasSpeakers;\n    }\n\n    public boolean getHasCamera() {\n        return hasCamera;\n    }\n\n    public void setHasCamera(boolean hasCamera) {\n        this.hasCamera = hasCamera;\n    }\n\n    public boolean getHasInMic() {\n        return hasInMic;\n    }\n\n    public void setHasInMic(boolean hasInMic) {\n        this.hasInMic = hasInMic;\n    }\n\n    public boolean getHasOutMic() {\n        return hasOutMic;\n    }\n\n    public void setHasOutMic(boolean hasOutMic) {\n        this.hasOutMic = hasOutMic;\n    }\n\n    public double getWeight() {\n        return weight;\n    }\n\n    public void setWeight(double weight) {\n        this.weight = weight;\n    }\n\n    public int getConnectionState() {\n        return connectionState;\n    }\n\n    public void setConnectionState(int connectionState) {\n        this.connectionState = connectionState;\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/supportedglasses/SmartGlassesOperatingSystem.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.supportedglasses;\n\npublic enum SmartGlassesOperatingSystem {\n    ANDROID_OS_GLASSES,\n    ACTIVELOOK_OS_GLASSES,\n    ULTRALITE_MCU_OS_GLASSES,\n    EVENREALITIES_G1_MCU_OS_GLASSES,\n    INMO_GO_MCU_OS_GLASSES,\n    AUDIO_WEARABLE_GLASSES\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/supportedglasses/TCLRayNeoXTwo.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.supportedglasses;\n\npublic class TCLRayNeoXTwo extends SmartGlassesDevice {\n    public TCLRayNeoXTwo() {\n        deviceModelName = \"TCL RayNeo X2\";\n        deviceIconName = \"tcl_rayneo_x_two\";\n        anySupport = true;\n        fullSupport = false;\n        glassesOs = SmartGlassesOperatingSystem.ANDROID_OS_GLASSES;\n        hasDisplay = true;\n        hasSpeakers = true;\n        hasCamera = true;\n        hasInMic = true;\n        hasOutMic = false; //unknown\n        weight = 120; //unknown\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/supportedglasses/VuzixShield.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.supportedglasses;\n\npublic class VuzixShield extends SmartGlassesDevice {\n    public VuzixShield() {\n        deviceModelName = \"Vuzix Shield\";\n        deviceIconName = \"vuzix_shield\";\n        anySupport = true;\n        fullSupport = true;\n        glassesOs = SmartGlassesOperatingSystem.ANDROID_OS_GLASSES;\n        hasDisplay = true;\n        hasSpeakers = true;\n        hasCamera = true;\n        hasInMic = true;\n        hasOutMic = true;\n        weight = 140;\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/supportedglasses/VuzixUltralite.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.supportedglasses;\n\npublic class VuzixUltralite extends SmartGlassesDevice {\n    public VuzixUltralite() {\n        deviceModelName = \"Vuzix Ultralite\";\n        deviceIconName = \"vuzix_ultralite\";\n        anySupport = true;\n        fullSupport = true;\n        glassesOs = SmartGlassesOperatingSystem.ULTRALITE_MCU_OS_GLASSES;\n        hasDisplay = true;\n        hasSpeakers = false;\n        hasCamera = false;\n        hasInMic = false;\n        hasOutMic = false;\n        useScoMic = true;\n        weight = 38;\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/texttospeech/TextToSpeechSystem.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.texttospeech;\n\nimport android.content.Context;\nimport android.media.AudioManager;\nimport android.os.Bundle;\nimport android.speech.tts.TextToSpeech;\nimport android.speech.tts.UtteranceProgressListener;\nimport android.util.Log;\n\nimport com.teamopensmartglasses.smartglassesmanager.eventbusmessages.PauseAsrEvent;\nimport com.teamopensmartglasses.smartglassesmanager.eventbusmessages.ScoStartEvent;\nimport com.teamopensmartglasses.smartglassesmanager.eventbusmessages.TextToSpeechEvent;\n\nimport org.greenrobot.eventbus.EventBus;\nimport org.greenrobot.eventbus.Subscribe;\n\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.UUID;\n\npublic class TextToSpeechSystem {\n    private  final String TAG = \"WearableAi_TextToSpeechSystem\";\n\n    private Context mContext;\n    public boolean isLoaded = false;\n    private TextToSpeech ttsModel;\n    private boolean sco;\n\n    public TextToSpeechSystem(Context context){\n        this.mContext = context;\n        this.sco = false;\n        EventBus.getDefault().register(this);\n    }\n\n    public void useSco(boolean useSco){\n        this.sco = useSco;\n    }\n\n//    public void setup(Locale language){\n    public void setup(){\n        Locale language = Locale.ENGLISH;\n        ttsModel = new TextToSpeech(mContext, status -> {\n            if (status == TextToSpeech.SUCCESS) {\n                ttsModel.setLanguage(language);\n//                ttsModel.setSpeechRate(1.6f);\n//                ttsModel.setPitch(0.8f);\n//                ttsModel.setAudioAttributes(new AudioAttributes.Builder()\n//                        .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)\n//                        .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)\n//                        .build());\n//                Log.d(\"TextToSpeech\",\"TTS Model initialized\");\n                this.isLoaded = true;\n//                Log.d(TAG, ttsModel.getVoices().toString());\n                Log.d(TAG, ttsModel.getDefaultEngine());\n            } else {\n//                Log.d(TAG, \"TTS failed with code: \" + status);\n            }\n        });\n    }\n\n    //default speak (english)\n    public void speak(String text){\n        speak(text, Locale.ENGLISH) ;\n    }\n\n    public void speak(String text, Locale locale){\n        Log.d(TAG, \"TTS speaking text: \" + text);\n        Log.d(TAG, \"TTS speaking this language: \" + locale.toString());\n        if (this.isLoaded){\n            //setup memory of this tts\n            HashMap<String, String> params = new HashMap<>();\n            String utteranceId = UUID.randomUUID().toString();\n            params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, utteranceId);\n\n            // TTS engine is initialized successfully\n            int result = ttsModel.setLanguage(locale);\n            if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {\n                Log.e(TAG, \"Language is not supported or missing data: \" + locale);\n                return;\n            }\n\n            ttsModel.setOnUtteranceProgressListener(new UtteranceProgressListener() {\n                @Override\n                public void onStart(String utteranceId) {\n                    // TTS starts speaking\n                    EventBus.getDefault().post(new PauseAsrEvent(true));\n                }\n\n                @Override\n                public void onDone(String utteranceId) {\n                    EventBus.getDefault().post(new PauseAsrEvent(false));\n                }\n\n                @Override\n                public void onError(String utteranceId) {\n                    // Handle TTS error\n                }\n            });\n\n            if (sco) {\n                Bundle ttsParams = new Bundle();\n                ttsParams.putInt(TextToSpeech.Engine.KEY_PARAM_STREAM, AudioManager.STREAM_VOICE_CALL);\n                ttsParams.putFloat(TextToSpeech.Engine.KEY_PARAM_VOLUME, 1.0f);\n                ttsModel.speak(text, TextToSpeech.QUEUE_FLUSH, ttsParams, utteranceId);\n            } else {\n                ttsModel.speak(text, TextToSpeech.QUEUE_FLUSH, null, utteranceId);\n            }\n        } else {\n            Log.d(TAG, \"TTS failed because not loaded.\");\n        }\n\n    }\n\n    public void destroy(){\n        EventBus.getDefault().unregister(this);\n        if (ttsModel != null) {\n            ttsModel.shutdown();\n        }\n\n//        Log.d(\"TextToSpeech\",\"TTS destroyed\");\n    }\n\n\n    @Subscribe\n    public void handleTtsEvent(TextToSpeechEvent event) {\n        String languageString = event.language;\n        Locale language = Locale.ENGLISH; // Default to English\n        switch (languageString.toLowerCase()) {\n            case \"english\":\n                language = Locale.ENGLISH;\n                break;\n            case \"chinese\":\n                language = Locale.CHINESE; // or Locale.SIMPLIFIED_CHINESE for more specificity\n                break;\n            case \"chinese (pinyin)\":\n                language = Locale.CHINESE; // or Locale.SIMPLIFIED_CHINESE for more specificity\n                break;\n            case \"italian\":\n                language = Locale.ITALIAN;\n                break;\n            case \"japanese\":\n                language = Locale.JAPANESE;\n                break;\n            case \"spanish\":\n                language = new Locale(\"es\", \"ES\");\n                break;\n            case \"russian\":\n                language = new Locale(\"ru\", \"RU\");\n                break;\n            case \"dutch\":\n                language = new Locale(\"nl\", \"NL\");\n                break;\n            case \"hebrew\":\n                language = new Locale(\"iw\", \"IL\");\n                break;\n            default:\n                // Log or alert the user that the language is not supported for direct Locale constants\n                Log.d(TAG, \"Language not supported by TTS: \" + languageString);\n                break;\n        }\n        speak(event.text, language);\n    }\n\n    @Subscribe\n    public void handleScoEvent(ScoStartEvent event) {\n        useSco(event.scoStart);\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/utils/AES.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.utils;\n\nimport android.util.Base64;\n\nimport java.io.UnsupportedEncodingException;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Arrays;\n\nimport javax.crypto.Cipher;\nimport javax.crypto.spec.SecretKeySpec;\n\nimport android.util.Log;\n\npublic class AES {\n    private static final String TAG = \"WearableIntelligenceSystem_AES\";\n\n    private static SecretKeySpec secretKey;\n    private static byte[] key;\n\n    public static void setKey(String myKey)\n    {\n        MessageDigest sha = null;\n        try {\n            key = myKey.getBytes(\"UTF-8\");\n            sha = MessageDigest.getInstance(\"SHA-1\");\n            key = sha.digest(key);\n            key = Arrays.copyOf(key, 16);\n            secretKey = new SecretKeySpec(key, \"AES\");\n        }\n        catch (NoSuchAlgorithmException e) {\n            e.printStackTrace();\n        }\n        catch (UnsupportedEncodingException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static String encrypt(String strToEncrypt, String secret)\n    {\n        try\n        {\n            setKey(secret);\n            Cipher cipher = Cipher.getInstance(\"AES/ECB/PKCS7Padding\");\n            cipher.init(Cipher.ENCRYPT_MODE, secretKey);\n            return Base64.encodeToString(cipher.doFinal(strToEncrypt.getBytes(\"UTF-8\")), Base64.DEFAULT);\n        }\n        catch (Exception e)\n        {\n            Log.d(TAG, \"Error while encrypting: \" + e.toString());\n        }\n        return null;\n    }\n\n    //bytes version\n    public static byte [] encrypt(byte [ ] bytesToEncrypt, String secret)\n    {\n        try\n        {\n            setKey(secret);\n            Cipher cipher = Cipher.getInstance(\"AES/ECB/PKCS7Padding\");\n            cipher.init(Cipher.ENCRYPT_MODE, secretKey);\n            return cipher.doFinal(bytesToEncrypt);\n        }\n        catch (Exception e)\n        {\n            Log.d(TAG, \"Error while encrypting: \" + e.toString());\n        }\n        return null;\n    }\n\n    //String version\n    public static String decrypt(String strToDecrypt, String secret)\n    {\n        try\n        {\n            Log.d(TAG, \"Secret key is: \" + secret);\n            setKey(secret);\n            Cipher cipher = Cipher.getInstance(\"AES/ECB/PKCS7PADDING\");\n            cipher.init(Cipher.DECRYPT_MODE, secretKey);\n            return new String(cipher.doFinal(Base64.decode(strToDecrypt, Base64.DEFAULT)));\n        }\n        catch (Exception e)\n        {\n            Log.d(TAG, \"Error while decrypting: \" + e.toString());\n        }\n        return null;\n    }\n\n    //bytes version\n    public static byte [] decrypt(byte [] bytesToDecrypt, String secret)\n    {\n        try\n        {\n            setKey(secret);\n            Cipher cipher = Cipher.getInstance(\"AES/ECB/PKCS7PADDING\");\n            cipher.init(Cipher.DECRYPT_MODE, secretKey);\n            return cipher.doFinal(bytesToDecrypt);\n        }\n        catch (Exception e)\n        {\n            Log.d(TAG, \"Error while decrypting: \" + e.toString());\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/utils/BitmapJavaUtils.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.utils;\n\nimport java.io.File;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.util.Log;\n\npublic class BitmapJavaUtils {\n    private static final String TAG = \"WearableAi_BitmapJavaUtils\";\n\n    public static Bitmap loadImageFromStorage(String path){\n        File imgFile = new  File(path);\n        if(imgFile.exists()){\n            Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());\n            return myBitmap;\n        } else {\n            Log.d(TAG, \"Image doesn't exist\");\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/utils/NetworkUtils.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.utils;\n\nimport android.util.Log;\n\nimport java.net.DatagramSocket;\nimport java.net.DatagramPacket;\n\nimport android.net.wifi.WifiManager;\nimport java.net.InetAddress;\nimport android.content.Context;\nimport android.net.wifi.WifiInfo;\nimport android.util.Pair;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.util.ArrayList;\nimport java.util.Enumeration;\nimport java.net.NetworkInterface;\nimport java.net.SocketException;\nimport java.net.InterfaceAddress;\nimport java.net.UnknownHostException;\nimport java.lang.reflect.Method;\nimport java.util.List;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\n\n// see https://stackoverflow.com/questions/14080573/getting-wifi-broadcast-address-in-android-wifi-hotspot for much of this code\npublic class NetworkUtils {\n    public static final String TAG = \"WearableAi_NetworkUtils\";\n\n    public static void sendBroadcast(String messageStr, DatagramSocket adv_socket, int port, Context context){\n        try {\n            byte[] sendData = messageStr.getBytes();\n            InetAddress my_ip;\n            if (isHotspotOn(context)){\n                String my_ip_hs = getHotspotIpAddress();\n                my_ip = InetAddress.getByName(my_ip_hs);\n            } else {\n                my_ip = getIpAddress();\n            }\n\n            InetAddress bca_ip = getBroadcastAddress(my_ip);\n            if (bca_ip == null){\n                //this probably means we aren't connect to or hosting WiFi\n                //but, some phones, even when wifi tether is on, need this, so let's try:\n                my_ip = getIpAddress();\n                bca_ip = getBroadcastAddress(my_ip);\n                if (bca_ip == null){\n                    Log.d(TAG, \"Broadcast address is null\");\n                    return;\n                }\n            }\n\n            DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, bca_ip, port);\n            adv_socket.send(sendPacket);\n        } catch (IOException e){\n            Log.d(TAG, \"FAILED TO SEND BROADCAST\");\n            e.printStackTrace();\n            return ;\n        }\n    }\n\n    public static InetAddress getBroadcast(InetAddress inetAddr) {\n\n        NetworkInterface temp;\n        InetAddress iAddr = null;\n        try {\n            temp = NetworkInterface.getByInetAddress(inetAddr);\n            List<InterfaceAddress> addresses = temp.getInterfaceAddresses();\n\n            for (InterfaceAddress inetAddress: addresses)\n\n                iAddr = inetAddress.getBroadcast();\n            return iAddr;\n\n        } catch (SocketException e) {\n\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    public static boolean isHotspotOn(Context context){\n        WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);\n        Method[] wmMethods = wifi.getClass().getDeclaredMethods();\n        for (Method method: wmMethods) {\n            if (method.getName().equals(\"isWifiApEnabled\")) {\n\n                try {\n                    if ((Boolean) method.invoke(wifi)) {\n//                        isInetConnOn = true;\n//                        iNetMode = 2;\n                        return true;\n                    } else {\n                        return false;\n                    }\n                } catch (IllegalArgumentException e) {\n                    e.printStackTrace();\n                } catch (IllegalAccessException e) {\n                    e.printStackTrace();\n                } catch (InvocationTargetException e) {\n                    e.printStackTrace();\n                }\n\n            }\n        }\n        return false;\n    }\n\n    public static InetAddress getIpAddress() {\n      InetAddress inetAddress = null;\n      InetAddress myAddr = null;\n\n      try {\n        for (Enumeration<NetworkInterface> networkInterface = NetworkInterface\n          .getNetworkInterfaces(); networkInterface.hasMoreElements();) {\n\n          NetworkInterface singleInterface = networkInterface.nextElement();\n\n          for (Enumeration<InetAddress> IpAddresses = singleInterface.getInetAddresses(); IpAddresses\n            .hasMoreElements();) {\n            inetAddress = IpAddresses.nextElement();\n\n            if (!inetAddress.isLoopbackAddress() && (singleInterface.getDisplayName()\n                .contains(\"wlan0\") ||\n                singleInterface.getDisplayName().contains(\"eth0\") ||\n                singleInterface.getDisplayName().contains(\"ap0\"))) {\n\n              myAddr = inetAddress;\n            }\n          }\n        }\n\n      } catch (SocketException ex) {\n        Log.e(TAG, ex.toString());\n      }\n      return myAddr;\n    }\n\n    public static String getHotspotIpAddress() {\n            String ip = \"\";\n            List<Pair<String, String>> ipAddys = new ArrayList<Pair<String, String>>();\n            String [] hotspots = new String [] {\"swlan\", \"ap\", \"wlan1\", \"wlan\"};\n\n            try {\n                Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface\n                        .getNetworkInterfaces();\n                while (enumNetworkInterfaces.hasMoreElements()) {\n                    NetworkInterface networkInterface = enumNetworkInterfaces\n                            .nextElement();\n                    Enumeration<InetAddress> enumInetAddress = networkInterface\n                            .getInetAddresses();\n                    while (enumInetAddress.hasMoreElements()) {\n                        InetAddress inetAddress = enumInetAddress.nextElement();\n                        if (inetAddress.isSiteLocalAddress()){\n                            ip = inetAddress.getHostAddress();\n                            ipAddys.add(new Pair(ip, networkInterface.getName()));\n                        }\n                    }\n                }\n            } catch (SocketException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                return null;\n            }\n\n            //go through all the ip addresses and choose the one most likely to be the hotspot\n            for (int i = 0; i < hotspots.length; i++) {\n                for (int j = 0; j < ipAddys.size(); j++) {\n                    if (ipAddys.get(j).second.contains(hotspots[i])){\n                       return ipAddys.get(j).first;\n                    }\n                }\n            }\n            return ip;\n    }\n\n    public static InetAddress getBroadcastAddress(InetAddress inetAddr) {\n\n        NetworkInterface temp;\n        InetAddress iAddr = null;\n        try {\n            temp = NetworkInterface.getByInetAddress(inetAddr);\n            List<InterfaceAddress> addresses = temp.getInterfaceAddresses();\n\n            for (InterfaceAddress inetAddress: addresses)\n\n                iAddr = inetAddress.getBroadcast();\n            return iAddr;\n\n        } catch (SocketException e) {\n\n            e.printStackTrace();\n            Log.d(TAG, \"getBroadcast\" + e.getMessage());\n        } catch (NullPointerException e){\n            Log.d(TAG, \"Null pointer on getBroadcastAdress, probably means we arent' connected to wifi AND we don't have a live wifi hotspot\");\n            return null;\n        }\n        return null;\n    }\n \n     public static String getLocalIpAddress(Context context) throws UnknownHostException {\n            WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);\n            assert wifiManager != null;\n            WifiInfo wifiInfo = wifiManager.getConnectionInfo();\n            int ipInt = wifiInfo.getIpAddress();\n            return InetAddress.getByAddress(ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(ipInt).array()).getHostAddress();\n    }\n\n\n\n\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/java/com/teamopensmartglasses/smartglassesmanager/utils/PermissionsUtils.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager.utils;\n\nimport android.Manifest;\nimport android.app.AlertDialog;\nimport android.content.DialogInterface;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.core.app.ActivityCompat;\nimport androidx.core.content.ContextCompat;\n\n//handle all of the permissions stuff\npublic class PermissionsUtils {\n    private AppCompatActivity mCallingActivity;\n    private String TAG;\n\n    public PermissionsUtils(AppCompatActivity callingActivity, String tag){\n        mCallingActivity = callingActivity;\n        TAG = tag;\n    }\n\n    //permissions\n    //file storage and SMS permissions\n    public final String[] EXTERNAL_PERMS = {Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE};\n    public final int EXTERNAL_REQUEST = 138;\n\n    //location permissions\n    //private int LOCATION_PERMISSION_CODE = 1;\n    private int REQUEST_PERMISSION_CODE = 1;\n    private int BACKGROUND_LOCATION_PERMISSION_CODE = 2;\n\n    //handle permissions\n    public boolean requestFilesPermission() {\n        boolean isPermissionOn = true;\n        final int version = Build.VERSION.SDK_INT;\n        if (version >= 23) {\n            if (!canAccessExternalSd()) {\n                isPermissionOn = false;\n              mCallingActivity.requestPermissions(EXTERNAL_PERMS, EXTERNAL_REQUEST);\n            }\n        }\n        return isPermissionOn;\n    }\n\n    public boolean canAccessExternalSd() {\n        return (hasPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE));\n    }\n\n    private boolean hasPermission(String perm) {\n        return (PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(mCallingActivity, perm));\n\n    }\n\n    public void checkPermission() {\n        if (ContextCompat.checkSelfPermission(mCallingActivity, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {\n            // Fine Location permission is granted\n            // Check if current android version >= 11, if >= 11 check for Background Location permission\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                if (ContextCompat.checkSelfPermission(mCallingActivity, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED) {\n                    // Background Location Permission is granted so do your work here\n                    //now, get file permissions\n                    requestFilesPermission();\n                } else {\n                    // Ask for Background Location Permission\n                    askPermissionForBackgroundUsage();\n                }\n            }\n        } else {\n            // Fine Location Permission is not granted so ask for permission\n            askForLocationPermission();\n        }\n    }\n\n    private void askForLocationPermission() {\n        Log.d(TAG, \"run askForLocationPermission\");\n        if (ActivityCompat.shouldShowRequestPermissionRationale(mCallingActivity, Manifest.permission.ACCESS_FINE_LOCATION)) {\n            new AlertDialog.Builder(mCallingActivity)\n                    .setTitle(\"Permission Needed!\")\n                    .setMessage(\"Location Permission Needed!\")\n                    .setPositiveButton(\"OK\", new DialogInterface.OnClickListener() {\n                        @Override\n                        public void onClick(DialogInterface dialog, int which) {\n                            ActivityCompat.requestPermissions(mCallingActivity,\n                                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.BLUETOOTH_CONNECT,Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.RECORD_AUDIO}, REQUEST_PERMISSION_CODE);\n                        }\n                    })\n                    .setNegativeButton(\"CANCEL\", new DialogInterface.OnClickListener() {\n                        @Override\n                        public void onClick(DialogInterface dialog, int which) {\n                            // Permission is denied by the user\n                        }\n                    })\n                    .create().show();\n        } else {\n            ActivityCompat.requestPermissions(mCallingActivity,\n                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.BLUETOOTH_CONNECT,Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.RECORD_AUDIO}, REQUEST_PERMISSION_CODE);\n        }\n    }\n\n    private void askPermissionForBackgroundUsage() {\n        Log.d(TAG, \"run askPermissionForBackgroundUsage\");\n        if (ActivityCompat.shouldShowRequestPermissionRationale(mCallingActivity, Manifest.permission.ACCESS_BACKGROUND_LOCATION)) {\n            new AlertDialog.Builder(mCallingActivity)\n                    .setTitle(\"Location permissions needed.\")\n                    .setMessage(\"To tag memories and data based on where you were, the WIS app needs to collect location data. Many features won't work without location permissions. To allow, tap \\\"Allow all the time\\\" on the next screen.\")\n                    .setPositiveButton(\"OK\", new DialogInterface.OnClickListener() {\n                        @Override\n                        public void onClick(DialogInterface dialog, int which) {\n                            ActivityCompat.requestPermissions(mCallingActivity,\n                                    new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION}, BACKGROUND_LOCATION_PERMISSION_CODE);\n                        }\n                    })\n                    .setNegativeButton(\"CANCEL\", new DialogInterface.OnClickListener() {\n                        @Override\n                        public void onClick(DialogInterface dialog, int which) {\n                            // User declined for Background Location Permission.\n                        }\n                    })\n                    .create().show();\n        } else {\n            ActivityCompat.requestPermissions(mCallingActivity,\n                    new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION}, BACKGROUND_LOCATION_PERMISSION_CODE);\n        }\n    }\n\n    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {\n        if (requestCode == REQUEST_PERMISSION_CODE) {\n            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {\n                // User granted location permission\n                // Now check if android version >= 11, if >= 11 check for Background Location Permission\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                    if (ContextCompat.checkSelfPermission(mCallingActivity, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED) {\n                        // Background Location Permission is granted so do your work here\n                        //now, get file permissions\n                        requestFilesPermission();\n                    } else {\n                        // Ask for Background Location Permission\n                        askPermissionForBackgroundUsage();\n                    }\n                }\n            } else {\n                // User denied location permission\n            }\n        } else if (requestCode == BACKGROUND_LOCATION_PERMISSION_CODE) {\n            //now, get file permissions\n            requestFilesPermission();\n            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {\n            }\n        }\n    }\n\n    public void getSomePermissions(){\n        ActivityCompat.requestPermissions(mCallingActivity,\n                new String[]{Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.RECORD_AUDIO}, REQUEST_PERMISSION_CODE);\n    }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/proto/com/google/audio/asr/cloud_speech_session_params.proto",
    "content": "syntax = \"proto2\";\n\npackage asr;\n\nimport \"com/google/audio/asr/cloud_speech_stream_observer_params.proto\";\nimport \"com/google/audio/codec_and_bitrate.proto\";\n\noption java_package = \"com.google.audio.asr\";\noption java_outer_classname = \"CloudSpeechSessionParamsProto\";\noption java_multiple_files = true;\n\nmessage CloudSpeechSessionParams {\n  // Parameters for the observer, who converts the speech protos into\n  // TranscriptionResult.\n  optional CloudSpeechStreamObserverParams observer_params = 1;\n\n  // Allows profanity to be filtered by the Cloud Speech API.\n  optional bool filter_profanity = 2;\n\n  // Details about how the audio signal should be compressed prior to sending it\n  // to the server.\n  message EncoderParams {\n    // If the encoder isn't supported, uncompressed audio will be used. When\n    // this is false, other EncoderParams fields are ignored.\n    optional bool enable_encoder = 1 [default = false];\n    optional audio.CodecAndBitrate codec = 2\n        [default = OGG_OPUS_BITRATE_32KBPS];\n\n    // Uses variable bitrate encoding, if available. Currently this is available\n    // for OggOpus only.\n    optional bool allow_vbr = 3 [default = true];\n  }\n\n  optional EncoderParams encoder_params = 3;\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/proto/com/google/audio/asr/cloud_speech_stream_observer_params.proto",
    "content": "syntax = \"proto2\";\n\npackage asr;\n\noption java_package = \"com.google.audio.asr\";\noption java_outer_classname = \"CloudSpeechSessionObserverParamsProto\";\noption java_multiple_files = true;\n\nmessage CloudSpeechStreamObserverParams {\n  // When true, hypotheses are held a bit longer until they likely will not\n  // change again before being displayed.\n  optional bool reject_unstable_hypotheses = 1;\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/proto/com/google/audio/asr/speech_recognition_model_options.proto",
    "content": "syntax = \"proto2\";\n\npackage asr;\n\noption java_package = \"com.google.audio.asr\";\noption java_outer_classname = \"SpeechRecognitionModelOptionsProto\";\noption java_multiple_files = true;\n\nmessage SpeechRecognitionModelOptions {\n  optional string locale = 1;  // Required.\n\n  // Select which model to use. Not all models are necessarily available for all\n  // recognition systems or locales. It is up to the individual session to warn\n  // the user about availability\n  enum SpecificModel {\n    DICTATION_DEFAULT = 0;\n    VIDEO = 1;\n  }\n\n  optional SpecificModel model = 2 [default = DICTATION_DEFAULT];\n\n  // Words to be passed to the speech recognizer as bias. It is up to each\n  // implementation to decide whether these will be used or not.\n  repeated string bias_words = 3;\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/proto/com/google/audio/asr/transcription_result.proto",
    "content": "syntax = \"proto2\";\n\npackage asr;\n\nimport \"com/google/audio/speaker_id_info.proto\";\nimport \"google/protobuf/timestamp.proto\";\n\noption java_package = \"com.google.audio.asr\";\noption java_outer_classname = \"TranscriptionResultProto\";\noption java_multiple_files = true;\n\nmessage TranscriptionResult {\n  // An utterance level copy of the text.\n  optional string text = 1;\n\n  // Confidence for the whole utterance [0, 1].\n  optional float confidence = 2;\n  // The epoch time at which the utterance was started.\n  optional google.protobuf.Timestamp start_timestamp = 7;\n  // The epoch time at which the utterance was completed.\n  optional google.protobuf.Timestamp end_timestamp = 3;\n\n  // The identity of the speaker.\n  optional audio.SpeakerIdInfo speaker_info = 5;\n\n  // Fine-grain information about each word.\n  // NOTE: the TranscriptResultFormatter may colorize the coarse-grain\n  // transcript by the corresponding word information such as confidence and\n  // speaker_id if fine-grain word_level_detail is not empty.\n  message Word {\n    optional string text = 1;\n    // Confidence for just this word [0, 1].\n    optional float confidence = 2;\n    // An integer tag for the identity of the active speaker.\n    optional audio.SpeakerIdInfo speaker_info = 3;\n    // The time at which the word was started.\n    optional google.protobuf.Timestamp start_timestamp = 4;\n    // The time at which the word was completed.\n    optional google.protobuf.Timestamp end_timestamp = 5;\n  }\n  // Word-level detail.\n  // NOTE: Some recognizers (namely the CloudSpeech API) do not give fine-grain\n  // information until results are finalized.\n  repeated Word word_level_detail = 4;\n\n  // The language code in this result.\n  // See https://cloud.google.com/speech-to-text/docs/languages for more\n  // details.\n  // For example,\n  // English (United States) : en-US\n  // Chinese, Mandarin (Traditional, Taiwan) : cmn-Hant-TW\n  optional string language_code = 6;\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/proto/com/google/audio/asr/transcription_result_formatter_options.proto",
    "content": "syntax = \"proto2\";\n\npackage asr;\n\nimport \"google/protobuf/duration.proto\";\n\noption java_package = \"com.google.audio.asr\";\noption java_outer_classname = \"TranscriptionResultFormatterOptionsProto\";\noption java_multiple_files = true;\n\nmessage TranscriptionResultFormatterOptions {\n  // Color selection for the text (does not change background). Dark colors for\n  // a black-on-white theme. Bright colors for a white-on-black theme.\n  enum TextColormap {\n    UNSPECIFIED_THEME = 0;\n    LIGHT_THEME = 1;\n    DARK_THEME = 2;\n  }\n\n  // Details on the manner in which the transcript will be colored.\n  enum TranscriptColoringStyle {\n    UNSPECIFIED_COLORING_STYLE = 0;  // Will do NO_COLORING.\n    NO_COLORING = 1;\n    COLOR_BY_UTTERANCE_LEVEL_CONFIDENCE = 2;\n    COLOR_BY_WORD_LEVEL_CONFIDENCE = 3;\n    COLOR_BY_SPEAKER_ID = 4;\n  }\n\n  enum SpeakerIndicationStyle {\n    UNSPECIFIED_SPEAKER_INDICATION_STYLE = 0;\n    NO_SPEAKER_INDICATION = 1;\n    SHOW_SPEAKER_NUMBER = 2;\n  }\n\n  // Silences longer than this will cause a space to be inserted.\n  optional google.protobuf.Duration extended_silence_duration_for_line_breaks =\n      1;\n\n  // Number of '\\n' characters to add in the event of extended silence.\n  // 1 moves to the next line, 2 leaves a blank space in between two lines,\n  // and so on...\n  optional int32 num_extended_silence_line_breaks = 2 [default = 0];\n\n  // Number of '\\n' characters to add in the event of language switch.\n  // 1 moves to the next line, 2 leaves a blank space in between two lines, and\n  // so on...\n  optional int32 num_language_switch_line_breaks = 3 [default = 1];\n\n  // Put current hypotheses in italics.\n  optional bool italicize_current_hypothesis = 4 [default = false];\n\n  // If true, use a yellow->blue colormap to indicate confidence.\n  optional TranscriptColoringStyle transcript_coloring_style = 5\n      [default = NO_COLORING];\n\n  // The color theme used for the text.\n  optional TextColormap text_colormap = 6 [default = DARK_THEME];\n\n  // A label that indicates which speaker is active.\n  optional SpeakerIndicationStyle speaker_indication_style = 7\n      [default = NO_SPEAKER_INDICATION];\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/proto/com/google/audio/codec_and_bitrate.proto",
    "content": "syntax = \"proto2\";\n\npackage audio;\n\noption java_package = \"com.google.audio\";\noption java_multiple_files = true;\n\n// In Java, (and excluding the FLAC entry) the bitrate in kilobits per second\n// can be obtained using CodecAndBitrate's getNumber() function.\nenum CodecAndBitrate {\n  UNDEFINED = 0;  // Do not pass this to the encoder.\n  AMRWB_BITRATE_6KBPS = 6600;\n  AMRWB_BITRATE_8KBPS = 8850;\n  AMRWB_BITRATE_12KBPS = 12650;\n  AMRWB_BITRATE_14KBPS = 14250;\n  AMRWB_BITRATE_15KBPS = 15850;\n  AMRWB_BITRATE_18KBPS = 18250;\n  AMRWB_BITRATE_19KBPS = 19850;\n  AMRWB_BITRATE_23KBPS = 23050;\n  AMRWB_BITRATE_24KBPS = 23850;\n  // For FLAC, the bitrate isn't specified.\n  FLAC = 1;\n  // Note: Opus isn't actually limited to specific bitrates like AMRWB is.\n  //\n  // Note that because we run the OggOpusEncoder in low-latency mode, the\n  // actual bitrate may be larger than this. See the ogg_opus_encoder lib for\n  // details.\n  //\n  // The effect of this will be larger at low bitrates and low block\n  // sizes. This is the bitrate used to configure the codec.\n  OGG_OPUS_BITRATE_12KBPS = 12000;\n  OGG_OPUS_BITRATE_16KBPS = 16000;\n  OGG_OPUS_BITRATE_24KBPS = 24000;\n  OGG_OPUS_BITRATE_32KBPS = 32000;\n  OGG_OPUS_BITRATE_64KBPS = 64000;\n  OGG_OPUS_BITRATE_96KBPS = 96000;\n  OGG_OPUS_BITRATE_128KBPS = 128000;\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/proto/com/google/audio/network_state.proto",
    "content": "syntax = \"proto2\";\n\npackage audio;\n\noption java_package = \"com.google.audio\";\noption java_multiple_files = true;\n\n// Contains information about whether we are connected to the network and\n// whether the connection is using WiFi.\nmessage NetworkState {\n  // If the network is connected.\n  optional bool connected = 1;  // Required.\n  // Typically, if false, this means using WiFi.\n  optional bool network_metered = 2;  // Required.\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/proto/com/google/audio/speaker_id_info.proto",
    "content": "syntax = \"proto2\";\n\npackage audio;\n\noption java_package = \"com.google.audio\";\noption java_multiple_files = true;\n\nmessage SpeakerIdInfo {\n  optional int32 speaker_id = 1;\n  // In the future, we may have things like the name of registered speakers\n  // etc.\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector\n    android:height=\"108dp\"\n    android:width=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#26A69A\"\n          android:pathData=\"M0,0h108v108h-108z\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M9,0L9,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,0L19,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M29,0L29,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M39,0L39,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M49,0L49,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M59,0L59,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M69,0L69,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M79,0L79,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M89,0L89,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M99,0L99,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,9L108,9\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,19L108,19\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,29L108,29\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,39L108,39\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,49L108,49\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,59L108,59\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,69L108,69\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,79L108,79\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,89L108,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,99L108,99\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,29L89,29\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,39L89,39\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,49L89,49\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,59L89,59\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,69L89,69\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,79L89,79\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M29,19L29,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M39,19L39,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M49,19L49,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M59,19L59,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M69,19L69,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M79,19L79,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n</vector>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/drawable/outline_device_hub_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M17,16l-4,-4V8.82C14.16,8.4 15,7.3 15,6c0,-1.66 -1.34,-3 -3,-3S9,4.34 9,6c0,1.3 0.84,2.4 2,2.82V12l-4,4H3v5h5v-3.05l4,-4.2 4,4.2V21h5v-5h-4z\"/>\n</vector>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/drawable/outline_groups_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M4,13c1.1,0 2,-0.9 2,-2c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2C2,12.1 2.9,13 4,13zM5.13,14.1C4.76,14.04 4.39,14 4,14c-0.99,0 -1.93,0.21 -2.78,0.58C0.48,14.9 0,15.62 0,16.43V18l4.5,0v-1.61C4.5,15.56 4.73,14.78 5.13,14.1zM20,13c1.1,0 2,-0.9 2,-2c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2C18,12.1 18.9,13 20,13zM24,16.43c0,-0.81 -0.48,-1.53 -1.22,-1.85C21.93,14.21 20.99,14 20,14c-0.39,0 -0.76,0.04 -1.13,0.1c0.4,0.68 0.63,1.46 0.63,2.29V18l4.5,0V16.43zM16.24,13.65c-1.17,-0.52 -2.61,-0.9 -4.24,-0.9c-1.63,0 -3.07,0.39 -4.24,0.9C6.68,14.13 6,15.21 6,16.39V18h12v-1.61C18,15.21 17.32,14.13 16.24,13.65zM8.07,16c0.09,-0.23 0.13,-0.39 0.91,-0.69c0.97,-0.38 1.99,-0.56 3.02,-0.56s2.05,0.18 3.02,0.56c0.77,0.3 0.81,0.46 0.91,0.69H8.07zM12,8c0.55,0 1,0.45 1,1s-0.45,1 -1,1s-1,-0.45 -1,-1S11.45,8 12,8M12,6c-1.66,0 -3,1.34 -3,3c0,1.66 1.34,3 3,3s3,-1.34 3,-3C15,7.34 13.66,6 12,6L12,6z\"/>\n</vector>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/drawable/outline_memory_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M15,9L9,9v6h6L15,9zM13,13h-2v-2h2v2zM21,11L21,9h-2L19,7c0,-1.1 -0.9,-2 -2,-2h-2L15,3h-2v2h-2L11,3L9,3v2L7,5c-1.1,0 -2,0.9 -2,2v2L3,9v2h2v2L3,13v2h2v2c0,1.1 0.9,2 2,2h2v2h2v-2h2v2h2v-2h2c1.1,0 2,-0.9 2,-2v-2h2v-2h-2v-2h2zM17,17L7,17L7,7h10v10z\"/>\n</vector>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/drawable/outline_settings_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98 0,-0.34 -0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.09,-0.16 -0.26,-0.25 -0.44,-0.25 -0.06,0 -0.12,0.01 -0.17,0.03l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.06,-0.02 -0.12,-0.03 -0.18,-0.03 -0.17,0 -0.34,0.09 -0.43,0.25l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98 0,0.33 0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.09,0.16 0.26,0.25 0.44,0.25 0.06,0 0.12,-0.01 0.17,-0.03l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.06,0.02 0.12,0.03 0.18,0.03 0.17,0 0.34,-0.09 0.43,-0.25l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM17.45,11.27c0.04,0.31 0.05,0.52 0.05,0.73 0,0.21 -0.02,0.43 -0.05,0.73l-0.14,1.13 0.89,0.7 1.08,0.84 -0.7,1.21 -1.27,-0.51 -1.04,-0.42 -0.9,0.68c-0.43,0.32 -0.84,0.56 -1.25,0.73l-1.06,0.43 -0.16,1.13 -0.2,1.35h-1.4l-0.19,-1.35 -0.16,-1.13 -1.06,-0.43c-0.43,-0.18 -0.83,-0.41 -1.23,-0.71l-0.91,-0.7 -1.06,0.43 -1.27,0.51 -0.7,-1.21 1.08,-0.84 0.89,-0.7 -0.14,-1.13c-0.03,-0.31 -0.05,-0.54 -0.05,-0.74s0.02,-0.43 0.05,-0.73l0.14,-1.13 -0.89,-0.7 -1.08,-0.84 0.7,-1.21 1.27,0.51 1.04,0.42 0.9,-0.68c0.43,-0.32 0.84,-0.56 1.25,-0.73l1.06,-0.43 0.16,-1.13 0.2,-1.35h1.39l0.19,1.35 0.16,1.13 1.06,0.43c0.43,0.18 0.83,0.41 1.23,0.71l0.91,0.7 1.06,-0.43 1.27,-0.51 0.7,1.21 -1.07,0.85 -0.89,0.7 0.14,1.13zM12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z\"/>\n</vector>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/drawable/pretty_thin_border.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" android:shape=\"rectangle\" >\n    <!-- use this for transparent -->\n    <!-- <solid android:color=\"#00000000\" /> -->\n    <!-- use this for a background colour -->\n    <solid android:color=\"#FFF\" />\n    <stroke android:width=\"2dip\" android:color=\"#000000\" />\n</shape>"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/drawable/rounded_corner.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n<!--    <stroke-->\n<!--        android:width=\"1dp\"-->\n<!--        android:color=\"@color/colorPrimaryDark\" />-->\n\n    <solid android:color=\"#fafafa\" />\n\n    <padding\n        android:left=\"1dp\"\n        android:right=\"1dp\"\n        android:bottom=\"1dp\"\n        android:top=\"1dp\" />\n\n    <corners android:radius=\"5dp\" />\n</shape>"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/drawable/rounded_corners_bg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"#FFFFFF\"/>\n    <stroke android:width=\"3dp\" android:color=\"#B1BCBE\" />\n    <corners android:radius=\"10dp\"/>\n    <padding android:left=\"0dp\" android:top=\"0dp\" android:right=\"0dp\" android:bottom=\"0dp\" />\n</shape>"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/drawable/rounded_shadow_bg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <item\n        android:width=\"48dp\"\n        android:height=\"48dp\"\n        android:bottom=\"68dp\"\n        android:right=\"-20dp\">\n        <bitmap\n            android:gravity=\"bottom|right\"\n            android:src=\"@drawable/rounded_corners_bg\" />\n    </item>\n    <item\n        android:height=\"68dp\"\n        android:left=\"-20dp\"\n        android:bottom=\"-20dp\"\n        android:width=\"68dp\">\n        <bitmap\n            android:gravity=\"bottom|left\"\n            android:src=\"@android:drawable/dialog_holo_light_frame\" />\n    </item>\n</layer-list>"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/drawable/sgm_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector\n    android:height=\"108dp\"\n    android:width=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#3DDC84\"\n          android:pathData=\"M0,0h108v108h-108z\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M9,0L9,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,0L19,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M29,0L29,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M39,0L39,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M49,0L49,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M59,0L59,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M69,0L69,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M79,0L79,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M89,0L89,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M99,0L99,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,9L108,9\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,19L108,19\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,29L108,29\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,39L108,39\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,49L108,49\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,59L108,59\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,69L108,69\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,79L108,79\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,89L108,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,99L108,99\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,29L89,29\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,39L89,39\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,49L89,49\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,59L89,59\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,69L89,69\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,79L89,79\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M29,19L29,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M39,19L39,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M49,19L49,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M59,19L59,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M69,19L69,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M79,19L79,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n</vector>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/drawable/textview_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <gradient\n        android:angle=\"90\"\n        android:startColor=\"@android:color/holo_blue_light\"\n        android:centerColor=\"@android:color/transparent\"\n        android:endColor=\"@android:color/transparent\"\n        />\n\n</shape>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/drawable/wis_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector\n    android:height=\"108dp\"\n    android:width=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#3DDC84\"\n          android:pathData=\"M0,0h108v108h-108z\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M9,0L9,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,0L19,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M29,0L29,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M39,0L39,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M49,0L49,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M59,0L59,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M69,0L69,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M79,0L79,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M89,0L89,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M99,0L99,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,9L108,9\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,19L108,19\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,29L108,29\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,39L108,39\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,49L108,49\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,59L108,59\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,69L108,69\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,79L108,79\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,89L108,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,99L108,99\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,29L89,29\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,39L89,39\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,49L89,49\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,59L89,59\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,69L89,69\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,79L89,79\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M29,19L29,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M39,19L39,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M49,19L49,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M59,19L59,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M69,19L69,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M79,19L79,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n</vector>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/drawable/wis_launcher_transparent_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector\n    android:height=\"108dp\"\n    android:width=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#3DDC84\"\n          android:pathData=\"M0,0h108v108h-108z\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M9,0L9,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,0L19,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M29,0L29,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M39,0L39,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M49,0L49,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M59,0L59,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M69,0L69,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M79,0L79,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M89,0L89,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M99,0L99,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,9L108,9\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,19L108,19\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,29L108,29\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,39L108,39\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,49L108,49\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,59L108,59\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,69L108,69\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,79L108,79\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,89L108,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,99L108,99\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,29L89,29\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,39L89,39\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,49L89,49\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,59L89,59\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,69L89,69\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,79L89,79\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M29,19L29,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M39,19L39,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M49,19L49,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M59,19L59,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M69,19L69,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M79,19L79,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n</vector>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\">\n    <path\n        android:fillType=\"evenOdd\"\n        android:pathData=\"M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z\"\n        android:strokeColor=\"#00000000\"\n        android:strokeWidth=\"1\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:endX=\"78.5885\"\n                android:endY=\"90.9159\"\n                android:startX=\"48.7653\"\n                android:startY=\"61.0927\"\n                android:type=\"linear\">\n                <item\n                    android:color=\"#44000000\"\n                    android:offset=\"0.0\" />\n                <item\n                    android:color=\"#00000000\"\n                    android:offset=\"1.0\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:fillColor=\"#FFFFFF\"\n        android:fillType=\"nonZero\"\n        android:pathData=\"M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z\"\n        android:strokeColor=\"#00000000\"\n        android:strokeWidth=\"1\" />\n</vector>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:id=\"@+id/mainlayout\"\n    android:layout_height=\"match_parent\">\n\n    <com.google.android.material.appbar.AppBarLayout\n        android:id=\"@+id/appbarlayout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        android:fitsSystemWindows=\"true\"\n        app:liftOnScroll=\"true\">\n\n        <androidx.constraintlayout.widget.ConstraintLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            >\n\n            <ImageView\n                android:id=\"@+id/imageView2\"\n                android:layout_width=\"70dp\"\n                android:layout_height=\"35dp\"\n                android:src=\"@drawable/sgm_app_transparent_bg_white_text_icon\"\n                android:background=\"@android:color/transparent\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintStart_toStartOf=\"parent\"\n                app:layout_constraintTop_toTopOf=\"parent\"></ImageView>\n\n            <TextView\n                android:id=\"@+id/seperator\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:text=\"|\"\n                android:textAlignment=\"center\"\n                android:textColor=\"#FFFFFFFF\"\n                android:textSize=\"35dp\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintTop_toTopOf=\"parent\"\n                app:layout_constraintStart_toEndOf=\"@+id/imageView2\"></TextView>\n\n            <androidx.appcompat.widget.Toolbar\n                android:id=\"@+id/main_toolbar\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                app:contentInsetStart=\"7dp\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintStart_toEndOf=\"@+id/seperator\"\n                app:titleTextColor=\"@android:color/white\" />\n        </androidx.constraintlayout.widget.ConstraintLayout>\n    </com.google.android.material.appbar.AppBarLayout>\n\n    <androidx.fragment.app.FragmentContainerView\n        android:id=\"@+id/nav_host_fragment\"\n        android:name=\"androidx.navigation.fragment.NavHostFragment\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        app:defaultNavHost=\"true\"\n\n        app:layout_constraintTop_toBottomOf=\"@id/appbarlayout\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:navGraph=\"@navigation/nav_graph\" />\n\n<!--    <com.google.android.material.bottomnavigation.BottomNavigationView-->\n<!--        android:id=\"@+id/bottom_nav_main_menu_nav\"-->\n<!--        android:layout_width=\"match_parent\"-->\n<!--        android:layout_height=\"wrap_content\"-->\n<!--        app:layout_constraintTop_toBottomOf=\"@id/nav_host_fragment\"-->\n<!--        app:layout_constraintBottom_toBottomOf=\"parent\"-->\n<!--        app:menu=\"@menu/bottom_nav_main_menu\" />-->\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/layout/all_transcripts_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/mainlayout\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/phrase_wall\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"0dp\"\n        android:background=\"@color/colorMainBackground\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.0\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        tools:listitem=\"@layout/phrase_recyclerview_item\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/layout/api_key_message.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\"\n    android:padding=\"10dp\">\n\n  <TextView\n      android:id=\"@+id/api_key_link_view\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:clickable=\"true\" />\n\n  <EditText\n      android:id=\"@+id/api_key_input\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:autofillHints=\"password\"\n      android:inputType=\"text\" />\n\n<!--  <TextView-->\n<!--      android:id=\"@+id/language_locale_view\"-->\n<!--      android:layout_width=\"wrap_content\"-->\n<!--      android:layout_height=\"wrap_content\"-->\n<!--      android:text=\"@string/select_language_message\" />-->\n\n<!--  <Spinner-->\n<!--      android:id=\"@+id/language_locale_spinner\"-->\n<!--      android:layout_width=\"match_parent\"-->\n<!--      android:layout_height=\"wrap_content\" />-->\n</LinearLayout>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/layout/connecting_to_glasses_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:id=\"@+id/textView4\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"5dp\"\n        android:text=\"Trying to Connect...\"\n        android:textColor=\"#4d4d4d\"\n        android:textSize=\"28dp\"\n        android:textStyle=\"bold\"\n        android:justificationMode=\"inter_word\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.498\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n\n    <ProgressBar\n        android:id=\"@+id/connected_glasses_image\"\n        style=\"?android:attr/progressBarStyleLarge\"\n        android:layout_width=\"195dp\"\n        android:layout_height=\"166dp\"\n        android:layout_marginTop=\"200dp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/textView4\"></ProgressBar>\n\n    <TextView\n        android:id=\"@+id/glasses_connected_message_tv\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"16dp\"\n        android:justificationMode=\"inter_word\"\n        android:text=\"Connecting to smart glasses...\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/connected_glasses_image\" />\n\n\n    <Button\n        android:id=\"@+id/ok_glasses_connected_button\"\n        android:layout_width=\"99dp\"\n        android:layout_height=\"66dp\"\n        android:layout_marginBottom=\"48dp\"\n        android:text=\"Cancel\"\n        app:backgroundTint=\"@color/red\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\" />\n\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/layout/default_app_dialog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\"\n    android:padding=\"10dp\">\n\n    <EditText\n        android:id=\"@+id/default_app_input\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:inputType=\"text\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/layout/export_data_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:id=\"@+id/textView3\"\n        android:layout_width=\"317dp\"\n        android:layout_height=\"78dp\"\n        android:layout_marginTop=\"116dp\"\n        android:text=\"Select date range of data to export:\"\n        android:textSize=\"24sp\"\n        android:textStyle=\"bold\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"></TextView>\n\n    <TextView\n        android:id=\"@+id/export_date_range_text_view\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"164dp\"\n        android:layout_marginEnd=\"28dp\"\n        android:textSize=\"20sp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/pick_date_button\"\n        tools:text=\"Jan 10 - Jan 15\" />\n\n    <TextView\n        android:id=\"@+id/textView7\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"164dp\"\n        android:text=\"Export Date Range: \"\n        android:textSize=\"20sp\"\n        app:layout_constraintEnd_toStartOf=\"@+id/export_date_range_text_view\"\n        app:layout_constraintHorizontal_bias=\"0.157\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/pick_date_button\" />\n\n    <Button\n        android:id=\"@+id/export_data_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"48dp\"\n        android:text=\"Export Data Now\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.48\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/textView7\"\n        app:layout_constraintVertical_bias=\"0.019\" />\n\n    <Button\n        android:id=\"@+id/pick_date_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:text=\"Select Date\"\n        android:textSize=\"18sp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.481\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/textView3\" />\n\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/layout/glasses_connected_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <TextView\n        android:id=\"@+id/textView4\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"5dp\"\n        android:text=\"Glasses Connected!\"\n        android:textColor=\"#4d4d4d\"\n        android:textSize=\"28dp\"\n        android:textStyle=\"bold\"\n        android:justificationMode=\"inter_word\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.498\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n\n    <ImageView\n        android:id=\"@+id/connected_glasses_image\"\n        android:layout_width=\"230dp\"\n        android:layout_height=\"230dp\"\n        android:layout_marginTop=\"200dp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/textView4\">\n        ></ImageView>\n\n    <TextView\n        android:id=\"@+id/glasses_connected_message_tv\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"16dp\"\n        android:justificationMode=\"inter_word\"\n        android:text=\"Glasses are connected!\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/connected_glasses_image\" />\n\n\n    <Button\n        android:id=\"@+id/ok_glasses_connected_button\"\n        android:layout_width=\"99dp\"\n        android:layout_height=\"66dp\"\n        android:layout_marginBottom=\"48dp\"\n        android:text=\"Ok\"\n        app:backgroundTint=\"@color/green\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\" />\n\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/layout/image_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginLeft=\"5dp\"\n    android:layout_marginRight=\"5dp\"\n    android:orientation=\"vertical\"\n    >\n\n    <ImageView\n        android:id=\"@+id/imageView\"\n        android:adjustViewBounds=\"true\"\n        android:layout_centerInParent=\"true\"\n        android:layout_width=\"350dp\"\n        android:layout_height=\"wrap_content\"\n        tools:srcCompat=\"@tools:sample/avatars\" />\n\n    <TextView\n        android:id=\"@+id/textView\"\n        android:layout_width=\"350dp\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"TextView\"\n        android:textAlignment=\"center\"\n        android:textSize=\"22dp\"\n        android:textStyle=\"bold\" />\n</LinearLayout>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/layout/main_ui_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"48dp\"\n        android:paddingTop=\"7dp\"\n        android:text=\"Intelligence Tools\"\n        android:textSize=\"35sp\"\n        android:textStyle=\"bold\"\n        app:layout_constraintBottom_toTopOf=\"@+id/memory_tools\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.496\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintVertical_bias=\"1.0\" />\n\n    <Button\n        android:id=\"@+id/memory_tools\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"84dp\"\n        android:text=\"Memory Tools\"\n        app:layout_constraintBottom_toTopOf=\"@+id/textView2\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.498\"\n        app:layout_constraintStart_toStartOf=\"parent\" />\n\n    <TextView\n        android:id=\"@+id/textView2\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"28dp\"\n        android:paddingTop=\"7dp\"\n        android:text=\"Settings\"\n        android:textSize=\"35sp\"\n        android:textStyle=\"bold\"\n        app:layout_constraintBottom_toTopOf=\"@+id/kill_wearableai_service\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\" />\n\n    <Button\n        android:id=\"@+id/kill_wearableai_service\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"40dp\"\n        android:text=\"Kill WearableAI Service\"\n        app:layout_constraintBottom_toTopOf=\"@+id/send_test_card_old\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\" />\n\n    <Button\n        android:id=\"@+id/send_test_card_old\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"40dp\"\n        android:text=\"Start WearableAI Service\"\n        app:layout_constraintBottom_toTopOf=\"@+id/start_hotspot\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\" />\n\n    <Button\n        android:id=\"@+id/start_hotspot\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"84dp\"\n        android:text=\"Start Wifi Hotspot\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\" />\n\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/layout/menu_item_exposed_dropdown.xml",
    "content": "<TextView\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:padding=\"16dp\"\n    android:ellipsize=\"end\"\n    android:maxLines=\"1\"\n    android:textAppearance=\"?attr/textAppearanceSubtitle1\"\n/>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/layout/phrase_context_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n\n    <TextView\n        android:id=\"@+id/image_header\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"POV Images\"\n        android:textSize=\"22sp\"\n        android:textStyle=\"bold\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.055\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n\n    <HorizontalScrollView\n        android:id=\"@+id/gallery_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_gravity=\"center\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.0\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/image_header\">\n\n        <LinearLayout\n            android:id=\"@+id/image_gallery\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"horizontal\" />\n    </HorizontalScrollView>\n\n    <TextView\n        android:id=\"@+id/map_header\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"2dp\"\n        android:text=\"Location\"\n        android:textSize=\"22sp\"\n        android:textStyle=\"bold\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.049\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/gallery_holder\" />\n\n    <ImageView\n        android:id=\"@+id/map_image_view\"\n        android:layout_width=\"383dp\"\n        android:layout_height=\"294dp\"\n        android:layout_marginTop=\"2dp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.497\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/map_header\"\n        tools:srcCompat=\"@drawable/elon\" />\n\n    <TextView\n        android:id=\"@+id/people_header\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"2dp\"\n        android:text=\"People\"\n        android:textSize=\"22sp\"\n        android:textStyle=\"bold\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.052\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/map_image_view\" />\n\n    <TextView\n        android:id=\"@+id/people_list\"\n        android:layout_width=\"381dp\"\n        android:layout_height=\"72dp\"\n        android:layout_marginTop=\"2dp\"\n        android:text=\"- person 1\\n-person 2\\n-person 3\"\n        android:textSize=\"18sp\"\n        android:textStyle=\"\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/people_header\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/layout/phrase_recyclerview_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_margin=\"0dp\"\n    android:background=\"@android:drawable/dialog_holo_light_frame\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n<TextView\n        android:id=\"@+id/textView\"\n        style=\"@style/phrase_title\"\n        android:textColor=\"@color/recyclertextcolor\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n</LinearLayout>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/layout/reference_card_recyclerview_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:background=\"@android:drawable/dialog_holo_light_frame\"\n    android:layout_height=\"wrap_content\">\n\n    <ImageView\n        android:id=\"@+id/image_image_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_margin=\"4dp\"\n        android:layout_height=\"140dp\"\n        tools:srcCompat=\"@drawable/elon\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_margin=\"4dp\"\n        style=\"@style/text_box\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n        <LinearLayout\n            android:orientation=\"vertical\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n            <TextView\n                android:id=\"@+id/title_text_view\"\n                style=\"@style/reference_title\"\n                android:layout_height=\"wrap_content\"\n                android:textAlignment=\"viewStart\"\n                android:textStyle=\"bold\"\n                tools:text=\"Title Here\" />\n\n            <TextView\n                android:id=\"@+id/start_date_text_view\"\n                style=\"@style/reference_date\"\n                android:layout_height=\"wrap_content\"\n                android:layout_width=\"match_parent\"\n                android:textStyle=\"bold\"\n                tools:text=\"Start: Jan 20, 1999\" />\n            <TextView\n                android:id=\"@+id/stop_date_text_view\"\n                style=\"@style/reference_date\"\n                android:layout_height=\"wrap_content\"\n                android:layout_width=\"match_parent\"\n                android:textStyle=\"bold\"\n                tools:text=\"End: Jan 20, 1999\" />\n        </LinearLayout>\n        <TextView\n            android:id=\"@+id/summary_text_view\"\n            style=\"@style/reference_summary\"\n            android:layout_height=\"wrap_content\"\n            android:layout_width=\"match_parent\"\n            android:textAlignment=\"viewStart\"\n            android:textStyle=\"bold\"\n            tools:text=\"I think that this is the way to go, it seems to fit what we may need\" />\n    </LinearLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/layout/response_text_box.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\"\n    android:paddingRight=\"6dp\"\n    android:paddingLeft=\"6dp\"\n    android:paddingTop=\"12dp\">\n\n    <TextView\n        android:id=\"@+id/textView\"\n        android:layout_width=\"match_parent\"\n        android:padding=\"12dp\"\n        android:layout_height=\"wrap_content\"\n        android:textSize=\"30sp\"\n        android:hint=\"Text here my man.\"\n        android:background=\"@drawable/rounded_corner\"\n        android:textColor=\"#000000\"/>\n</LinearLayout>"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/layout/select_glasses_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\nxmlns:tools=\"http://schemas.android.com/tools\"\nandroid:layout_width=\"match_parent\"\nandroid:layout_height=\"match_parent\"\nxmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <TextView\n        android:id=\"@+id/textView6\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop =\"5dp\"\n        android:text=\"Select your smart glasses:\"\n        android:textColor=\"#4d4d4d\"\n        android:textSize=\"28dp\"\n        android:textStyle=\"bold\"\n        android:justificationMode=\"inter_word\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"></TextView>\n\n    <ListView\n        android:id=\"@+id/smart_glasses_list\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_marginRight=\"5dp\"\n        android:layout_marginLeft=\"5dp\"\n        android:layout_marginTop=\"75dp\"\n        android:layout_marginBottom=\"130dp\"\n        android:choiceMode=\"singleChoice\"\n        android:listSelector=\"@android:color/darker_gray\"\n        ></ListView>\n\n    <Button\n        android:id=\"@+id/select_smart_glasses_button\"\n        android:layout_width=\"99dp\"\n        android:layout_height=\"66dp\"\n        android:layout_marginRight =\"72dp\"\n        android:layout_marginBottom=\"48dp\"\n        android:text=\"Select\"\n        app:backgroundTint=\"@color/green\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/smart_glasses_list\" />\n\n    <Button\n        android:id=\"@+id/cancel_select_smart_glasses_button\"\n        android:layout_width=\"99dp\"\n        android:layout_height=\"66dp\"\n        android:layout_marginBottom=\"48dp\"\n        android:layout_marginLeft=\"72dp\"\n        android:text=\"Cancel\"\n        app:backgroundTint=\"@color/red\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/smart_glasses_list\" />\n\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/layout/settings_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <TextView\n        android:id=\"@+id/textView5\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"88dp\"\n        android:text=\"Wearable\"\n        android:textSize=\"32dp\"\n        android:textStyle=\"bold\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.498\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n\n    <Button\n        android:id=\"@+id/connect_smart_glasses\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"11dp\"\n        android:text=\"Start Wearable\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/textView5\" />\n\n    <Button\n        android:id=\"@+id/kill_wearableai_service\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"11dp\"\n        android:text=\"Stop Wearable\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/connect_smart_glasses\" />\n\n\n    <TextView\n        android:id=\"@+id/textView6\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"68dp\"\n        android:text=\"Settings\"\n        android:textSize=\"32dp\"\n        android:textStyle=\"bold\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/kill_wearableai_service\" />\n\n    <Switch\n        android:id=\"@+id/google_asr_switch\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"36dp\"\n        android:text=\"Google ASR\"\n        android:textSize=\"20dp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/textView6\" />\n\n    <Button\n        android:id=\"@+id/google_api_change\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"11dp\"\n        android:text=\"Set Google API Key\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/google_asr_switch\" />\n\n\n    <Spinner\n        android:id=\"@+id/targetLanguageSpinner\"\n        android:layout_width=\"250dp\"\n        android:layout_height=\"29dp\"\n        android:layout_marginTop=\"40dp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/google_api_change\" />\n\n\n    <!--    <Button-->\n<!--        android:id=\"@+id/start_live_captions\"-->\n<!--        android:layout_width=\"wrap_content\"-->\n<!--        android:layout_height=\"wrap_content\"-->\n<!--        android:layout_marginTop=\"25dp\"-->\n<!--        android:text=\"Start Live Captions\"-->\n<!--        app:layout_constraintEnd_toEndOf=\"parent\"-->\n<!--        app:layout_constraintStart_toStartOf=\"parent\"-->\n<!--        app:layout_constraintTop_toBottomOf=\"@+id/send_test_card_old\" />-->\n\n\n<!--    <Button-->\n<!--        android:id=\"@+id/trigger_tpa_command\"-->\n<!--        android:layout_width=\"wrap_content\"-->\n<!--        android:layout_height=\"wrap_content\"-->\n<!--        android:layout_marginTop=\"25dp\"-->\n<!--        android:text=\"Trigger Hello World Command\"-->\n<!--        app:layout_constraintEnd_toEndOf=\"parent\"-->\n<!--        app:layout_constraintStart_toStartOf=\"parent\"-->\n<!--        app:layout_constraintTop_toBottomOf=\"@+id/start_live_captions\" />-->\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/layout/smart_glasses_debug_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n\n    <Button\n        android:id=\"@+id/send_test_card_old\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"388dp\"\n        android:text=\"Send Test Card to Glasses\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/layout/smart_glasses_list_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <ImageView\n        android:id=\"@+id/glasses_icon\"\n        android:layout_width=\"85dp\"\n        android:layout_height=\"65dp\"\n        android:padding=\"5dp\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n\n    <TextView\n        android:id=\"@+id/glasses_name\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:padding=\"2dp\"\n        android:text=\"Coolest Smart Glasses\"\n        android:layout_marginLeft=\"4dp\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\"\n        android:textColor=\"#4d4d4d\"\n        android:textStyle=\"bold\"\n        app:layout_constraintStart_toEndOf=\"@+id/glasses_icon\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n\n    <TextView\n        android:id=\"@+id/glasses_support\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginLeft=\"4dp\"\n        android:text=\"Fully Supported\"\n        app:layout_constraintStart_toEndOf=\"@+id/glasses_icon\"\n        app:layout_constraintTop_toBottomOf=\"@+id/glasses_name\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/menu/bottom_nav_main_menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  Copyright 2017 The Android Open Source Project\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n      http://www.apache.org/licenses/LICENSE-2.0\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <item\n        android:id=\"@+id/memory_page\"\n        android:enabled=\"true\"\n        android:icon=\"@drawable/outline_memory_white_24\"\n        android:title=\"Memory Tools\"/>\n    <item\n        android:id=\"@+id/smart_glasses_debug_page\"\n        android:enabled=\"true\"\n        android:icon=\"@drawable/outline_device_hub_white_24\"\n        android:title=\"Smart Glasses\"/>\n    <item\n        android:id=\"@+id/settings_page\"\n        android:enabled=\"true\"\n        android:icon=\"@drawable/outline_settings_white_24\"\n        android:title=\"Settings\"/>\n\n</menu>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/menu/memory_cache_menu.xml",
    "content": "<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item\n        android:id=\"@+id/name_cache\"\n        android:title=\"Name Cache\"\n        android:showAsAction=\"always\"/>\n</menu>"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\"/>\n    <foreground android:drawable=\"@mipmap/ic_launcher_foreground\"/>\n</adaptive-icon>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\"/>\n    <foreground android:drawable=\"@mipmap/ic_launcher_foreground\"/>\n</adaptive-icon>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/mipmap-anydpi-v26/sgm_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/sgm_launcher_background\"/>\n    <foreground android:drawable=\"@mipmap/sgm_launcher_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/mipmap-anydpi-v26/sgm_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/sgm_launcher_background\"/>\n    <foreground android:drawable=\"@mipmap/sgm_launcher_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/mipmap-anydpi-v26/wis_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/wis_launcher_background\"/>\n    <foreground android:drawable=\"@mipmap/wis_launcher_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/mipmap-anydpi-v26/wis_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/wis_launcher_background\"/>\n    <foreground android:drawable=\"@mipmap/wis_launcher_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/mipmap-anydpi-v26/wis_launcher_transparent.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/wis_launcher_transparent_background\"/>\n    <foreground android:drawable=\"@mipmap/wis_launcher_transparent_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/mipmap-anydpi-v26/wis_launcher_transparent_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/wis_launcher_transparent_background\"/>\n    <foreground android:drawable=\"@mipmap/wis_launcher_transparent_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/navigation/nav_graph.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<navigation xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n<!--    <fragment-->\n<!--        android:id=\"@+id/nav_main_ui\"-->\n<!--        android:name=\"com.teamopensmartglasses.smartglassesmanager.ui.MainUi\"-->\n<!--        tools:layout=\"@layout/main_ui_fragment\"-->\n<!--        android:label=\"Home Main Page\" >-->\n<!--    </fragment>-->\n<!--    <fragment-->\n<!--        android:id=\"@+id/nav_smart_glasses_debug\"-->\n<!--        android:name=\"com.teamopensmartglasses.smartglassesmanager.ui.SmartGlassesDebugUi\"-->\n<!--        tools:layout=\"@layout/smart_glasses_debug_fragment\"-->\n<!--        android:label=\"Smart Glasses + Debug\" >-->\n<!--    </fragment>-->\n<!--    <fragment-->\n<!--        android:id=\"@+id/nav_settings\"-->\n<!--        android:name=\"com.teamopensmartglasses.smartglassesmanager.ui.SettingsUi\"-->\n<!--        tools:layout=\"@layout/settings_fragment\"-->\n<!--        android:label=\"Smart Glasses Manager\" >-->\n<!--    </fragment>-->\n<!--    <fragment-->\n<!--        android:id=\"@+id/nav_select_smart_glasses\"-->\n<!--        android:name=\"com.teamopensmartglasses.smartglassesmanager.ui.SelectSmartGlassesUi\"-->\n<!--        tools:layout=\"@layout/select_glasses_fragment\"-->\n<!--        android:label=\"Select Smart Glasses\" >-->\n<!--    </fragment>-->\n<!--    <fragment-->\n<!--        android:id=\"@+id/nav_connecting_to_smart_glasses\"-->\n<!--        android:name=\"com.teamopensmartglasses.smartglassesmanager.ui.ConnectingToSmartGlassesUi\"-->\n<!--        tools:layout=\"@layout/connecting_to_glasses_fragment\"-->\n<!--        android:label=\"Connecting to Smart Glasses\" >-->\n<!--    </fragment>-->\n<!--    <fragment-->\n<!--        android:id=\"@+id/nav_connected_to_smart_glasses\"-->\n<!--        android:name=\"com.teamopensmartglasses.smartglassesmanager.ui.GlassesConnectedFragment\"-->\n<!--        tools:layout=\"@layout/glasses_connected_fragment\"-->\n<!--        android:label=\"Connected to Smart Glasses\" >-->\n<!--    </fragment>-->\n<!--    <fragment-->\n<!--        android:id=\"@+id/nav_all_transcripts\"-->\n<!--        android:name=\"com.teamopensmartglasses.smartglassesmanager.ui.AllTranscriptsUi\"-->\n<!--        tools:layout=\"@layout/all_transcripts_fragment\"-->\n<!--        android:label=\"All Transcripts\" >-->\n<!--        <action-->\n<!--            android:id=\"@+id/action_nav_memory_tools_to_nav_all_transcripts\"-->\n<!--            app:destination=\"@id/nav_all_transcripts\" />-->\n<!--    </fragment>-->\n<!--    <fragment-->\n<!--        android:id=\"@+id/nav_export_data\"-->\n<!--        android:name=\"com.teamopensmartglasses.smartglassesmanager.ui.ExportDataUi\"-->\n<!--        tools:layout=\"@layout/export_data_fragment\"-->\n<!--        android:label=\"Export Data\" >-->\n<!--    </fragment>-->\n<!--    <fragment-->\n<!--        android:id=\"@+id/nav_phrase_context\"-->\n<!--        android:name=\"com.teamopensmartglasses.smartglassesmanager.ui.PhraseContextUi\"-->\n<!--        tools:layout=\"@layout/phrase_context_fragment\"-->\n<!--        android:label=\"Phrase Context\" >-->\n<!--        <action-->\n<!--            android:id=\"@+id/action_nav_all_transcripts_to_nav_phrase_context\"-->\n<!--            app:destination=\"@id/nav_phrase_context\" />-->\n<!--        <action-->\n<!--            android:id=\"@+id/action_nav_mxt_cache_to_nav_phrase_context\"-->\n<!--            app:destination=\"@id/nav_phrase_context\" />-->\n<!--    </fragment>-->\n</navigation>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#960000</color>\n    <color name=\"colorPrimaryDark\">#560000</color>\n    <color name=\"colorAccent\">#970000</color>\n\n    <color name=\"buttonLabel\">#eeff41</color>\n\n    <color name=\"colorPhraseBackground\">#dfd8d8</color>\n    <color name=\"colorMainBackground\">#dfd8d8</color>\n    <color name=\"recyclertextcolor\">#222222</color>\n\n    <color name=\"red\">#DFBA0000</color>\n    <color name=\"green\">#FF009E00</color>\n    <color name=\"blue\">#FF0000AF</color>\n</resources>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/values/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  Copyright 2017 The Android Open Source Project\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n      http://www.apache.org/licenses/LICENSE-2.0\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n\n<resources>\n    <dimen name=\"cat_card_demo_min_height\">200dp</dimen>\n    <dimen name=\"content_padding_top\">16dp</dimen>\n    <!-- Rich Media Demo Dimensions -->\n    <dimen name=\"cat_card_rich_media_demo_min_height\">148dp</dimen>\n    <dimen name=\"cat_card_single_spacing\">8dp</dimen>\n    <dimen name=\"cat_card_double_spacing\">16dp</dimen>\n    <dimen name=\"cat_card_triple_spacing\">24dp</dimen>\n    <dimen name=\"cat_card_content_padding\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">Smart Glasses Manager</string>\n    <string name=\"key\">TEMPORARYKEY_CHANGETHISKEY</string>\n    <string name=\"no_camera_access\" translatable=\"false\">Please grant camera permissions.</string>\n    <string name=\"medium_text\">text</string>\n    <string name=\"memory_hint\">Enter memory to save here</string>\n    <string name=\"tag_label\">Choose Tag</string>\n\n    <string-array name=\"exposed_dropdown_content\">\n        <item>Wearable</item>\n        <item>Engineering</item>\n        <item>Ideas</item>\n        <item>Personal</item>\n    </string-array>\n\n\n    <!-- Entering API key message. -->\n    <string name=\"api_key_message\">Enter G-Cloud API key</string>\n    <!-- API key document link. -->\n    <string name=\"api_key_doc_link\">See &lt;a href=\"https://cloud.google.com/docs/authentication/api-keys\">here&lt;/a> for more details.</string>\n    <!-- Selecting language message. -->\n    <string name=\"select_language_message\">Select language. See  &lt;a href=\"https://cloud.google.com/speech-to-text/docs/languages\">here&lt;/a> for more details.</string>\n    <string name=\"say_something\">Say something!</string>\n    <!-- Internal code use. -->\n    <string name=\"SHARED_PREF_KEY\">api_key</string>\n    <string name=\"PREFERRED_WEARABLE\">preferred_wearable</string>\n    <string name=\"DEFAULT_COMMAND_SHARED_PREF_KEY\">default_command_key</string>\n    <string name=\"DEFAULT_COMMAND_SET_SHARED_PREF_KEY\">default_command_set_key</string>\n\n    <string name=\"SHARED_PREF_ASR_KEY\">shared_pref_api_key</string>\n    <string name=\"SHARED_PREF_TRANSCRIBE_LANGUAGE\">shared_pref_transcribe_language</string>\n    <string name=\"SHARED_PREF_TARGET_LANGUAGE\">shared_pref_target_language</string>\n    <string name=\"SHARED_PREF_SOURCE_LANGUAGE\">shared_pref_source_language</string>\n    <string name=\"SHARED_PREF_LIVE_CAPTIONS_TRANSLATION\">shared_pref_live_captions</string>\n</resources>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.MaterialComponents.Light.NoActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n  <style name=\"phrase_title\">\n        <item name=\"android:layout_width\">match_parent</item>\n<!--        <item name=\"android:layout_marginBottom\">8dp</item>-->\n<!--        <item name=\"android:paddingLeft\">8dp</item>-->\n        <item name=\"android:layout_marginRight\">4dp</item>\n          <item name=\"android:layout_marginLeft\">4dp</item>\n      <!--        <item name=\"android:background\">@color/colorPhraseBackground</item>-->\n        <item name=\"android:textAppearance\">@android:style/TextAppearance.Large</item>\n    </style>\n\n\n    <style name=\"text_box\">\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_margin\">8dp</item>\n    </style>\n\n    <style name=\"reference_title\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_marginBottom\">2dp</item>\n        <item name=\"android:textAppearance\">@android:style/TextAppearance.Large</item>\n    </style>\n\n    <style name=\"reference_date\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_marginBottom\">2dp</item>\n        <item name=\"android:textAppearance\">@android:style/TextAppearance.Medium</item>\n    </style>\n\n    <style name=\"reference_summary\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_marginBottom\">2dp</item>\n        <item name=\"android:textAppearance\">@android:style/TextAppearance.Small</item>\n    </style>\n\n\n    <!-- bottom bar for facial recognition naming autocomplete -->\n    <style name=\"AppBottomSheetDialogTheme\" parent=\"Theme.Design.Light.BottomSheetDialog\">\n        <item name=\"bottomSheetStyle\">@style/AppModalStyle</item>\n        <item name=\"android:windowIsFloating\">false</item>\n        <item name=\"android:windowSoftInputMode\">adjustResize</item>\n    </style>\n\n    <style name=\"AppModalStyle\" parent=\"Widget.Design.BottomSheet.Modal\">\n        <item name=\"behavior_peekHeight\">400dp</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/main/res/xml/file_provider.xml",
    "content": "<paths xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <external-path name=\"external_files\" path=\".\"/>\n</paths>"
  },
  {
    "path": "SGM_android/SmartGlassesManager/src/test/java/com/teamopensmartglasses/smartglassesmanager/ExampleUnitTest.java",
    "content": "package com.teamopensmartglasses.smartglassesmanager;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.4.1)\ninclude(ExternalProject)\n\nset(opus_tools_src ${CMAKE_CURRENT_SOURCE_DIR}/opus_tools/src)\nExternalProject_Add(external_opus_tools\n        GIT_REPOSITORY    \"https://github.com/xiph/opus-tools/\"\n        GIT_TAG           \"14f650f64260115098d55fb91e1f83110cb628d3\"\n        SOURCE_DIR        \"${opus_tools_src}\"\n        CONFIGURE_COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/build/include_files_helper.sh ${CMAKE_CURRENT_SOURCE_DIR}/build/\n        COMMAND  ${CMAKE_COMMAND} -E copy\n                ${CMAKE_CURRENT_BINARY_DIR}/build/libogg/${ANDROID_ABI}/include/ogg/config_types.h\n                ${CMAKE_CURRENT_SOURCE_DIR}/../src/main/cpp/libogg/\n        COMMAND ${CMAKE_COMMAND} ${opus_tools_src}\n        -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}\n        -DANDROID_ABI=${ANDROID_ABI}\n        -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/build/opus_tools/${ANDROID_ABI}\n        BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/build/opus_tools/${ANDROID_ABI}/lib/\n        INSTALL_COMMAND  \"\"\n        COMMAND\n        ${CMAKE_COMMAND} -E copy\n        ${CMAKE_CURRENT_BINARY_DIR}/build/opus_tools/${ANDROID_ABI}/lib/libopus_header.a\n        ${CMAKE_CURRENT_SOURCE_DIR}/opus_tools/lib/${ANDROID_ABI}/\n        )\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/CMakeLists_libogg.txt",
    "content": "cmake_minimum_required(VERSION 3.4.1)\ninclude(ExternalProject)\n\nset(libogg_src ${CMAKE_CURRENT_SOURCE_DIR}/libogg/src)\nExternalProject_Add(external_libogg\n        GIT_REPOSITORY    \"https://github.com/xiph/ogg.git\"\n        GIT_TAG           \"934385378f45f11586b03b6214bf5f363649f3b6\"\n        SOURCE_DIR        \"${libogg_src}\"\n        CONFIGURE_COMMAND ${CMAKE_COMMAND} ${libogg_src}\n        -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}\n        -DANDROID_ABI=${ANDROID_ABI}\n        -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/build/libogg/${ANDROID_ABI}\n        INSTALL_COMMAND ${CMAKE_MAKE_PROGRAM} install\n        &&\n        ${CMAKE_COMMAND} -E copy\n        ${CMAKE_CURRENT_BINARY_DIR}/build/libogg/${ANDROID_ABI}/lib/libogg.a\n        ${CMAKE_CURRENT_SOURCE_DIR}/libogg/lib/${ANDROID_ABI}/\n        )\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/CMakeLists_libopus.txt",
    "content": "cmake_minimum_required(VERSION 3.4.1)\ninclude(ExternalProject)\n\nset(libopus_src ${CMAKE_CURRENT_SOURCE_DIR}/libopus/src)\nExternalProject_Add(external_libopus\n        GIT_REPOSITORY    \"https://github.com/xiph/opus\"\n        GIT_TAG           \"ad8fe90db79b7d2a135e3dfd2ed6631b0c5662ab\"\n        SOURCE_DIR        \"${libopus_src}\"\n        CONFIGURE_COMMAND ${CMAKE_COMMAND} ${libopus_src}\n        -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}\n        -DANDROID_ABI=${ANDROID_ABI}\n        -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/build/libopus/${ANDROID_ABI}\n        INSTALL_COMMAND ${CMAKE_MAKE_PROGRAM} install\n        &&\n        ${CMAKE_COMMAND} -E copy\n        ${CMAKE_CURRENT_BINARY_DIR}/build/libopus/${ANDROID_ABI}/lib/libopus.a\n        ${CMAKE_CURRENT_SOURCE_DIR}/libopus/lib/${ANDROID_ABI}/\n        )\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/CMakeLists_opus-tools.txt",
    "content": "cmake_minimum_required(VERSION 3.4.1)\ninclude(ExternalProject)\n\nset(opus_tools_src ${CMAKE_CURRENT_SOURCE_DIR}/opus_tools/src)\nExternalProject_Add(external_opus_tools\n        GIT_REPOSITORY    \"https://github.com/xiph/opus-tools/\"\n        GIT_TAG           \"14f650f64260115098d55fb91e1f83110cb628d3\"\n        SOURCE_DIR        \"${opus_tools_src}\"\n        CONFIGURE_COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/build/include_files_helper.sh ${CMAKE_CURRENT_SOURCE_DIR}/build/\n        COMMAND  ${CMAKE_COMMAND} -E copy\n                ${CMAKE_CURRENT_BINARY_DIR}/build/libogg/${ANDROID_ABI}/include/ogg/config_types.h\n                ${CMAKE_CURRENT_SOURCE_DIR}/../src/main/cpp/libogg/\n        COMMAND ${CMAKE_COMMAND} ${opus_tools_src}\n        -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}\n        -DANDROID_ABI=${ANDROID_ABI}\n        -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/build/opus_tools/${ANDROID_ABI}\n        BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/build/opus_tools/${ANDROID_ABI}/lib/\n        INSTALL_COMMAND  \"\"\n        COMMAND\n        ${CMAKE_COMMAND} -E copy\n        ${CMAKE_CURRENT_BINARY_DIR}/build/opus_tools/${ANDROID_ABI}/lib/libopus_header.a\n        ${CMAKE_CURRENT_SOURCE_DIR}/opus_tools/lib/${ANDROID_ABI}/\n        )\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/.gitignore",
    "content": "INSTALL\nlibtool\nMakefile.in\naclocal.m4\nautom4te.cache\nconfig.guess\nconfig.h.in\nconfig.sub\nconfigure\ndepcomp\ninstall-sh\nltmain.sh\nmissing\ncompile\nMakefile\nconfig.h\nconfig.log\nconfig.status\nsrc/info_opus.o\nsrc/opusinfo.o\nsrc/audio-in.o\nsrc/diag_range.o\nsrc/opus_header.o\nsrc/opusdec.o\nsrc/opusenc.o\nsrc/resample.o\nsrc/wav_io.o\nsrc/wave_out.o\nsrc/.deps/\nsrc/.dirstamp\nstamp-h1\nopusenc\nopusdec\nopusinfo\nopusenc.exe\nopusdec.exe\nopusinfo.exe\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/AUTHORS",
    "content": "Gregory Maxwell (greg@xiph.org)\nJean-Marc Valin - Original opusdec implementation / Resampler\nThorvald Natvig - Resampler\nMichael Smith   - Ogginfo (basis of opusinfo)\nJohn Edwards    - Windows audio output\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/CMakeLists.txt",
    "content": "# For opus_tools only.\ncmake_minimum_required(VERSION 3.4.1)\nset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=gnu++11\")\nadd_library(opus_header STATIC src/opus_header.c)"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/COPYING",
    "content": "\nOpus-tools, with the exception of opusinfo.[ch] is available under\nthe following two clause BSD-style license:\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n\n- Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n\n- Redistributions in binary form must reproduce the above copyright\nnotice, this list of conditions and the following disclaimer in the\ndocumentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER\nOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\nEXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\nPROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\nPROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\nLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\nNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n\nOpusinfo is a fork of ogginfo from the vorbis-tools package\n(http://www.xiph.org). It is available under the GPL:\n\n\t\t    GNU GENERAL PUBLIC LICENSE\n\t\t       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\t\t\t    Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Library General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\f\n\t\t    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\f\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\f\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\f\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n\t\t\t    NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n\t\t     END OF TERMS AND CONDITIONS\n\f\n\t    How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program; if not, write to the Free Software\n    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year  name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Library General\nPublic License instead of this License.\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/ChangeLog",
    "content": "2012-05-16  Gregory Maxwell  <greg@xiph.org>\n\n        * Initial public version, 0.1.0\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/Makefile.am",
    "content": "\n#AUTOMAKE_OPTIONS = subdir-objects 1.6 dist-zip\nAUTOMAKE_OPTIONS = subdir-objects 1.11 dist-zip dist-xz\n\nSUBDIRS = .\n\nINCLUDES = -I$(top_srcdir)/src\n\nAM_CFLAGS = $(OGG_CFLAGS) $(Opus_CFLAGS) -DOPUSTOOLS -D_FORTIFY_SOURCE=2 -DHAVE_GETOPT_H -DSPX_RESAMPLE_EXPORT= -DRANDOM_PREFIX=opustools -DOUTSIDE_SPEEX -DFLOATING_POINT\n\nbin_PROGRAMS = opusenc opusdec opusinfo\n\nnoinst_HEADERS = src/arch.h \\\n                 src/diag_range.h \\\n                 src/info_opus.h \\\n                 src/lpc.h \\\n                 src/opusenc.h \\\n                 src/opus_header.h \\\n                 src/opusinfo.h \\\n                 src/os_support.h \\\n                 src/speex_resampler.h \\\n                 src/stack_alloc.h \\\n                 src/wave_out.h \\\n                 src/wav_io.h\n\nEXTRA_DIST = Makefile.unix\n\ndist_man_MANS = man/opusenc.1 man/opusdec.1 man/opusinfo.1\n\nopusenc_SOURCES = src/opus_header.c src/opusenc.c src/resample.c src/audio-in.c src/diag_range.c src/lpc.c\nopusenc_LDADD = $(OGG_LIBS) $(Opus_LIBS) -lm\nopusenc_MANS = man/opusenc.1\n\nopusdec_SOURCES = src/opus_header.c src/wav_io.c src/wave_out.c src/opusdec.c src/resample.c src/diag_range.c\nopusdec_LDADD = $(OGG_LIBS) $(Opus_LIBS) $(OSS_LIBS) -lm\nopusdec_MANS = man/opusdec.1\n\nopusinfo_SOURCES = src/opus_header.c src/opusinfo.c src/info_opus.c\nopusinfo_LDADD = $(OGG_LIBS)\nopusinfo_MANS = man/opusinfo.1\n\n#TESTS = FIXME\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/Makefile.unix",
    "content": "#Opus-tools should be built with autotools, not this makefile.\n#Run ./configure to run autotools/autoconf.\n#This makefile exists as a fallback where autotools isn't working.\n#CC=gcc\nCFLAGS:=-DPACKAGE='\"opus-tools\"' -DVERSION='\"0.1.2git\"' -DOPUSTOOLS -O2 -g -c -Wall -Wextra -DHAVE_GETOPT_H -DSPX_RESAMPLE_EXPORT= -DRANDOM_PREFIX=opustools -DOUTSIDE_SPEEX -DFLOATING_POINT $(CFLAGS)\nINCLUDES=-I../opus/include\n\nall: opusenc opusdec opusinfo\n\n.c.o:\n\t$(CC) $(CFLAGS) $(INCLUDES) $< -o $@\n\nopusenc: src/opus_header.o src/opusenc.o src/resample.o src/audio-in.o src/diag_range.o src/lpc.o\n\t$(CC) $(LDFLAGS) src/opus_header.o src/audio-in.o src/diag_range.o src/opusenc.o src/resample.o src/lpc.o -o opusenc ../opus/.libs/libopus.a -lm -logg\n\nopusdec: src/opus_header.o src/wav_io.o src/wave_out.o src/opusdec.o src/resample.o src/diag_range.o\n\t$(CC) $(LDFLAGS) src/wave_out.o src/opus_header.o src/wav_io.o src/diag_range.o src/opusdec.o src/resample.o -o opusdec ../opus/.libs/libopus.a -lm -logg\n\nopusinfo: src/opus_header.o src/opusinfo.o src/info_opus.o\n\t$(CC) $(LDFLAGS) src/opus_header.o src/opusinfo.o src/info_opus.o -o opusinfo -logg\n\nclean:\n\trm -f src/*.o opusenc opusdec opusinfo\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/NEWS",
    "content": ""
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/README",
    "content": ""
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/autogen.sh",
    "content": "#!/bin/sh\n# Run this to set up the build system: configure, makefiles, etc.\n# (based on the version in enlightenment's cvs)\n\npackage=\"opus-tools\"\n\nolddir=`pwd`\nsrcdir=`dirname $0`\ntest -z \"$srcdir\" && srcdir=.\n\ncd \"$srcdir\"\nDIE=0\n\necho \"checking for autoconf... \"\n(autoconf --version) < /dev/null > /dev/null 2>&1 || {\n        echo\n        echo \"You must have autoconf installed to compile $package.\"\n        echo \"Download the appropriate package for your distribution,\"\n        echo \"or get the source tarball at ftp://ftp.gnu.org/pub/gnu/\"\n        DIE=1\n}\n\nVERSIONGREP=\"sed -e s/.*[^0-9\\.]\\([0-9]\\.[0-9]*\\).*/\\1/\"\nVERSIONMKINT=\"sed -e s/[^0-9]//\"\n\n# do we need automake?\nif test -r Makefile.am; then\n  AM_OPTIONS=`fgrep AUTOMAKE_OPTIONS Makefile.am`\n  AM_NEEDED=`echo $AM_OPTIONS | $VERSIONGREP`\n  if test \"$AM_NEEDED\" = \"$AM_OPTIONS\"; then\n    AM_NEEDED=\"\"\n  fi\n  if test -z $AM_NEEDED; then\n    echo -n \"checking for automake... \"\n    AUTOMAKE=automake\n    ACLOCAL=aclocal\n    if ($AUTOMAKE --version < /dev/null > /dev/null 2>&1); then\n      echo \"yes\"\n    else\n      echo \"no\"\n      AUTOMAKE=\n    fi\n  else\n    echo -n \"checking for automake $AM_NEEDED or later... \"\n    for am in automake-$AM_NEEDED automake$AM_NEEDED automake; do\n      ($am --version < /dev/null > /dev/null 2>&1) || continue\n      ver=`$am --version < /dev/null | head -n 1 | $VERSIONGREP | $VERSIONMKINT`\n      verneeded=`echo $AM_NEEDED | $VERSIONMKINT`\n      if test $ver -ge $verneeded; then\n        AUTOMAKE=$am\n        echo $AUTOMAKE\n        break\n      fi\n    done\n    test -z $AUTOMAKE &&  echo \"no\"\n    echo -n \"checking for aclocal $AM_NEEDED or later... \"\n    for ac in aclocal-$AM_NEEDED aclocal$AM_NEEDED aclocal; do\n      ($ac --version < /dev/null > /dev/null 2>&1) || continue\n      ver=`$ac --version < /dev/null | head -n 1 | $VERSIONGREP | $VERSIONMKINT`\n      verneeded=`echo $AM_NEEDED | $VERSIONMKINT`\n      if test $ver -ge $verneeded; then\n        ACLOCAL=$ac\n        echo $ACLOCAL\n        break\n      fi\n    done\n    test -z $ACLOCAL && echo \"no\"\n  fi\n  test -z $AUTOMAKE || test -z $ACLOCAL && {\n        echo\n        echo \"You must have automake installed to compile $package.\"\n        echo \"Download the appropriate package for your distribution,\"\n        echo \"or get the source tarball at ftp://ftp.gnu.org/pub/gnu/\"\n        exit 1\n  }\nfi\n\necho -n \"checking for libtool... \"\nfor LIBTOOLIZE in libtoolize glibtoolize nope; do\n  ($LIBTOOLIZE --version) < /dev/null > /dev/null 2>&1 && break\ndone\nif test x$LIBTOOLIZE = xnope; then\n  echo \"nope.\"\n  LIBTOOLIZE=libtoolize\nelse\n  echo $LIBTOOLIZE\nfi\n($LIBTOOLIZE --version) < /dev/null > /dev/null 2>&1 || {\n\techo\n\techo \"You must have libtool installed to compile $package.\"\n\techo \"Download the appropriate package for your system,\"\n\techo \"or get the source from one of the GNU ftp sites\"\n\techo \"listed in http://www.gnu.org/order/ftp.html\"\n\tDIE=1\n}\n\nif test \"$DIE\" -eq 1; then\n        exit 1\nfi\n\necho \"Generating configuration files for $package, please wait....\"\n\necho \"  $ACLOCAL $ACLOCAL_FLAGS\"\n$ACLOCAL $ACLOCAL_FLAGS || exit 1\necho \"  autoheader\"\nautoheader || exit 1\necho \"  $LIBTOOLIZE --automake\"\n$LIBTOOLIZE --automake || exit 1\necho \"  $AUTOMAKE --add-missing $AUTOMAKE_FLAGS\"\n$AUTOMAKE --add-missing $AUTOMAKE_FLAGS || exit 1\necho \"  autoconf\"\nautoconf || exit 1\n\ncd $olddir\n#$srcdir/configure \"$@\" && echo\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/configure.ac",
    "content": "dnl Process this file with autoconf to produce a configure script. -*-m4-*-\n\nAC_INIT(src/opusenc.c)\n\nAM_CONFIG_HEADER([config.h])\n\ndnl enable silent rules on automake 1.11 and later\nm4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])\n\nOPUSTOOLS_MAJOR_VERSION=0\nOPUSTOOLS_MINOR_VERSION=1\nOPUSTOOLS_MICRO_VERSION=2\nOPUSTOOLS_EXTRA_VERSION=git\n\nOPUSTOOLS_VERSION=\"$OPUSTOOLS_MAJOR_VERSION.$OPUSTOOLS_MINOR_VERSION.$OPUSTOOLS_MICRO_VERSION$OPUSTOOLS_EXTRA_VERSION\"\nAC_MSG_CHECKING([git revision])\nGIT_VERSION=$(git describe --tags --match 'v*' 2>/dev/null | sed 's/^v//')\nif test -z \"$GIT_VERSION\"; then\n  AC_MSG_RESULT([no])\nelse\n  AC_MSG_RESULT([$GIT_VERSION])\n  OPUSTOOLS_VERSION=\"$GIT_VERSION\"\nfi\n\n# For automake.\nVERSION=$OPUSTOOLS_VERSION\nPACKAGE=opus-tools\n\nAM_INIT_AUTOMAKE($PACKAGE, $VERSION)\nAM_MAINTAINER_MODE\n\nAC_CANONICAL_HOST\nAM_PROG_CC_C_O\n\nAC_PROG_CC_C99\nAC_C_BIGENDIAN\nAC_C_CONST\nAC_C_INLINE\n\n#Use a hacked up version of autoconf's AC_C_RESTRICT because it's not\n#strong enough a test to detect old buggy versions of GCC (e.g. 2.95.3)\nAC_CACHE_CHECK([for C/C++ restrict keyword], ac_cv_c_restrict,\n  [ac_cv_c_restrict=no\n   # The order here caters to the fact that C++ does not require restrict.\n   for ac_kw in __restrict __restrict__ _Restrict restrict; do\n     AC_COMPILE_IFELSE([AC_LANG_PROGRAM(\n      [[typedef int * int_ptr;\n\tint foo (int_ptr $ac_kw ip, int * $ac_kw baz[]) {\n\treturn ip[0];\n       }]],\n      [[int s[1];\n\tint * $ac_kw t = s;\n\tt[0] = 0;\n\treturn foo(t, (void *)0)]])],\n      [ac_cv_c_restrict=$ac_kw])\n     test \"$ac_cv_c_restrict\" != no && break\n   done\n  ])\n AH_VERBATIM([restrict],\n[/* Define to the equivalent of the C99 'restrict' keyword, or to\n   nothing if this is not supported.  Do not define if restrict is\n   supported directly.  */\n#undef restrict\n/* Work around a bug in Sun C++: it does not support _Restrict or\n   __restrict__, even though the corresponding Sun C compiler ends up with\n   \"#define restrict _Restrict\" or \"#define restrict __restrict__\" in the\n   previous line.  Perhaps some future version of Sun C++ will work with\n   restrict; if so, hopefully it defines __RESTRICT like Sun C does.  */\n#if defined __SUNPRO_CC && !defined __RESTRICT\n# define _Restrict\n# define __restrict__\n#endif])\n case $ac_cv_c_restrict in\n   restrict) ;;\n   no) AC_DEFINE([restrict], []) ;;\n   *)  AC_DEFINE_UNQUOTED([restrict], [$ac_cv_c_restrict]) ;;\n esac\n\nAC_MSG_CHECKING(for C99 variable-size arrays)\nAC_TRY_COMPILE( [], [static int x; char a[++x]; a[sizeof a - 1] = 0; int N; return a[0];],\n[has_var_arrays=yes;AC_DEFINE([VAR_ARRAYS], [], [Use C99 variable-size arrays])\n],\nhas_var_arrays=no\n)\nAC_MSG_RESULT($has_var_arrays)\n\nAC_CHECK_FUNC(exp,[fp_libm_not_needed=yes;LIBM=],[fp_libm_not_needed=dunno])\nif test x\"$fp_libm_not_needed\" = xdunno; then\n  AC_CHECK_LIB([m], [exp], [LIBS=\"-lm $LIBS\"; LIBM=\"-lm\"],[LIBM=])\nfi\nAC_SUBST([LIBM])\n\nAC_CHECK_LIB(winmm, main)\n\nAC_DEFINE_UNQUOTED(OPUSTOOLS_MAJOR_VERSION, ${OPUSTOOLS_MAJOR_VERSION}, [Version major])\nAC_DEFINE_UNQUOTED(OPUSTOOLS_MINOR_VERSION, ${OPUSTOOLS_MINOR_VERSION}, [Version minor])\nAC_DEFINE_UNQUOTED(OPUSTOOLS_MICRO_VERSION, ${OPUSTOOLS_MICRO_VERSION}, [Version micro])\nAC_DEFINE_UNQUOTED(OPUSTOOLS_EXTRA_VERSION, \"${OPUSTOOLS_EXTRA_VERSION}\", [Version extra])\n\nac_enable_assertions=\"no\"\nAC_ARG_ENABLE(assertions, [  --enable-assertions     enable additional software error checking],\n[if test \"$enableval\" = yes; then\n  ac_enable_assertions=\"yes\"\n  AC_DEFINE([ENABLE_ASSERTIONS], , [Assertions])\nfi])\n\ndnl check for Ogg\nHAVE_OGG=no\n\ndnl first check through pkg-config since it's more flexible\n\ndnl check for pkg-config itself so we don't try the m4 macro without pkg-config\nAC_CHECK_PROG(HAVE_PKG_CONFIG, pkg-config, yes)\nif test \"x$HAVE_PKG_CONFIG\" = \"xyes\"\nthen\n  PKG_CHECK_MODULES(OGG, ogg >= 1.3, HAVE_OGG=yes, HAVE_OGG=no)\nfi\nif test \"x$HAVE_OGG\" = \"xno\"\nthen\n  dnl fall back to the old school test\n  XIPH_PATH_OGG(, AC_MSG_ERROR([\n    libogg is required to build this package!\n    please see http://www.xiph.org/ for how to\n    obtain a copy.\n  ]))\n  cflags_save=$CFLAGS\n  libs_save=$LIBS\n  CFLAGS=\"$CFLAGS $OGG_CFLAGS\"\n  LIBS=\"$LIBS $OGG_LIBS\"\n  AC_CHECK_FUNC(ogg_stream_flush_fill, , [\n    AC_MSG_ERROR([newer libogg version (1.3 or later) required])\n  ])\n  CFLAGS=$cflags_save\n  LIBS=$libs_save\nfi\n\ndnl check for Opus\nHAVE_OPUS=no\n\ndnl first check through pkg-config since it's more flexible\n\ndnl check for pkg-config itself so we don't try the m4 macro without pkg-config\nAC_CHECK_PROG(HAVE_PKG_CONFIG, pkg-config, yes)\nif test \"x$HAVE_PKG_CONFIG\" = \"xyes\"\nthen\n  PKG_CHECK_MODULES(Opus, opus >= 0.9.10, HAVE_OPUS=yes, HAVE_OPUS=no)\nfi\nif test \"x$HAVE_OPUS\" = \"xno\"\nthen\n  AC_MSG_ERROR([\n    Opus is required to build this package!\n    please see http://opus-codec.org/ for how to\n    obtain a copy.])\nfi\n\ndnl check for OSS\nHAVE_OSS=no\nAC_CHECK_HEADERS([sys/soundcard.h soundcard.h machine/soundcard.h],[\n  HAVE_OSS=yes\n  break\n])\nif test x$HAVE_OSS != xyes; then\n  AC_MSG_WARN([OSS audio support not found -- no direct audio output in opusdec])\nfi\n\ndnl OpenBSD needs -lossaudio to use the oss interface\nOSS_LIBS=\ncase \"$host_os\" in\n  openbsd*)\n    OSS_LIBS='-lossaudio'\n    ;;\nesac\nAC_SUBST(OSS_LIBS)\n\n\ndnl Enable stack-protector-all only on x86 where it's well supported.\ndnl on some platforms it causes crashes. Hopefully the OS's default's\ndnl include this on platforms that work but have been missed here.\n\non_x86=no\ncase \"$host_cpu\" in\ni[[3456]]86 | x86_64)\n  on_x86=yes\n  ;;\nesac\n\nuse_stack_protector=no\n\nif test $ac_cv_c_compiler_gnu = yes && test $on_x86 = yes; then\nsaved_CFLAGS=\"$CFLAGS\"\nCFLAGS=\"$CFLAGS -fstack-protector-all\"\nAC_MSG_CHECKING([if ${CC} supports -fstack-protector-all])\nAC_LINK_IFELSE([AC_LANG_SOURCE([void main(void){char foo;}])],\n      [ AC_MSG_RESULT([yes])\n        STACK_PROTECTOR=\"-fstack-protector-all\"; use_stack_protector=yes ],\n        AC_MSG_RESULT([no]))\nCFLAGS=\"$saved_CFLAGS $STACK_PROTECTOR\"\nfi\n\nsave_CFLAGS=\"$CFLAGS\"\nsave_LDFLAGS=\"$LDFLAGS\"\nsave_LIBS=\"$LIBS\"\nCFLAGS=\"$CFLAGS -fPIE $Opus_CFLAGS\"\nLDFLAGS=\"$LDFLAGS -pie -Wl,-z,relro -Wl,-z,now\"\nLIBS=\"$LIBS $Opus_LIBS\"\nAC_MSG_CHECKING([for PIE support])\nAC_LINK_IFELSE([AC_LANG_SOURCE([\n#include <opus.h>\nvoid main () {\n  OpusDecoder *dec = opus_decoder_create(48000, 2, 0L);\n}])],\n               [have_pie=yes],\n               [have_pie=no])\nAC_MSG_RESULT([$have_pie])\nif test \"x$have_pie\" = \"xyes\"; then\n    PIE_CFLAGS=\"-fPIE\"\n    PIE_LDFLAGS=\"-pie -Wl,-z,relro -Wl,-z,now\"\nfi\nCFLAGS=\"$save_CFLAGS $PIE_CFLAGS\"\nLDFLAGS=\"$save_LDFLAGS $PIE_LDFLAGS\"\nLIBS=\"$save_LIBS\"\n\nCFLAGS=\"$CFLAGS -W\"\n\nsaved_CFLAGS=\"$CFLAGS\"\nCFLAGS=\"$CFLAGS -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes\"\nAC_MSG_CHECKING([if ${CC} supports -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes])\nAC_COMPILE_IFELSE([AC_LANG_SOURCE([char foo;])],\n      [ AC_MSG_RESULT([yes])\n        EXTRA_WARNS=\"-Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes\" ],\n        AC_MSG_RESULT([no]))\nCFLAGS=\"$saved_CFLAGS $EXTRA_WARNS\"\n\nAC_CHECK_FUNCS([lrintf])\nAC_CHECK_FUNCS([lrint])\nAC_CHECK_FUNCS([__malloc_hook])\n\nAC_CHECK_SIZEOF(short)\nAC_CHECK_SIZEOF(int)\nAC_CHECK_SIZEOF(long)\nAC_CHECK_SIZEOF(long long)\n\nif test x$has_char16 = \"xyes\" ; then\n        case 1 in\n                $ac_cv_sizeof_short) SIZE16=\"short\";;\n                $ac_cv_sizeof_int) SIZE16=\"int\";;\n        esac\nelse\n        case 2 in\n                $ac_cv_sizeof_short) SIZE16=\"short\";;\n                $ac_cv_sizeof_int) SIZE16=\"int\";;\n        esac\nfi\n\nif test x$has_char16 = \"xyes\" ; then\n        case 2 in\n                $ac_cv_sizeof_int) SIZE32=\"int\";;\n                $ac_cv_sizeof_long) SIZE32=\"long\";;\n                $ac_cv_sizeof_short) SIZE32=\"short\";;\n        esac\nelse\n        case 4 in\n                $ac_cv_sizeof_int) SIZE32=\"int\";;\n                $ac_cv_sizeof_long) SIZE32=\"long\";;\n                $ac_cv_sizeof_short) SIZE32=\"short\";;\n        esac\nfi\n\nAC_SUBST(SIZE16)\nAC_SUBST(SIZE32)\n\nAC_OUTPUT([Makefile])\n\nAC_MSG_RESULT([\n------------------------------------------------------------------------\n  $PACKAGE $VERSION:  Automatic configuration OK.\n\n    Compiler support:\n\n      C99 var arrays: ................ ${has_var_arrays}\n      C99 lrintf: .................... ${ac_cv_func_lrintf}\n      Stack protector: ............... ${use_stack_protector}\n      PIE: ........................... ${have_pie}\n\n    General configuration:\n\n      Assertion checking: ............ ${ac_enable_assertions}\n\n------------------------------------------------------------------------\n])\n\necho \"Type \\\"make; make install\\\" to compile and install\";\necho \"Type \\\"make check\\\" to run the test suite\";\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/man/opusdec.1",
    "content": ".\\\" Process this file with\n.\\\" groff -man -Tascii opusdec.1\n.\\\"\n.TH opusdec 1 2012-05-28 \"Xiph.Org Foundation\" \"opus-tools\"\n\n.SH NAME\nopusdec \\- decode audio from Opus format to WAV (or simple audio output)\n\n.SH SYNOPSIS\n.B opusdec\n[\n.B -hv\n] [\n.B --mono\n] [\n.B --stereo\n] [\n.B --rate Hz\n] [\n.B --no-dither\n] [\n.B --packet-loss pct\n] [\n.B --save-range file\n]\n.B input.opus\n[\n.B output.wav\n]\n\n.SH DESCRIPTION\n\n.B opusdec\ndecodes Opus files into PCM Wave (uncompressed) files.\n\nIf the input file is specified as\n.B \"-\"\n, then\n.B opusdec\nwill read from stdin. Likewise, an output filename of\n.B \"-\"\nwill cause output to be to stdout.\n\nIf no output is specified\n.B opusdec\nwill attempt to play the audio in realtime if it supports\naudio playback on your system.\n\n.SH \"OPTIONS\"\n.IP \"-h, --help\"\nPrint help message\n.IP \"-v, --version\"\nDisplay version information\n.IP \"--quiet\"\nSuppresses program output\n.IP \"--mono\"\n.br\nForce decoding in mono\n.IP \"--stereo\"\nForce decoding in stereo\n.IP \"--rate\"\n.br\nForce decoding at sampling rate n Hz\n.IP \"--no-dither\"\nDo not dither 16-bit output\n.IP \"--packet-loss\"\nSimulate n % random Opus packet loss\n.IP \"--save-range\"\nSaves check values for every frame to a file\n\n.SH EXAMPLES\nDecode a file\n.B input.opus\nto\n.B output.wav\n.RS\nopusdec input.opus output.wav\n.RE\n\nPlay a file\n.B input.opus\nand force output at 48000 regardless of\nthe original sampling rate\n.br\n.I (48kHz output may be faster, due to avoiding resampling and some sound hardware produces higher quality output when run at 48kHz)\n.RS\nopusdec --rate 48000 input.opus\n.RE\n\nRe-encode a high bitrate Opus file to a lower rate\n.RS\nopusdec input.opus - | opusenc --bitrate 64 - output.opus\n.RE\n\nPlay an http stream\n.B http://icecast.somwhere.org:8000/stream.opus\nwith the help of curl on a system with pulseaudio\n.br\n.I (press ctrl-c to quit)\n.RS\ncurl http://icecast.somwhere.org:8000/stream.opus | padsp opusdec -\n.RE\n\n.SH AUTHORS\n.br\nJean-Marc Valin <jmvalin@jmvalin.ca>\n.br\nGregory Maxwell <greg@xiph.org>\n\n.SH BUGS\n\nOpusdec does not currently reject all invalid files which it should reject.\nIt also doesn't provide very helpful output for the corrupted files it\ndoes reject. Use \\fBopusinfo\\fR(1) for somewhat better diagnostics.\n\n.SH SEE ALSO\n.BR opusenc (1),\n.BR opusinfo (1)\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/man/opusenc.1",
    "content": ".\\\" Process this file with\n.\\\" groff -man -Tascii opusenc.1\n.\\\"\n.TH opusenc 1 2012-05-28 \"Xiph.Org Foundation\" \"opus-tools\"\n\n.SH NAME\nopusenc \\- encode audio into the Opus format\n\n.SH SYNOPSIS\n.B opusenc\n[\n.B -v\n] [\n.B -h\n] [\n.B --speech\n] [\n.B --music\n] [\n.B --bitrate\n.I kbit/sec\n] [\n.B --vbr\n] [\n.B --cvbr\n] [\n.B --hard-cbr\n] [\n.B --comp\n.I complexity\n] [\n.B --framesize\n.I 2.5, 5, 10, 20, 40, 60\n] [\n.B --expect-loss\n.I pct\n] [\n.B --downmix-mono\n] [\n.B --downmix-stereo\n] [\n.B --max-delay\n.I ms\n] [\n.B --save-range\n.I file\n] [\n.B --set-ctl-int\n.I ctl=value\n] [\n.B --uncoupled\n] [\n.B --comment\n.I tag=value\n] [\n.B --artist\n.I author\n] [\n.B --title\n.I track title\n] [\n.B --raw\n] [\n.B --raw-bits\n.I bits/sample\n] [\n.B --raw-rate\n.I Hz\n] [\n.B --raw-chan\n.I N\n] [\n.B --raw-endianness\n.I flag\n] [\n.B --ignorelength\n]\n.I input.wav\n.I output.opus\n\n.SH DESCRIPTION\n.B opusenc\nreads audio data in either raw, Wave, or AIFF format and encodes it into an\nOpus stream. If the input file is \"-\" audio data is read from stdin.\nLikewise, if the output file is \"-\" opus data is written to stdout.\n\nUnless quieted\n.B opusenc\ndisplays fancy statistics about the encoding progress.\n\n.SH OPTIONS\n.IP \"-h, --help\"\nShow command help\n.IP \"-v, --version\"\nShow the version number\n.IP \"--speech\"\nOptimize for speech\n.IP \"--music\"\nOptimize for music\n.IP \"--bitrate N.nnn\"\nEncoding bitrate in kbit/sec (6-256 per channel)\n.IP \"--vbr\"\nUse variable bitrate encoding (default)\n.IP \"--cvbr\"\nUse constrained variable bitrate encoding\n.IP \"--hard-cbr\"\nUse hard constant bitrate encoding\n.IP \"--comp N\"\nEncoding computational complexity (0-10, default: 10)\n.IP \"--framesize N\"\nMaximum frame size in milliseconds (2.5, 5, 10, 20, 40, 60, default: 20)\n.br\nSmaller framesizes achieve lower latency but less quality at a given\nbitrate.\n.br\nSizes greater than 20ms are only interesting at fairly low\nbitrates.\n.IP \"--expect-loss N\"\nPercentage packet loss to expect (default: 0)\n.IP \"--downmix-mono\"\nDownmix to mono\n.IP \"--downmix-stereo\"\nDownmix to stereo (if >2 channels input)\n.IP \"--max-delay N\"\nMaximum container delay in milliseconds (0-1000, default: 1000)\n.IP \"--save-range file\"\nSaves check values for every frame to a file\n.IP \"--set-ctl-int x=y\"\nPass the encoder control x with value y (advanced)\nPreface with s: to direct the ctl to multistream s\n.br\nThis may be used multiple times\n.IP \"--uncoupled\"\nUse one mono stream per channel\n.IP \"--comment tag=value\"\nAdd an extra comment.  This may be used multiple times, and all\ninstances will be added to each of the input files specified. The argument\nshould be in the form \"tag=value\".\nSee the vorbis-comment specification for well known tag names:\nhttp://www.xiph.org/vorbis/doc/v-comment.html\n.IP \"--artist artist\"\nSet the artist comment field in the comments to\n.I artist\n.IP \"--title title\"\nSet the track title comment field to\n.I title\n.IP \"--raw\"\nRaw (headerless) PCM input\n.IP \"--raw-bits N\"\nSet bits/sample for raw input (default: 16)\n.IP \"--raw-rate N\"\nSet sampling rate for raw input (default: 48000)\n.IP \"--raw-chan N\"\nSet number of channels for raw input (default: 2)\n.IP \"--raw-endianness [0/1]\"\nSet the endianness for raw input: 1 for bigendian, 0 for little (defaults to 0)\n.IP \"--ignorelength\"\nAlways ignore the datalength in Wave headers. Opusenc automatically ignores\nthe length when its implausible (very small or very large) but some STDIN\nusage may still need this option to avoid truncation.\n\n.SH EXAMPLES\n\nSimplest usage. Take input as input.wav and produce output as output.opus:\n.RS\nopusenc input.wav output.opus\n.RE\n.PP\n\nProduce a very high quality encode with a target rate of 160kbps:\n.RS\nopusenc --bitrate 160 input.wav output.opus\n.RE\n.PP\n\nRecord and send a live stream to an Icecast HTTP streaming server using oggfwd:\n.RS\narecord -c 2 -r 48000 -twav - | opusenc --bitrate 96 -  - | oggfwd icecast.somewhere.org 8000 password /stream.opus\n.RE\n.PP\n\n.SH NOTES\n\nWhile it is possible to use opusenc for low latency streaming (e.g. with --max-delay set to 0\nand netcat instead of Icecast) it's not really designed for this, and the Ogg container\nand TCP transport aren't the best tools for that application. Shell\npipelines themselves will often have high buffering. The ability to set\nframesizes as low as 2.5 ms in opusenc mostly exists to try out the quality\nof the format with low latency settings, but not really for actual low\nlatency usage.\n.br\nInteractive usage should use UDP/RTP directly.\n\n.SH AUTHORS\n.br\nGregory Maxwell <greg@xiph.org>\n\n.SH SEE ALSO\n.BR opusdec (1),\n.BR opusinfo (1),\n.BR oggfwd (1)\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/man/opusinfo.1",
    "content": ".\\\" Process this file with\n.\\\" groff -man -Tascii opusinfo.1\n.\\\"\n.TH opusinfo 1 2012-05-28 \"Xiph.Org Foundation\" \"opus-tools\"\n\n.SH NAME\nopusinfo \\- gives information about Opus files and does extensive validity checking\n\n.SH SYNOPSIS\n.B opusinfo\n[\n.B -q\n] [\n.B -v\n] [\n.B -h\n]\n.I file1.opus\n.B ...\n.I fileN.opus\n\n.SH DESCRIPTION\n.B opusinfo\nreads one or more Opus files and prints information about stream contents\n(including chained and/or multiplexed streams) to standard output. It will\ndetect (but not correct) a wide range of common defects, with many\nadditional checks specifically for Opus streams.\n\nFor all stream types\n.B opusinfo\nwill print the filename being processed, the stream serial numbers, and various\ncommon error conditions.\n\nFor\n.B Opus\nstreams, information including the version used for encoding, number of channels\nand other header information, the bitrate and playback length, the contents of the\ncomment header, and general statistics about the stream are printed.\n\nOpusinfo is a fork of \\fBogginfo\\fR(1) with the non-opus parts largely removed.\n\n.SH OPTIONS\n.IP -h\nShow a help and usage message.\n.IP -q\nQuiet mode. This may be specified multiple times. Doing so once will remove\nthe detailed informative messages; twice will remove warnings as well.\n.IP -v\nVerbose mode. At the current time, this does not do anything.\n\n.SH NOTES\n\nThere are many kinds of errored, invalid, non-normative, or otherwise\nunwise stream constructions which opusinfo will not produce warnings\non. Passing opusinfo with flying colors is not certification of the\ncorrectness of a stream. Future versions may detect more error\nconditions.\n\n.SH AUTHORS\n.br\nMichael Smith <msmith@xiph.org>\n.br\nGregory Maxwell <greg@xiph.org>\n\n.SH SEE ALSO\n\n.BR opusdec (1),\n.BR opusenc (1)\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/arch.h",
    "content": "/* Copyright (C) 2003 Jean-Marc Valin */\n/**\n   @file arch.h\n   @brief Various architecture definitions Speex\n*/\n/*\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n   \n   - Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n   \n   - Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n   \n   - Neither the name of the Xiph.org Foundation nor the names of its\n   contributors may be used to endorse or promote products derived from\n   this software without specific prior written permission.\n   \n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR\n   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifndef ARCH_H\n#define ARCH_H\n\n#ifndef SPEEX_VERSION\n#define SPEEX_MAJOR_VERSION 1         /**< Major Speex version. */\n#define SPEEX_MINOR_VERSION 1         /**< Minor Speex version. */\n#define SPEEX_MICRO_VERSION 15        /**< Micro Speex version. */\n#define SPEEX_EXTRA_VERSION \"\"        /**< Extra Speex version. */\n#define SPEEX_VERSION \"speex-1.2beta3\"  /**< Speex version string. */\n#endif\n\n/* A couple test to catch stupid option combinations */\n#ifdef FIXED_POINT\n\n#ifdef FLOATING_POINT\n#error You cannot compile as floating point and fixed point at the same time\n#endif\n#ifdef _USE_SSE\n#error SSE is only for floating-point\n#endif\n#if ((defined (ARM4_ASM)||defined (ARM4_ASM)) && defined(BFIN_ASM)) || (defined (ARM4_ASM)&&defined(ARM5E_ASM))\n#error Make up your mind. What CPU do you have?\n#endif\n#ifdef VORBIS_PSYCHO\n#error Vorbis-psy model currently not implemented in fixed-point\n#endif\n\n#else\n\n#ifndef FLOATING_POINT\n#error You now need to define either FIXED_POINT or FLOATING_POINT\n#endif\n#if defined (ARM4_ASM) || defined(ARM5E_ASM) || defined(BFIN_ASM)\n#error I suppose you can have a [ARM4/ARM5E/Blackfin] that has float instructions?\n#endif\n#ifdef FIXED_POINT_DEBUG\n#error \"Don't you think enabling fixed-point is a good thing to do if you want to debug that?\"\n#endif\n\n\n#endif\n\n#ifndef OUTSIDE_SPEEX\n#include \"../include/speex/speex_types.h\"\n#endif\n\n#define ABS(x) ((x) < 0 ? (-(x)) : (x))      /**< Absolute integer value. */\n#define ABS16(x) ((x) < 0 ? (-(x)) : (x))    /**< Absolute 16-bit value.  */\n#define MIN16(a,b) ((a) < (b) ? (a) : (b))   /**< Maximum 16-bit value.   */\n#define MAX16(a,b) ((a) > (b) ? (a) : (b))   /**< Maximum 16-bit value.   */\n#define ABS32(x) ((x) < 0 ? (-(x)) : (x))    /**< Absolute 32-bit value.  */\n#define MIN32(a,b) ((a) < (b) ? (a) : (b))   /**< Maximum 32-bit value.   */\n#define MAX32(a,b) ((a) > (b) ? (a) : (b))   /**< Maximum 32-bit value.   */\n\n#ifdef FIXED_POINT\n\ntypedef spx_int16_t spx_word16_t;\ntypedef spx_int32_t spx_word32_t;\ntypedef spx_word32_t spx_mem_t;\ntypedef spx_word16_t spx_coef_t;\ntypedef spx_word16_t spx_lsp_t;\ntypedef spx_word32_t spx_sig_t;\n\n#define Q15ONE 32767\n\n#define LPC_SCALING  8192\n#define SIG_SCALING  16384\n#define LSP_SCALING  8192.\n#define GAMMA_SCALING 32768.\n#define GAIN_SCALING 64\n#define GAIN_SCALING_1 0.015625\n\n#define LPC_SHIFT    13\n#define LSP_SHIFT    13\n#define SIG_SHIFT    14\n#define GAIN_SHIFT   6\n\n#define VERY_SMALL 0\n#define VERY_LARGE32 ((spx_word32_t)2147483647)\n#define VERY_LARGE16 ((spx_word16_t)32767)\n#define Q15_ONE ((spx_word16_t)32767)\n\n\n#ifdef FIXED_DEBUG\n#include \"fixed_debug.h\"\n#else\n\n#include \"fixed_generic.h\"\n\n#ifdef ARM5E_ASM\n#include \"fixed_arm5e.h\"\n#elif defined (ARM4_ASM)\n#include \"fixed_arm4.h\"\n#elif defined (BFIN_ASM)\n#include \"fixed_bfin.h\"\n#endif\n\n#endif\n\n\n#else\n\ntypedef float spx_mem_t;\ntypedef float spx_coef_t;\ntypedef float spx_lsp_t;\ntypedef float spx_sig_t;\ntypedef float spx_word16_t;\ntypedef float spx_word32_t;\n\n#define Q15ONE 1.0f\n#define LPC_SCALING  1.f\n#define SIG_SCALING  1.f\n#define LSP_SCALING  1.f\n#define GAMMA_SCALING 1.f\n#define GAIN_SCALING 1.f\n#define GAIN_SCALING_1 1.f\n\n\n#define VERY_SMALL 1e-15f\n#define VERY_LARGE32 1e15f\n#define VERY_LARGE16 1e15f\n#define Q15_ONE ((spx_word16_t)1.f)\n\n#define QCONST16(x,bits) (x)\n#define QCONST32(x,bits) (x)\n\n#define NEG16(x) (-(x))\n#define NEG32(x) (-(x))\n#define EXTRACT16(x) (x)\n#define EXTEND32(x) (x)\n#define SHR16(a,shift) (a)\n#define SHL16(a,shift) (a)\n#define SHR32(a,shift) (a)\n#define SHL32(a,shift) (a)\n#define PSHR16(a,shift) (a)\n#define PSHR32(a,shift) (a)\n#define VSHR32(a,shift) (a)\n#define SATURATE16(x,a) (x)\n#define SATURATE32(x,a) (x)\n\n#define PSHR(a,shift)       (a)\n#define SHR(a,shift)       (a)\n#define SHL(a,shift)       (a)\n#define SATURATE(x,a) (x)\n\n#define ADD16(a,b) ((a)+(b))\n#define SUB16(a,b) ((a)-(b))\n#define ADD32(a,b) ((a)+(b))\n#define SUB32(a,b) ((a)-(b))\n#define MULT16_16_16(a,b)     ((a)*(b))\n#define MULT16_16(a,b)     ((spx_word32_t)(a)*(spx_word32_t)(b))\n#define MAC16_16(c,a,b)     ((c)+(spx_word32_t)(a)*(spx_word32_t)(b))\n\n#define MULT16_32_Q11(a,b)     ((a)*(b))\n#define MULT16_32_Q13(a,b)     ((a)*(b))\n#define MULT16_32_Q14(a,b)     ((a)*(b))\n#define MULT16_32_Q15(a,b)     ((a)*(b))\n#define MULT16_32_P15(a,b)     ((a)*(b))\n\n#define MAC16_32_Q11(c,a,b)     ((c)+(a)*(b))\n#define MAC16_32_Q15(c,a,b)     ((c)+(a)*(b))\n\n#define MAC16_16_Q11(c,a,b)     ((c)+(a)*(b))\n#define MAC16_16_Q13(c,a,b)     ((c)+(a)*(b))\n#define MAC16_16_P13(c,a,b)     ((c)+(a)*(b))\n#define MULT16_16_Q11_32(a,b)     ((a)*(b))\n#define MULT16_16_Q13(a,b)     ((a)*(b))\n#define MULT16_16_Q14(a,b)     ((a)*(b))\n#define MULT16_16_Q15(a,b)     ((a)*(b))\n#define MULT16_16_P15(a,b)     ((a)*(b))\n#define MULT16_16_P13(a,b)     ((a)*(b))\n#define MULT16_16_P14(a,b)     ((a)*(b))\n\n#define DIV32_16(a,b)     (((spx_word32_t)(a))/(spx_word16_t)(b))\n#define PDIV32_16(a,b)     (((spx_word32_t)(a))/(spx_word16_t)(b))\n#define DIV32(a,b)     (((spx_word32_t)(a))/(spx_word32_t)(b))\n#define PDIV32(a,b)     (((spx_word32_t)(a))/(spx_word32_t)(b))\n\n\n#endif\n\n\n#if defined (CONFIG_TI_C54X) || defined (CONFIG_TI_C55X)\n\n/* 2 on TI C5x DSP */\n#define BYTES_PER_CHAR 2 \n#define BITS_PER_CHAR 16\n#define LOG2_BITS_PER_CHAR 4\n\n#else \n\n#define BYTES_PER_CHAR 1\n#define BITS_PER_CHAR 8\n#define LOG2_BITS_PER_CHAR 3\n\n#endif\n\n\n\n#ifdef FIXED_DEBUG\nextern long long spx_mips;\n#endif\n\n\n#endif\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/audio-in.c",
    "content": "/* Copyright 2000-2002, Michael Smith <msmith@xiph.org>\n             2010, Monty <monty@xiph.org>\n   AIFF/AIFC support from OggSquish, (c) 1994-1996 Monty <xiphmont@xiph.org>\n   (From GPL code in oggenc relicensed by permission from Monty and Msmith)\n   File: audio-in.c\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n\n   - Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n   - Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR\n   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifdef HAVE_CONFIG_H\n# include <config.h>\n#endif\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <sys/types.h>\n#include <math.h>\n\n#ifdef WIN32\n# include <malloc.h>\n# include <windows.h> /*GetFileType()*/\n# include <io.h>      /*_get_osfhandle()*/\n#else\n# ifdef HAVE_ALLOCA_H\n#  include <alloca.h>\n# else\n#  include <stdlib.h>\n# endif\n#endif\n\n#ifdef ENABLE_NLS\n#include <libintl.h>\n#define _(X) gettext(X)\n#else\n#define _(X) (X)\n#define textdomain(X)\n#define bindtextdomain(X, Y)\n#endif\n#ifdef gettext_noop\n#define N_(X) gettext_noop(X)\n#else\n#define N_(X) (X)\n#endif\n\n#include <ogg/ogg.h>\n#include \"opusenc.h\"\n#include \"speex_resampler.h\"\n#include \"lpc.h\"\n#include \"opus_header.h\"\n\n#ifdef HAVE_LIBFLAC\n#include \"flac.h\"\n#endif\n\n/* Macros to read header data */\n#define READ_U32_LE(buf) \\\n    (((buf)[3]<<24)|((buf)[2]<<16)|((buf)[1]<<8)|((buf)[0]&0xff))\n\n#define READ_U16_LE(buf) \\\n    (((buf)[1]<<8)|((buf)[0]&0xff))\n\n#define READ_U32_BE(buf) \\\n    (((buf)[0]<<24)|((buf)[1]<<16)|((buf)[2]<<8)|((buf)[3]&0xff))\n\n#define READ_U16_BE(buf) \\\n    (((buf)[0]<<8)|((buf)[1]&0xff))\n\n/* Define the supported formats here */\ninput_format formats[] = {\n    {wav_id, 12, wav_open, wav_close, \"wav\", N_(\"WAV file reader\")},\n    {aiff_id, 12, aiff_open, wav_close, \"aiff\", N_(\"AIFF/AIFC file reader\")},\n#ifdef HAVE_LIBFLAC\n    {flac_id,     4, flac_open, flac_close, \"flac\", N_(\"FLAC file reader\")},\n    {oggflac_id, 32, flac_open, flac_close, \"ogg\", N_(\"Ogg FLAC file reader\")},\n#endif\n    {NULL, 0, NULL, NULL, NULL, NULL}\n};\n\ninput_format *open_audio_file(FILE *in, oe_enc_opt *opt)\n{\n    int j=0;\n    unsigned char *buf=NULL;\n    int buf_size=0, buf_filled=0;\n    int size,ret;\n\n    while(formats[j].id_func)\n    {\n        size = formats[j].id_data_len;\n        if(size >= buf_size)\n        {\n            buf = realloc(buf, size);\n            buf_size = size;\n        }\n\n        if(size > buf_filled)\n        {\n            ret = fread(buf+buf_filled, 1, buf_size-buf_filled, in);\n            buf_filled += ret;\n\n            if(buf_filled < size)\n            { /* File truncated */\n                j++;\n                continue;\n            }\n        }\n\n        if(formats[j].id_func(buf, buf_filled))\n        {\n            /* ok, we now have something that can handle the file */\n            if(formats[j].open_func(in, opt, buf, buf_filled)) {\n                free(buf);\n                return &formats[j];\n            }\n        }\n        j++;\n    }\n\n    free(buf);\n\n    return NULL;\n}\n\nstatic int seek_forward(FILE *in, unsigned int length)\n{\n    if(fseek(in, length, SEEK_CUR))\n    {\n        /* Failed. Do it the hard way. */\n        unsigned char buf[1024];\n        unsigned int seek_needed = length;\n        int seeked;\n        while(seek_needed > 0)\n        {\n            seeked = fread(buf, 1, seek_needed>1024?1024:seek_needed, in);\n            if(!seeked)\n                return 0; /* Couldn't read more, can't read file */\n            else\n                seek_needed -= seeked;\n        }\n    }\n    return 1;\n}\n\nstatic int find_wav_chunk(FILE *in, char *type, unsigned int *len)\n{\n    unsigned char buf[8];\n\n    while(1)\n    {\n        if(fread(buf,1,8,in) < 8) /* Suck down a chunk specifier */\n        {\n            fprintf(stderr, _(\"Warning: Unexpected EOF in reading WAV header\\n\"));\n            return 0; /* EOF before reaching the appropriate chunk */\n        }\n\n        if(memcmp(buf, type, 4))\n        {\n            *len = READ_U32_LE(buf+4);\n            if(!seek_forward(in, *len))\n                return 0;\n\n            buf[4] = 0;\n            fprintf(stderr, _(\"Skipping chunk of type \\\"%s\\\", length %d\\n\"), buf, *len);\n        }\n        else\n        {\n            *len = READ_U32_LE(buf+4);\n            return 1;\n        }\n    }\n}\n\nstatic int find_aiff_chunk(FILE *in, char *type, unsigned int *len)\n{\n    unsigned char buf[8];\n    int restarted = 0;\n\n    while(1)\n    {\n        if(fread(buf,1,8,in) <8)\n        {\n            if(!restarted) {\n                /* Handle out of order chunks by seeking back to the start\n                 * to retry */\n                restarted = 1;\n                fseek(in, 12, SEEK_SET);\n                continue;\n            }\n            fprintf(stderr, _(\"Warning: Unexpected EOF in AIFF chunk\\n\"));\n            return 0;\n        }\n\n        *len = READ_U32_BE(buf+4);\n\n        if(memcmp(buf,type,4))\n        {\n            if((*len) & 0x1)\n                (*len)++;\n\n            if(!seek_forward(in, *len))\n                return 0;\n        }\n        else\n            return 1;\n    }\n}\n\ndouble read_IEEE80(unsigned char *buf)\n{\n    int s=buf[0]&0xff;\n    int e=((buf[0]&0x7f)<<8)|(buf[1]&0xff);\n    double f=((unsigned long)(buf[2]&0xff)<<24)|\n        ((buf[3]&0xff)<<16)|\n        ((buf[4]&0xff)<<8) |\n         (buf[5]&0xff);\n\n    if(e==32767)\n    {\n        if(buf[2]&0x80)\n            return HUGE_VAL; /* Really NaN, but this won't happen in reality */\n        else\n        {\n            if(s)\n                return -HUGE_VAL;\n            else\n                return HUGE_VAL;\n        }\n    }\n\n    f=ldexp(f,32);\n    f+= ((buf[6]&0xff)<<24)|\n        ((buf[7]&0xff)<<16)|\n        ((buf[8]&0xff)<<8) |\n         (buf[9]&0xff);\n\n    return ldexp(f, e-16446);\n}\n\n/* AIFF/AIFC support adapted from the old OggSQUISH application */\nint aiff_id(unsigned char *buf, int len)\n{\n    if(len<12) return 0; /* Truncated file, probably */\n\n    if(memcmp(buf, \"FORM\", 4))\n        return 0;\n\n    if(memcmp(buf+8, \"AIF\",3))\n        return 0;\n\n    if(buf[11]!='C' && buf[11]!='F')\n        return 0;\n\n    return 1;\n}\n\nstatic int aiff_permute_matrix[6][6] =\n{\n  {0},              /* 1.0 mono   */\n  {0,1},            /* 2.0 stereo */\n  {0,2,1},          /* 3.0 channel ('wide') stereo */\n  {0,1,2,3},        /* 4.0 discrete quadraphonic (WARN) */\n  {0,2,1,3,4},      /* 5.0 surround (WARN) */\n  {0,1,2,3,4,5},    /* 5.1 surround (WARN)*/\n};\n\nint aiff_open(FILE *in, oe_enc_opt *opt, unsigned char *buf, int buflen)\n{\n    int aifc; /* AIFC or AIFF? */\n    unsigned int len;\n    unsigned char *buffer;\n    unsigned char buf2[8];\n    int bigendian = 1;\n    aiff_fmt format;\n    aifffile *aiff;\n    int i;\n    (void)buflen;/*unused*/\n\n    if(buf[11]=='C')\n        aifc=1;\n    else\n        aifc=0;\n\n    if(!find_aiff_chunk(in, \"COMM\", &len))\n    {\n        fprintf(stderr, _(\"Warning: No common chunk found in AIFF file\\n\"));\n        return 0; /* EOF before COMM chunk */\n    }\n\n    if(len < 18)\n    {\n        fprintf(stderr, _(\"Warning: Truncated common chunk in AIFF header\\n\"));\n        return 0; /* Weird common chunk */\n    }\n\n    buffer = alloca(len);\n\n    if(fread(buffer,1,len,in) < len)\n    {\n        fprintf(stderr, _(\"Warning: Unexpected EOF in reading AIFF header\\n\"));\n        return 0;\n    }\n\n    format.channels = READ_U16_BE(buffer);\n    format.totalframes = READ_U32_BE(buffer+2);\n    format.samplesize = READ_U16_BE(buffer+6);\n    format.rate = (int)read_IEEE80(buffer+8);\n\n    if(aifc)\n    {\n        if(len < 22)\n        {\n            fprintf(stderr, _(\"Warning: AIFF-C header truncated.\\n\"));\n            return 0;\n        }\n\n        if(!memcmp(buffer+18, \"NONE\", 4))\n        {\n            bigendian = 1;\n        }\n        else if(!memcmp(buffer+18, \"sowt\", 4))\n        {\n            bigendian = 0;\n        }\n        else\n        {\n            fprintf(stderr, _(\"Warning: Can't handle compressed AIFF-C (%c%c%c%c)\\n\"), *(buffer+18), *(buffer+19), *(buffer+20), *(buffer+21));\n            return 0; /* Compressed. Can't handle */\n        }\n    }\n\n    if(!find_aiff_chunk(in, \"SSND\", &len))\n    {\n        fprintf(stderr, _(\"Warning: No SSND chunk found in AIFF file\\n\"));\n        return 0; /* No SSND chunk -> no actual audio */\n    }\n\n    if(len < 8)\n    {\n        fprintf(stderr, _(\"Warning: Corrupted SSND chunk in AIFF header\\n\"));\n        return 0;\n    }\n\n    if(fread(buf2,1,8, in) < 8)\n    {\n        fprintf(stderr, _(\"Warning: Unexpected EOF reading AIFF header\\n\"));\n        return 0;\n    }\n\n    format.offset = READ_U32_BE(buf2);\n    format.blocksize = READ_U32_BE(buf2+4);\n\n    if( format.blocksize == 0 &&\n        (format.samplesize == 16 || format.samplesize == 8))\n    {\n        /* From here on, this is very similar to the wav code. Oh well. */\n\n        opt->rate = format.rate;\n        opt->channels = format.channels;\n        opt->read_samples = wav_read; /* Similar enough, so we use the same */\n        opt->total_samples_per_channel = format.totalframes;\n\n        aiff = malloc(sizeof(aifffile));\n        aiff->f = in;\n        aiff->samplesread = 0;\n        aiff->channels = format.channels;\n        aiff->samplesize = format.samplesize;\n        aiff->totalsamples = format.totalframes;\n        aiff->bigendian = bigendian;\n\n        if(aiff->channels>3)\n          fprintf(stderr,\"WARNING: AIFF[-C] files with greater than three channels use\\n\"\n                  \"speaker locations incompatable with Vorbis suppound definitions.\\n\"\n                  \"Not performaing channel location mapping.\\n\");\n\n        opt->readdata = (void *)aiff;\n\n        aiff->channel_permute = malloc(aiff->channels * sizeof(int));\n        if (aiff->channels <= 6)\n            /* Where we know the mappings, use them. */\n            memcpy(aiff->channel_permute, aiff_permute_matrix[aiff->channels-1],\n                    sizeof(int) * aiff->channels);\n        else\n            /* Use a default 1-1 mapping */\n            for (i=0; i < aiff->channels; i++)\n                aiff->channel_permute[i] = i;\n\n        seek_forward(in, format.offset); /* Swallow some data */\n        return 1;\n    }\n    else\n    {\n        fprintf(stderr,\n                _(\"Warning: OggEnc does not support this type of AIFF/AIFC file\\n\"\n                \" Must be 8 or 16 bit PCM.\\n\"));\n        return 0;\n    }\n}\n\nint wav_id(unsigned char *buf, int len)\n{\n    if(len<12) return 0; /* Something screwed up */\n\n    if(memcmp(buf, \"RIFF\", 4))\n        return 0; /* Not wave */\n\n    /*flen = READ_U32_LE(buf+4);*/ /* We don't use this */\n\n    if(memcmp(buf+8, \"WAVE\",4))\n        return 0; /* RIFF, but not wave */\n\n    return 1;\n}\n\nint wav_open(FILE *in, oe_enc_opt *opt, unsigned char *oldbuf, int buflen)\n{\n    unsigned char buf[40];\n    unsigned int len;\n    int samplesize;\n    wav_fmt format;\n    wavfile *wav;\n    int i;\n    (void)buflen;/*unused*/\n    (void)oldbuf;/*unused*/\n\n    /* Ok. At this point, we know we have a WAV file. Now we have to detect\n     * whether we support the subtype, and we have to find the actual data\n     * We don't (for the wav reader) need to use the buffer we used to id this\n     * as a wav file (oldbuf)\n     */\n\n    if(!find_wav_chunk(in, \"fmt \", &len))\n        return 0; /* EOF */\n\n    if(len < 16)\n    {\n        fprintf(stderr, _(\"Warning: Unrecognised format chunk in WAV header\\n\"));\n        return 0; /* Weird format chunk */\n    }\n\n    /* A common error is to have a format chunk that is not 16, 18 or\n     * 40 bytes in size.  This is incorrect, but not fatal, so we only\n     * warn about it instead of refusing to work with the file.\n     * Please, if you have a program that's creating format chunks of\n     * sizes other than 16 or 18 bytes in size, report a bug to the\n     * author.\n     */\n    if(len!=16 && len!=18 && len!=40)\n        fprintf(stderr,\n                _(\"Warning: INVALID format chunk in wav header.\\n\"\n                \" Trying to read anyway (may not work)...\\n\"));\n\n    if(len>40)len=40;\n\n    if(fread(buf,1,len,in) < len)\n    {\n        fprintf(stderr, _(\"Warning: Unexpected EOF in reading WAV header\\n\"));\n        return 0;\n    }\n\n    format.format =      READ_U16_LE(buf);\n    format.channels =    READ_U16_LE(buf+2);\n    format.samplerate =  READ_U32_LE(buf+4);\n    format.bytespersec = READ_U32_LE(buf+8);\n    format.align =       READ_U16_LE(buf+12);\n    format.samplesize =  READ_U16_LE(buf+14);\n\n    if(format.format == -2) /* WAVE_FORMAT_EXTENSIBLE */\n    {\n      if(len<40)\n      {\n        fprintf(stderr,\"ERROR: Extended WAV format header invalid (too small)\\n\");\n        return 0;\n      }\n\n      format.mask = READ_U32_LE(buf+20);\n      /* warn the user if the format mask is not a supported/expected type */\n      switch(format.mask){\n      case 1539: /* 4.0 using side surround instead of back */\n        fprintf(stderr,\"WARNING: WAV file uses side surround instead of rear for quadraphonic;\\n\"\n                \"remapping side speakers to rear in encoding.\\n\");\n        break;\n      case 1551: /* 5.1 using side instead of rear */\n        fprintf(stderr,\"WARNING: WAV file uses side surround instead of rear for 5.1;\\n\"\n                \"remapping side speakers to rear in encoding.\\n\");\n        break;\n      case 319:  /* 6.1 using rear instead of side */\n        fprintf(stderr,\"WARNING: WAV file uses rear surround instead of side for 6.1;\\n\"\n                \"remapping rear speakers to side in encoding.\\n\");\n        break;\n      case 255:  /* 7.1 'Widescreen' */\n        fprintf(stderr,\"WARNING: WAV file is a 7.1 'Widescreen' channel mapping;\\n\"\n                \"remapping speakers to Vorbis 7.1 format.\\n\");\n        break;\n      case 0:    /* default/undeclared */\n      case 1:    /* mono */\n      case 3:    /* stereo */\n      case 51:   /* quad */\n      case 55:   /* 5.0 */\n      case 63:   /* 5.1 */\n      case 1807: /* 6.1 */\n      case 1599: /* 7.1 */\n        break;\n      default:\n        fprintf(stderr,\"WARNING: Unknown WAV surround channel mask: %d\\n\"\n                \"blindly mapping speakers using default SMPTE/ITU ordering.\\n\",\n                format.mask);\n        break;\n      }\n      format.format = READ_U16_LE(buf+24);\n    }\n\n    if(!find_wav_chunk(in, \"data\", &len))\n        return 0; /* EOF */\n\n    if(format.format == 1)\n    {\n        samplesize = format.samplesize/8;\n        opt->read_samples = wav_read;\n    }\n    else if(format.format == 3)\n    {\n        samplesize = 4;\n        opt->read_samples = wav_ieee_read;\n    }\n    else\n    {\n        fprintf(stderr,\n                _(\"ERROR: Wav file is unsupported type (must be standard PCM\\n\"\n                \" or type 3 floating point PCM\\n\"));\n        return 0;\n    }\n\n    if(format.align != format.channels * samplesize) {\n        /* This is incorrect according to the spec. Warn loudly, then ignore\n         * this value.\n         */\n        fprintf(stderr, _(\"Warning: WAV 'block alignment' value is incorrect, \"\n                    \"ignoring.\\n\"\n                    \"The software that created this file is incorrect.\\n\"));\n    }\n\n    if(format.samplesize == samplesize*8 &&\n            (format.samplesize == 24 || format.samplesize == 16 ||\n             format.samplesize == 8 ||\n         (format.samplesize == 32 && format.format == 3)))\n    {\n        /* OK, good - we have the one supported format,\n           now we want to find the size of the file */\n        opt->rate = format.samplerate;\n        opt->channels = format.channels;\n\n        wav = malloc(sizeof(wavfile));\n        wav->f = in;\n        wav->samplesread = 0;\n        wav->bigendian = 0;\n        wav->channels = format.channels; /* This is in several places. The price\n                                            of trying to abstract stuff. */\n        wav->samplesize = format.samplesize;\n\n        if(len>(format.channels*samplesize*4U) && len<((1U<<31)-65536) && opt->ignorelength!=1) /*Length provided is plausible.*/\n        {\n            opt->total_samples_per_channel = len/(format.channels*samplesize);\n        }\n#ifdef WIN32\n        /*On Mingw/Win32 fseek() returns zero on pipes.*/\n        else if (opt->ignorelength==1 || ((GetFileType((HANDLE)_get_osfhandle(fileno(in)))&~FILE_TYPE_REMOTE)!=FILE_TYPE_DISK))\n#else\n        else if (opt->ignorelength==1)\n#endif\n        {\n           opt->total_samples_per_channel = 0;\n        }\n        else\n        {\n            opus_int64 pos;\n            pos = ftell(in);\n            if(fseek(in, 0, SEEK_END) == -1)\n            {\n                opt->total_samples_per_channel = 0; /* Give up */\n            }\n            else\n            {\n                opt->total_samples_per_channel = (ftell(in) - pos)/\n                    (format.channels*samplesize);\n                fseek(in,pos, SEEK_SET);\n            }\n        }\n        wav->totalsamples = opt->total_samples_per_channel;\n\n        opt->readdata = (void *)wav;\n\n        wav->channel_permute = malloc(wav->channels * sizeof(int));\n        if (wav->channels <= 8)\n            /* Where we know the mappings, use them. */\n            memcpy(wav->channel_permute, wav_permute_matrix[wav->channels-1],\n                    sizeof(int) * wav->channels);\n        else\n            /* Use a default 1-1 mapping */\n            for (i=0; i < wav->channels; i++)\n                wav->channel_permute[i] = i;\n\n        return 1;\n    }\n    else\n    {\n        fprintf(stderr,\n                _(\"ERROR: Wav file is unsupported subformat (must be 8,16, or 24 bit PCM\\n\"\n                \"or floating point PCM\\n\"));\n        return 0;\n    }\n}\n\nlong wav_read(void *in, float *buffer, int samples)\n{\n    wavfile *f = (wavfile *)in;\n    int sampbyte = f->samplesize / 8;\n    signed char *buf = alloca(samples*sampbyte*f->channels);\n    long bytes_read = fread(buf, 1, samples*sampbyte*f->channels, f->f);\n    int i,j;\n    opus_int64 realsamples;\n    int *ch_permute = f->channel_permute;\n\n    if(f->totalsamples && f->samplesread +\n            bytes_read/(sampbyte*f->channels) > f->totalsamples) {\n        bytes_read = sampbyte*f->channels*(f->totalsamples - f->samplesread);\n    }\n\n    realsamples = bytes_read/(sampbyte*f->channels);\n    f->samplesread += realsamples;\n\n    if(f->samplesize==8)\n    {\n        unsigned char *bufu = (unsigned char *)buf;\n        for(i = 0; i < realsamples; i++)\n        {\n            for(j=0; j < f->channels; j++)\n            {\n                buffer[i*f->channels+j]=((int)(bufu[i*f->channels + ch_permute[j]])-128)/128.0f;\n            }\n        }\n    }\n    else if(f->samplesize==16)\n    {\n        if(!f->bigendian)\n        {\n            for(i = 0; i < realsamples; i++)\n            {\n                for(j=0; j < f->channels; j++)\n                {\n                    buffer[i*f->channels+j] = ((buf[i*2*f->channels + 2*ch_permute[j] + 1]<<8) |\n                                    (buf[i*2*f->channels + 2*ch_permute[j]] & 0xff))/32768.0f;\n                }\n            }\n        }\n        else\n        {\n            for(i = 0; i < realsamples; i++)\n            {\n                for(j=0; j < f->channels; j++)\n                {\n                    buffer[i*f->channels+j]=((buf[i*2*f->channels + 2*ch_permute[j]]<<8) |\n                                  (buf[i*2*f->channels + 2*ch_permute[j] + 1] & 0xff))/32768.0f;\n                }\n            }\n        }\n    }\n    else if(f->samplesize==24)\n    {\n        if(!f->bigendian) {\n            for(i = 0; i < realsamples; i++)\n            {\n                for(j=0; j < f->channels; j++)\n                {\n                    buffer[i*f->channels+j] = ((buf[i*3*f->channels + 3*ch_permute[j] + 2] << 16) |\n                      (((unsigned char *)buf)[i*3*f->channels + 3*ch_permute[j] + 1] << 8) |\n                      (((unsigned char *)buf)[i*3*f->channels + 3*ch_permute[j]] & 0xff))\n                        / 8388608.0f;\n\n                }\n            }\n        }\n        else {\n            fprintf(stderr, _(\"Big endian 24 bit PCM data is not currently \"\n                              \"supported, aborting.\\n\"));\n            return 0;\n        }\n    }\n    else {\n        fprintf(stderr, _(\"Internal error: attempt to read unsupported \"\n                          \"bitdepth %d\\n\"), f->samplesize);\n        return 0;\n    }\n\n    return realsamples;\n}\n\nlong wav_ieee_read(void *in, float *buffer, int samples)\n{\n    wavfile *f = (wavfile *)in;\n    float *buf = alloca(samples*4*f->channels); /* de-interleave buffer */\n    long bytes_read = fread(buf,1,samples*4*f->channels, f->f);\n    int i,j;\n    opus_int64 realsamples;\n\n    if(f->totalsamples && f->samplesread +\n            bytes_read/(4*f->channels) > f->totalsamples)\n        bytes_read = 4*f->channels*(f->totalsamples - f->samplesread);\n\n    realsamples = bytes_read/(4*f->channels);\n    f->samplesread += realsamples;\n\n    for(i=0; i < realsamples; i++)\n        for(j=0; j < f->channels; j++)\n            buffer[i*f->channels+j] = buf[i*f->channels + f->channel_permute[j]];\n\n    return realsamples;\n}\n\nvoid wav_close(void *info)\n{\n    wavfile *f = (wavfile *)info;\n    free(f->channel_permute);\n\n    free(f);\n}\n\nint raw_open(FILE *in, oe_enc_opt *opt, unsigned char *buf, int buflen)\n{\n    wav_fmt format; /* fake wave header ;) */\n    wavfile *wav = malloc(sizeof(wavfile));\n    int i;\n    (void)buf;/*unused*/\n    (void)buflen;/*unused*/\n\n    /* construct fake wav header ;) */\n    format.format =      2;\n    format.channels =    opt->channels;\n    format.samplerate =  opt->rate;\n    format.samplesize =  opt->samplesize;\n    format.bytespersec = opt->channels * opt->rate * opt->samplesize / 8;\n    format.align =       format.bytespersec;\n    wav->f =             in;\n    wav->samplesread =   0;\n    wav->bigendian =     opt->endianness;\n    wav->channels =      format.channels;\n    wav->samplesize =    opt->samplesize;\n    wav->totalsamples =  0;\n    wav->channel_permute = malloc(wav->channels * sizeof(int));\n    for (i=0; i < wav->channels; i++)\n      wav->channel_permute[i] = i;\n\n    opt->read_samples = wav_read;\n    opt->readdata = (void *)wav;\n    opt->total_samples_per_channel = 0; /* raw mode, don't bother */\n    return 1;\n}\n\ntypedef struct {\n    audio_read_func real_reader;\n    void *real_readdata;\n    int channels;\n    float scale_factor;\n} scaler;\n\nstatic long read_scaler(void *data, float *buffer, int samples) {\n    scaler *d = data;\n    long in_samples = d->real_reader(d->real_readdata, buffer, samples);\n    int i;\n\n    for(i=0; i < d->channels*in_samples; i++) {\n       buffer[i] *= d->scale_factor;\n    }\n\n    return in_samples;\n}\n\nvoid setup_scaler(oe_enc_opt *opt, float scale) {\n    scaler *d = calloc(1, sizeof(scaler));\n\n    d->real_reader = opt->read_samples;\n    d->real_readdata = opt->readdata;\n\n    opt->read_samples = read_scaler;\n    opt->readdata = d;\n    d->channels = opt->channels;\n    d->scale_factor = scale;\n}\n\ntypedef struct {\n    audio_read_func real_reader;\n    void *real_readdata;\n    ogg_int64_t *original_samples;\n    int channels;\n    int lpc_ptr;\n    int *extra_samples;\n    float *lpc_out;\n} padder;\n\nstatic long read_padder(void *data, float *buffer, int samples) {\n    padder *d = data;\n    long in_samples = d->real_reader(d->real_readdata, buffer, samples);\n    int i, extra=0;\n    const int lpc_order=32;\n\n    if(d->original_samples)*d->original_samples+=in_samples;\n\n    if(in_samples<samples){\n      if(d->lpc_ptr<0){\n        d->lpc_out=calloc(d->channels * *d->extra_samples, sizeof(*d->lpc_out));\n        if(in_samples>lpc_order*2){\n          float *lpc=alloca(lpc_order*sizeof(*lpc));\n          for(i=0;i<d->channels;i++){\n            vorbis_lpc_from_data(buffer+i,lpc,in_samples,lpc_order,d->channels);\n            vorbis_lpc_predict(lpc,buffer+i+(in_samples-lpc_order)*d->channels,\n                               lpc_order,d->lpc_out+i,*d->extra_samples,d->channels);\n          }\n        }\n        d->lpc_ptr=0;\n      }\n      extra=samples-in_samples;\n      if(extra>*d->extra_samples)extra=*d->extra_samples;\n      *d->extra_samples-=extra;\n    }\n    memcpy(buffer+in_samples*d->channels,d->lpc_out+d->lpc_ptr*d->channels,extra*d->channels*sizeof(*buffer));\n    d->lpc_ptr+=extra;\n    return in_samples+extra;\n}\n\nvoid setup_padder(oe_enc_opt *opt,ogg_int64_t *original_samples) {\n    padder *d = calloc(1, sizeof(padder));\n\n    d->real_reader = opt->read_samples;\n    d->real_readdata = opt->readdata;\n\n    opt->read_samples = read_padder;\n    opt->readdata = d;\n    d->channels = opt->channels;\n    d->extra_samples = &opt->extraout;\n    d->original_samples=original_samples;\n    d->lpc_ptr = -1;\n    d->lpc_out = NULL;\n}\n\nvoid clear_padder(oe_enc_opt *opt) {\n    padder *d = opt->readdata;\n\n    opt->read_samples = d->real_reader;\n    opt->readdata = d->real_readdata;\n\n    if(d->lpc_out)free(d->lpc_out);\n    free(d);\n}\n\ntypedef struct {\n    SpeexResamplerState *resampler;\n    audio_read_func real_reader;\n    void *real_readdata;\n    float *bufs;\n    int channels;\n    int bufpos;\n    int bufsize;\n    int done;\n} resampler;\n\nstatic long read_resampled(void *d, float *buffer, int samples)\n{\n    resampler *rs = d;\n    int out_samples=0;\n    float *pcmbuf;\n    int *inbuf;\n    pcmbuf=rs->bufs;\n    inbuf=&rs->bufpos;\n    while(out_samples<samples){\n      int i;\n      int reading, ret;\n      unsigned in_len, out_len;\n      reading=1024-*inbuf;\n      ret=rs->real_reader(rs->real_readdata, pcmbuf+*inbuf*rs->channels, reading);\n      *inbuf+=ret;\n      in_len=*inbuf;\n      out_len=samples-out_samples;\n      speex_resampler_process_interleaved_float(rs->resampler, pcmbuf, &in_len, buffer+out_samples*rs->channels, &out_len);\n      if(ret==0&&in_len==0){\n        for(i=out_samples*rs->channels;i<samples*rs->channels;i++)buffer[i]=0;\n        return out_samples;\n      }\n      out_samples+=out_len;\n      for(i=0;i<rs->channels*(*inbuf-(long int)in_len);i++)pcmbuf[i]=pcmbuf[i+rs->channels*in_len];\n      *inbuf-=in_len;\n    }\n    return out_samples;\n}\n\nint setup_resample(oe_enc_opt *opt, int complexity, long outfreq) {\n    resampler *rs = calloc(1, sizeof(resampler));\n    int err;\n\n    rs->bufsize = 2048; /* Shrug */\n    rs->bufpos = 0;\n\n    rs->real_reader = opt->read_samples;\n    rs->real_readdata = opt->readdata;\n    rs->channels = opt->channels;\n    rs->done = 0;\n    rs->resampler = speex_resampler_init(rs->channels, opt->rate, outfreq, complexity, &err);\n    if(err!=0)fprintf(stderr, _(\"resampler error: %s\\n\"), speex_resampler_strerror(err));\n\n    opt->skip+=speex_resampler_get_output_latency(rs->resampler);\n\n    rs->bufs = malloc(sizeof(float) * rs->bufsize * opt->channels);\n\n    opt->read_samples = read_resampled;\n    opt->readdata = rs;\n    if(opt->total_samples_per_channel)\n        opt->total_samples_per_channel = (int)((float)opt->total_samples_per_channel *\n            ((float)outfreq/(float)opt->rate));\n    opt->rate = outfreq;\n\n    return 0;\n}\n\nvoid clear_resample(oe_enc_opt *opt) {\n    resampler *rs = opt->readdata;\n\n    opt->read_samples = rs->real_reader;\n    opt->readdata = rs->real_readdata;\n    speex_resampler_destroy(rs->resampler);\n\n    free(rs->bufs);\n\n    free(rs);\n}\n\ntypedef struct {\n    audio_read_func real_reader;\n    void *real_readdata;\n    float *bufs;\n    float *matrix;\n    int in_channels;\n    int out_channels;\n} downmix;\n\nstatic long read_downmix(void *data, float *buffer, int samples)\n{\n    downmix *d = data;\n    long in_samples = d->real_reader(d->real_readdata, d->bufs, samples);\n    int i,j,k,in_ch,out_ch;\n\n    in_ch=d->in_channels;\n    out_ch=d->out_channels;\n\n    for(i=0;i<in_samples;i++){\n      for(j=0;j<out_ch;j++){\n        float *samp;\n        samp=&buffer[i*out_ch+j];\n        *samp=0;\n        for(k=0;k<in_ch;k++){\n          *samp+=d->bufs[i*in_ch+k]*d->matrix[in_ch*j+k];\n        }\n      }\n    }\n    return in_samples;\n}\n\nint setup_downmix(oe_enc_opt *opt, int out_channels) {\n    static const float stupid_matrix[7][8][2]={\n      /*2*/  {{1,0},{0,1}},\n      /*3*/  {{1,0},{0.7071f,0.7071f},{0,1}},\n      /*4*/  {{1,0},{0,1},{0.866f,0.5f},{0.5f,0.866f}},\n      /*5*/  {{1,0},{0.7071f,0.7071f},{0,1},{0.866f,0.5f},{0.5f,0.866f}},\n      /*6*/  {{1,0},{0.7071f,0.7071f},{0,1},{0.866f,0.5f},{0.5f,0.866f},{0.7071f,0.7071f}},\n      /*7*/  {{1,0},{0.7071f,0.7071f},{0,1},{0.866f,0.5f},{0.5f,0.866f},{0.6123f,0.6123f},{0.7071f,0.7071f}},\n      /*8*/  {{1,0},{0.7071f,0.7071f},{0,1},{0.866f,0.5f},{0.5f,0.866f},{0.866f,0.5f},{0.5f,0.866f},{0.7071f,0.7071f}},\n    };\n    float sum;\n    downmix *d;\n    int i,j;\n\n    if(opt->channels<=out_channels || out_channels>2 || (out_channels==2&&opt->channels>8) || opt->channels<=0 || out_channels<=0) {\n        fprintf(stderr, \"Downmix must actually downmix and only knows mono/stereo out.\\n\");\n        if(opt->channels>8)fprintf(stderr, \"Downmix also only knows how to mix >8ch to mono.\\n\");\n        return 0;\n    }\n\n    d = calloc(1, sizeof(downmix));\n    d->bufs = malloc(sizeof(float)*opt->channels*4096);\n    d->matrix = malloc(sizeof(float)*opt->channels*out_channels);\n    d->real_reader = opt->read_samples;\n    d->real_readdata = opt->readdata;\n    d->in_channels=opt->channels;\n    d->out_channels=out_channels;\n\n    if(out_channels==1&&d->in_channels>8){\n      for(i=0;i<d->in_channels;i++)d->matrix[i]=1.0f/d->in_channels;\n    }else if(out_channels==2){\n      for(j=0;j<d->out_channels;j++)\n        for(i=0;i<d->in_channels;i++)d->matrix[d->in_channels*j+i]=\n          stupid_matrix[opt->channels-2][i][j];\n    }else{\n      for(i=0;i<d->in_channels;i++)d->matrix[i]=\n        (stupid_matrix[opt->channels-2][i][0])+\n        (stupid_matrix[opt->channels-2][i][1]);\n    }\n    sum=0;\n    for(i=0;i<d->in_channels*d->out_channels;i++)sum+=d->matrix[i];\n    sum=(float)out_channels/sum;\n    for(i=0;i<d->in_channels*d->out_channels;i++)d->matrix[i]*=sum;\n    opt->read_samples = read_downmix;\n    opt->readdata = d;\n\n    opt->channels = out_channels;\n    return out_channels;\n}\n\nvoid clear_downmix(oe_enc_opt *opt) {\n    downmix *d = opt->readdata;\n\n    opt->read_samples = d->real_reader;\n    opt->readdata = d->real_readdata;\n    opt->channels = d->in_channels; /* other things in cleanup rely on this */\n\n    free(d->bufs);\n    free(d->matrix);\n    free(d);\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/diag_range.c",
    "content": "/* Copyright (C)2012 Xiph.Org Foundation\n   Copyright (C)2012 Gregory Maxwell\n   Copyright (C)2012 Jean-Marc Valin\n   File: diag_range.c\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n\n   - Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n   - Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR\n   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifdef HAVE_CONFIG_H\n# include \"config.h\"\n#endif\n\n#ifdef _WIN32\n#define I64FORMAT \"I64d\"\n#define I64uFORMAT \"I64u\"\n#else\n#define I64FORMAT \"lld\"\n#define I64uFORMAT \"llu\"\n#endif\n\n#include <stdio.h>\n#include <opus.h>\n#include \"diag_range.h\"\n\n/*This is some non-exported code copied wholesale from libopus.\n *Normal programs shouldn't need these functions, but we use them here\n *to parse deep inside multichannel packets in order to get diagnostic\n *data for save-range. If you're thinking about copying it and you aren't\n *making an opus stream diagnostic tool, you're probably doing something\n *wrong.*/\nstatic int parse_size(const unsigned char *data, opus_int32 len, short *size)\n{\n   if (len<1)\n   {\n      *size = -1;\n      return -1;\n   } else if (data[0]<252)\n   {\n      *size = data[0];\n      return 1;\n   } else if (len<2)\n   {\n      *size = -1;\n      return -1;\n   } else {\n      *size = 4*data[1] + data[0];\n      return 2;\n   }\n}\n\nstatic int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,\n      int self_delimited, unsigned char *out_toc,\n      const unsigned char *frames[48], short size[48], int *payload_offset)\n{\n   int i, bytes;\n   int count;\n   int cbr;\n   unsigned char ch, toc;\n   int framesize;\n   int last_size;\n   const unsigned char *data0 = data;\n\n   if (size==NULL)\n      return OPUS_BAD_ARG;\n\n   framesize = opus_packet_get_samples_per_frame(data, 48000);\n\n   cbr = 0;\n   toc = *data++;\n   len--;\n   last_size = len;\n   switch (toc&0x3)\n   {\n   /* One frame */\n   case 0:\n      count=1;\n      break;\n   /* Two CBR frames */\n   case 1:\n      count=2;\n      cbr = 1;\n      if (!self_delimited)\n      {\n         if (len&0x1)\n            return OPUS_INVALID_PACKET;\n         size[0] = last_size = len/2;\n      }\n      break;\n   /* Two VBR frames */\n   case 2:\n      count = 2;\n      bytes = parse_size(data, len, size);\n      len -= bytes;\n      if (size[0]<0 || size[0] > len)\n         return OPUS_INVALID_PACKET;\n      data += bytes;\n      last_size = len-size[0];\n      break;\n   /* Multiple CBR/VBR frames (from 0 to 120 ms) */\n   case 3:\n      if (len<1)\n         return OPUS_INVALID_PACKET;\n      /* Number of frames encoded in bits 0 to 5 */\n      ch = *data++;\n      count = ch&0x3F;\n      if (count <= 0 || framesize*count > 5760)\n         return OPUS_INVALID_PACKET;\n      len--;\n      /* Padding flag is bit 6 */\n      if (ch&0x40)\n      {\n         int padding=0;\n         int p;\n         do {\n            if (len<=0)\n               return OPUS_INVALID_PACKET;\n            p = *data++;\n            len--;\n            padding += p==255 ? 254: p;\n         } while (p==255);\n         len -= padding;\n      }\n      if (len<0)\n         return OPUS_INVALID_PACKET;\n      /* VBR flag is bit 7 */\n      cbr = !(ch&0x80);\n      if (!cbr)\n      {\n         /* VBR case */\n         last_size = len;\n         for (i=0;i<count-1;i++)\n         {\n            bytes = parse_size(data, len, size+i);\n            len -= bytes;\n            if (size[i]<0 || size[i] > len)\n               return OPUS_INVALID_PACKET;\n            data += bytes;\n            last_size -= bytes+size[i];\n         }\n         if (last_size<0)\n            return OPUS_INVALID_PACKET;\n      } else if (!self_delimited)\n      {\n         /* CBR case */\n         last_size = len/count;\n         if (last_size*count!=len)\n            return OPUS_INVALID_PACKET;\n         for (i=0;i<count-1;i++)\n            size[i] = last_size;\n      }\n      break;\n   }\n   /* Self-delimited framing has an extra size for the last frame. */\n   if (self_delimited)\n   {\n      bytes = parse_size(data, len, size+count-1);\n      len -= bytes;\n      if (size[count-1]<0 || size[count-1] > len)\n         return OPUS_INVALID_PACKET;\n      data += bytes;\n      /* For CBR packets, apply the size to all the frames. */\n      if (cbr)\n      {\n         if (size[count-1]*count > len)\n            return OPUS_INVALID_PACKET;\n         for (i=0;i<count-1;i++)\n            size[i] = size[count-1];\n      } else if(size[count-1] > last_size)\n         return OPUS_INVALID_PACKET;\n   } else\n   {\n      /* Because it's not encoded explicitly, it's possible the size of the\n         last packet (or all the packets, for the CBR case) is larger than\n         1275. Reject them here.*/\n      if (last_size > 1275)\n         return OPUS_INVALID_PACKET;\n      size[count-1] = last_size;\n   }\n\n   if (frames)\n   {\n      for (i=0;i<count;i++)\n      {\n         frames[i] = data;\n         data += size[i];\n      }\n   }\n\n   if (out_toc)\n      *out_toc = toc;\n\n   if (payload_offset)\n      *payload_offset = data-data0;\n\n   return count;\n}\n\nvoid save_range(FILE *frange, int frame_size, unsigned char *packet, int nbBytes, opus_uint32 *rngs, int nb_streams){\n  int i, parsed_size;\n  const unsigned char *subpkt;\n  static const char *bw_strings[5]={\"NB\",\"MB\",\"WB\",\"SWB\",\"FB\"};\n  static const char *mode_strings[3]={\"LP\",\"HYB\",\"MDCT\"};\n  fprintf(frange,\"%d, %d, \",frame_size,nbBytes);\n  subpkt=packet;\n  parsed_size=nbBytes;\n  for(i=0;i<nb_streams;i++){\n    int j,payload_offset,nf;\n    const unsigned char *frames[48];\n    unsigned char toc;\n    short size[48];\n    payload_offset=0;\n    nf=opus_packet_parse_impl(subpkt,parsed_size,i+1!=nb_streams,\n      &toc,frames,size,&payload_offset);\n    fprintf(frange,\"[[%d\",(int)(frames[0]-subpkt));\n    for(j=0;j<nf;j++)fprintf(frange,\", %d\",size[j]);\n    fprintf(frange,\"], %s, %s, %c, %d\",\n       mode_strings[((((subpkt[0]>>3)+48)&92)+4)>>5],\n       bw_strings[opus_packet_get_bandwidth(subpkt)-OPUS_BANDWIDTH_NARROWBAND],\n       subpkt[0]&4?'S':'M',opus_packet_get_samples_per_frame(subpkt,48000));\n    fprintf(frange,\", %\" I64uFORMAT \"]%s\",(unsigned long long)rngs[i],i+1==nb_streams?\"\\n\":\", \");\n    parsed_size-=payload_offset;\n    subpkt+=payload_offset;\n  }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/diag_range.h",
    "content": "/* Copyright (C)2012 Xiph.Org Foundation\n   File: diag_range.h\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n\n   - Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n   - Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR\n   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\nvoid save_range(FILE *frange, int frame_size, unsigned char *packet, int nbBytes, opus_uint32 *rngs, int nb_streams);\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/info_opus.c",
    "content": "/* Copyright (C)2012 Gregory Maxwell\n   File: info_opus.c\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n\n   - Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n   - Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR\n   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifdef HAVE_CONFIG_H\n#include <config.h>\n#endif\n\n#include <stdlib.h>\n#include <string.h>\n\n#include <ogg/ogg.h>\n\n#ifndef OPUSTOOLS\n# include \"ogginfo2.h\"\n#else\n# include \"opusinfo.h\"\n#endif\n#include \"opus_header.h\"\n#include \"info_opus.h\"\n\n/* From libopus, src/opus_decode.c */\nstatic int packet_get_samples_per_frame(const unsigned char *data, ogg_int32_t Fs)\n{\n   int audiosize;\n   if (data[0]&0x80)\n   {\n      audiosize = ((data[0]>>3)&0x3);\n      audiosize = (Fs<<audiosize)/400;\n   } else if ((data[0]&0x60) == 0x60)\n   {\n      audiosize = (data[0]&0x08) ? Fs/50 : Fs/100;\n   } else {\n      audiosize = ((data[0]>>3)&0x3);\n      if (audiosize == 3)\n         audiosize = Fs*60/1000;\n      else\n         audiosize = (Fs<<audiosize)/100;\n   }\n   return audiosize;\n}\n\n/* From libopus, src/opus_decode.c */\nstatic int packet_get_nb_frames(const unsigned char packet[], ogg_int32_t len)\n{\n   int count;\n   if (len<1)\n      return -1;\n   count = packet[0]&0x3;\n   if (count==0)\n      return 1;\n   else if (count!=3)\n      return 2;\n   else if (len<2)\n      return -4;\n   else\n      return packet[1]&0x3F;\n}\n\n#define readle32(buf, base) (((buf[base+3]<<24)&0xff000000)| \\\n                             ((buf[base+2]<<16)&0xff0000)| \\\n                             ((buf[base+1]<<8)&0xff00)| \\\n                              (buf[base]&0xff))\n\nvoid info_opus_process(stream_processor *stream, ogg_page *page )\n{\n    ogg_packet packet;\n    ogg_int64_t page_samples=0;\n    misc_opus_info *inf = stream->data;\n    int header=0, packets=0;\n    int res;\n\n    ogg_stream_pagein(&stream->os, page);\n    if(inf->doneheaders < 2)\n        header = 1;\n    inf->last_eos = ogg_page_eos(page);\n\n    while(1) {\n        ogg_int32_t spp;\n        res = ogg_stream_packetout(&stream->os, &packet);\n        if(res < 0) {\n           oi_warn(_(\"WARNING: discontinuity in stream (%d)\\n\"), stream->num);\n           continue;\n        }\n        else if (res == 0)\n            break;\n\n        packets++;\n        if(inf->doneheaders < 2) {\n            if(inf->doneheaders==0 && opus_header_parse(packet.packet,packet.bytes,&inf->oh)!=1) {\n                oi_warn(_(\"WARNING: Could not decode Opus header \"\n                       \"packet %d - invalid Opus stream (%d)\\n\"),\n                        inf->doneheaders, stream->num);\n                continue;\n            } else if (inf->doneheaders==0){\n                if(inf->oh.preskip<120)oi_warn(_(\"WARNING: Implausibly low preskip in Opus stream (%d)\\n\"),stream->num);\n            }\n            if(inf->doneheaders==1 && (packet.bytes<8 || memcmp(packet.packet, \"OpusTags\",8)!=0)) {\n               oi_warn(_(\"WARNING: Could not decode OpusTags header \"\n                       \"packet %d - invalid Opus stream (%d)\\n\"),\n                        inf->doneheaders, stream->num);\n                continue;\n            } else if (inf->doneheaders==1) {\n                char *tmp;\n                char *c=(char *)packet.packet;\n                int length, len, i, nb_fields;\n\n                length=packet.bytes;\n                if (length<(8+4+4)) {\n                    oi_warn(_(\"Invalid/corrupted comments in stream %d\\n\"),stream->num);\n                    continue;\n                }\n                c += 8;\n                len=readle32(c, 0);\n                c+=4;\n                if (len < 0 || len>(length-16)) {\n                    oi_warn(_(\"Invalid/corrupted comments in stream %d\\n\"),stream->num);\n                    continue;\n                }\n                tmp=calloc(len+1,1);\n                memcpy(tmp,c,len);\n                oi_info(_(\"Encoded with %s\\n\"),tmp);\n                free(tmp);\n                c+=len;\n                /*The -16 check above makes sure we can read this.*/\n                nb_fields=readle32(c, 0);\n                c+=4;\n                length-=16+len;\n                if (nb_fields < 0 || nb_fields>(length>>2)) {\n                    oi_warn(_(\"Invalid/corrupted comments in stream %d\\n\"),stream->num);\n                    continue;\n                }\n                if(nb_fields)oi_info(_(\"User comments section follows...\\n\"));\n                for (i=0;i<nb_fields;i++) {\n                    char *comment;\n                    if (length<4) {\n                        oi_warn(_(\"Invalid/corrupted comments in stream %d\\n\"),stream->num);\n                        break;\n                    }\n                    len=readle32(c, 0);\n                    c+=4;\n                    length-=4;\n                    if (len < 0 || len>length) {\n                        oi_warn(_(\"Invalid/corrupted comments in stream %d\\n\"),stream->num);\n                        break;\n                    }\n                    /*check_xiph_comment expects a null terminated comment*/\n                    comment=malloc((len+1)*sizeof(char));\n                    memcpy(comment,c,len);\n                    comment[len]=0;\n                    check_xiph_comment(stream, i, comment, len);\n                    free(comment);\n                    c+=len;\n                    length-=len;\n                }\n            }\n\n            inf->doneheaders++;\n            continue;\n        }\n        if(packet.bytes>=2 && memcmp(packet.packet, \"Op\",2)==0) {\n            oi_warn(_(\"WARNING: Invalid packet or misplaced header in stream %d\\n\"),stream->num);\n            continue;\n        }\n        if(packet.bytes<1) {\n            oi_warn(_(\"WARNING: Invalid zero byte packet in stream %d\\n\"),stream->num);\n            continue;\n        }\n        spp = packet_get_nb_frames(packet.packet,packet.bytes);\n        if(spp<1 || spp>48) {\n            oi_warn(_(\"WARNING: Invalid packet TOC in stream %d\\n\"),stream->num);\n            continue;\n        }\n        spp *= packet_get_samples_per_frame(packet.packet,48000);\n        if(spp<120 || spp>5760 || (spp%120)!=0) {\n            oi_warn(_(\"WARNING: Invalid packet TOC in stream %d\\n\"),stream->num);\n            continue;\n        }\n        inf->total_samples += spp;\n        page_samples += spp;\n        inf->total_packets++;\n        inf->last_packet_duration = spp;\n        if(inf->max_packet_duration<spp)inf->max_packet_duration=spp;\n        if(inf->min_packet_duration>spp)inf->min_packet_duration=spp;\n        if(inf->max_packet_bytes<packet.bytes)inf->max_packet_bytes=packet.bytes;\n        if(inf->min_packet_bytes>packet.bytes)inf->min_packet_bytes=packet.bytes;\n    }\n\n    if(!header) {\n        ogg_int64_t gp = ogg_page_granulepos(page);\n        if(gp > 0) {\n            if(gp < inf->lastgranulepos)\n                oi_warn(_(\"WARNING: granulepos in stream %d decreases from %\"\n                        I64FORMAT \" to %\" I64FORMAT \"\\n\" ),\n                        stream->num, inf->lastgranulepos, gp);\n            if(inf->lastgranulepos==0 && inf->firstgranule==-1) {\n                /*First timed page, now we can recover the start time.*/\n                inf->firstgranule = gp-inf->total_samples;\n                if(inf->firstgranule<0) {\n                  /*There shouldn't be any negative samples after counting the samples in the page backwards\n                    from the first GP, but if this is the last page of the stream there may need to be to trim.*/\n                  if(!ogg_page_eos(page))oi_warn(_(\"WARNING: Samples with negative granpos in stream %d\\n\"),stream->num);\n                  else inf->firstgranule=0;\n                }\n            }\n            if(inf->total_samples<gp-inf->firstgranule)oi_warn(_(\"WARNING: Sample count behind granule (%\" I64FORMAT \">%\" I64FORMAT \") in stream %d\\n\"),\n                (long long)inf->total_samples,(long long)(gp-inf->firstgranule),stream->num);\n            if(!ogg_page_eos(page) && (inf->total_samples>gp-inf->firstgranule))\n                oi_warn(_(\"WARNING: Sample count ahead of granule (%\" I64FORMAT \">%\" I64FORMAT \") in stream %d\\n\"),\n                (long long)inf->total_samples,(long long)(gp-inf->firstgranule),stream->num);\n            inf->lastlastgranulepos = inf->lastgranulepos;\n            inf->lastgranulepos = gp;\n            if(!packets)\n                oi_warn(_(\"WARNING: Page with positive granpos (%\" I64FORMAT \") on a page with no completed packets in stream %d\\n\"),gp,stream->num);\n        }\n        else if(packets) {\n            /* Only do this if we saw at least one packet ending on this page.\n             * It's legal (though very unusual) to have no packets in a page at\n             * all - this is occasionally used to have an empty EOS page */\n            oi_warn(_(\"Negative or zero granulepos (%\" I64FORMAT \") on Opus stream outside of headers. This file was created by a buggy encoder\\n\"), gp);\n        }\n        inf->overhead_bytes += page->header_len;\n        if(page_samples)inf->last_page_duration = page_samples;\n        if(inf->max_page_duration<page_samples)inf->max_page_duration=page_samples;\n        if(inf->min_page_duration>page_samples)inf->min_page_duration=page_samples;\n        inf->total_pages++;\n    } else {\n        /* Headers and metadata are pure overhead. */\n        inf->overhead_bytes += page->header_len + page->body_len;\n    }\n    inf->bytes += page->header_len + page->body_len;\n}\n\nvoid info_opus_end(stream_processor *stream)\n{\n    misc_opus_info *inf = stream->data;\n\n    oi_info(_(\"Opus stream %d:\\n\"),stream->num);\n\n    if(inf && inf->total_packets>0){\n        int i;\n        long minutes, seconds, milliseconds;\n        double time;\n        time = (inf->lastgranulepos-inf->firstgranule-inf->oh.preskip) / 48000.;\n        if(time<=0)time=0;\n        minutes = (long)(time) / 60;\n        seconds = (long)(time - minutes*60);\n        milliseconds = (long)((time - minutes*60 - seconds)*1000);\n        if(inf->lastgranulepos-inf->firstgranule<inf->oh.preskip)\n           oi_error(_(\"\\tERROR: stream %d has a negative duration: %\" I64FORMAT \"-%\" I64FORMAT \"-%d=%\" I64FORMAT \"\\n\"),stream->num,\n           inf->lastgranulepos,inf->firstgranule,inf->oh.preskip,inf->lastgranulepos-inf->firstgranule-inf->oh.preskip);\n        if((inf->total_samples-inf->last_page_duration)>(inf->lastgranulepos-inf->firstgranule))\n           oi_error(_(\"\\tERROR: stream %d has interior holes or more than one page of end trimming\\n\"),stream->num);\n        if(inf->last_eos &&( (inf->last_page_duration-inf->last_packet_duration)>(inf->lastgranulepos-inf->lastlastgranulepos)))\n           oi_warn(_(\"\\tWARNING: stream %d has more than one packet of end trimming\\n\"),stream->num);\n        if(inf->max_page_duration>=240000)\n           oi_warn(_(\"\\tWARNING: stream %d has high muxing delay\\n\"),stream->num);\n        oi_info(_(\"\\tPre-skip: %d\\n\"),inf->oh.preskip);\n        oi_info(_(\"\\tPlayback gain: %gdB\\n\"),inf->oh.gain/256.);\n        oi_info(_(\"\\tChannels: %d\\n\"),inf->oh.channels);\n        if(inf->oh.input_sample_rate)oi_info(_(\"\\tOriginal sample rate: %dHz\\n\"),inf->oh.input_sample_rate);\n        if(inf->oh.nb_streams>1)oi_info(_(\"\\tStreams: %d, Coupled: %d\\n\"),inf->oh.nb_streams,inf->oh.nb_coupled);\n        if(inf->oh.channel_mapping>0) {\n          oi_info(_(\"\\tChannel Mapping family: %d Map:\"),inf->oh.channel_mapping);\n          for(i=0;i<inf->oh.channels;i++)oi_info(\"%s%d%s\",i==0?\" [\":\", \",inf->oh.stream_map[i],i==inf->oh.channels-1?\"]\\n\":\"\");\n        }\n        if(inf->total_packets)oi_info(_(\"\\tPacket duration: %6.1fms (max), %6.1fms (avg), %6.1fms (min)\\n\"),\n            inf->max_packet_duration/48.,inf->total_samples/(double)inf->total_packets/48.,inf->min_packet_duration/48.);\n        if(inf->total_pages)oi_info(_(\"\\tPage duration: %8.1fms (max), %6.1fms (avg), %6.1fms (min)\\n\"),\n            inf->max_page_duration/48.,inf->total_samples/(double)inf->total_pages/48.,inf->min_page_duration/48.);\n        oi_info(_(\"\\tTotal data length: %\" I64FORMAT \" bytes (overhead: %0.3g%%)\\n\"),inf->bytes,(double)inf->overhead_bytes/inf->bytes*100.);\n        oi_info(_(\"\\tPlayback length: %ldm:%02ld.%03lds\\n\"), minutes, seconds, milliseconds);\n        oi_info(_(\"\\tAverage bitrate: %0.4g kb/s, w/o overhead: %.04g kb/s%s\\n\"),time<=0?0:inf->bytes*8/time/1000.0,\n            time<=0?0:(inf->bytes-inf->overhead_bytes)*8/time/1000.0,\n            (inf->min_packet_duration==inf->max_packet_duration)&&(inf->min_packet_bytes==inf->max_packet_bytes)?\" (hard-CBR)\":\"\");\n    } else {\n      oi_warn(_(\"\\tWARNING: stream %d is empty\\n\"),stream->num);\n    }\n    free(stream->data);\n}\n\nvoid info_opus_start(stream_processor *stream)\n{\n    misc_opus_info *oinfo;\n\n    stream->type = \"opus\";\n    stream->process_page = info_opus_process;\n    stream->process_end = info_opus_end;\n\n    stream->data = calloc(1, sizeof(misc_opus_info));\n\n    oinfo = stream->data;\n    oinfo->firstgranule=-1;\n    oinfo->min_packet_duration=5760;\n    oinfo->min_page_duration=5760*255;\n    oinfo->min_packet_bytes=2147483647;\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/info_opus.h",
    "content": "/* Copyright (C)2012 Gregory Maxwell\n   File: info_opus.h\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n\n   - Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n   - Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR\n   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\ntypedef struct {\n    OpusHeader  oh;\n    ogg_int64_t bytes;\n    ogg_int64_t overhead_bytes;\n    ogg_int64_t lastlastgranulepos;\n    ogg_int64_t lastgranulepos;\n    ogg_int64_t firstgranule;\n    ogg_int64_t total_samples;\n    ogg_int64_t total_packets;\n    ogg_int64_t total_pages;\n    ogg_int32_t last_packet_duration;\n    ogg_int32_t last_page_duration;\n    ogg_int32_t max_page_duration;\n    ogg_int32_t min_page_duration;\n    ogg_int32_t max_packet_duration;\n    ogg_int32_t min_packet_duration;\n    ogg_int32_t max_packet_bytes;\n    ogg_int32_t min_packet_bytes;\n    int last_eos;\n\n    int doneheaders;\n} misc_opus_info;\n\nvoid info_opus_start(stream_processor *stream);\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/lpc.c",
    "content": "/********************************************************************\n *                                                                  *\n * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *\n * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *\n * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *\n * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *\n *                                                                  *\n * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009             *\n * by the Xiph.Org Foundation http://www.xiph.org/                  *\n *                                                                  *\n ********************************************************************\n\n  function: LPC low level routines\n  last mod: $Id: lpc.c 16227 2009-07-08 06:58:46Z xiphmont $\n\n ********************************************************************/\n\n/* Some of these routines (autocorrelator, LPC coefficient estimator)\n   are derived from code written by Jutta Degener and Carsten Bormann;\n   thus we include their copyright below.  The entirety of this file\n   is freely redistributable on the condition that both of these\n   copyright notices are preserved without modification.  */\n\n/* Preserved Copyright: *********************************************/\n\n/* Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann,\nTechnische Universita\"t Berlin\n\nAny use of this software is permitted provided that this notice is not\nremoved and that neither the authors nor the Technische Universita\"t\nBerlin are deemed to have made any representations as to the\nsuitability of this software for any purpose nor are held responsible\nfor any defects of this software. THERE IS ABSOLUTELY NO WARRANTY FOR\nTHIS SOFTWARE.\n\nAs a matter of courtesy, the authors request to be informed about uses\nthis software has found, about bugs in this software, and about any\nimprovements that may be of general interest.\n\nBerlin, 28.11.1994\nJutta Degener\nCarsten Bormann\n\n*********************************************************************/\n\n#include <stdlib.h>\n#include <string.h>\n#include <math.h>\n#include \"stack_alloc.h\"\n#include \"lpc.h\"\n\n/* Autocorrelation LPC coeff generation algorithm invented by\n   N. Levinson in 1947, modified by J. Durbin in 1959. */\n\n/* Input : n elements of time doamin data\n   Output: m lpc coefficients, excitation energy */\n\nfloat vorbis_lpc_from_data(float *data,float *lpci,int n,int m,int stride){\n  double *aut=alloca(sizeof(*aut)*(m+1));\n  double *lpc=alloca(sizeof(*lpc)*(m));\n  double error;\n  double epsilon;\n  int i,j;\n\n  /* autocorrelation, p+1 lag coefficients */\n  j=m+1;\n  while(j--){\n    double d=0; /* double needed for accumulator depth */\n    for(i=j;i<n;i++)d+=(double)data[i*stride]*data[(i-j)*stride];\n    aut[j]=d;\n  }\n\n  /* Generate lpc coefficients from autocorr values */\n\n  /* set our noise floor to about -100dB */\n  error=aut[0] * (1. + 1e-10);\n  epsilon=1e-9*aut[0]+1e-10;\n\n  for(i=0;i<m;i++){\n    double r= -aut[i+1];\n\n    if(error<epsilon){\n      memset(lpc+i,0,(m-i)*sizeof(*lpc));\n      goto done;\n    }\n\n    /* Sum up this iteration's reflection coefficient; note that in\n       Vorbis we don't save it.  If anyone wants to recycle this code\n       and needs reflection coefficients, save the results of 'r' from\n       each iteration. */\n\n    for(j=0;j<i;j++)r-=lpc[j]*aut[i-j];\n    r/=error;\n\n    /* Update LPC coefficients and total error */\n\n    lpc[i]=r;\n    for(j=0;j<i/2;j++){\n      double tmp=lpc[j];\n\n      lpc[j]+=r*lpc[i-1-j];\n      lpc[i-1-j]+=r*tmp;\n    }\n    if(i&1)lpc[j]+=lpc[j]*r;\n\n    error*=1.-r*r;\n\n  }\n\n done:\n\n  /* slightly damp the filter */\n  {\n    double g = .99;\n    double damp = g;\n    for(j=0;j<m;j++){\n      lpc[j]*=damp;\n      damp*=g;\n    }\n  }\n\n  for(j=0;j<m;j++)lpci[j]=(float)lpc[j];\n\n  /* we need the error value to know how big an impulse to hit the\n     filter with later */\n\n  return error;\n}\n\nvoid vorbis_lpc_predict(float *coeff,float *prime,int m,\n                     float *data,long n,int stride){\n\n  /* in: coeff[0...m-1] LPC coefficients\n         prime[0...m-1] initial values (allocated size of n+m-1)\n    out: data[0...n-1] data samples */\n\n  long i,j,o,p;\n  float y;\n  float *work=alloca(sizeof(*work)*(m+n));\n\n  if(!prime)\n    for(i=0;i<m;i++)\n      work[i]=0.f;\n  else\n    for(i=0;i<m;i++)\n      work[i]=prime[i*stride];\n\n  for(i=0;i<n;i++){\n    y=0;\n    o=i;\n    p=m;\n    for(j=0;j<m;j++)\n      y-=work[o++]*coeff[--p];\n\n    data[i*stride]=work[o]=y;\n  }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/lpc.h",
    "content": "/********************************************************************\n *                                                                  *\n * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *\n * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *\n * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *\n * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *\n *                                                                  *\n * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007             *\n * by the Xiph.Org Foundation http://www.xiph.org/                  *\n *                                                                  *\n ********************************************************************\n\n  function: LPC low level routines\n  last mod: $Id: lpc.h 16037 2009-05-26 21:10:58Z xiphmont $\n\n ********************************************************************/\n\n#ifndef _V_LPC_H_\n#define _V_LPC_H_\n\n/* simple linear scale LPC code */\nextern float vorbis_lpc_from_data(float *data,float *lpc,int n,int m,int stride);\n\nextern void vorbis_lpc_predict(float *coeff,float *prime,int m,\n                               float *data,long n,int stride);\n\n#endif\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/opus_header.c",
    "content": "/* Copyright (C)2012 Xiph.Org Foundation\n   File: opus_header.c\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n\n   - Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n   - Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR\n   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifdef HAVE_CONFIG_H\n# include \"config.h\"\n#endif\n\n#include \"opus_header.h\"\n#include <string.h>\n#include <stdio.h>\n\n/* Header contents:\n  - \"OpusHead\" (64 bits)\n  - version number (8 bits)\n  - Channels C (8 bits)\n  - Pre-skip (16 bits)\n  - Sampling rate (32 bits)\n  - Gain in dB (16 bits, S7.8)\n  - Mapping (8 bits, 0=single stream (mono/stereo) 1=Vorbis mapping,\n             2..254: reserved, 255: multistream with no mapping)\n\n  - if (mapping != 0)\n     - N = totel number of streams (8 bits)\n     - M = number of paired streams (8 bits)\n     - C times channel origin\n          - if (C<2*M)\n             - stream = byte/2\n             - if (byte&0x1 == 0)\n                 - left\n               else\n                 - right\n          - else\n             - stream = byte-M\n*/\n\ntypedef struct {\n   unsigned char *data;\n   int maxlen;\n   int pos;\n} Packet;\n\ntypedef struct {\n   const unsigned char *data;\n   int maxlen;\n   int pos;\n} ROPacket;\n\nstatic int write_uint32(Packet *p, ogg_uint32_t val)\n{\n   if (p->pos>p->maxlen-4)\n      return 0;\n   p->data[p->pos  ] = (val    ) & 0xFF;\n   p->data[p->pos+1] = (val>> 8) & 0xFF;\n   p->data[p->pos+2] = (val>>16) & 0xFF;\n   p->data[p->pos+3] = (val>>24) & 0xFF;\n   p->pos += 4;\n   return 1;\n}\n\nstatic int write_uint16(Packet *p, ogg_uint16_t val)\n{\n   if (p->pos>p->maxlen-2)\n      return 0;\n   p->data[p->pos  ] = (val    ) & 0xFF;\n   p->data[p->pos+1] = (val>> 8) & 0xFF;\n   p->pos += 2;\n   return 1;\n}\n\nstatic int write_chars(Packet *p, const unsigned char *str, int nb_chars)\n{\n   int i;\n   if (p->pos>p->maxlen-nb_chars)\n      return 0;\n   for (i=0;i<nb_chars;i++)\n      p->data[p->pos++] = str[i];\n   return 1;\n}\n\nstatic int read_uint32(ROPacket *p, ogg_uint32_t *val)\n{\n   if (p->pos>p->maxlen-4)\n      return 0;\n   *val =  (ogg_uint32_t)p->data[p->pos  ];\n   *val |= (ogg_uint32_t)p->data[p->pos+1]<< 8;\n   *val |= (ogg_uint32_t)p->data[p->pos+2]<<16;\n   *val |= (ogg_uint32_t)p->data[p->pos+3]<<24;\n   p->pos += 4;\n   return 1;\n}\n\nstatic int read_uint16(ROPacket *p, ogg_uint16_t *val)\n{\n   if (p->pos>p->maxlen-2)\n      return 0;\n   *val =  (ogg_uint16_t)p->data[p->pos  ];\n   *val |= (ogg_uint16_t)p->data[p->pos+1]<<8;\n   p->pos += 2;\n   return 1;\n}\n\nstatic int read_chars(ROPacket *p, unsigned char *str, int nb_chars)\n{\n   int i;\n   if (p->pos>p->maxlen-nb_chars)\n      return 0;\n   for (i=0;i<nb_chars;i++)\n      str[i] = p->data[p->pos++];\n   return 1;\n}\n\nint opus_header_parse(const unsigned char *packet, int len, OpusHeader *h)\n{\n   int i;\n   char str[9];\n   ROPacket p;\n   unsigned char ch;\n   ogg_uint16_t shortval;\n\n   p.data = packet;\n   p.maxlen = len;\n   p.pos = 0;\n   str[8] = 0;\n   if (len<19)return 0;\n   read_chars(&p, (unsigned char*)str, 8);\n   if (memcmp(str, \"OpusHead\", 8)!=0)\n      return 0;\n\n   if (!read_chars(&p, &ch, 1))\n      return 0;\n   h->version = ch;\n   if((h->version&240) != 0) /* Only major version 0 supported. */\n      return 0;\n\n   if (!read_chars(&p, &ch, 1))\n      return 0;\n   h->channels = ch;\n   if (h->channels == 0)\n      return 0;\n\n   if (!read_uint16(&p, &shortval))\n      return 0;\n   h->preskip = shortval;\n\n   if (!read_uint32(&p, &h->input_sample_rate))\n      return 0;\n\n   if (!read_uint16(&p, &shortval))\n      return 0;\n   h->gain = (short)shortval;\n\n   if (!read_chars(&p, &ch, 1))\n      return 0;\n   h->channel_mapping = ch;\n\n   if (h->channel_mapping != 0)\n   {\n      if (!read_chars(&p, &ch, 1))\n         return 0;\n\n      if (ch<1)\n         return 0;\n      h->nb_streams = ch;\n\n      if (!read_chars(&p, &ch, 1))\n         return 0;\n\n      if (ch>h->nb_streams || (ch+h->nb_streams)>255)\n         return 0;\n      h->nb_coupled = ch;\n\n      /* Multi-stream support */\n      for (i=0;i<h->channels;i++)\n      {\n         if (!read_chars(&p, &h->stream_map[i], 1))\n            return 0;\n         if (h->stream_map[i]>(h->nb_streams+h->nb_coupled) && h->stream_map[i]!=255)\n            return 0;\n      }\n   } else {\n      if(h->channels>2)\n         return 0;\n      h->nb_streams = 1;\n      h->nb_coupled = h->channels>1;\n      h->stream_map[0]=0;\n      h->stream_map[1]=1;\n   }\n   /*For version 0/1 we know there won't be any more data\n     so reject any that have data past the end.*/\n   if ((h->version==0 || h->version==1) && p.pos != len)\n      return 0;\n   return 1;\n}\n\nint opus_header_to_packet(const OpusHeader *h, unsigned char *packet, int len)\n{\n   int i;\n   Packet p;\n   unsigned char ch;\n\n   p.data = packet;\n   p.maxlen = len;\n   p.pos = 0;\n   if (len<19)return 0;\n   if (!write_chars(&p, (const unsigned char*)\"OpusHead\", 8))\n      return 0;\n   /* Version is 1 */\n   ch = 1;\n   if (!write_chars(&p, &ch, 1))\n      return 0;\n\n   ch = h->channels;\n   if (!write_chars(&p, &ch, 1))\n      return 0;\n\n   if (!write_uint16(&p, h->preskip))\n      return 0;\n\n   if (!write_uint32(&p, h->input_sample_rate))\n      return 0;\n\n   if (!write_uint16(&p, h->gain))\n      return 0;\n\n   ch = h->channel_mapping;\n   if (!write_chars(&p, &ch, 1))\n      return 0;\n\n   if (h->channel_mapping != 0)\n   {\n      ch = h->nb_streams;\n      if (!write_chars(&p, &ch, 1))\n         return 0;\n\n      ch = h->nb_coupled;\n      if (!write_chars(&p, &ch, 1))\n         return 0;\n\n      /* Multi-stream support */\n      for (i=0;i<h->channels;i++)\n      {\n         if (!write_chars(&p, &h->stream_map[i], 1))\n            return 0;\n      }\n   }\n\n   return p.pos;\n}\n\n/* This is just here because it's a convenient file linked by both opusenc and\n   opusdec (to guarantee this maps stays in sync). */\nconst int wav_permute_matrix[8][8] =\n{\n  {0},              /* 1.0 mono   */\n  {0,1},            /* 2.0 stereo */\n  {0,2,1},          /* 3.0 channel ('wide') stereo */\n  {0,1,2,3},        /* 4.0 discrete quadraphonic */\n  {0,2,1,3,4},      /* 5.0 surround */\n  {0,2,1,4,5,3},    /* 5.1 surround */\n  {0,2,1,5,6,4,3},  /* 6.1 surround */\n  {0,2,1,6,7,4,5,3} /* 7.1 surround (classic theater 8-track) */\n};\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/opus_header.h",
    "content": "/* Copyright (C)2012 Xiph.Org Foundation\n   File: opus_header.h\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n\n   - Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n   - Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR\n   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifndef OPUS_HEADER_H\n#define OPUS_HEADER_H\n\n#include \"../../../../src/main/cpp/libogg/ogg.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct {\n   int version;\n   int channels; /* Number of channels: 1..255 */\n   int preskip;\n   ogg_uint32_t input_sample_rate;\n   int gain; /* in dB S7.8 should be zero whenever possible */\n   int channel_mapping;\n   /* The rest is only used if channel_mapping != 0 */\n   int nb_streams;\n   int nb_coupled;\n   unsigned char stream_map[255];\n} OpusHeader;\n\nint opus_header_parse(const unsigned char *header, int len, OpusHeader *h);\nint opus_header_to_packet(const OpusHeader *h, unsigned char *packet, int len);\n\nextern const int wav_permute_matrix[8][8];\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/opusdec.c",
    "content": "/* Copyright (c) 2002-2007 Jean-Marc Valin\n   Copyright (c) 2008 CSIRO\n   Copyright (c) 2007-2012 Xiph.Org Foundation\n   File: opusdec.c\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n\n   - Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n   - Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR\n   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifdef HAVE_CONFIG_H\n# include \"config.h\"\n#endif\n\n#include <stdio.h>\n#if !defined WIN32 && !defined _WIN32\n#include <unistd.h>\n#endif\n#ifdef HAVE_GETOPT_H\n#include <getopt.h>\n#endif\n/*#ifndef HAVE_GETOPT_LONG\n#include \"getopt_win.h\"\n#endif*/\n#include <stdlib.h>\n#include <limits.h>\n#include <string.h>\n\n#include <opus.h>\n#include <opus_multistream.h>\n#include <ogg/ogg.h>\n\n#if defined WIN32 || defined _WIN32\n#include \"wave_out.h\"\n/* We need the following two to set stdout to binary */\n#include <io.h>\n#include <fcntl.h>\n#endif\n#include <math.h>\n\n#ifdef _WIN32\n#define I64FORMAT \"I64d\"\n#else\n#define I64FORMAT \"lld\"\n#endif\n\n#if defined HAVE_SYS_SOUNDCARD_H || defined HAVE_MACHINE_SOUNDCARD_H || HAVE_SOUNDCARD_H\n#ifdef HAVE_SYS_SOUNDCARD_H\n# include <sys/soundcard.h>\n#elif HAVE_MACHINE_SOUNDCARD_H\n# include <machine/soundcard.h>\n#else\n# include <soundcard.h>\n#endif\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <fcntl.h>\n#include <sys/ioctl.h>\n\n#elif defined HAVE_SYS_AUDIOIO_H\n#include <sys/types.h>\n#include <fcntl.h>\n#include <sys/ioctl.h>\n#include <sys/audioio.h>\n#ifndef AUDIO_ENCODING_SLINEAR\n#define AUDIO_ENCODING_SLINEAR AUDIO_ENCODING_LINEAR /* Solaris */\n#endif\n\n#endif\n\n#include <string.h>\n#include \"wav_io.h\"\n#include \"opus_header.h\"\n#include \"diag_range.h\"\n#include \"speex_resampler.h\"\n\n#define MINI(_a,_b)      ((_a)<(_b)?(_a):(_b))\n#define MAXI(_a,_b)      ((_a)>(_b)?(_a):(_b))\n#define CLAMPI(_a,_b,_c) (MAXI(_a,MINI(_b,_c)))\n\n/* 120ms at 48000 */\n#define MAX_FRAME_SIZE (960*6)\n\n#define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \\\n                           ((buf[base+2]<<16)&0xff0000)| \\\n                           ((buf[base+1]<<8)&0xff00)| \\\n                           (buf[base]&0xff))\n\ntypedef struct shapestate shapestate;\nstruct shapestate {\n  float * b_buf;\n  float * a_buf;\n  int fs;\n  int mute;\n};\n\nstatic unsigned int rngseed = 22222;\nstatic inline unsigned int fast_rand(void) {\n  rngseed = (rngseed * 96314165) + 907633515;\n  return rngseed;\n}\n\n/* This implements a 16 bit quantization with full triangular dither\n   and IIR noise shaping. The noise shaping filters were designed by\n   Sebastian Gesemann based on the LAME ATH curves with flattening\n   to limit their peak gain to 20dB.\n   (Everyone elses' noise shaping filters are mildly crazy)\n   The 48kHz version of this filter is just a warped version of the\n   44.1kHz filter and probably could be improved by shifting the\n   HF shelf up in frequency a little bit since 48k has a bit more\n   room and being more conservative against bat-ears is probably\n   more important than more noise suppression.\n   This process can increase the peak level of the signal (in theory\n   by the peak error of 1.5 +20dB though this much is unobservable rare)\n   so to avoid clipping the signal is attenuated by a couple thousandths\n   of a dB. Initially the approach taken here was to only attenuate by\n   the 99.9th percentile, making clipping rare but not impossible (like\n   SoX) but the limited gain of the filter means that the worst case was\n   only two thousandths of a dB more, so this just uses the worst case.\n   The attenuation is probably also helpful to prevent clipping in the DAC\n   reconstruction filters or downstream resampling in any case.*/\nstatic inline void shape_dither_toshort(shapestate *_ss, short *_o, float *_i, int _n, int _CC)\n{\n  const float gains[3]={32768.f-15.f,32768.f-15.f,32768.f-3.f};\n  const float fcoef[3][8] =\n  {\n    {2.2374f, -.7339f, -.1251f, -.6033f, 0.9030f, .0116f, -.5853f, -.2571f}, /* 48.0kHz noise shaping filter sd=2.34*/\n    {2.2061f, -.4706f, -.2534f, -.6214f, 1.0587f, .0676f, -.6054f, -.2738f}, /* 44.1kHz noise shaping filter sd=2.51*/\n    {1.0000f, 0.0000f, 0.0000f, 0.0000f, 0.0000f,0.0000f, 0.0000f, 0.0000f}, /* lowpass noise shaping filter sd=0.65*/\n  };\n  int i;\n  int rate=_ss->fs==44100?1:(_ss->fs==48000?0:2);\n  float gain=gains[rate];\n  float *b_buf;\n  float *a_buf;\n  int mute=_ss->mute;\n  b_buf=_ss->b_buf;\n  a_buf=_ss->a_buf;\n  if(mute>64)\n    memset(a_buf,0,sizeof(float)*_CC*4);\n  for(i=0;i<_n;i++)\n  {\n    int c;\n    int pos = i*_CC;\n    int silent=1;\n    for(c=0;c<_CC;c++)\n    {\n      int j, si;\n      float r,s,err=0;\n      silent&=_i[pos+c]==0;\n      s=_i[pos+c]*gain;\n      for(j=0;j<4;j++)\n        err += fcoef[rate][j]*b_buf[c*4+j] - fcoef[rate][j+4]*a_buf[c*4+j];\n      memmove(&a_buf[c*4+1],&a_buf[c*4],sizeof(float)*3);\n      memmove(&b_buf[c*4+1],&b_buf[c*4],sizeof(float)*3);\n      a_buf[c*4]=err;\n      s = s - err;\n      r=(float)fast_rand()*(1/(float)UINT_MAX) - (float)fast_rand()*(1/(float)UINT_MAX);\n      if (mute>16)r=0;\n      /*Clamp in float out of paranoia that the input will be >96dBFS and wrap if the\n        integer is clamped.*/\n      _o[pos+c] = si = lrintf(fmaxf(-32768,fminf(s + r,32767)));\n      /*Including clipping in the noise shaping is generally disastrous:\n        the futile effort to restore the clipped energy results in more clipping.\n        However, small amounts-- at the level which could normally be created by\n        dither and rounding-- are harmless and can even reduce clipping somewhat\n        due to the clipping sometimes reducing the dither+rounding error.*/\n      b_buf[c*4] = (mute>16)?0:fmaxf(-1.5f,fminf(si - s,1.5f));\n    }\n    mute++;\n    if(!silent)mute=0;\n  }\n  _ss->mute=MINI(mute,960);\n}\n\nstatic void print_comments(char *comments, int length)\n{\n   char *c=comments;\n   int len, i, nb_fields, err=0;\n\n   if (length<(8+4+4))\n   {\n      fprintf (stderr, \"Invalid/corrupted comments\\n\");\n      return;\n   }\n   if (strncmp(c, \"OpusTags\", 8) != 0)\n   {\n      fprintf (stderr, \"Invalid/corrupted comments\\n\");\n      return;\n   }\n   c += 8;\n   fprintf(stderr, \"Encoded with \");\n   len=readint(c, 0);\n   c+=4;\n   if (len < 0 || len>(length-16))\n   {\n      fprintf (stderr, \"Invalid/corrupted comments\\n\");\n      return;\n   }\n   err&=fwrite(c, 1, len, stderr)!=(unsigned)len;\n   c+=len;\n   fprintf (stderr, \"\\n\");\n   /*The -16 check above makes sure we can read this.*/\n   nb_fields=readint(c, 0);\n   c+=4;\n   length-=16+len;\n   if (nb_fields < 0 || nb_fields>(length>>2))\n   {\n      fprintf (stderr, \"Invalid/corrupted comments\\n\");\n      return;\n   }\n   for (i=0;i<nb_fields;i++)\n   {\n      if (length<4)\n      {\n         fprintf (stderr, \"Invalid/corrupted comments\\n\");\n         return;\n      }\n      len=readint(c, 0);\n      c+=4;\n      length-=4;\n      if (len < 0 || len>length)\n      {\n         fprintf (stderr, \"Invalid/corrupted comments\\n\");\n         return;\n      }\n      err&=fwrite(c, 1, len, stderr)!=(unsigned)len;\n      c+=len;\n      length-=len;\n      fprintf (stderr, \"\\n\");\n   }\n}\n\nFILE *out_file_open(char *outFile, int *wav_format, int rate, int mapping_family, int *channels)\n{\n   FILE *fout=NULL;\n   /*Open output file*/\n   if (strlen(outFile)==0)\n   {\n#if defined HAVE_SYS_SOUNDCARD_H\n      int audio_fd, format, stereo;\n      audio_fd=open(\"/dev/dsp\", O_WRONLY);\n      if (audio_fd<0)\n      {\n         perror(\"Cannot open /dev/dsp\");\n         exit(1);\n      }\n\n      format=AFMT_S16_NE;\n      if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format)==-1)\n      {\n         perror(\"SNDCTL_DSP_SETFMT\");\n         close(audio_fd);\n         exit(1);\n      }\n\n      stereo=0;\n      if (*channels==2)\n         stereo=1;\n      if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo)==-1)\n      {\n         perror(\"SNDCTL_DSP_STEREO\");\n         close(audio_fd);\n         exit(1);\n      }\n      if (stereo!=0)\n      {\n         if (*channels==1)\n            fprintf (stderr, \"Cannot set mono mode, will decode in stereo\\n\");\n         *channels=2;\n      }\n\n      if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate)==-1)\n      {\n         perror(\"SNDCTL_DSP_SPEED\");\n         close(audio_fd);\n         exit(1);\n      }\n      fout = fdopen(audio_fd, \"w\");\n      if(!fout)\n      {\n        perror(\"Cannot open output\");\n        exit(1);\n      }\n#elif defined HAVE_SYS_AUDIOIO_H\n      audio_info_t info;\n      int audio_fd;\n\n      audio_fd = open(\"/dev/audio\", O_WRONLY);\n      if (audio_fd<0)\n      {\n         perror(\"Cannot open /dev/audio\");\n         exit(1);\n      }\n\n      AUDIO_INITINFO(&info);\n#ifdef AUMODE_PLAY    /* NetBSD/OpenBSD */\n      info.mode = AUMODE_PLAY;\n#endif\n      info.play.encoding = AUDIO_ENCODING_SLINEAR;\n      info.play.precision = 16;\n      info.play.input_sample_rate = rate;\n      info.play.channels = *channels;\n\n      if (ioctl(audio_fd, AUDIO_SETINFO, &info) < 0)\n      {\n         perror (\"AUDIO_SETINFO\");\n         exit(1);\n      }\n      fout = fdopen(audio_fd, \"w\");\n      if(!fout)\n      {\n        perror(\"Cannot open output\");\n        exit(1);\n      }\n#elif defined WIN32 || defined _WIN32\n      {\n         unsigned int opus_channels = *channels;\n         if (Set_WIN_Params (INVALID_FILEDESC, rate, SAMPLE_SIZE, opus_channels))\n         {\n            fprintf (stderr, \"Can't access %s\\n\", \"WAVE OUT\");\n            exit(1);\n         }\n      }\n#else\n      fprintf (stderr, \"No soundcard support\\n\");\n      exit(1);\n#endif\n   } else {\n      if (strcmp(outFile,\"-\")==0)\n      {\n#if defined WIN32 || defined _WIN32\n         _setmode(_fileno(stdout), _O_BINARY);\n#endif\n         fout=stdout;\n      }\n      else\n      {\n         fout = fopen(outFile, \"wb\");\n         if (!fout)\n         {\n            perror(outFile);\n            exit(1);\n         }\n         if (*wav_format)\n         {\n            *wav_format = write_wav_header(fout, rate, mapping_family, *channels);\n            if (*wav_format < 0)\n            {\n               fprintf (stderr, \"Error writing WAV header.\\n\");\n               exit(1);\n            }\n         }\n      }\n   }\n   return fout;\n}\n\nvoid usage(void)\n{\n   printf (\"Usage: opusdec [options] input_file.opus [output_file]\\n\");\n   printf (\"\\n\");\n   printf (\"Decodes a Opus file and produce a WAV file or raw file\\n\");\n   printf (\"\\n\");\n   printf (\"input_file can be:\\n\");\n   printf (\"  filename.opus        regular Opus file\\n\");\n   printf (\"  -                    stdin\\n\");\n   printf (\"\\n\");\n   printf (\"output_file can be:\\n\");\n   printf (\"  filename.wav         Wav file\\n\");\n   printf (\"  filename.*           Raw PCM file (any extension other than .wav)\\n\");\n   printf (\"  -                    stdout\\n\");\n   printf (\"  (nothing)            Will be played to soundcard\\n\");\n   printf (\"\\n\");\n   printf (\"Options:\\n\");\n   printf (\" --mono                Force decoding in mono\\n\");\n   printf (\" --stereo              Force decoding in stereo\\n\");\n   printf (\" --rate n              Force decoding at sampling rate n Hz\\n\");\n   printf (\" --no-dither           Do not dither 16-bit output\\n\");\n   printf (\" --packet-loss n       Simulate n %% random packet loss\\n\");\n   printf (\" --save-range file     Saves check values for every frame to a file\\n\");\n   printf (\" -h, --help            This help\\n\");\n   printf (\" -v, --version         Version information\\n\");\n   printf (\" --quiet               Quiet mode\\n\");\n   printf (\"\\n\");\n}\n\nvoid version(void)\n{\n   printf(\"opusdec %s %s (using %s)\\n\",PACKAGE,VERSION,opus_get_version_string());\n   printf(\"Copyright (C) 2008-2012 Xiph.Org Foundation\\n\");\n}\n\nvoid version_short(void)\n{\n   printf(\"opusdec %s %s (using %s)\\n\",PACKAGE,VERSION,opus_get_version_string());\n   printf(\"Copyright (C) 2008-2012 Xiph.Org Foundation\\n\");\n}\n\nstatic OpusMSDecoder *process_header(ogg_packet *op, opus_int32 *rate, int *mapping_family, int *channels, int *preskip, float *gain, int *streams, int wav_format, int quiet)\n{\n   int err;\n   OpusMSDecoder *st;\n   OpusHeader header;\n\n   if (opus_header_parse(op->packet, op->bytes, &header)==0)\n   {\n      fprintf(stderr, \"Cannot parse header\\n\");\n      return NULL;\n   }\n\n   *mapping_family = header.channel_mapping;\n   *channels = header.channels;\n   if(wav_format)adjust_wav_mapping(*mapping_family, *channels, header.stream_map);\n\n   if(!*rate)*rate=header.input_sample_rate;\n   /*If the rate is unspecified we decode to 48000*/\n   if(*rate==0)*rate=48000;\n   if(*rate<8000||*rate>192000){\n     fprintf(stderr,\"Warning: Crazy input_rate %d, decoding to 48000 instead.\\n\",*rate);\n     *rate=48000;\n   }\n\n   *preskip = header.preskip;\n   st = opus_multistream_decoder_create(48000, header.channels, header.nb_streams, header.nb_coupled, header.stream_map, &err);\n   if(err != OPUS_OK){\n     fprintf(stderr, \"Cannot create encoder: %s\\n\", opus_strerror(err));\n     return NULL;\n   }\n   if (!st)\n   {\n      fprintf (stderr, \"Decoder initialization failed: %s\\n\", opus_strerror(err));\n      return NULL;\n   }\n\n   *streams=header.nb_streams;\n\n   *gain = pow(10., header.gain/5120.);\n\n   if (!quiet)\n   {\n      fprintf(stderr, \"Decoding %d Hz %saudio\", *rate, *rate!=(int)header.input_sample_rate?\"(forced) \":\"\");\n      fprintf(stderr, \" (%d channel%s)\",*channels,*channels>1?\"s\":\"\");\n      if(header.version!=1)fprintf(stderr, \", Header v%d\",header.version);\n      fprintf(stderr, \"\\n\");\n      if (header.gain!=0)printf(\"Playback gain: %f (%f dB)\\n\", *gain, header.gain/256.);\n   }\n\n   return st;\n}\n\nopus_int64 audio_write(float *pcm, int channels, int frame_size, FILE *fout, SpeexResamplerState *resampler,\n                       int *skip, shapestate *shapemem, int file, opus_int64 maxout)\n{\n   opus_int64 sampout=0;\n   int i,ret,tmp_skip;\n   unsigned out_len;\n   short out[MAX_FRAME_SIZE*channels];\n   float buf[MAX_FRAME_SIZE*channels];\n   float *output;\n   maxout=maxout<0?0:maxout;\n   do {\n     if (skip){\n       tmp_skip = (*skip>frame_size) ? (int)frame_size : *skip;\n       *skip -= tmp_skip;\n     } else {\n       tmp_skip = 0;\n     }\n     if (resampler){\n       output=buf;\n       unsigned in_len;\n       in_len = frame_size-tmp_skip;\n       out_len = 1024<maxout?1024:maxout;\n       speex_resampler_process_interleaved_float(resampler, pcm+channels*tmp_skip, &in_len, buf, &out_len);\n       pcm += channels*(in_len+tmp_skip);\n       frame_size -= in_len+tmp_skip;\n     } else {\n       output=pcm+channels*tmp_skip;\n       out_len=frame_size-tmp_skip;\n       frame_size=0;\n     }\n\n     /*Convert to short and save to output file*/\n     if (shapemem){\n       shape_dither_toshort(shapemem,out,output,out_len,channels);\n     }else{\n       for (i=0;i<(int)out_len*channels;i++)\n         out[i]=(short)lrintf(fmax(-32768,fmin(output[i]*32768.f,32767)));\n     }\n     if ((le_short(1)!=1)&&file){\n       for (i=0;i<(int)out_len*channels;i++)\n         out[i]=le_short(out[i]);\n     }\n\n     if(maxout>0)\n     {\n#if defined WIN32 || defined _WIN32\n       if(!file){\n         ret=WIN_Play_Samples (out, sizeof(short) * channels * (out_len<maxout?out_len:maxout));\n         if(ret>0)ret/=sizeof(short)*channels;\n         else fprintf(stderr, \"Error playing audio.\\n\");\n       }else\n#endif\n         ret=fwrite(out, 2*channels, out_len<maxout?out_len:maxout, fout);\n       sampout+=ret;\n       maxout-=ret;\n     }\n   } while (frame_size>0 && maxout>0);\n   return sampout;\n}\n\nint main(int argc, char **argv)\n{\n   int c;\n   int option_index = 0;\n   char *inFile, *outFile;\n   FILE *fin, *fout=NULL, *frange=NULL;\n   float *output;\n   int frame_size=0;\n   OpusMSDecoder *st=NULL;\n   opus_int64 packet_count=0;\n   int total_links=0;\n   int stream_init = 0;\n   int quiet = 0;\n   ogg_int64_t page_granule=0;\n   ogg_int64_t link_out=0;\n   struct option long_options[] =\n   {\n      {\"help\", no_argument, NULL, 0},\n      {\"quiet\", no_argument, NULL, 0},\n      {\"version\", no_argument, NULL, 0},\n      {\"version-short\", no_argument, NULL, 0},\n      {\"rate\", required_argument, NULL, 0},\n      {\"mono\", no_argument, NULL, 0},\n      {\"stereo\", no_argument, NULL, 0},\n      {\"no-dither\", no_argument, NULL, 0},\n      {\"packet-loss\", required_argument, NULL, 0},\n      {\"save-range\", required_argument, NULL, 0},\n      {0, 0, 0, 0}\n   };\n   ogg_sync_state oy;\n   ogg_page       og;\n   ogg_packet     op;\n   ogg_stream_state os;\n   int close_in=0;\n   int eos=0;\n   ogg_int64_t audio_size=0;\n   float loss_percent=-1;\n   int channels=-1;\n   int mapping_family;\n   int rate=0;\n   int wav_format=0;\n   int preskip=0;\n   int gran_offset=0;\n   int has_opus_stream=0;\n   ogg_int32_t opus_serialno;\n   int dither=1;\n   shapestate shapemem;\n   SpeexResamplerState *resampler=NULL;\n   float gain=1;\n   int streams=0;\n\n   output=0;\n   shapemem.a_buf=0;\n   shapemem.b_buf=0;\n   shapemem.mute=960;\n   shapemem.fs=0;\n\n   /*Process options*/\n   while(1)\n   {\n      c = getopt_long (argc, argv, \"hvV\",\n                       long_options, &option_index);\n      if (c==-1)\n         break;\n\n      switch(c)\n      {\n      case 0:\n         if (strcmp(long_options[option_index].name,\"help\")==0)\n         {\n            usage();\n            exit(0);\n         } else if (strcmp(long_options[option_index].name,\"quiet\")==0)\n         {\n            quiet = 1;\n         } else if (strcmp(long_options[option_index].name,\"version\")==0)\n         {\n            version();\n            exit(0);\n         } else if (strcmp(long_options[option_index].name,\"version-short\")==0)\n         {\n            version_short();\n            exit(0);\n         } else if (strcmp(long_options[option_index].name,\"mono\")==0)\n         {\n            channels=1;\n         } else if (strcmp(long_options[option_index].name,\"stereo\")==0)\n         {\n            channels=2;\n         } else if (strcmp(long_options[option_index].name,\"no-dither\")==0)\n         {\n            dither=0;\n         } else if (strcmp(long_options[option_index].name,\"rate\")==0)\n         {\n            rate=atoi (optarg);\n        }else if(strcmp(long_options[option_index].name,\"save-range\")==0){\n          frange=fopen(optarg,\"w\");\n          if(frange==NULL){\n            perror(optarg);\n            fprintf(stderr,\"Could not open save-range file: %s\\n\",optarg);\n            fprintf(stderr,\"Must provide a writable file name.\\n\");\n            exit(1);\n          }\n         } else if (strcmp(long_options[option_index].name,\"packet-loss\")==0)\n         {\n            loss_percent = atof(optarg);\n         }\n         break;\n      case 'h':\n         usage();\n         exit(0);\n         break;\n      case 'v':\n         version();\n         exit(0);\n         break;\n      case '?':\n         usage();\n         exit(1);\n         break;\n      }\n   }\n   if (argc-optind!=2 && argc-optind!=1)\n   {\n      usage();\n      exit(1);\n   }\n   inFile=argv[optind];\n\n   if (argc-optind==2)\n      outFile=argv[optind+1];\n   else\n      outFile = \"\";\n   wav_format = strlen(outFile)>=4 && (\n                                       strcmp(outFile+strlen(outFile)-4,\".wav\")==0\n                                       || strcmp(outFile+strlen(outFile)-4,\".WAV\")==0);\n   /*Open input file*/\n   if (strcmp(inFile, \"-\")==0)\n   {\n#if defined WIN32 || defined _WIN32\n      _setmode(_fileno(stdin), _O_BINARY);\n#endif\n      fin=stdin;\n   }\n   else\n   {\n      fin = fopen(inFile, \"rb\");\n      if (!fin)\n      {\n         perror(inFile);\n         exit(1);\n      }\n      close_in=1;\n   }\n\n\n   /*Init Ogg data struct*/\n   ogg_sync_init(&oy);\n\n   /*Main decoding loop*/\n\n   while (1)\n   {\n      char *data;\n      int i, nb_read;\n      /*Get the ogg buffer for writing*/\n      data = ogg_sync_buffer(&oy, 200);\n      /*Read bitstream from input file*/\n      nb_read = fread(data, sizeof(char), 200, fin);\n      ogg_sync_wrote(&oy, nb_read);\n\n      /*Loop for all complete pages we got (most likely only one)*/\n      while (ogg_sync_pageout(&oy, &og)==1)\n      {\n         if (stream_init == 0) {\n            ogg_stream_init(&os, ogg_page_serialno(&og));\n            stream_init = 1;\n         }\n         if (ogg_page_serialno(&og) != os.serialno) {\n            /* so all streams are read. */\n            ogg_stream_reset_serialno(&os, ogg_page_serialno(&og));\n         }\n         /*Add page to the bitstream*/\n         ogg_stream_pagein(&os, &og);\n         page_granule = ogg_page_granulepos(&og);\n         /*Extract all available packets*/\n         while (ogg_stream_packetout(&os, &op) == 1)\n         {\n            if (op.b_o_s && op.bytes>=8 && !memcmp(op.packet, \"OpusHead\", 8)) {\n               if(!has_opus_stream)\n               {\n                 opus_serialno = os.serialno;\n                 has_opus_stream = 1;\n                 link_out = 0;\n                 packet_count = 0;\n                 eos = 0;\n                 total_links++;\n               } else {\n                 fprintf(stderr,\"Warning: ignoring opus stream %\" I64FORMAT \"\\n\",(long long)os.serialno);\n               }\n            }\n            if (!has_opus_stream || os.serialno != opus_serialno)\n               break;\n            /*If first packet, process as OPUS header*/\n            if (packet_count==0)\n            {\n               st = process_header(&op, &rate, &mapping_family, &channels, &preskip, &gain, &streams, wav_format, quiet);\n               if (!st)\n                  exit(1);\n               gran_offset=preskip;\n               if(!shapemem.a_buf)\n               {\n                  shapemem.a_buf=calloc(channels,sizeof(float)*4);\n                  shapemem.b_buf=calloc(channels,sizeof(float)*4);\n                  shapemem.fs=rate;\n               }\n               if(!output)output=malloc(sizeof(float)*MAX_FRAME_SIZE*channels);\n               if (rate != 48000)\n               {\n                  int err;\n                  resampler = speex_resampler_init(channels, 48000, rate, 5, &err);\n                  if (err!=0)\n                     fprintf(stderr, \"resampler error: %s\\n\", speex_resampler_strerror(err));\n                  speex_resampler_skip_zeros(resampler);\n               }\n               if(!fout)fout=out_file_open(outFile, &wav_format, rate, mapping_family, &channels);\n            } else if (packet_count==1)\n            {\n               if (!quiet)\n                  print_comments((char*)op.packet, op.bytes);\n            } else {\n               opus_int64 maxout;\n               int lost=0;\n               if (loss_percent>0 && 100*((float)rand())/RAND_MAX<loss_percent)\n                  lost=1;\n\n               /*End of stream condition*/\n               if (op.e_o_s && os.serialno == opus_serialno)eos=1; /* don't care for anything except opus eos */\n\n               int ret;\n               opus_int64 outsamp;\n               /*Decode frame*/\n               if (!lost)\n                  ret = opus_multistream_decode_float(st, (unsigned char*)op.packet, op.bytes, output, MAX_FRAME_SIZE, 0);\n               else\n                  ret = opus_multistream_decode_float(st, NULL, 0, output, MAX_FRAME_SIZE, 0);\n\n               if (ret<0)\n               {\n                  fprintf (stderr, \"Decoding error: %s\\n\", opus_strerror(ret));\n                  break;\n               }\n               frame_size = ret;\n\n               if(frange!=NULL){\n                 OpusDecoder *od;\n                 opus_uint32 rngs[streams];\n                 for(i=0;i<streams;i++){\n                   ret=opus_multistream_decoder_ctl(st,OPUS_MULTISTREAM_GET_DECODER_STATE(i,&od));\n                   ret=opus_decoder_ctl(od,OPUS_GET_FINAL_RANGE(&rngs[i]));\n                 }\n                 save_range(frange,frame_size*(48000/48000/*decoding_rate*/),op.packet,op.bytes,\n                            rngs,streams);\n               }\n\n               /* Apply header gain */\n               for (i=0;i<frame_size*channels;i++)\n                  output[i] *= gain;\n\n               maxout=((page_granule-gran_offset)*rate/48000)-link_out;\n               outsamp=audio_write(output, channels, frame_size, fout, resampler, &preskip, dither?&shapemem:0, strlen(outFile)!=0,0>maxout?0:maxout);\n               link_out+=outsamp;\n               audio_size+=sizeof(short)*outsamp*channels;\n            }\n            packet_count++;\n         }\n         /* Drain the resampler */\n         if(eos && resampler)\n         {\n            float *zeros;\n            int drain;\n\n            zeros=(float *)calloc(100*channels,sizeof(float));\n            drain = speex_resampler_get_input_latency(resampler);\n            do {\n               opus_int64 outsamp;\n               int tmp = drain;\n               if (tmp > 100)\n                  tmp = 100;\n               outsamp=audio_write(zeros, channels, tmp, fout, resampler, NULL, &shapemem, strlen(outFile)==0, ((page_granule-gran_offset)*rate/48000)-link_out);\n               link_out+=outsamp;\n               audio_size+=sizeof(short)*outsamp*channels;\n               drain -= tmp;\n            } while (drain>0);\n            free(zeros);\n            speex_resampler_destroy(resampler);\n            resampler=NULL;\n         }\n         if(eos)\n         {\n            has_opus_stream=0;\n            if(st)opus_multistream_decoder_destroy(st);\n            st=NULL;\n         }\n      }\n      if (feof(fin))\n         break;\n   }\n\n   if (fout && wav_format>=0 && audio_size<0x7FFFFFFF)\n   {\n      if (fseek(fout,4,SEEK_SET)==0)\n      {\n         int tmp;\n         tmp = le_int(audio_size+20+wav_format);\n         if(fwrite(&tmp,4,1,fout)!=1)fprintf(stderr,\"Error writing end length.\\n\");\n         if (fseek(fout,16+wav_format,SEEK_CUR)==0)\n         {\n            tmp = le_int(audio_size);\n            if(fwrite(&tmp,4,1,fout)!=1)fprintf(stderr,\"Error writing header length.\\n\");\n         } else\n         {\n            fprintf (stderr, \"First seek worked, second didn't\\n\");\n         }\n      } else {\n         fprintf (stderr, \"Cannot seek on wave file, size will be incorrect\\n\");\n      }\n   }\n\n   if(!total_links)fprintf (stderr, \"This doesn't look like a Opus file\\n\");\n\n   if (stream_init)\n      ogg_stream_clear(&os);\n   ogg_sync_clear(&oy);\n\n#if defined WIN32 || defined _WIN32\n   if (strlen(outFile)==0)\n      WIN_Audio_close ();\n#endif\n\n   if(shapemem.a_buf)free(shapemem.a_buf);\n   if(shapemem.b_buf)free(shapemem.b_buf);\n\n   if(output)free(output);\n\n   if(frange)fclose(frange);\n\n   if (close_in)\n      fclose(fin);\n   if (fout != NULL)\n      fclose(fout);\n\n   return 0;\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/opusenc.c",
    "content": "/* Copyright (C)2002-2011 Jean-Marc Valin\n   Copyright (C)2007-2012 Xiph.Org Foundation\n   Copyright (C)2008-2012 Gregory Maxwell\n   File: opusenc.c\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n\n   - Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n   - Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR\n   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifdef HAVE_CONFIG_H\n# include \"config.h\"\n#endif\n\n#include <stdio.h>\n#include <getopt.h>\n\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <sys/time.h>\n#include <math.h>\n\n#ifdef _MSC_VER\n#define snprintf _snprintf\n#endif\n\n#ifdef _WIN32\n#define I64FORMAT \"I64d\"\n#else\n#define I64FORMAT \"lld\"\n#endif\n\n#include <opus.h>\n#include <opus_multistream.h>\n#include <ogg/ogg.h>\n#include \"wav_io.h\"\n\n#include \"opus_header.h\"\n#include \"opusenc.h\"\n#include \"diag_range.h\"\n\n#if defined WIN32 || defined _WIN32\n/* We need the following two to set stdout to binary */\n#include <io.h>\n#include <fcntl.h>\n#endif\n\n#ifdef VALGRIND\n#include <valgrind/memcheck.h>\n#define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y))\n#define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y))\n#else\n#define VG_UNDEF(x,y)\n#define VG_CHECK(x,y)\n#endif\n\nstatic void comment_init(char **comments, int* length, const char *vendor_string);\nstatic void comment_add(char **comments, int* length, char *tag, char *val);\n\n/*Write an Ogg page to a file pointer*/\nstatic inline int oe_write_page(ogg_page *page, FILE *fp)\n{\n   int written;\n   written=fwrite(page->header,1,page->header_len, fp);\n   written+=fwrite(page->body,1,page->body_len, fp);\n   return written;\n}\n\n#define MAX_FRAME_BYTES 61295\n#define IMIN(a,b) ((a) < (b) ? (a) : (b))   /**< Minimum int value.   */\n#define IMAX(a,b) ((a) > (b) ? (a) : (b))   /**< Maximum int value.   */\n\nvoid opustoolsversion(const char *opusversion)\n{\n  printf(\"opusenc %s %s (using %s)\\n\",PACKAGE,VERSION,opusversion);\n  printf(\"Copyright (C) 2008-2012 Xiph.Org Foundation\\n\");\n}\n\nvoid opustoolsversion_short(const char *opusversion)\n{\n  printf(\"opusenc %s %s (using %s)\\n\",PACKAGE,VERSION,opusversion);\n  printf(\"Copyright (C) 2008-2012 Xiph.Org Foundation\\n\");\n}\n\nvoid usage(void)\n{\n  printf(\"Usage: opusenc [options] input_file output_file.opus\\n\");\n  printf(\"\\n\");\n  printf(\"Encodes input_file using Opus. It can read the WAV, AIFF, or raw files.\\n\");\n  printf(\"\\nGeneral options:\\n\");\n  printf(\" -h, --help         This help\\n\");\n  printf(\" -v, --version      Version information\\n\");\n  printf(\" --quiet            Quiet mode\\n\");\n  printf(\"\\n\");\n  printf(\"input_file can be:\\n\");\n  printf(\"  filename.wav      file\\n\");\n  printf(\"  -                 stdin\\n\");\n  printf(\"\\n\");\n  printf(\"output_file can be:\\n\");\n  printf(\"  filename.opus     compressed file\\n\");\n  printf(\"  -                 stdout\\n\");\n  printf(\"\\nEncoding options:\\n\");\n  printf(\" --speech           Optimize for speech\\n\");\n  printf(\" --music            Optimize for music\\n\");\n  printf(\" --bitrate n.nnn    Encoding bitrate in kbit/sec (6-256 per channel)\\n\");\n  printf(\" --vbr              Use variable bitrate encoding (default)\\n\");\n  printf(\" --cvbr             Use constrained variable bitrate encoding\\n\");\n  printf(\" --hard-cbr         Use hard constant bitrate encoding\\n\");\n  printf(\" --comp n           Encoding complexity (0-10, default: 10)\\n\");\n  printf(\" --framesize n      Maximum frame size in milliseconds\\n\");\n  printf(\"                      (2.5, 5, 10, 20, 40, 60, default: 20)\\n\");\n  printf(\" --expect-loss      Percentage packet loss to expect (default: 0)\\n\");\n  printf(\" --downmix-mono     Downmix to mono\\n\");\n  printf(\" --downmix-stereo   Downmix to stereo (if >2 channels)\\n\");\n  printf(\" --max-delay n      Maximum container delay in milliseconds\\n\");\n  printf(\"                      (0-1000, default: 1000)\\n\");\n  printf(\"\\nDiagnostic options:\\n\");\n  printf(\" --save-range file  Saves check values for every frame to a file\\n\");\n  printf(\" --set-ctl-int x=y  Pass the encoder control x with value y (advanced)\\n\");\n  printf(\"                      Preface with s: to direct the ctl to multistream s\\n\");\n  printf(\"                      This may be used multiple times\\n\");\n  printf(\" --uncoupled        Use one mono stream per channel\\n\");\n  printf(\"\\nMetadata options:\\n\");\n  printf(\" --comment          Add the given string as an extra comment\\n\");\n  printf(\"                      This may be used multiple times\\n\");\n  printf(\" --artist           Author of this track\\n\");\n  printf(\" --title            Title for this track\\n\");\n  printf(\"\\nInput options:\\n\");\n  printf(\" --raw              Raw input\\n\");\n  printf(\" --raw-bits n       Set bits/sample for raw input (default: 16)\\n\");\n  printf(\" --raw-rate n       Set sampling rate for raw input (default: 48000)\\n\");\n  printf(\" --raw-chan n       Set number of channels for raw input (default: 2)\\n\");\n  printf(\" --raw-endianness n 1 for bigendian, 0 for little (defaults to 0)\\n\");\n  printf(\" --ignorelength     Always ignore the datalength in Wave headers\\n\");\n}\n\nstatic inline void print_time(double seconds)\n{\n  opus_int64 hours, minutes;\n  hours=seconds/3600;\n  seconds-=hours*3600.;\n  minutes=seconds/60;\n  seconds-=minutes*60.;\n  if(hours)fprintf(stderr,\" %\" I64FORMAT \" hour%s%s\",hours,hours>1?\"s\":\"\",\n                   minutes&&!(seconds>0)?\" and\":\"\");\n  if(minutes)fprintf(stderr,\"%s%\" I64FORMAT \" minute%s%s\",hours?\", \":\" \",minutes,\n                     minutes>1?\"s\":\"\",!hours&&seconds>0?\" and\":seconds>0?\", and\":\"\");\n  if(seconds>0)fprintf(stderr,\" %0.4g second%s\",seconds,seconds!=1?\"s\":\"\");\n}\n\nint main(int argc, char **argv)\n{\n  static const input_format raw_format = {NULL, 0, raw_open, wav_close, \"raw\",N_(\"RAW file reader\")};\n  int option_index=0;\n  struct option long_options[] =\n  {\n    {\"quiet\", no_argument, NULL, 0},\n    {\"bitrate\", required_argument, NULL, 0},\n    {\"hard-cbr\",no_argument,NULL, 0},\n    {\"vbr\",no_argument,NULL, 0},\n    {\"cvbr\",no_argument,NULL, 0},\n    {\"comp\", required_argument, NULL, 0},\n    {\"framesize\", required_argument, NULL, 0},\n    {\"expect-loss\", required_argument, NULL, 0},\n    {\"downmix-mono\",no_argument,NULL, 0},\n    {\"downmix-stereo\",no_argument,NULL, 0},\n    {\"no-downmix\",no_argument,NULL, 0},\n    {\"max-delay\", required_argument, NULL, 0},\n    {\"save-range\", required_argument, NULL, 0},\n    {\"set-ctl-int\", required_argument, NULL, 0},\n    {\"uncoupled\", no_argument, NULL, 0},\n    {\"help\", no_argument, NULL, 0},\n    {\"raw\", no_argument, NULL, 0},\n    {\"raw-bits\", required_argument, NULL, 0},\n    {\"raw-rate\", required_argument, NULL, 0},\n    {\"raw-chan\", required_argument, NULL, 0},\n    {\"raw-endianness\", required_argument, NULL, 0},\n    {\"ignorelength\", no_argument, NULL, 0},\n    {\"rate\", required_argument, NULL, 0},\n    {\"music\", no_argument, NULL, 0},\n    {\"speech\", no_argument, NULL, 0},\n    {\"version\", no_argument, NULL, 0},\n    {\"version-short\", no_argument, NULL, 0},\n    {\"comment\", required_argument, NULL, 0},\n    {\"artist\", required_argument, NULL, 0},\n    {\"title\", required_argument, NULL, 0},\n    {0, 0, 0, 0}\n  };\n  int i, ret;\n  OpusMSEncoder      *st;\n  const char         *opus_version;\n  unsigned char      *packet;\n  float              *input;\n  /*I/O*/\n  oe_enc_opt         inopt;\n  const input_format *in_format;\n  char               *inFile;\n  char               *outFile;\n  char               *range_file;\n  FILE               *fin;\n  FILE               *fout;\n  FILE               *frange;\n  ogg_stream_state   os;\n  ogg_page           og;\n  ogg_packet         op;\n  ogg_int64_t        last_granulepos=0;\n  ogg_int64_t        enc_granulepos=0;\n  ogg_int64_t        original_samples=0;\n  ogg_int32_t        id=-1;\n  int                last_segments=0;\n  int                eos=0;\n  OpusHeader         header;\n  int                comments_length;\n  char               ENCODER_string[64];\n  char               *comments;\n  /*Counters*/\n  opus_int64         nb_encoded=0;\n  opus_int64         bytes_written=0;\n  opus_int64         pages_out=0;\n  opus_int64         total_bytes=0;\n  opus_int64         total_samples=0;\n  opus_int32         nbBytes;\n  opus_int32         nb_samples;\n  opus_int32         peak_bytes=0;\n  opus_int32         min_bytes;\n  struct timeval     start_time;\n  struct timeval     stop_time;\n  time_t             last_spin=0;\n  int                last_spin_len=0;\n  /*Settings*/\n  int                quiet=0;\n  int                max_frame_bytes;\n  opus_int32         bitrate=-1;\n  opus_int32         rate=48000;\n  opus_int32         coding_rate=48000;\n  opus_int32         frame_size=960;\n  int                chan=2;\n  int                with_hard_cbr=0;\n  int                with_cvbr=0;\n  int                signal=OPUS_AUTO;\n  int                expect_loss=0;\n  int                complexity=10;\n  int                downmix=0;\n  int                uncoupled=0;\n  int                *opt_ctls_ctlval;\n  int                opt_ctls=0;\n  int                max_ogg_delay=48000; /*48kHz samples*/\n  opus_int32         lookahead=0;\n  unsigned char      mapping[256];\n  int                force_narrow=0;\n\n  opt_ctls_ctlval=NULL;\n  frange=NULL;\n  range_file=NULL;\n  in_format=NULL;\n  inopt.channels=chan;\n  inopt.rate=coding_rate=rate;\n  inopt.samplesize=16;\n  inopt.endianness=0;\n  inopt.rawmode=0;\n  inopt.ignorelength=0;\n\n  for(i=0;i<256;i++)mapping[i]=i;\n\n  opus_version=opus_get_version_string();\n  /*Vendor string should just be the encoder library,\n    the ENCODER comment specifies the tool used.*/\n  comment_init(&comments, &comments_length, opus_version);\n  snprintf(ENCODER_string, sizeof(ENCODER_string), \"opusenc from %s %s\\n\",PACKAGE,VERSION);\n  comment_add(&comments, &comments_length, \"ENCODER=\", ENCODER_string);\n\n  /*Process command-line options*/\n  while(1){\n    int c;\n    c=getopt_long(argc, argv, \"hv\",\n                  long_options, &option_index);\n    if(c==-1)\n       break;\n\n    switch(c){\n      case 0:\n        if(strcmp(long_options[option_index].name,\"quiet\")==0){\n          quiet=1;\n        }else if(strcmp(long_options[option_index].name,\"bitrate\")==0){\n          bitrate=atof(optarg)*1000.;\n        }else if(strcmp(long_options[option_index].name,\"hard-cbr\")==0){\n          with_hard_cbr=1;\n          with_cvbr=0;\n        }else if(strcmp(long_options[option_index].name,\"cvbr\")==0){\n          with_cvbr=1;\n          with_hard_cbr=0;\n        }else if(strcmp(long_options[option_index].name,\"vbr\")==0){\n          with_cvbr=0;\n          with_hard_cbr=0;\n        }else if(strcmp(long_options[option_index].name,\"help\")==0){\n          usage();\n          exit(0);\n        }else if(strcmp(long_options[option_index].name,\"version\")==0){\n          opustoolsversion(opus_version);\n          exit(0);\n        }else if(strcmp(long_options[option_index].name,\"version-short\")==0){\n          opustoolsversion_short(opus_version);\n          exit(0);\n        }else if(strcmp(long_options[option_index].name,\"ignorelength\")==0){\n          inopt.ignorelength=1;\n        }else if(strcmp(long_options[option_index].name,\"raw\")==0){\n          inopt.rawmode=1;\n        }else if(strcmp(long_options[option_index].name,\"raw-bits\")==0){\n          inopt.rawmode=1;\n          inopt.samplesize=atoi(optarg);\n          if(inopt.samplesize!=8&&inopt.samplesize!=16&&inopt.samplesize!=24){\n            fprintf(stderr,\"Invalid bit-depth: %s\\n\",optarg);\n            fprintf(stderr,\"--raw-bits must be one of 8,16, or 24\\n\");\n            exit(1);\n          }\n        }else if(strcmp(long_options[option_index].name,\"raw-rate\")==0){\n          inopt.rawmode=1;\n          inopt.rate=atoi(optarg);\n        }else if(strcmp(long_options[option_index].name,\"raw-chan\")==0){\n          inopt.rawmode=1;\n          inopt.channels=atoi(optarg);\n        }else if(strcmp(long_options[option_index].name,\"raw-endianness\")==0){\n          inopt.rawmode=1;\n          inopt.endianness=atoi(optarg);\n        }else if(strcmp(long_options[option_index].name,\"music\")==0){\n          signal=OPUS_SIGNAL_MUSIC;\n        }else if(strcmp(long_options[option_index].name,\"speech\")==0){\n          signal=OPUS_SIGNAL_VOICE;\n        }else if(strcmp(long_options[option_index].name,\"downmix-mono\")==0){\n          downmix=1;\n        }else if(strcmp(long_options[option_index].name,\"downmix-stereo\")==0){\n          downmix=2;\n        }else if(strcmp(long_options[option_index].name,\"no-downmix\")==0){\n          downmix=-1;\n        }else if(strcmp(long_options[option_index].name,\"expect-loss\")==0){\n          expect_loss=atoi(optarg);\n          if(expect_loss>100||expect_loss<0){\n            fprintf(stderr,\"Invalid expect-loss: %s\\n\",optarg);\n            fprintf(stderr,\"Expected loss is a percent and must be 0-100.\\n\");\n            exit(1);\n          }\n        }else if(strcmp(long_options[option_index].name,\"comp\")==0){\n          complexity=atoi(optarg);\n          if(complexity>10||complexity<0){\n            fprintf(stderr,\"Invalid complexity: %s\\n\",optarg);\n            fprintf(stderr,\"Complexity must be 0-10.\\n\");\n            exit(1);\n          }\n        }else if(strcmp(long_options[option_index].name,\"framesize\")==0){\n          if(strcmp(optarg,\"2.5\")==0)frame_size=120;\n          else if(strcmp(optarg,\"5\")==0)frame_size=240;\n          else if(strcmp(optarg,\"10\")==0)frame_size=480;\n          else if(strcmp(optarg,\"20\")==0)frame_size=960;\n          else if(strcmp(optarg,\"40\")==0)frame_size=1920;\n          else if(strcmp(optarg,\"60\")==0)frame_size=2880;\n          else{\n            fprintf(stderr,\"Invalid framesize: %s\\n\",optarg);\n            fprintf(stderr,\"Framesize must be 2.5, 5, 10, 20, 40, or 60.\\n\");\n            exit(1);\n          }\n        }else if(strcmp(long_options[option_index].name,\"max-delay\")==0){\n          max_ogg_delay=floor(atof(optarg)*48.);\n          if(max_ogg_delay<0||max_ogg_delay>48000){\n            fprintf(stderr,\"Invalid max-delay: %s\\n\",optarg);\n            fprintf(stderr,\"max-delay 0-1000 ms.\\n\");\n            exit(1);\n          }\n        }else if(strcmp(long_options[option_index].name,\"set-ctl-int\")==0){\n          int len=strlen(optarg),target;\n          char *spos,*tpos;\n          spos=strchr(optarg,'=');\n          if(len<3||spos==NULL||(spos-optarg)<1||(spos-optarg)>=len){\n            fprintf(stderr, \"Invalid set-ctl-int: %s\\n\", optarg);\n            fprintf(stderr, \"Syntax is --set-ctl-int intX=intY or\\n\");\n            fprintf(stderr, \"Syntax is --set-ctl-int intS:intX=intY\\n\");\n            exit(1);\n          }\n          tpos=strchr(optarg,':');\n          if(tpos==NULL){\n            target=-1;\n            tpos=optarg-1;\n          }else target=atoi(optarg);\n          if((atoi(tpos+1)&1)!=0){\n            fprintf(stderr, \"Invalid set-ctl-int: %s\\n\", optarg);\n            fprintf(stderr, \"libopus set CTL values are even.\\n\");\n            exit(1);\n          }\n          if(opt_ctls==0)opt_ctls_ctlval=malloc(sizeof(int)*3);\n          else opt_ctls_ctlval=realloc(opt_ctls_ctlval,sizeof(int)*(opt_ctls+1)*3);\n          opt_ctls_ctlval[opt_ctls*3]=target;\n          opt_ctls_ctlval[opt_ctls*3+1]=atoi(tpos+1);\n          opt_ctls_ctlval[opt_ctls*3+2]=atoi(spos+1);\n          opt_ctls++;\n        }else if(strcmp(long_options[option_index].name,\"save-range\")==0){\n          frange=fopen(optarg,\"w\");\n          if(frange==NULL){\n            perror(optarg);\n            fprintf(stderr,\"Could not open save-range file: %s\\n\",optarg);\n            fprintf(stderr,\"Must provide a writable file name.\\n\");\n            exit(1);\n          }\n          range_file=optarg;\n        }else if(strcmp(long_options[option_index].name,\"uncoupled\")==0){\n          uncoupled=1;\n        }else if(strcmp(long_options[option_index].name,\"comment\")==0){\n          if(!strchr(optarg,'=')){\n            fprintf(stderr, \"Invalid comment: %s\\n\", optarg);\n            fprintf(stderr, \"Comments must be of the form name=value\\n\");\n            exit(1);\n          }\n          comment_add(&comments, &comments_length, NULL, optarg);\n        }else if(strcmp(long_options[option_index].name,\"artist\")==0){\n          comment_add(&comments, &comments_length, \"artist=\", optarg);\n        } else if(strcmp(long_options[option_index].name,\"title\")==0){\n          comment_add(&comments, &comments_length, \"title=\", optarg);\n        }\n        break;\n      case 'h':\n        usage();\n        exit(0);\n        break;\n      case 'v':\n        opustoolsversion(opus_version);\n        exit(0);\n        break;\n      case '?':\n        usage();\n        exit(1);\n        break;\n    }\n  }\n  if(argc-optind!=2){\n    usage();\n    exit(1);\n  }\n  inFile=argv[optind];\n  outFile=argv[optind+1];\n\n  if(strcmp(inFile, \"-\")==0){\n#if defined WIN32 || defined _WIN32\n    _setmode(_fileno(stdin), _O_BINARY);\n#elif defined OS2\n    _fsetmode(stdin,\"b\");\n#endif\n    fin=stdin;\n  }else{\n    fin=fopen(inFile, \"rb\");\n    if(!fin){\n      perror(inFile);\n      exit(1);\n    }\n  }\n\n  if(inopt.rawmode){\n    in_format = &raw_format;\n    in_format->open_func(fin, &inopt, NULL, 0);\n  }else in_format=open_audio_file(fin,&inopt);\n\n  if(!in_format){\n    fprintf(stderr,\"Error parsing input file: %s\\n\",inFile);\n    exit(1);\n  }\n\n  if(downmix==0&&inopt.channels>2&&bitrate>0&&bitrate<(32000*inopt.channels)){\n    if(!quiet)fprintf(stderr,\"Notice: Surround bitrate less than 32kbit/sec/channel, downmixing.\\n\");\n    downmix=inopt.channels>8?1:2;\n  }\n\n  if(downmix>0&&downmix<inopt.channels)downmix=setup_downmix(&inopt,downmix);\n  else downmix=0;\n\n  rate=inopt.rate;\n  chan=inopt.channels;\n  inopt.skip=0;\n\n  /*In order to code the complete length we'll need to do a little padding*/\n  setup_padder(&inopt,&original_samples);\n\n  if(rate>24000)coding_rate=48000;\n  else if(rate>16000)coding_rate=24000;\n  else if(rate>12000)coding_rate=16000;\n  else if(rate>8000)coding_rate=12000;\n  else coding_rate=8000;\n\n  frame_size=frame_size/(48000/coding_rate);\n\n  /*Scale the resampler complexity, but only for 48000 output because\n    the near-cutoff behavior matters a lot more at lower rates.*/\n  if(rate!=coding_rate)setup_resample(&inopt,coding_rate==48000?complexity/2:5,coding_rate);\n\n  /*OggOpus headers*/ /*FIXME: broke forcemono*/\n  header.channels=chan;\n  header.nb_streams=header.channels;\n  header.nb_coupled=0;\n  if(header.channels<=8&&!uncoupled){\n    static const unsigned char opusenc_streams[8][10]={\n      /*Coupled, NB_bitmap, mapping...*/\n      /*1*/ {0,   0, 0},\n      /*2*/ {1,   0, 0,1},\n      /*3*/ {1,   0, 0,2,1},\n      /*4*/ {2,   0, 0,1,2,3},\n      /*5*/ {2,   0, 0,4,1,2,3},\n      /*6*/ {2,1<<3, 0,4,1,2,3,5},\n      /*7*/ {2,1<<4, 0,4,1,2,3,5,6},\n      /*6*/ {3,1<<4, 0,6,1,2,3,4,5,7}\n    };\n    for(i=0;i<header.channels;i++)mapping[i]=opusenc_streams[header.channels-1][i+2];\n    force_narrow=opusenc_streams[header.channels-1][1];\n    header.nb_coupled=opusenc_streams[header.channels-1][0];\n    header.nb_streams=header.channels-header.nb_coupled;\n  }\n  header.channel_mapping=header.channels>8?255:header.nb_streams>1;\n  if(header.channel_mapping>0)for(i=0;i<header.channels;i++)header.stream_map[i]=mapping[i];\n  /* 0 dB gain is the recommended unless you know what you're doing */\n  header.gain=0;\n  header.input_sample_rate=rate;\n\n  min_bytes=max_frame_bytes=(1275*3+7)*header.nb_streams;\n  packet=malloc(sizeof(unsigned char)*max_frame_bytes);\n  if(packet==NULL){\n    fprintf(stderr,\"Error allocating packet buffer.\\n\");\n    exit(1);\n  }\n\n  /*Initialize OPUS encoder*/\n  /*Framesizes <10ms can only use the MDCT modes, so we switch on RESTRICTED_LOWDELAY\n    to save the extra 2.5ms of codec lookahead when we'll be using only small frames.*/\n  st=opus_multistream_encoder_create(coding_rate, chan, header.nb_streams, header.nb_coupled,\n     mapping, frame_size<480/(48000/coding_rate)?OPUS_APPLICATION_RESTRICTED_LOWDELAY:OPUS_APPLICATION_AUDIO, &ret);\n  if(ret!=OPUS_OK){\n    fprintf(stderr, \"Cannot create encoder: %s\\n\", opus_strerror(ret));\n    exit(1);\n  }\n\n  ret=opus_multistream_encoder_ctl(st, OPUS_SET_SIGNAL(signal));\n  if(ret!=OPUS_OK){\n    fprintf(stderr,\"OPUS_SET_SIGNAL returned: %s\\n\",opus_strerror(ret));\n    exit(1);\n  }\n\n  if(force_narrow!=0){\n    for(i=0;i<header.nb_streams;i++){\n      if(force_narrow&(1<<i)){\n        OpusEncoder *oe;\n        opus_multistream_encoder_ctl(st,OPUS_MULTISTREAM_GET_ENCODER_STATE(i,&oe));\n        ret=opus_encoder_ctl(oe, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));\n        if(ret!=OPUS_OK){\n          fprintf(stderr,\"OPUS_SET_MAX_BANDWIDTH on stream %d returned: %s\\n\",i,opus_strerror(ret));\n          exit(1);\n        }\n      }\n    }\n  }\n\n  bitrate=bitrate>0?bitrate:64000*header.nb_streams+32000*header.nb_coupled;\n\n  if(bitrate>(1024000*chan)||bitrate<500){\n    fprintf(stderr,\"Error: Bitrate %d bits/sec is insane.\\nDid you mistake bits for kilobits?\\n\",bitrate);\n    fprintf(stderr,\"--bitrate values from 6-256 kbit/sec per channel are meaningful.\\n\");\n    exit(1);\n  }\n  bitrate=IMIN(chan*256000,bitrate);\n\n  ret=opus_multistream_encoder_ctl(st, OPUS_SET_BITRATE(bitrate));\n  if(ret!=OPUS_OK){\n    fprintf(stderr,\"OPUS_SET_BITRATE returned: %s\\n\",opus_strerror(ret));\n    exit(1);\n  }\n\n  ret=opus_multistream_encoder_ctl(st, OPUS_SET_VBR(!with_hard_cbr));\n  if(ret!=OPUS_OK){\n    fprintf(stderr,\"OPUS_SET_VBR returned: %s\\n\",opus_strerror(ret));\n    exit(1);\n  }\n\n  if(!with_hard_cbr){\n    ret=opus_multistream_encoder_ctl(st, OPUS_SET_VBR_CONSTRAINT(with_cvbr));\n    if(ret!=OPUS_OK){\n      fprintf(stderr,\"OPUS_SET_VBR_CONSTRAINT returned: %s\\n\",opus_strerror(ret));\n      exit(1);\n    }\n  }\n\n  ret=opus_multistream_encoder_ctl(st, OPUS_SET_COMPLEXITY(complexity));\n  if(ret!=OPUS_OK){\n    fprintf(stderr,\"OPUS_SET_COMPLEXITY returned: %s\\n\",opus_strerror(ret));\n    exit(1);\n  }\n\n  ret=opus_multistream_encoder_ctl(st, OPUS_SET_PACKET_LOSS_PERC(expect_loss));\n  if(ret!=OPUS_OK){\n    fprintf(stderr,\"OPUS_SET_PACKET_LOSS_PERC returned: %s\\n\",opus_strerror(ret));\n    exit(1);\n  }\n\n  /*This should be the last set of CTLs, except the lookahead get, so it can override the defaults.*/\n  for(i=0;i<opt_ctls;i++){\n    int target=opt_ctls_ctlval[i*3];\n    if(target==-1){\n      ret=opus_multistream_encoder_ctl(st,opt_ctls_ctlval[i*3+1],opt_ctls_ctlval[i*3+2]);\n      if(ret!=OPUS_OK){\n        fprintf(stderr,\"opus_multistream_encoder_ctl(st,%d,%d) returned: %s\\n\",opt_ctls_ctlval[i*3+1],opt_ctls_ctlval[i*3+2],opus_strerror(ret));\n        exit(1);\n      }\n    }else if(target<header.nb_streams){\n      OpusEncoder *oe;\n      opus_multistream_encoder_ctl(st,OPUS_MULTISTREAM_GET_ENCODER_STATE(i,&oe));\n      ret=opus_encoder_ctl(oe, opt_ctls_ctlval[i*3+1],opt_ctls_ctlval[i*3+2]);\n      if(ret!=OPUS_OK){\n        fprintf(stderr,\"opus_encoder_ctl(st[%d],%d,%d) returned: %s\\n\",target,opt_ctls_ctlval[i*3+1],opt_ctls_ctlval[i*3+2],opus_strerror(ret));\n        exit(1);\n      }\n    }else{\n      fprintf(stderr,\"--set-ctl-int target stream %d is higher than the maximum stream number %d.\\n\",target,header.nb_streams-1);\n      exit(1);\n    }\n  }\n\n  /*We do the lookahead check late so user CTLs can change it*/\n  ret=opus_multistream_encoder_ctl(st, OPUS_GET_LOOKAHEAD(&lookahead));\n  if(ret!=OPUS_OK){\n    fprintf(stderr,\"OPUS_GET_LOOKAHEAD returned: %s\\n\",opus_strerror(ret));\n    exit(1);\n  }\n  inopt.skip+=lookahead;\n  /*Regardless of the rate we're coding at the ogg timestamping/skip is\n    always timed at 48000.*/\n  header.preskip=inopt.skip*(48000./coding_rate);\n  /* Extra samples that need to be read to compensate for the pre-skip */\n  inopt.extraout=(int)header.preskip*(rate/48000.);\n\n  if(!quiet){\n    int opus_app;\n    fprintf(stderr,\"Encoding using %s\",opus_version);\n    opus_multistream_encoder_ctl(st,OPUS_GET_APPLICATION(&opus_app));\n    if(opus_app==OPUS_APPLICATION_VOIP)fprintf(stderr,\" (VoIP)\\n\");\n    else if(opus_app==OPUS_APPLICATION_AUDIO)fprintf(stderr,\" (audio)\\n\");\n    else if(opus_app==OPUS_APPLICATION_RESTRICTED_LOWDELAY)fprintf(stderr,\" (low-delay)\\n\");\n    else fprintf(stderr,\" (unknown)\\n\");\n    fprintf(stderr,\"-----------------------------------------------------\\n\");\n    fprintf(stderr,\"   Input: %0.6gkHz %d channel%s\\n\",\n            header.input_sample_rate/1000.,chan,chan<2?\"\":\"s\");\n    fprintf(stderr,\"  Output: %d channel%s (\",header.channels,header.channels<2?\"\":\"s\");\n    if(header.nb_coupled>0)fprintf(stderr,\"%d coupled\",header.nb_coupled*2);\n    if(header.nb_streams-header.nb_coupled>0)fprintf(stderr,\n       \"%s%d uncoupled\",header.nb_coupled>0?\", \":\"\",\n       header.nb_streams-header.nb_coupled);\n    fprintf(stderr,\")\\n          %0.2gms packets, %0.6gkbit/sec%s\\n\",\n       frame_size/(coding_rate/1000.), bitrate/1000.,\n       with_hard_cbr?\" CBR\":with_cvbr?\" CVBR\":\" VBR\");\n    fprintf(stderr,\" Preskip: %d\\n\",header.preskip);\n\n    if(frange!=NULL)fprintf(stderr,\"         Writing final range file %s\\n\",range_file);\n    fprintf(stderr,\"\\n\");\n  }\n\n  if(strcmp(outFile,\"-\")==0){\n#if defined WIN32 || defined _WIN32\n    _setmode(_fileno(stdout), _O_BINARY);\n#endif\n    fout=stdout;\n  }else{\n    fout=fopen(outFile, \"wb\");\n    if(!fout){\n      perror(outFile);\n      exit(1);\n    }\n  }\n\n  /*Initialize Ogg stream struct*/\n  gettimeofday(&start_time,NULL);\n  srand(((getpid()&65535)<<15)^start_time.tv_sec^start_time.tv_usec);\n  if(ogg_stream_init(&os, rand())==-1){\n    fprintf(stderr,\"Error: stream init failed\\n\");\n    exit(1);\n  }\n  start_time.tv_sec=0;\n\n  /*Write header*/\n  {\n    unsigned char header_data[100];\n    int packet_size=opus_header_to_packet(&header, header_data, 100);\n    op.packet=header_data;\n    op.bytes=packet_size;\n    op.b_o_s=1;\n    op.e_o_s=0;\n    op.granulepos=0;\n    op.packetno=0;\n    ogg_stream_packetin(&os, &op);\n\n    while((ret=ogg_stream_flush(&os, &og))){\n      if(!ret)break;\n      ret=oe_write_page(&og, fout);\n      if(ret!=og.header_len+og.body_len){\n        fprintf(stderr,\"Error: failed writing header to output stream\\n\");\n        exit(1);\n      }\n      bytes_written+=ret;\n      pages_out++;\n    }\n\n    op.packet=(unsigned char *)comments;\n    op.bytes=comments_length;\n    op.b_o_s=0;\n    op.e_o_s=0;\n    op.granulepos=0;\n    op.packetno=1;\n    ogg_stream_packetin(&os, &op);\n  }\n\n  /* writing the rest of the opus header packets */\n  while((ret=ogg_stream_flush(&os, &og))){\n    if(!ret)break;\n    ret=oe_write_page(&og, fout);\n    if(ret!=og.header_len + og.body_len){\n      fprintf(stderr,\"Error: failed writing header to output stream\\n\");\n      exit(1);\n    }\n    bytes_written+=ret;\n    pages_out++;\n  }\n\n  free(comments);\n\n  input=malloc(sizeof(float)*frame_size*chan);\n  if(input==NULL){\n    fprintf(stderr,\"Error: couldn't allocate sample buffer.\\n\");\n    exit(1);\n  }\n\n  /*Main encoding loop (one frame per iteration)*/\n  eos=0;\n  nb_samples=-1;\n  while(!op.e_o_s){\n    int size_segments,cur_frame_size;\n    id++;\n\n    if(nb_samples<0){\n      nb_samples = inopt.read_samples(inopt.readdata,input,frame_size);\n      total_samples+=nb_samples;\n      if(nb_samples<frame_size)op.e_o_s=1;\n      else op.e_o_s=0;\n    }\n    op.e_o_s|=eos;\n\n    if(start_time.tv_sec==0)gettimeofday(&start_time,NULL);\n\n    cur_frame_size=frame_size;\n\n    /*No fancy end padding, just fill with zeros for now.*/\n    if(nb_samples<cur_frame_size)for(i=nb_samples*chan;i<cur_frame_size*chan;i++)input[i]=0;\n\n    /*Encode current frame*/\n    VG_UNDEF(packet,max_frame_bytes);\n    VG_CHECK(input,sizeof(float)*chan*cur_frame_size);\n    nbBytes=opus_multistream_encode_float(st, input, cur_frame_size, packet, max_frame_bytes);\n    if(nbBytes<0){\n      fprintf(stderr, \"Encoding failed: %s. Aborting.\\n\", opus_strerror(nbBytes));\n      break;\n    }\n    VG_CHECK(packet,nbBytes);\n    VG_UNDEF(input,sizeof(float)*chan*cur_frame_size);\n    nb_encoded+=cur_frame_size;\n    enc_granulepos+=cur_frame_size*48000/coding_rate;\n    total_bytes+=nbBytes;\n    size_segments=(nbBytes+255)/255;\n    peak_bytes=IMAX(nbBytes,peak_bytes);\n    min_bytes=IMIN(nbBytes,min_bytes);\n\n    if(frange!=NULL){\n      OpusEncoder *oe;\n      opus_uint32 rngs[header.nb_streams];\n      for(i=0;i<header.nb_streams;i++){\n        ret=opus_multistream_encoder_ctl(st,OPUS_MULTISTREAM_GET_ENCODER_STATE(i,&oe));\n        ret=opus_encoder_ctl(oe,OPUS_GET_FINAL_RANGE(&rngs[i]));\n      }\n      save_range(frange,cur_frame_size*(48000/coding_rate),packet,nbBytes,\n                 rngs,header.nb_streams);\n    }\n\n    /*Flush early if adding this packet would make us end up with a\n      continued page which we wouldn't have otherwise.*/\n    while((((size_segments<=255)&&(last_segments+size_segments>255))||\n           (enc_granulepos-last_granulepos>max_ogg_delay))&&\n#ifdef OLD_LIBOGG\n           ogg_stream_flush(&os, &og)){\n#else\n           ogg_stream_flush_fill(&os, &og,255*255)){\n#endif\n      if(ogg_page_packets(&og)!=0)last_granulepos=ogg_page_granulepos(&og);\n      last_segments-=og.header[26];\n      ret=oe_write_page(&og, fout);\n      if(ret!=og.header_len+og.body_len){\n         fprintf(stderr,\"Error: failed writing data to output stream\\n\");\n         exit(1);\n      }\n      bytes_written+=ret;\n      pages_out++;\n    }\n\n    /*The downside of early reading is if the input is an exact\n      multiple of the frame_size you'll get an extra frame that needs\n      to get cropped off. The downside of late reading is added delay.\n      If your ogg_delay is 120ms or less we'll assume you want the\n      low delay behavior.*/\n    if((!op.e_o_s)&&max_ogg_delay>5760){\n      nb_samples = inopt.read_samples(inopt.readdata,input,frame_size);\n      total_samples+=nb_samples;\n      if(nb_samples<frame_size)eos=1;\n      if(nb_samples==0)op.e_o_s=1;\n    } else nb_samples=-1;\n\n    op.packet=(unsigned char *)packet;\n    op.bytes=nbBytes;\n    op.b_o_s=0;\n    op.granulepos=enc_granulepos;\n    if(op.e_o_s){\n      /*We compute the final GP as ceil(len*48k/input_rate). When a resampling\n        decoder does the matching floor(len*input/48k) conversion the length will\n        be exactly the same as the input.*/\n      op.granulepos=((original_samples*48000+rate-1)/rate)+header.preskip;\n    }\n    op.packetno=2+id;\n    ogg_stream_packetin(&os, &op);\n    last_segments+=size_segments;\n\n    /*If the stream is over or we're sure that the delayed flush will fire,\n      go ahead and flush now to avoid adding delay.*/\n    while((op.e_o_s||(enc_granulepos+frame_size-last_granulepos>max_ogg_delay)||\n           (last_segments>=255))?\n#ifdef OLD_LIBOGG\n    /*Libogg > 1.2.2 allows us to achieve lower overhead by\n      producing larger pages. For 20ms frames this is only relevant\n      above ~32kbit/sec.*/\n           ogg_stream_flush(&os, &og):\n           ogg_stream_pageout(&os, &og)){\n#else\n           ogg_stream_flush_fill(&os, &og,255*255):\n           ogg_stream_pageout_fill(&os, &og,255*255)){\n#endif\n      if(ogg_page_packets(&og)!=0)last_granulepos=ogg_page_granulepos(&og);\n      last_segments-=og.header[26];\n      ret=oe_write_page(&og, fout);\n      if(ret!=og.header_len+og.body_len){\n         fprintf(stderr,\"Error: failed writing data to output stream\\n\");\n         exit(1);\n      }\n      bytes_written+=ret;\n      pages_out++;\n    }\n\n    if(!quiet){\n      gettimeofday(&stop_time,NULL);\n      if(stop_time.tv_sec>last_spin){\n        double estbitrate;\n        double coded_seconds=nb_encoded/(double)coding_rate;\n        double wall_time=(stop_time.tv_sec-start_time.tv_sec)+\n          (stop_time.tv_usec-start_time.tv_usec)*1e-06;\n        char sbuf[55];\n        static const char spinner[]=\"|/-\\\\\";\n        if(!with_hard_cbr){\n          double tweight=1./(1+exp(-((coded_seconds/10.)-3.)));\n          estbitrate=(total_bytes*8.0/coded_seconds)*tweight+\n                      bitrate*(1.-tweight);\n        }else estbitrate=nbBytes*8*((double)coding_rate/frame_size);\n        for(i=0;i<last_spin_len;i++)fprintf(stderr,\" \");\n        if(inopt.total_samples_per_channel>0 && inopt.total_samples_per_channel<nb_encoded){\n          snprintf(sbuf,54,\"\\r[%c] %02d%% \",spinner[last_spin&3],\n          (int)floor(nb_encoded/(double)(inopt.total_samples_per_channel+inopt.skip)*100.));\n        }else{\n          snprintf(sbuf,54,\"\\r[%c] \",spinner[last_spin&3]);\n        }\n        last_spin_len=strlen(sbuf);\n        snprintf(sbuf+last_spin_len,54-last_spin_len,\n          \"%02d:%02d:%02d.%02d %4.3gx realtime, %5.4gkbit/s\\r\",\n          (int)(coded_seconds/3600),(int)(coded_seconds/60)%60,\n          (int)(coded_seconds)%60,(int)(coded_seconds*100)%100,\n          coded_seconds/wall_time,\n          estbitrate/1000.);\n        fprintf(stderr,\"%s\",sbuf);\n        last_spin_len=strlen(sbuf);\n        last_spin=stop_time.tv_sec;\n      }\n    }\n  }\n  gettimeofday(&stop_time,NULL);\n\n  for(i=0;i<last_spin_len;i++)fprintf(stderr,\" \");\n  if(last_spin_len)fprintf(stderr,\"\\r\");\n\n  if(!quiet){\n    double coded_seconds=nb_encoded/(double)coding_rate;\n    double wall_time=(stop_time.tv_sec-start_time.tv_sec)+\n      (stop_time.tv_usec-start_time.tv_usec)*1e-06;\n    fprintf(stderr,\"Encoding complete\\n\");\n    fprintf(stderr,\"-----------------------------------------------------\\n\");\n    fprintf(stderr,\"    Encoded:\");\n    print_time(coded_seconds);\n    fprintf(stderr,\"\\n    Runtime:\");\n    print_time(wall_time);\n    fprintf(stderr,\"\\n             (%0.4gx realtime)\\n\",coded_seconds/wall_time);\n    fprintf(stderr,\"      Wrote: %\" I64FORMAT \" bytes, %d packets, %\" I64FORMAT \" pages\\n\",bytes_written,id+1,pages_out);\n    fprintf(stderr,\"    Bitrate: %0.6gkbit/s (without overhead)\\n\",\n            total_bytes*8.0/(coded_seconds)/1000.0);\n    fprintf(stderr,\" Rate range: %0.6gkbit/s to %0.6gkbit/s\\n             (%d to %d bytes per packet)\\n\",\n            min_bytes*8*((double)coding_rate/frame_size/1000.),\n            peak_bytes*8*((double)coding_rate/frame_size/1000.),min_bytes,peak_bytes);\n    fprintf(stderr,\"   Overhead: %0.3g%% (container+metadata)\\n\",(bytes_written-total_bytes)/(double)bytes_written*100.);\n#ifdef OLD_LIBOGG\n    if(max_ogg_delay>(frame_size*(48000/coding_rate)*4))fprintf(stderr,\"   (use libogg 1.3 or later for lower overhead)\\n\");\n#endif\n    fprintf(stderr,\"\\n\");\n  }\n\n  opus_multistream_encoder_destroy(st);\n  ogg_stream_clear(&os);\n  free(packet);\n  free(input);\n  if(opt_ctls)free(opt_ctls_ctlval);\n\n  if(rate!=coding_rate)clear_resample(&inopt);\n  clear_padder(&inopt);\n  if(downmix)clear_downmix(&inopt);\n  in_format->close_func(inopt.readdata);\n  if(fin)fclose(fin);\n  if(fout)fclose(fout);\n  if(frange)fclose(frange);\n  return 0;\n}\n\n/*\n Comments will be stored in the Vorbis style.\n It is describled in the \"Structure\" section of\n    http://www.xiph.org/ogg/vorbis/doc/v-comment.html\n\n However, Opus and other non-vorbis formats omit the \"framing_bit\".\n\nThe comment header is decoded as follows:\n  1) [vendor_length] = read an unsigned integer of 32 bits\n  2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets\n  3) [user_comment_list_length] = read an unsigned integer of 32 bits\n  4) iterate [user_comment_list_length] times {\n     5) [length] = read an unsigned integer of 32 bits\n     6) this iteration's user comment = read a UTF-8 vector as [length] octets\n     }\n  7) done.\n*/\n\n#define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \\\n                           ((buf[base+2]<<16)&0xff0000)| \\\n                           ((buf[base+1]<<8)&0xff00)| \\\n                           (buf[base]&0xff))\n#define writeint(buf, base, val) do{ buf[base+3]=((val)>>24)&0xff; \\\n                                     buf[base+2]=((val)>>16)&0xff; \\\n                                     buf[base+1]=((val)>>8)&0xff; \\\n                                     buf[base]=(val)&0xff; \\\n                                 }while(0)\n\nstatic void comment_init(char **comments, int* length, const char *vendor_string)\n{\n  /*The 'vendor' field should be the actual encoding library used.*/\n  int vendor_length=strlen(vendor_string);\n  int user_comment_list_length=0;\n  int len=8+4+vendor_length+4;\n  char *p=(char*)malloc(len);\n  if(p==NULL){\n    fprintf(stderr, \"malloc failed in comment_init()\\n\");\n    exit(1);\n  }\n  memcpy(p, \"OpusTags\", 8);\n  writeint(p, 8, vendor_length);\n  memcpy(p+12, vendor_string, vendor_length);\n  writeint(p, 12+vendor_length, user_comment_list_length);\n  *length=len;\n  *comments=p;\n}\n\nstatic void comment_add(char **comments, int* length, char *tag, char *val)\n{\n  char* p=*comments;\n  int vendor_length=readint(p, 8);\n  int user_comment_list_length=readint(p, 8+4+vendor_length);\n  int tag_len=(tag?strlen(tag):0);\n  int val_len=strlen(val);\n  int len=(*length)+4+tag_len+val_len;\n\n  p=(char*)realloc(p, len);\n  if(p==NULL){\n    fprintf(stderr, \"realloc failed in comment_add()\\n\");\n    exit(1);\n  }\n\n  writeint(p, *length, tag_len+val_len);      /* length of comment */\n  if(tag) memcpy(p+*length+4, tag, tag_len);  /* comment */\n  memcpy(p+*length+4+tag_len, val, val_len);  /* comment */\n  writeint(p, 8+4+vendor_length, user_comment_list_length+1);\n  *comments=p;\n  *length=len;\n}\n#undef readint\n#undef writeint\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/opusenc.h",
    "content": "#ifndef __OPUSENC_H\n#define __OPUSENC_H\n\n#include <opus_types.h>\n\n#ifdef ENABLE_NLS\n#include <libintl.h>\n#define _(X) gettext(X)\n#else\n#define _(X) (X)\n#define textdomain(X)\n#define bindtextdomain(X, Y)\n#endif\n#ifdef gettext_noop\n#define N_(X) gettext_noop(X)\n#else\n#define N_(X) (X)\n#endif\n\ntypedef long (*audio_read_func)(void *src, float *buffer, int samples);\n\ntypedef struct\n{\n    audio_read_func read_samples;\n    void *readdata;\n    opus_int64 total_samples_per_channel;\n    int rawmode;\n    int channels;\n    long rate;\n    int samplesize;\n    int endianness;\n    char *infilename;\n    int ignorelength;\n    int skip;\n    int extraout;\n} oe_enc_opt;\n\nvoid setup_scaler(oe_enc_opt *opt, float scale);\nvoid clear_scaler(oe_enc_opt *opt);\nvoid setup_padder(oe_enc_opt *opt, ogg_int64_t *original_samples);\nvoid clear_padder(oe_enc_opt *opt);\nint setup_downmix(oe_enc_opt *opt, int out_channels);\nvoid clear_downmix(oe_enc_opt *opt);\n\ntypedef struct\n{\n    int (*id_func)(unsigned char *buf, int len); /* Returns true if can load file */\n    int id_data_len; /* Amount of data needed to id whether this can load the file */\n    int (*open_func)(FILE *in, oe_enc_opt *opt, unsigned char *buf, int buflen);\n    void (*close_func)(void *);\n    char *format;\n    char *description;\n} input_format;\n\ntypedef struct {\n    short format;\n    short channels;\n    int samplerate;\n    int bytespersec;\n    short align;\n    short samplesize;\n    unsigned int mask;\n} wav_fmt;\n\ntypedef struct {\n    short channels;\n    short samplesize;\n    opus_int64 totalsamples;\n    opus_int64 samplesread;\n    FILE *f;\n    short bigendian;\n    int *channel_permute;\n} wavfile;\n\ntypedef struct {\n    short channels;\n    opus_int64 totalframes;\n    short samplesize;\n    int rate;\n    int offset;\n    int blocksize;\n} aiff_fmt;\n\ntypedef wavfile aifffile; /* They're the same */\n\ninput_format *open_audio_file(FILE *in, oe_enc_opt *opt);\n\nint raw_open(FILE *in, oe_enc_opt *opt, unsigned char *buf, int buflen);\nint wav_open(FILE *in, oe_enc_opt *opt, unsigned char *buf, int buflen);\nint aiff_open(FILE *in, oe_enc_opt *opt, unsigned char *buf, int buflen);\nint wav_id(unsigned char *buf, int len);\nint aiff_id(unsigned char *buf, int len);\nvoid wav_close(void *);\nvoid raw_close(void *);\nint setup_resample(oe_enc_opt *opt, int complexity, long outfreq);\nvoid clear_resample(oe_enc_opt *opt);\n\nlong wav_read(void *, float *buffer, int samples);\nlong wav_ieee_read(void *, float *buffer, int samples);\n\n#endif /* __OPUSENC_H */\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/opusinfo.c",
    "content": "/* Opusinfo\n *\n * A tool to describe opus file contents and metadata.\n *\n * This is a fork of ogginfo from the vorbis-tools package\n * which has been cut down to only have opus support.\n *\n * Ogginfo is\n * Copyright 2002-2005 Michael Smith <msmith@xiph.org>\n * Licensed under the GNU GPL, distributed with this program.\n */\n\n#ifdef HAVE_CONFIG_H\n#include <config.h>\n#endif\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <errno.h>\n#include <string.h>\n#include <stdarg.h>\n#include <getopt.h>\n#include <math.h>\n\n#include <ogg/ogg.h>\n\n/*No NLS support for now*/\n#define _(X) (X)\n\n#include \"opusinfo.h\"\n#include \"opus_header.h\"\n#include \"info_opus.h\"\n\n#define CHUNK 4500\n\nstatic int printlots = 0;\nstatic int printinfo = 1;\nstatic int printwarn = 1;\nstatic int verbose = 1;\n\nstatic int flawed;\n\n#define CONSTRAINT_PAGE_AFTER_EOS   1\n#define CONSTRAINT_MUXING_VIOLATED  2\n\nstatic stream_set *create_stream_set(void) {\n    stream_set *set = calloc(1, sizeof(stream_set));\n\n    set->streams = calloc(5, sizeof(stream_processor));\n    set->allocated = 5;\n    set->used = 0;\n\n    return set;\n}\n\nvoid oi_info(char *format, ...)\n{\n    va_list ap;\n\n    if(!printinfo)\n        return;\n\n    va_start(ap, format);\n    vfprintf(stdout, format, ap);\n    va_end(ap);\n}\n\nvoid oi_warn(char *format, ...)\n{\n    va_list ap;\n\n    flawed = 1;\n    if(!printwarn)\n        return;\n\n    va_start(ap, format);\n    vfprintf(stdout, format, ap);\n    va_end(ap);\n}\n\nvoid oi_error(char *format, ...)\n{\n    va_list ap;\n\n    flawed = 1;\n\n    va_start(ap, format);\n    vfprintf(stdout, format, ap);\n    va_end(ap);\n}\n\nvoid check_xiph_comment(stream_processor *stream, int i, const char *comment,\n    int comment_length)\n{\n    char *sep = strchr(comment, '=');\n    int j;\n    int broken = 0;\n    unsigned char *val;\n    int bytes;\n    int remaining;\n\n    if(sep == NULL) {\n        oi_warn(_(\"WARNING: Comment %d in stream %d has invalid \"\n              \"format, does not contain '=': \\\"%s\\\"\\n\"),\n              i, stream->num, comment);\n             return;\n    }\n\n    for(j=0; j < sep-comment; j++) {\n        if(comment[j] < 0x20 || comment[j] > 0x7D) {\n            oi_warn(_(\"WARNING: Invalid comment fieldname in \"\n                   \"comment %d (stream %d): \\\"%s\\\"\\n\"),\n                   i, stream->num, comment);\n            broken = 1;\n            break;\n        }\n    }\n\n    if(broken)\n\treturn;\n\n    val = (unsigned char *)comment;\n\n    j = sep-comment+1;\n    while(j < comment_length)\n    {\n        remaining = comment_length - j;\n        if((val[j] & 0x80) == 0)\n            bytes = 1;\n        else if((val[j] & 0x40) == 0x40) {\n            if((val[j] & 0x20) == 0)\n                bytes = 2;\n            else if((val[j] & 0x10) == 0)\n                bytes = 3;\n            else if((val[j] & 0x08) == 0)\n                bytes = 4;\n            else if((val[j] & 0x04) == 0)\n                bytes = 5;\n            else if((val[j] & 0x02) == 0)\n                bytes = 6;\n            else {\n                oi_warn(_(\"WARNING: Illegal UTF-8 sequence in \"\n                    \"comment %d (stream %d): length marker wrong\\n\"),\n                    i, stream->num);\n                broken = 1;\n                break;\n            }\n        }\n        else {\n            oi_warn(_(\"WARNING: Illegal UTF-8 sequence in comment \"\n                \"%d (stream %d): length marker wrong\\n\"), i, stream->num);\n            broken = 1;\n            break;\n        }\n\n        if(bytes > remaining) {\n            oi_warn(_(\"WARNING: Illegal UTF-8 sequence in comment \"\n                \"%d (stream %d): too few bytes\\n\"), i, stream->num);\n            broken = 1;\n            break;\n        }\n\n        switch(bytes) {\n            case 1:\n                /* No more checks needed */\n                break;\n            case 2:\n                if((val[j+1] & 0xC0) != 0x80)\n                    broken = 1;\n                if((val[j] & 0xFE) == 0xC0)\n                    broken = 1;\n                break;\n            case 3:\n                if(!((val[j] == 0xE0 && val[j+1] >= 0xA0 && val[j+1] <= 0xBF &&\n                         (val[j+2] & 0xC0) == 0x80) ||\n                     (val[j] >= 0xE1 && val[j] <= 0xEC &&\n                         (val[j+1] & 0xC0) == 0x80 &&\n                         (val[j+2] & 0xC0) == 0x80) ||\n                     (val[j] == 0xED && val[j+1] >= 0x80 &&\n                         val[j+1] <= 0x9F &&\n                         (val[j+2] & 0xC0) == 0x80) ||\n                     (val[j] >= 0xEE && val[j] <= 0xEF &&\n                         (val[j+1] & 0xC0) == 0x80 &&\n                         (val[j+2] & 0xC0) == 0x80)))\n                     broken = 1;\n                 if(val[j] == 0xE0 && (val[j+1] & 0xE0) == 0x80)\n                     broken = 1;\n                 break;\n            case 4:\n                 if(!((val[j] == 0xF0 && val[j+1] >= 0x90 &&\n                         val[j+1] <= 0xBF &&\n                         (val[j+2] & 0xC0) == 0x80 &&\n                         (val[j+3] & 0xC0) == 0x80) ||\n                     (val[j] >= 0xF1 && val[j] <= 0xF3 &&\n                         (val[j+1] & 0xC0) == 0x80 &&\n                         (val[j+2] & 0xC0) == 0x80 &&\n                         (val[j+3] & 0xC0) == 0x80) ||\n                     (val[j] == 0xF4 && val[j+1] >= 0x80 &&\n                         val[j+1] <= 0x8F &&\n                         (val[j+2] & 0xC0) == 0x80 &&\n                         (val[j+3] & 0xC0) == 0x80)))\n                     broken = 1;\n                 if(val[j] == 0xF0 && (val[j+1] & 0xF0) == 0x80)\n                     broken = 1;\n                 break;\n             /* 5 and 6 aren't actually allowed at this point */\n             case 5:\n                 broken = 1;\n                 break;\n             case 6:\n                 broken = 1;\n                 break;\n         }\n\n         if(broken) {\n             char *simple = malloc (comment_length + 1);\n             char *seq = malloc (comment_length * 3 + 1);\n             static char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',\n                                  '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};\n             int k, c1 = 0, c2 = 0;\n             for (k = 0; k < comment_length; k++) {\n               seq[c1++] = hex[((unsigned char)comment[k]) >> 4];\n               seq[c1++] = hex[((unsigned char)comment[k]) & 0xf];\n               seq[c1++] = ' ';\n\n               if(comment[k] < 0x20 || comment[k] > 0x7D)\n                 simple[c2++] = '?';\n               else\n                 simple[c2++] = comment[k];\n             }\n             seq[c1] = 0;\n             simple[c2] = 0;\n             oi_warn(_(\"WARNING: Illegal UTF-8 sequence in comment \"\n                   \"%d (stream %d): invalid sequence \\\"%s\\\": %s\\n\"), i,\n                   stream->num, simple, seq);\n             broken = 1;\n             free (simple);\n             free (seq);\n             break;\n         }\n\n         j += bytes;\n     }\n\n     if(!broken) {\n         oi_info(\"\\t%s\\n\", comment);\n     }\n}\n\nstatic void process_null(stream_processor *stream, ogg_page *page)\n{\n    /* This is for invalid streams. */\n    (void)stream;\n    (void)page;\n}\n\nstatic void process_other(stream_processor *stream, ogg_page *page )\n{\n    ogg_packet packet;\n\n    ogg_stream_pagein(&stream->os, page);\n\n    while(ogg_stream_packetout(&stream->os, &packet) > 0) {\n        /* Should we do anything here? Currently, we don't */\n    }\n}\n\n\nstatic void free_stream_set(stream_set *set)\n{\n    int i;\n    for(i=0; i < set->used; i++) {\n        if(!set->streams[i].end) {\n            oi_warn(_(\"WARNING: EOS not set on stream %d (normal for live streams)\\n\"),\n                    set->streams[i].num);\n            if(set->streams[i].process_end)\n                set->streams[i].process_end(&set->streams[i]);\n        }\n        ogg_stream_clear(&set->streams[i].os);\n    }\n\n    free(set->streams);\n    free(set);\n}\n\nstatic int streams_open(stream_set *set)\n{\n    int i;\n    int res=0;\n    for(i=0; i < set->used; i++) {\n        if(!set->streams[i].end)\n            res++;\n    }\n\n    return res;\n}\n\nstatic void null_start(stream_processor *stream)\n{\n    stream->process_end = NULL;\n    stream->type = \"invalid\";\n    stream->process_page = process_null;\n}\n\nstatic void other_start(stream_processor *stream, char *type)\n{\n    if(type)\n        stream->type = type;\n    else\n        stream->type = \"unknown\";\n    stream->process_page = process_other;\n    stream->process_end = NULL;\n}\n\nstatic stream_processor *find_stream_processor(stream_set *set, ogg_page *page)\n{\n    ogg_uint32_t serial = ogg_page_serialno(page);\n    int i;\n    int invalid = 0;\n    int constraint = 0;\n    stream_processor *stream;\n\n    for(i=0; i < set->used; i++) {\n        if(serial == set->streams[i].serial) {\n            /* We have a match! */\n            stream = &(set->streams[i]);\n\n            set->in_headers = 0;\n            /* if we have detected EOS, then this can't occur here. */\n            if(stream->end) {\n                stream->isillegal = 1;\n                stream->constraint_violated = CONSTRAINT_PAGE_AFTER_EOS;\n                return stream;\n            }\n\n            stream->isnew = 0;\n            stream->start = ogg_page_bos(page);\n            stream->end = ogg_page_eos(page);\n            stream->serial = serial;\n            return stream;\n        }\n    }\n\n    /* If there are streams open, and we've reached the end of the\n     * headers, then we can't be starting a new stream.\n     * XXX: might this sometimes catch ok streams if EOS flag is missing,\n     * but the stream is otherwise ok?\n     */\n    if(streams_open(set) && !set->in_headers) {\n        constraint = CONSTRAINT_MUXING_VIOLATED;\n        invalid = 1;\n    }\n\n    set->in_headers = 1;\n\n    if(set->allocated < set->used)\n        stream = &set->streams[set->used];\n    else {\n        set->allocated += 5;\n        set->streams = realloc(set->streams, sizeof(stream_processor)*\n                set->allocated);\n        stream = &set->streams[set->used];\n    }\n    set->used++;\n    stream->num = set->used; /* We count from 1 */\n\n    stream->isnew = 1;\n    stream->isillegal = invalid;\n    stream->constraint_violated = constraint;\n\n    {\n        int res;\n        int has_oi_supported=0;\n        ogg_packet packet;\n\n        /* We end up processing the header page twice, but that's ok. */\n        ogg_stream_init(&stream->os, serial);\n        ogg_stream_pagein(&stream->os, page);\n        res = ogg_stream_packetout(&stream->os, &packet);\n        if(res <= 0) {\n            oi_warn(_(\"WARNING: Invalid header page, no packet found\\n\"));\n            null_start(stream);\n        }\n        else if(packet.bytes >= 19 && memcmp(packet.packet, \"OpusHead\", 8)==0)\n            info_opus_start(stream);\n        else if(packet.bytes >= 7 && memcmp(packet.packet, \"\\x01vorbis\", 7)==0) {\n            other_start(stream, \"Vorbis\");\n            has_oi_supported=1;\n        } else if(packet.bytes >= 7 && memcmp(packet.packet, \"\\x80theora\", 7)==0) {\n            other_start(stream, \"Theora\");\n            has_oi_supported=1;\n        } else if(packet.bytes >= 8 && memcmp(packet.packet, \"OggMIDI\\0\", 8)==0)\n            other_start(stream, \"MIDI\");\n        else if(packet.bytes >= 5 && memcmp(packet.packet, \"\\177FLAC\", 5)==0)\n            other_start(stream, \"FLAC\");\n        else if(packet.bytes == 4 && memcmp(packet.packet, \"fLaC\", 4)==0)\n            other_start(stream, \"FLAC (legacy)\");\n        else if(packet.bytes >= 8 && memcmp(packet.packet, \"Speex   \", 8)==0)\n            other_start(stream, \"speex\");\n        else if(packet.bytes >= 8 && memcmp(packet.packet, \"fishead\\0\", 8)==0)\n            other_start(stream, \"skeleton\");\n        else if(packet.bytes >= 5 && memcmp(packet.packet, \"BBCD\\0\", 5)==0)\n            other_start(stream, \"dirac\");\n        else if(packet.bytes >= 8 && memcmp(packet.packet, \"KW-DIRAC\", 8)==0)\n            other_start(stream, \"dirac (legacy)\");\n        else if(packet.bytes >= 8 && memcmp(packet.packet, \"\\x80kate\\0\\0\\0\", 8)==0) {\n            other_start(stream, \"Kate\");\n            has_oi_supported=1;\n        } else\n            other_start(stream, NULL);\n\n        res = ogg_stream_packetout(&stream->os, &packet);\n        if(res > 0) {\n            oi_warn(_(\"WARNING: Invalid header page in stream %d, \"\n                              \"contains multiple packets\\n\"), stream->num);\n        }\n        if(has_oi_supported)oi_info(_(\"Use ogginfo for more information on this file.\\n\"));\n\n        /* re-init, ready for processing */\n        ogg_stream_clear(&stream->os);\n        ogg_stream_init(&stream->os, serial);\n   }\n\n   stream->start = ogg_page_bos(page);\n   stream->end = ogg_page_eos(page);\n   stream->serial = serial;\n   stream->shownillegal = 0;\n   stream->seqno = ogg_page_pageno(page);\n\n   if(stream->serial == 0 || stream->serial == 0xFFFFFFFFUL) {\n       oi_info(_(\"Note: Stream %d has serial number %d, which is legal but may \"\n              \"cause problems with some tools.\\n\"), stream->num,\n               stream->serial);\n   }\n\n   return stream;\n}\n\nstatic int get_next_page(FILE *f, ogg_sync_state *ogsync, ogg_page *page,\n        ogg_int64_t *written)\n{\n    int ret;\n    char *buffer;\n    int bytes;\n\n    while((ret = ogg_sync_pageseek(ogsync, page)) <= 0) {\n        if(ret < 0) {\n            /* unsynced, we jump over bytes to a possible capture - we don't need to read more just yet */\n            oi_warn(_(\"WARNING: Hole in data (%d bytes) found at approximate offset %\" I64FORMAT \" bytes. Corrupted Ogg.\\n\"), -ret, *written);\n            continue;\n        }\n\n        /* zero return, we didn't have enough data to find a whole page, read */\n        buffer = ogg_sync_buffer(ogsync, CHUNK);\n        bytes = fread(buffer, 1, CHUNK, f);\n        if(bytes <= 0) {\n            ogg_sync_wrote(ogsync, 0);\n            return 0;\n        }\n        ogg_sync_wrote(ogsync, bytes);\n        *written += bytes;\n    }\n\n    return 1;\n}\n\nstatic void process_file(char *filename) {\n    FILE *file = fopen(filename, \"rb\");\n    ogg_sync_state ogsync;\n    ogg_page page;\n    stream_set *processors = create_stream_set();\n    int gotpage = 0;\n    ogg_int64_t written = 0;\n\n    if(!file) {\n        oi_error(_(\"Error opening input file \\\"%s\\\": %s\\n\"), filename,\n                    strerror(errno));\n        return;\n    }\n\n    printf(_(\"Processing file \\\"%s\\\"...\\n\\n\"), filename);\n\n    ogg_sync_init(&ogsync);\n\n    while(get_next_page(file, &ogsync, &page, &written)) {\n        stream_processor *p = find_stream_processor(processors, &page);\n        gotpage = 1;\n\n        if(!p) {\n            oi_error(_(\"Could not find a processor for stream, bailing\\n\"));\n            return;\n        }\n\n        if(p->isillegal && !p->shownillegal) {\n            char *constraint;\n            switch(p->constraint_violated) {\n                case CONSTRAINT_PAGE_AFTER_EOS:\n                    constraint = _(\"Page found for stream after EOS flag\");\n                    break;\n                case CONSTRAINT_MUXING_VIOLATED:\n                    constraint = _(\"Ogg muxing constraints violated, new \"\n                                   \"stream before EOS of all previous streams\");\n                    break;\n                default:\n                    constraint = _(\"Error unknown.\");\n            }\n\n            oi_warn(_(\"WARNING: illegally placed page(s) for logical stream %d\\n\"\n                   \"This indicates a corrupt Ogg file: %s.\\n\"),\n                    p->num, constraint);\n            p->shownillegal = 1;\n            /* If it's a new stream, we want to continue processing this page\n             * anyway to suppress additional spurious errors\n             */\n            if(!p->isnew)\n                continue;\n        }\n\n        if(p->isnew) {\n            oi_info(_(\"New logical stream (#%d, serial: %08x): type %s\\n\"),\n                    p->num, p->serial, p->type);\n            if(!p->start)\n                oi_warn(_(\"WARNING: stream start flag not set on stream %d\\n\"),\n                        p->num);\n        }\n        else if(p->start)\n            oi_warn(_(\"WARNING: stream start flag found in mid-stream \"\n                      \"on stream %d\\n\"), p->num);\n\n        if(p->seqno++ != ogg_page_pageno(&page)) {\n            if(!p->lostseq)\n                oi_warn(_(\"WARNING: sequence number gap in stream %d. Got page \"\n                       \"%ld when expecting page %ld. Indicates missing data.%s\\n\"\n                       ), p->num, ogg_page_pageno(&page), p->seqno - 1, p->seqno-1==2?_(\" (normal for live streams)\"):\"\");\n            p->seqno = ogg_page_pageno(&page);\n            p->lostseq = 1;\n        }\n        else\n            p->lostseq = 0;\n\n        if(!p->isillegal) {\n            p->process_page(p, &page);\n\n            if(p->end) {\n                if(p->process_end)\n                    p->process_end(p);\n                oi_info(_(\"Logical stream %d ended\\n\"), p->num);\n                p->isillegal = 1;\n                p->constraint_violated = CONSTRAINT_PAGE_AFTER_EOS;\n            }\n        }\n    }\n\n    if(!gotpage)\n        oi_error(_(\"ERROR: No Ogg data found in file \\\"%s\\\".\\n\"\n                \"Input probably not Ogg.\\n\"), filename);\n\n    free_stream_set(processors);\n\n    ogg_sync_clear(&ogsync);\n\n    fclose(file);\n}\n\nstatic void version (void) {\n    printf (_(\"opusinfo from %s %s\\n\"), PACKAGE, VERSION);\n}\n\nstatic void usage(void) {\n    version ();\n    printf (_(\" by the Xiph.Org Foundation (http://www.xiph.org/)\\n\\n\"));\n    printf(_(\"(c) 2003-2005 Michael Smith <msmith@xiph.org>\\n\"\n             \"(c) 2012 Gregory Maxwell <greg@xiph.org>\\n\\n\"\n             \"Opusinfo is a fork of ogginfo from the vorbis-tools package\\n\"\n             \"which has been cut down to only support opus files.\\n\\n\"\n             \"Usage: opusinfo [flags] file1.opus [file2.opus ... fileN.opus]\\n\"\n             \"Flags supported:\\n\"\n             \"\\t-h Show this help message.\\n\"\n             \"\\t-q Make less verbose. Once will remove detailed informative\\n\"\n             \"\\t   messages, twice will remove warnings.\\n\"\n             \"\\t-v Make more verbose. This may enable more detailed checks\\n\"\n             \"\\t   for some stream types.\\n\"));\n    printf (_(\"\\t-V Output version information and exit.\\n\"));\n}\n\nint main(int argc, char **argv) {\n    int f, ret;\n\n    if(argc < 2) {\n        fprintf(stdout,\n                _(\"Usage: opusinfo [flags] file1.opus [file2.opus ... fileN.opus]\\n\"\n                  \"\\n\"\n                  \"opusinfo is a tool for printing information about Opus files\\n\"\n                  \"and for diagnosing problems with them.\\n\"\n                  \"Full help shown with \\\"opusinfo -h\\\".\\n\"));\n        exit(1);\n    }\n\n    while((ret = getopt(argc, argv, \"hqvV\")) >= 0) {\n        switch(ret) {\n            case 'h':\n                usage();\n                return 0;\n            case 'V':\n                version();\n                return 0;\n            case 'v':\n                verbose++;\n                break;\n            case 'q':\n                verbose--;\n                break;\n        }\n    }\n\n    if(verbose > 1)\n        printlots = 1;\n    if(verbose < 1)\n        printinfo = 0;\n    if(verbose < 0)\n        printwarn = 0;\n\n    if(optind >= argc) {\n        fprintf(stderr,\n                _(\"No input files specified. \\\"opusinfo -h\\\" for help\\n\"));\n        return 1;\n    }\n\n    ret = 0;\n\n    for(f=optind; f < argc; f++) {\n        flawed = 0;\n        process_file(argv[f]);\n        if(flawed != 0)\n            ret = flawed;\n    }\n\n    return ret;\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/opusinfo.h",
    "content": "/* Ogginfo\n *\n * A tool to describe ogg file contents and metadata.\n *\n * Copyright 2002-2005 Michael Smith <msmith@xiph.org>\n * Licensed under the GNU GPL, distributed with this program.\n */\n\n/*No NLS support for now*/\n#define _(X) (X)\n\n#ifdef _WIN32\n#define I64FORMAT \"I64d\"\n#else\n#define I64FORMAT \"lld\"\n#endif\n\ntypedef struct _stream_processor {\n    void (*process_page)(struct _stream_processor *, ogg_page *);\n    void (*process_end)(struct _stream_processor *);\n    int isillegal;\n    int constraint_violated;\n    int shownillegal;\n    int isnew;\n    long seqno;\n    int lostseq;\n\n    int start;\n    int end;\n\n    int num;\n    char *type;\n\n    ogg_uint32_t serial; /* must be 32 bit unsigned */\n    ogg_stream_state os;\n    void *data;\n} stream_processor;\n\ntypedef struct {\n    stream_processor *streams;\n    int allocated;\n    int used;\n\n    int in_headers;\n} stream_set;\n\n\nvoid oi_info(char *format, ...);\nvoid oi_warn(char *format, ...);\nvoid oi_error(char *format, ...);\nvoid check_xiph_comment(stream_processor *stream, int i, const char *comment, int comment_length);\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/os_support.h",
    "content": "/* Copyright (C) 2007 Jean-Marc Valin\n      \n   File: os_support.h\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions are\n   met:\n\n   1. Redistributions of source code must retain the above copyright notice,\n   this list of conditions and the following disclaimer.\n\n   2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n   3. The name of the author may not be used to endorse or promote products\n   derived from this software without specific prior written permission.\n\n   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n   DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,\n   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\n   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n   POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifndef OS_SUPPORT_H\n#define OS_SUPPORT_H\n\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n#ifdef OS_SUPPORT_CUSTOM\n#include \"os_support_custom.h\"\n#endif\n\n/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_free \n    NOTE: speex_alloc needs to CLEAR THE MEMORY */\n#ifndef OVERRIDE_SPEEX_ALLOC\nstatic inline void *speex_alloc (int size)\n{\n   /* WARNING: this is not equivalent to malloc(). If you want to use malloc() \n      or your own allocator, YOU NEED TO CLEAR THE MEMORY ALLOCATED. Otherwise\n      you will experience strange bugs */\n   return calloc(size,1);\n}\n#endif\n\n/** Same as speex_alloc, except that the area is only needed inside a Speex call (might cause problem with wideband though) */\n#ifndef OVERRIDE_SPEEX_ALLOC_SCRATCH\nstatic inline void *speex_alloc_scratch (int size)\n{\n   /* Scratch space doesn't need to be cleared */\n   return calloc(size,1);\n}\n#endif\n\n/** Speex wrapper for realloc. To do your own dynamic allocation, all you need to do is replace this function, speex_alloc and speex_free */\n#ifndef OVERRIDE_SPEEX_REALLOC\nstatic inline void *speex_realloc (void *ptr, int size)\n{\n   return realloc(ptr, size);\n}\n#endif\n\n/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_alloc */\n#ifndef OVERRIDE_SPEEX_FREE\nstatic inline void speex_free (void *ptr)\n{\n   free(ptr);\n}\n#endif\n\n/** Same as speex_free, except that the area is only needed inside a Speex call (might cause problem with wideband though) */\n#ifndef OVERRIDE_SPEEX_FREE_SCRATCH\nstatic inline void speex_free_scratch (void *ptr)\n{\n   free(ptr);\n}\n#endif\n\n/** Copy n bytes of memory from src to dst. The 0* term provides compile-time type checking  */\n#ifndef OVERRIDE_SPEEX_COPY\n#define SPEEX_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) ))\n#endif\n\n/** Copy n bytes of memory from src to dst, allowing overlapping regions. The 0* term \n    provides compile-time type checking */\n#ifndef OVERRIDE_SPEEX_MOVE\n#define SPEEX_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) ))\n#endif\n\n/** Set n bytes of memory to value of c, starting at address s */\n#ifndef OVERRIDE_SPEEX_MEMSET\n#define SPEEX_MEMSET(dst, c, n) (memset((dst), (c), (n)*sizeof(*(dst))))\n#endif\n\n\n#ifndef OVERRIDE_SPEEX_FATAL\nstatic inline void _speex_fatal(const char *str, const char *file, int line)\n{\n   fprintf (stderr, \"Fatal (internal) error in %s, line %d: %s\\n\", file, line, str);\n   exit(1);\n}\n#endif\n\n#ifndef OVERRIDE_SPEEX_WARNING\nstatic inline void speex_warning(const char *str)\n{\n#ifndef DISABLE_WARNINGS\n   fprintf (stderr, \"warning: %s\\n\", str);\n#endif\n}\n#endif\n\n#ifndef OVERRIDE_SPEEX_WARNING_INT\nstatic inline void speex_warning_int(const char *str, int val)\n{\n#ifndef DISABLE_WARNINGS\n   fprintf (stderr, \"warning: %s %d\\n\", str, val);\n#endif\n}\n#endif\n\n#ifndef OVERRIDE_SPEEX_NOTIFY\nstatic inline void speex_notify(const char *str)\n{\n#ifndef DISABLE_NOTIFICATIONS\n   fprintf (stderr, \"notification: %s\\n\", str);\n#endif\n}\n#endif\n\n#ifndef OVERRIDE_SPEEX_PUTC\n/** Speex wrapper for putc */\nstatic inline void _speex_putc(int ch, void *file)\n{\n   FILE *f = (FILE *)file;\n   fprintf(f, \"%c\", ch);\n}\n#endif\n\n#define speex_fatal(str) _speex_fatal(str, __FILE__, __LINE__);\n#define speex_assert(cond) {if (!(cond)) {speex_fatal(\"assertion failed: \" #cond);}}\n\n#ifndef RELEASE\nstatic inline void print_vec(float *vec, int len, char *name)\n{\n   int i;\n   printf (\"%s \", name);\n   for (i=0;i<len;i++)\n      printf (\" %f\", vec[i]);\n   printf (\"\\n\");\n}\n#endif\n\n#endif\n\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/resample.c",
    "content": "/* Copyright (C) 2007-2008 Jean-Marc Valin\n   Copyright (C) 2008      Thorvald Natvig\n      \n   File: resample.c\n   Arbitrary resampling code\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions are\n   met:\n\n   1. Redistributions of source code must retain the above copyright notice,\n   this list of conditions and the following disclaimer.\n\n   2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n   3. The name of the author may not be used to endorse or promote products\n   derived from this software without specific prior written permission.\n\n   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n   DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,\n   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\n   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n   POSSIBILITY OF SUCH DAMAGE.\n*/\n\n/*\n   The design goals of this code are:\n      - Very fast algorithm\n      - SIMD-friendly algorithm\n      - Low memory requirement\n      - Good *perceptual* quality (and not best SNR)\n\n   Warning: This resampler is relatively new. Although I think I got rid of \n   all the major bugs and I don't expect the API to change anymore, there\n   may be something I've missed. So use with caution.\n\n   This algorithm is based on this original resampling algorithm:\n   Smith, Julius O. Digital Audio Resampling Home Page\n   Center for Computer Research in Music and Acoustics (CCRMA), \n   Stanford University, 2007.\n   Web published at http://www-ccrma.stanford.edu/~jos/resample/.\n\n   There is one main difference, though. This resampler uses cubic \n   interpolation instead of linear interpolation in the above paper. This\n   makes the table much smaller and makes it possible to compute that table\n   on a per-stream basis. In turn, being able to tweak the table for each \n   stream makes it possible to both reduce complexity on simple ratios \n   (e.g. 2/3), and get rid of the rounding operations in the inner loop. \n   The latter both reduces CPU time and makes the algorithm more SIMD-friendly.\n*/\n\n#ifdef HAVE_CONFIG_H\n# include \"config.h\"\n#endif\n\n#ifdef OUTSIDE_SPEEX\n#include <stdlib.h>\nstatic void *speex_alloc (int size) {return calloc(size,1);}\nstatic void *speex_realloc (void *ptr, int size) {return realloc(ptr, size);}\nstatic void speex_free (void *ptr) {free(ptr);}\n#include \"speex_resampler.h\"\n#include \"arch.h\"\n#else /* OUTSIDE_SPEEX */\n               \n#include \"../include/speex/speex_resampler.h\"\n#include \"arch.h\"\n#include \"os_support.h\"\n#endif /* OUTSIDE_SPEEX */\n\n#include \"stack_alloc.h\"\n#include <math.h>\n\n#ifndef M_PI\n#define M_PI 3.14159263\n#endif\n\n#ifdef FIXED_POINT\n#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x)))  \n#else\n#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x))))  \n#endif\n               \n#define IMAX(a,b) ((a) > (b) ? (a) : (b))\n#define IMIN(a,b) ((a) < (b) ? (a) : (b))\n\n#ifndef NULL\n#define NULL 0\n#endif\n\n#ifdef _USE_SSE\n#include \"resample_sse.h\"\n#endif\n\n/* Numer of elements to allocate on the stack */\n#ifdef VAR_ARRAYS\n#define FIXED_STACK_ALLOC 8192\n#else\n#define FIXED_STACK_ALLOC 1024\n#endif\n\ntypedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *);\n\nstruct SpeexResamplerState_ {\n   spx_uint32_t in_rate;\n   spx_uint32_t out_rate;\n   spx_uint32_t num_rate;\n   spx_uint32_t den_rate;\n   \n   int    quality;\n   spx_uint32_t nb_channels;\n   spx_uint32_t filt_len;\n   spx_uint32_t mem_alloc_size;\n   spx_uint32_t buffer_size;\n   int          int_advance;\n   int          frac_advance;\n   float  cutoff;\n   spx_uint32_t oversample;\n   int          initialised;\n   int          started;\n   \n   /* These are per-channel */\n   spx_int32_t  *last_sample;\n   spx_uint32_t *samp_frac_num;\n   spx_uint32_t *magic_samples;\n   \n   spx_word16_t *mem;\n   spx_word16_t *sinc_table;\n   spx_uint32_t sinc_table_length;\n   resampler_basic_func resampler_ptr;\n         \n   int    in_stride;\n   int    out_stride;\n} ;\n\nstatic double kaiser12_table[68] = {\n   0.99859849, 1.00000000, 0.99859849, 0.99440475, 0.98745105, 0.97779076,\n   0.96549770, 0.95066529, 0.93340547, 0.91384741, 0.89213598, 0.86843014,\n   0.84290116, 0.81573067, 0.78710866, 0.75723148, 0.72629970, 0.69451601,\n   0.66208321, 0.62920216, 0.59606986, 0.56287762, 0.52980938, 0.49704014,\n   0.46473455, 0.43304576, 0.40211431, 0.37206735, 0.34301800, 0.31506490,\n   0.28829195, 0.26276832, 0.23854851, 0.21567274, 0.19416736, 0.17404546,\n   0.15530766, 0.13794294, 0.12192957, 0.10723616, 0.09382272, 0.08164178,\n   0.07063950, 0.06075685, 0.05193064, 0.04409466, 0.03718069, 0.03111947,\n   0.02584161, 0.02127838, 0.01736250, 0.01402878, 0.01121463, 0.00886058,\n   0.00691064, 0.00531256, 0.00401805, 0.00298291, 0.00216702, 0.00153438,\n   0.00105297, 0.00069463, 0.00043489, 0.00025272, 0.00013031, 0.0000527734,\n   0.00001000, 0.00000000};\n/*\nstatic double kaiser12_table[36] = {\n   0.99440475, 1.00000000, 0.99440475, 0.97779076, 0.95066529, 0.91384741,\n   0.86843014, 0.81573067, 0.75723148, 0.69451601, 0.62920216, 0.56287762,\n   0.49704014, 0.43304576, 0.37206735, 0.31506490, 0.26276832, 0.21567274,\n   0.17404546, 0.13794294, 0.10723616, 0.08164178, 0.06075685, 0.04409466,\n   0.03111947, 0.02127838, 0.01402878, 0.00886058, 0.00531256, 0.00298291,\n   0.00153438, 0.00069463, 0.00025272, 0.0000527734, 0.00000500, 0.00000000};\n*/\nstatic double kaiser10_table[36] = {\n   0.99537781, 1.00000000, 0.99537781, 0.98162644, 0.95908712, 0.92831446,\n   0.89005583, 0.84522401, 0.79486424, 0.74011713, 0.68217934, 0.62226347,\n   0.56155915, 0.50119680, 0.44221549, 0.38553619, 0.33194107, 0.28205962,\n   0.23636152, 0.19515633, 0.15859932, 0.12670280, 0.09935205, 0.07632451,\n   0.05731132, 0.04193980, 0.02979584, 0.02044510, 0.01345224, 0.00839739,\n   0.00488951, 0.00257636, 0.00115101, 0.00035515, 0.00000000, 0.00000000};\n\nstatic double kaiser8_table[36] = {\n   0.99635258, 1.00000000, 0.99635258, 0.98548012, 0.96759014, 0.94302200,\n   0.91223751, 0.87580811, 0.83439927, 0.78875245, 0.73966538, 0.68797126,\n   0.63451750, 0.58014482, 0.52566725, 0.47185369, 0.41941150, 0.36897272,\n   0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758,\n   0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490,\n   0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000};\n   \nstatic double kaiser6_table[36] = {\n   0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003,\n   0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565,\n   0.71712752, 0.67172623, 0.62508937, 0.57774224, 0.53019925, 0.48295561,\n   0.43647969, 0.39120616, 0.34752997, 0.30580127, 0.26632152, 0.22934058,\n   0.19505503, 0.16360756, 0.13508755, 0.10953262, 0.08693120, 0.06722600,\n   0.05031820, 0.03607231, 0.02432151, 0.01487334, 0.00752000, 0.00000000};\n\nstruct FuncDef {\n   double *table;\n   int oversample;\n};\n      \nstatic struct FuncDef _KAISER12 = {kaiser12_table, 64};\n#define KAISER12 (&_KAISER12)\n/*static struct FuncDef _KAISER12 = {kaiser12_table, 32};\n#define KAISER12 (&_KAISER12)*/\nstatic struct FuncDef _KAISER10 = {kaiser10_table, 32};\n#define KAISER10 (&_KAISER10)\nstatic struct FuncDef _KAISER8 = {kaiser8_table, 32};\n#define KAISER8 (&_KAISER8)\nstatic struct FuncDef _KAISER6 = {kaiser6_table, 32};\n#define KAISER6 (&_KAISER6)\n\nstruct QualityMapping {\n   int base_length;\n   int oversample;\n   float downsample_bandwidth;\n   float upsample_bandwidth;\n   struct FuncDef *window_func;\n};\n\n\n/* This table maps conversion quality to internal parameters. There are two\n   reasons that explain why the up-sampling bandwidth is larger than the \n   down-sampling bandwidth:\n   1) When up-sampling, we can assume that the spectrum is already attenuated\n      close to the Nyquist rate (from an A/D or a previous resampling filter)\n   2) Any aliasing that occurs very close to the Nyquist rate will be masked\n      by the sinusoids/noise just below the Nyquist rate (guaranteed only for\n      up-sampling).\n*/\nstatic const struct QualityMapping quality_map[11] = {\n   {  8,  4, 0.830f, 0.860f, KAISER6 }, /* Q0 */\n   { 16,  4, 0.850f, 0.880f, KAISER6 }, /* Q1 */\n   { 32,  4, 0.882f, 0.910f, KAISER6 }, /* Q2 */  /* 82.3% cutoff ( ~60 dB stop) 6  */\n   { 48,  8, 0.895f, 0.917f, KAISER8 }, /* Q3 */  /* 84.9% cutoff ( ~80 dB stop) 8  */\n   { 64,  8, 0.921f, 0.940f, KAISER8 }, /* Q4 */  /* 88.7% cutoff ( ~80 dB stop) 8  */\n   { 80, 16, 0.922f, 0.940f, KAISER10}, /* Q5 */  /* 89.1% cutoff (~100 dB stop) 10 */\n   { 96, 16, 0.940f, 0.945f, KAISER10}, /* Q6 */  /* 91.5% cutoff (~100 dB stop) 10 */\n   {128, 16, 0.950f, 0.950f, KAISER10}, /* Q7 */  /* 93.1% cutoff (~100 dB stop) 10 */\n   {160, 16, 0.960f, 0.960f, KAISER10}, /* Q8 */  /* 94.5% cutoff (~100 dB stop) 10 */\n   {192, 32, 0.968f, 0.968f, KAISER12}, /* Q9 */  /* 95.5% cutoff (~100 dB stop) 10 */\n   {256, 32, 0.975f, 0.975f, KAISER12}, /* Q10 */ /* 96.6% cutoff (~100 dB stop) 10 */\n};\n/*8,24,40,56,80,104,128,160,200,256,320*/\nstatic double compute_func(float x, struct FuncDef *func)\n{\n   float y, frac;\n   double interp[4];\n   int ind; \n   y = x*func->oversample;\n   ind = (int)floor(y);\n   frac = (y-ind);\n   /* CSE with handle the repeated powers */\n   interp[3] =  -0.1666666667*frac + 0.1666666667*(frac*frac*frac);\n   interp[2] = frac + 0.5*(frac*frac) - 0.5*(frac*frac*frac);\n   /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/\n   interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac);\n   /* Just to make sure we don't have rounding problems */\n   interp[1] = 1.f-interp[3]-interp[2]-interp[0];\n   \n   /*sum = frac*accum[1] + (1-frac)*accum[2];*/\n   return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3];\n}\n\n#if 0\n#include <stdio.h>\nint main(int argc, char **argv)\n{\n   int i;\n   for (i=0;i<256;i++)\n   {\n      printf (\"%f\\n\", compute_func(i/256., KAISER12));\n   }\n   return 0;\n}\n#endif\n\n#ifdef FIXED_POINT\n/* The slow way of computing a sinc for the table. Should improve that some day */\nstatic spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func)\n{\n   /*fprintf (stderr, \"%f \", x);*/\n   float xx = x * cutoff;\n   if (fabs(x)<1e-6f)\n      return WORD2INT(32768.*cutoff);\n   else if (fabs(x) > .5f*N)\n      return 0;\n   /*FIXME: Can it really be any slower than this? */\n   return WORD2INT(32768.*cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func));\n}\n#else\n/* The slow way of computing a sinc for the table. Should improve that some day */\nstatic spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func)\n{\n   /*fprintf (stderr, \"%f \", x);*/\n   float xx = x * cutoff;\n   if (fabs(x)<1e-6)\n      return cutoff;\n   else if (fabs(x) > .5*N)\n      return 0;\n   /*FIXME: Can it really be any slower than this? */\n   return cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func);\n}\n#endif\n\n#ifdef FIXED_POINT\nstatic void cubic_coef(spx_word16_t x, spx_word16_t interp[4])\n{\n   /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation\n   but I know it's MMSE-optimal on a sinc */\n   spx_word16_t x2, x3;\n   x2 = MULT16_16_P15(x, x);\n   x3 = MULT16_16_P15(x, x2);\n   interp[0] = PSHR32(MULT16_16(QCONST16(-0.16667f, 15),x) + MULT16_16(QCONST16(0.16667f, 15),x3),15);\n   interp[1] = EXTRACT16(EXTEND32(x) + SHR32(SUB32(EXTEND32(x2),EXTEND32(x3)),1));\n   interp[3] = PSHR32(MULT16_16(QCONST16(-0.33333f, 15),x) + MULT16_16(QCONST16(.5f,15),x2) - MULT16_16(QCONST16(0.16667f, 15),x3),15);\n   /* Just to make sure we don't have rounding problems */\n   interp[2] = Q15_ONE-interp[0]-interp[1]-interp[3];\n   if (interp[2]<32767)\n      interp[2]+=1;\n}\n#else\nstatic void cubic_coef(spx_word16_t frac, spx_word16_t interp[4])\n{\n   /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation\n   but I know it's MMSE-optimal on a sinc */\n   interp[0] =  -0.16667f*frac + 0.16667f*frac*frac*frac;\n   interp[1] = frac + 0.5f*frac*frac - 0.5f*frac*frac*frac;\n   /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/\n   interp[3] = -0.33333f*frac + 0.5f*frac*frac - 0.16667f*frac*frac*frac;\n   /* Just to make sure we don't have rounding problems */\n   interp[2] = 1.-interp[0]-interp[1]-interp[3];\n}\n#endif\n\nstatic int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)\n{\n   const int N = st->filt_len;\n   int out_sample = 0;\n   int last_sample = st->last_sample[channel_index];\n   spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];\n   const spx_word16_t *sinc_table = st->sinc_table;\n   const int out_stride = st->out_stride;\n   const int int_advance = st->int_advance;\n   const int frac_advance = st->frac_advance;\n   const spx_uint32_t den_rate = st->den_rate;\n   spx_word32_t sum;\n   int j;\n\n   while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))\n   {\n      const spx_word16_t *sinct = & sinc_table[samp_frac_num*N];\n      const spx_word16_t *iptr = & in[last_sample];\n\n#ifndef OVERRIDE_INNER_PRODUCT_SINGLE\n      sum = 0;\n      for(j=0;j<N;j++) sum += MULT16_16(sinct[j], iptr[j]);\n\n/*    This code is slower on most DSPs which have only 2 accumulators.\n      Plus this this forces truncation to 32 bits and you lose the HW guard bits.\n      I think we can trust the compiler and let it vectorize and/or unroll itself.\n      spx_word32_t accum[4] = {0,0,0,0};\n      for(j=0;j<N;j+=4) {\n        accum[0] += MULT16_16(sinct[j], iptr[j]);\n        accum[1] += MULT16_16(sinct[j+1], iptr[j+1]);\n        accum[2] += MULT16_16(sinct[j+2], iptr[j+2]);\n        accum[3] += MULT16_16(sinct[j+3], iptr[j+3]);\n      }\n      sum = accum[0] + accum[1] + accum[2] + accum[3];\n*/\n#else\n      sum = inner_product_single(sinct, iptr, N);\n#endif\n\n      out[out_stride * out_sample++] = SATURATE32(PSHR32(sum, 15), 32767);\n      last_sample += int_advance;\n      samp_frac_num += frac_advance;\n      if (samp_frac_num >= den_rate)\n      {\n         samp_frac_num -= den_rate;\n         last_sample++;\n      }\n   }\n\n   st->last_sample[channel_index] = last_sample;\n   st->samp_frac_num[channel_index] = samp_frac_num;\n   return out_sample;\n}\n\n#ifdef FIXED_POINT\n#else\n/* This is the same as the previous function, except with a double-precision accumulator */\nstatic int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)\n{\n   const int N = st->filt_len;\n   int out_sample = 0;\n   int last_sample = st->last_sample[channel_index];\n   spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];\n   const spx_word16_t *sinc_table = st->sinc_table;\n   const int out_stride = st->out_stride;\n   const int int_advance = st->int_advance;\n   const int frac_advance = st->frac_advance;\n   const spx_uint32_t den_rate = st->den_rate;\n   double sum;\n   int j;\n\n   while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))\n   {\n      const spx_word16_t *sinct = & sinc_table[samp_frac_num*N];\n      const spx_word16_t *iptr = & in[last_sample];\n\n#ifndef OVERRIDE_INNER_PRODUCT_DOUBLE\n      double accum[4] = {0,0,0,0};\n\n      for(j=0;j<N;j+=4) {\n        accum[0] += sinct[j]*iptr[j];\n        accum[1] += sinct[j+1]*iptr[j+1];\n        accum[2] += sinct[j+2]*iptr[j+2];\n        accum[3] += sinct[j+3]*iptr[j+3];\n      }\n      sum = accum[0] + accum[1] + accum[2] + accum[3];\n#else\n      sum = inner_product_double(sinct, iptr, N);\n#endif\n\n      out[out_stride * out_sample++] = PSHR32(sum, 15);\n      last_sample += int_advance;\n      samp_frac_num += frac_advance;\n      if (samp_frac_num >= den_rate)\n      {\n         samp_frac_num -= den_rate;\n         last_sample++;\n      }\n   }\n\n   st->last_sample[channel_index] = last_sample;\n   st->samp_frac_num[channel_index] = samp_frac_num;\n   return out_sample;\n}\n#endif\n\nstatic int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)\n{\n   const int N = st->filt_len;\n   int out_sample = 0;\n   int last_sample = st->last_sample[channel_index];\n   spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];\n   const int out_stride = st->out_stride;\n   const int int_advance = st->int_advance;\n   const int frac_advance = st->frac_advance;\n   const spx_uint32_t den_rate = st->den_rate;\n   int j;\n   spx_word32_t sum;\n\n   while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))\n   {\n      const spx_word16_t *iptr = & in[last_sample];\n\n      const int offset = samp_frac_num*st->oversample/st->den_rate;\n#ifdef FIXED_POINT\n      const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate);\n#else\n      const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate;\n#endif\n      spx_word16_t interp[4];\n\n\n#ifndef OVERRIDE_INTERPOLATE_PRODUCT_SINGLE\n      spx_word32_t accum[4] = {0,0,0,0};\n\n      for(j=0;j<N;j++) {\n        const spx_word16_t curr_in=iptr[j];\n        accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);\n        accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);\n        accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);\n        accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);\n      }\n\n      cubic_coef(frac, interp);\n      sum = MULT16_32_Q15(interp[0],SHR32(accum[0], 1)) + MULT16_32_Q15(interp[1],SHR32(accum[1], 1)) + MULT16_32_Q15(interp[2],SHR32(accum[2], 1)) + MULT16_32_Q15(interp[3],SHR32(accum[3], 1));\n#else\n      cubic_coef(frac, interp);\n      sum = interpolate_product_single(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);\n#endif\n      \n      out[out_stride * out_sample++] = SATURATE32(PSHR32(sum, 14), 32767);\n      last_sample += int_advance;\n      samp_frac_num += frac_advance;\n      if (samp_frac_num >= den_rate)\n      {\n         samp_frac_num -= den_rate;\n         last_sample++;\n      }\n   }\n\n   st->last_sample[channel_index] = last_sample;\n   st->samp_frac_num[channel_index] = samp_frac_num;\n   return out_sample;\n}\n\n#ifdef FIXED_POINT\n#else\n/* This is the same as the previous function, except with a double-precision accumulator */\nstatic int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)\n{\n   const int N = st->filt_len;\n   int out_sample = 0;\n   int last_sample = st->last_sample[channel_index];\n   spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];\n   const int out_stride = st->out_stride;\n   const int int_advance = st->int_advance;\n   const int frac_advance = st->frac_advance;\n   const spx_uint32_t den_rate = st->den_rate;\n   int j;\n   spx_word32_t sum;\n\n   while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))\n   {\n      const spx_word16_t *iptr = & in[last_sample];\n\n      const int offset = samp_frac_num*st->oversample/st->den_rate;\n#ifdef FIXED_POINT\n      const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate);\n#else\n      const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate;\n#endif\n      spx_word16_t interp[4];\n\n\n#ifndef OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE\n      double accum[4] = {0,0,0,0};\n\n      for(j=0;j<N;j++) {\n        const double curr_in=iptr[j];\n        accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);\n        accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);\n        accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);\n        accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);\n      }\n\n      cubic_coef(frac, interp);\n      sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]);\n#else\n      cubic_coef(frac, interp);\n      sum = interpolate_product_double(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);\n#endif\n      \n      out[out_stride * out_sample++] = PSHR32(sum,15);\n      last_sample += int_advance;\n      samp_frac_num += frac_advance;\n      if (samp_frac_num >= den_rate)\n      {\n         samp_frac_num -= den_rate;\n         last_sample++;\n      }\n   }\n\n   st->last_sample[channel_index] = last_sample;\n   st->samp_frac_num[channel_index] = samp_frac_num;\n   return out_sample;\n}\n#endif\n\nstatic void update_filter(SpeexResamplerState *st)\n{\n   spx_uint32_t old_length;\n   \n   old_length = st->filt_len;\n   st->oversample = quality_map[st->quality].oversample;\n   st->filt_len = quality_map[st->quality].base_length;\n   \n   if (st->num_rate > st->den_rate)\n   {\n      /* down-sampling */\n      st->cutoff = quality_map[st->quality].downsample_bandwidth * st->den_rate / st->num_rate;\n      /* FIXME: divide the numerator and denominator by a certain amount if they're too large */\n      st->filt_len = st->filt_len*st->num_rate / st->den_rate;\n      /* Round down to make sure we have a multiple of 4 */\n      st->filt_len &= (~0x3);\n      if (2*st->den_rate < st->num_rate)\n         st->oversample >>= 1;\n      if (4*st->den_rate < st->num_rate)\n         st->oversample >>= 1;\n      if (8*st->den_rate < st->num_rate)\n         st->oversample >>= 1;\n      if (16*st->den_rate < st->num_rate)\n         st->oversample >>= 1;\n      if (st->oversample < 1)\n         st->oversample = 1;\n   } else {\n      /* up-sampling */\n      st->cutoff = quality_map[st->quality].upsample_bandwidth;\n   }\n   \n   /* Choose the resampling type that requires the least amount of memory */\n   if (st->den_rate <= st->oversample)\n   {\n      spx_uint32_t i;\n      if (!st->sinc_table)\n         st->sinc_table = (spx_word16_t *)speex_alloc(st->filt_len*st->den_rate*sizeof(spx_word16_t));\n      else if (st->sinc_table_length < st->filt_len*st->den_rate)\n      {\n         st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,st->filt_len*st->den_rate*sizeof(spx_word16_t));\n         st->sinc_table_length = st->filt_len*st->den_rate;\n      }\n      for (i=0;i<st->den_rate;i++)\n      {\n         spx_int32_t j;\n         for (j=0;j<st->filt_len;j++)\n         {\n            st->sinc_table[i*st->filt_len+j] = sinc(st->cutoff,((j-(spx_int32_t)st->filt_len/2+1)-((float)i)/st->den_rate), st->filt_len, quality_map[st->quality].window_func);\n         }\n      }\n#ifdef FIXED_POINT\n      st->resampler_ptr = resampler_basic_direct_single;\n#else\n      if (st->quality>8)\n         st->resampler_ptr = resampler_basic_direct_double;\n      else\n         st->resampler_ptr = resampler_basic_direct_single;\n#endif\n      /*fprintf (stderr, \"resampler uses direct sinc table and normalised cutoff %f\\n\", cutoff);*/\n   } else {\n      spx_int32_t i;\n      if (!st->sinc_table)\n         st->sinc_table = (spx_word16_t *)speex_alloc((st->filt_len*st->oversample+8)*sizeof(spx_word16_t));\n      else if (st->sinc_table_length < st->filt_len*st->oversample+8)\n      {\n         st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,(st->filt_len*st->oversample+8)*sizeof(spx_word16_t));\n         st->sinc_table_length = st->filt_len*st->oversample+8;\n      }\n      for (i=-4;i<(spx_int32_t)(st->oversample*st->filt_len+4);i++)\n         st->sinc_table[i+4] = sinc(st->cutoff,(i/(float)st->oversample - st->filt_len/2), st->filt_len, quality_map[st->quality].window_func);\n#ifdef FIXED_POINT\n      st->resampler_ptr = resampler_basic_interpolate_single;\n#else\n      if (st->quality>8)\n         st->resampler_ptr = resampler_basic_interpolate_double;\n      else\n         st->resampler_ptr = resampler_basic_interpolate_single;\n#endif\n      /*fprintf (stderr, \"resampler uses interpolated sinc table and normalised cutoff %f\\n\", cutoff);*/\n   }\n   st->int_advance = st->num_rate/st->den_rate;\n   st->frac_advance = st->num_rate%st->den_rate;\n\n   \n   /* Here's the place where we update the filter memory to take into account\n      the change in filter length. It's probably the messiest part of the code\n      due to handling of lots of corner cases. */\n   if (!st->mem)\n   {\n      spx_uint32_t i;\n      st->mem_alloc_size = st->filt_len-1 + st->buffer_size;\n      st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));\n      for (i=0;i<st->nb_channels*st->mem_alloc_size;i++)\n         st->mem[i] = 0;\n      /*speex_warning(\"init filter\");*/\n   } else if (!st->started)\n   {\n      spx_uint32_t i;\n      st->mem_alloc_size = st->filt_len-1 + st->buffer_size;\n      st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));\n      for (i=0;i<st->nb_channels*st->mem_alloc_size;i++)\n         st->mem[i] = 0;\n      /*speex_warning(\"reinit filter\");*/\n   } else if (st->filt_len > old_length)\n   {\n      spx_int32_t i;\n      /* Increase the filter length */\n      /*speex_warning(\"increase filter size\");*/\n      int old_alloc_size = st->mem_alloc_size;\n      if ((st->filt_len-1 + st->buffer_size) > st->mem_alloc_size)\n      {\n         st->mem_alloc_size = st->filt_len-1 + st->buffer_size;\n         st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));\n      }\n      for (i=st->nb_channels-1;i>=0;i--)\n      {\n         spx_int32_t j;\n         spx_uint32_t olen = old_length;\n         /*if (st->magic_samples[i])*/\n         {\n            /* Try and remove the magic samples as if nothing had happened */\n            \n            /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */\n            olen = old_length + 2*st->magic_samples[i];\n            for (j=old_length-2+st->magic_samples[i];j>=0;j--)\n               st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]] = st->mem[i*old_alloc_size+j];\n            for (j=0;j<st->magic_samples[i];j++)\n               st->mem[i*st->mem_alloc_size+j] = 0;\n            st->magic_samples[i] = 0;\n         }\n         if (st->filt_len > olen)\n         {\n            /* If the new filter length is still bigger than the \"augmented\" length */\n            /* Copy data going backward */\n            for (j=0;j<olen-1;j++)\n               st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = st->mem[i*st->mem_alloc_size+(olen-2-j)];\n            /* Then put zeros for lack of anything better */\n            for (;j<st->filt_len-1;j++)\n               st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = 0;\n            /* Adjust last_sample */\n            st->last_sample[i] += (st->filt_len - olen)/2;\n         } else {\n            /* Put back some of the magic! */\n            st->magic_samples[i] = (olen - st->filt_len)/2;\n            for (j=0;j<st->filt_len-1+st->magic_samples[i];j++)\n               st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]];\n         }\n      }\n   } else if (st->filt_len < old_length)\n   {\n      spx_uint32_t i;\n      /* Reduce filter length, this a bit tricky. We need to store some of the memory as \"magic\"\n         samples so they can be used directly as input the next time(s) */\n      for (i=0;i<st->nb_channels;i++)\n      {\n         spx_uint32_t j;\n         spx_uint32_t old_magic = st->magic_samples[i];\n         st->magic_samples[i] = (old_length - st->filt_len)/2;\n         /* We must copy some of the memory that's no longer used */\n         /* Copy data going backward */\n         for (j=0;j<st->filt_len-1+st->magic_samples[i]+old_magic;j++)\n            st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]];\n         st->magic_samples[i] += old_magic;\n      }\n   }\n\n}\n\nSPX_RESAMPLE_EXPORT SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)\n{\n   return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err);\n}\n\nSPX_RESAMPLE_EXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)\n{\n   spx_uint32_t i;\n   SpeexResamplerState *st;\n   if (quality > 10 || quality < 0)\n   {\n      if (err)\n         *err = RESAMPLER_ERR_INVALID_ARG;\n      return NULL;\n   }\n   st = (SpeexResamplerState *)speex_alloc(sizeof(SpeexResamplerState));\n   st->initialised = 0;\n   st->started = 0;\n   st->in_rate = 0;\n   st->out_rate = 0;\n   st->num_rate = 0;\n   st->den_rate = 0;\n   st->quality = -1;\n   st->sinc_table_length = 0;\n   st->mem_alloc_size = 0;\n   st->filt_len = 0;\n   st->mem = 0;\n   st->resampler_ptr = 0;\n         \n   st->cutoff = 1.f;\n   st->nb_channels = nb_channels;\n   st->in_stride = 1;\n   st->out_stride = 1;\n   \n#ifdef FIXED_POINT\n   st->buffer_size = 160;\n#else\n   st->buffer_size = 160;\n#endif\n   \n   /* Per channel data */\n   st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int));\n   st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int));\n   st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int));\n   for (i=0;i<nb_channels;i++)\n   {\n      st->last_sample[i] = 0;\n      st->magic_samples[i] = 0;\n      st->samp_frac_num[i] = 0;\n   }\n\n   speex_resampler_set_quality(st, quality);\n   speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate);\n\n   \n   update_filter(st);\n   \n   st->initialised = 1;\n   if (err)\n      *err = RESAMPLER_ERR_SUCCESS;\n\n   return st;\n}\n\nSPX_RESAMPLE_EXPORT void speex_resampler_destroy(SpeexResamplerState *st)\n{\n   speex_free(st->mem);\n   speex_free(st->sinc_table);\n   speex_free(st->last_sample);\n   speex_free(st->magic_samples);\n   speex_free(st->samp_frac_num);\n   speex_free(st);\n}\n\nstatic int speex_resampler_process_native(SpeexResamplerState *st, spx_uint32_t channel_index, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)\n{\n   int j=0;\n   const int N = st->filt_len;\n   int out_sample = 0;\n   spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size;\n   spx_uint32_t ilen;\n   \n   st->started = 1;\n   \n   /* Call the right resampler through the function ptr */\n   out_sample = st->resampler_ptr(st, channel_index, mem, in_len, out, out_len);\n   \n   if (st->last_sample[channel_index] < (spx_int32_t)*in_len)\n      *in_len = st->last_sample[channel_index];\n   *out_len = out_sample;\n   st->last_sample[channel_index] -= *in_len;\n   \n   ilen = *in_len;\n\n   for(j=0;j<N-1;++j)\n     mem[j] = mem[j+ilen];\n\n   return RESAMPLER_ERR_SUCCESS;\n}\n\nstatic int speex_resampler_magic(SpeexResamplerState *st, spx_uint32_t channel_index, spx_word16_t **out, spx_uint32_t out_len) {\n   spx_uint32_t tmp_in_len = st->magic_samples[channel_index];\n   spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size;\n   const int N = st->filt_len;\n   \n   speex_resampler_process_native(st, channel_index, &tmp_in_len, *out, &out_len);\n\n   st->magic_samples[channel_index] -= tmp_in_len;\n   \n   /* If we couldn't process all \"magic\" input samples, save the rest for next time */\n   if (st->magic_samples[channel_index])\n   {\n      spx_uint32_t i;\n      for (i=0;i<st->magic_samples[channel_index];i++)\n         mem[N-1+i]=mem[N-1+i+tmp_in_len];\n   }\n   *out += out_len*st->out_stride;\n   return out_len;\n}\n\n#ifdef FIXED_POINT\nSPX_RESAMPLE_EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)\n#else\nSPX_RESAMPLE_EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)\n#endif\n{\n   int j;\n   spx_uint32_t ilen = *in_len;\n   spx_uint32_t olen = *out_len;\n   spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size;\n   const int filt_offs = st->filt_len - 1;\n   const spx_uint32_t xlen = st->mem_alloc_size - filt_offs;\n   const int istride = st->in_stride;\n\n   if (st->magic_samples[channel_index]) \n      olen -= speex_resampler_magic(st, channel_index, &out, olen);\n   if (! st->magic_samples[channel_index]) {\n      while (ilen && olen) {\n        spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen;\n        spx_uint32_t ochunk = olen;\n \n        if (in) {\n           for(j=0;j<ichunk;++j)\n              x[j+filt_offs]=in[j*istride];\n        } else {\n          for(j=0;j<ichunk;++j)\n            x[j+filt_offs]=0;\n        }\n        speex_resampler_process_native(st, channel_index, &ichunk, out, &ochunk);\n        ilen -= ichunk;\n        olen -= ochunk;\n        out += ochunk * st->out_stride;\n        if (in)\n           in += ichunk * istride;\n      }\n   }\n   *in_len -= ilen;\n   *out_len -= olen;\n   return RESAMPLER_ERR_SUCCESS;\n}\n\n#ifdef FIXED_POINT\nSPX_RESAMPLE_EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)\n#else\nSPX_RESAMPLE_EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)\n#endif\n{\n   int j;\n   const int istride_save = st->in_stride;\n   const int ostride_save = st->out_stride;\n   spx_uint32_t ilen = *in_len;\n   spx_uint32_t olen = *out_len;\n   spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size;\n   const spx_uint32_t xlen = st->mem_alloc_size - (st->filt_len - 1);\n#ifdef VAR_ARRAYS\n   const unsigned int ylen = (olen < FIXED_STACK_ALLOC) ? olen : FIXED_STACK_ALLOC;\n   VARDECL(spx_word16_t *ystack);\n   ALLOC(ystack, ylen, spx_word16_t);\n#else\n   const unsigned int ylen = FIXED_STACK_ALLOC;\n   spx_word16_t ystack[FIXED_STACK_ALLOC];\n#endif\n\n   st->out_stride = 1;\n   \n   while (ilen && olen) {\n     spx_word16_t *y = ystack;\n     spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen;\n     spx_uint32_t ochunk = (olen > ylen) ? ylen : olen;\n     spx_uint32_t omagic = 0;\n\n     if (st->magic_samples[channel_index]) {\n       omagic = speex_resampler_magic(st, channel_index, &y, ochunk);\n       ochunk -= omagic;\n       olen -= omagic;\n     }\n     if (! st->magic_samples[channel_index]) {\n       if (in) {\n         for(j=0;j<ichunk;++j)\n#ifdef FIXED_POINT\n           x[j+st->filt_len-1]=WORD2INT(in[j*istride_save]);\n#else\n           x[j+st->filt_len-1]=in[j*istride_save];\n#endif\n       } else {\n         for(j=0;j<ichunk;++j)\n           x[j+st->filt_len-1]=0;\n       }\n\n       speex_resampler_process_native(st, channel_index, &ichunk, y, &ochunk);\n     } else {\n       ichunk = 0;\n       ochunk = 0;\n     }\n\n     for (j=0;j<ochunk+omagic;++j)\n#ifdef FIXED_POINT\n        out[j*ostride_save] = ystack[j];\n#else\n        out[j*ostride_save] = WORD2INT(ystack[j]);\n#endif\n     \n     ilen -= ichunk;\n     olen -= ochunk;\n     out += (ochunk+omagic) * ostride_save;\n     if (in)\n       in += ichunk * istride_save;\n   }\n   st->out_stride = ostride_save;\n   *in_len -= ilen;\n   *out_len -= olen;\n\n   return RESAMPLER_ERR_SUCCESS;\n}\n\nSPX_RESAMPLE_EXPORT int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)\n{\n   spx_uint32_t i;\n   int istride_save, ostride_save;\n   spx_uint32_t bak_len = *out_len;\n   istride_save = st->in_stride;\n   ostride_save = st->out_stride;\n   st->in_stride = st->out_stride = st->nb_channels;\n   for (i=0;i<st->nb_channels;i++)\n   {\n      *out_len = bak_len;\n      if (in != NULL)\n         speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len);\n      else\n         speex_resampler_process_float(st, i, NULL, in_len, out+i, out_len);\n   }\n   st->in_stride = istride_save;\n   st->out_stride = ostride_save;\n   return RESAMPLER_ERR_SUCCESS;\n}\n               \nSPX_RESAMPLE_EXPORT int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)\n{\n   spx_uint32_t i;\n   int istride_save, ostride_save;\n   spx_uint32_t bak_len = *out_len;\n   istride_save = st->in_stride;\n   ostride_save = st->out_stride;\n   st->in_stride = st->out_stride = st->nb_channels;\n   for (i=0;i<st->nb_channels;i++)\n   {\n      *out_len = bak_len;\n      if (in != NULL)\n         speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len);\n      else\n         speex_resampler_process_int(st, i, NULL, in_len, out+i, out_len);\n   }\n   st->in_stride = istride_save;\n   st->out_stride = ostride_save;\n   return RESAMPLER_ERR_SUCCESS;\n}\n\nSPX_RESAMPLE_EXPORT int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate)\n{\n   return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate);\n}\n\nSPX_RESAMPLE_EXPORT void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate)\n{\n   *in_rate = st->in_rate;\n   *out_rate = st->out_rate;\n}\n\nSPX_RESAMPLE_EXPORT int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate)\n{\n   spx_uint32_t fact;\n   spx_uint32_t old_den;\n   spx_uint32_t i;\n   if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den)\n      return RESAMPLER_ERR_SUCCESS;\n   \n   old_den = st->den_rate;\n   st->in_rate = in_rate;\n   st->out_rate = out_rate;\n   st->num_rate = ratio_num;\n   st->den_rate = ratio_den;\n   /* FIXME: This is terribly inefficient, but who cares (at least for now)? */\n   for (fact=2;fact<=IMIN(st->num_rate, st->den_rate);fact++)\n   {\n      while ((st->num_rate % fact == 0) && (st->den_rate % fact == 0))\n      {\n         st->num_rate /= fact;\n         st->den_rate /= fact;\n      }\n   }\n      \n   if (old_den > 0)\n   {\n      for (i=0;i<st->nb_channels;i++)\n      {\n         st->samp_frac_num[i]=st->samp_frac_num[i]*st->den_rate/old_den;\n         /* Safety net */\n         if (st->samp_frac_num[i] >= st->den_rate)\n            st->samp_frac_num[i] = st->den_rate-1;\n      }\n   }\n   \n   if (st->initialised)\n      update_filter(st);\n   return RESAMPLER_ERR_SUCCESS;\n}\n\nSPX_RESAMPLE_EXPORT void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den)\n{\n   *ratio_num = st->num_rate;\n   *ratio_den = st->den_rate;\n}\n\nSPX_RESAMPLE_EXPORT int speex_resampler_set_quality(SpeexResamplerState *st, int quality)\n{\n   if (quality > 10 || quality < 0)\n      return RESAMPLER_ERR_INVALID_ARG;\n   if (st->quality == quality)\n      return RESAMPLER_ERR_SUCCESS;\n   st->quality = quality;\n   if (st->initialised)\n      update_filter(st);\n   return RESAMPLER_ERR_SUCCESS;\n}\n\nSPX_RESAMPLE_EXPORT void speex_resampler_get_quality(SpeexResamplerState *st, int *quality)\n{\n   *quality = st->quality;\n}\n\nSPX_RESAMPLE_EXPORT void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride)\n{\n   st->in_stride = stride;\n}\n\nSPX_RESAMPLE_EXPORT void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride)\n{\n   *stride = st->in_stride;\n}\n\nSPX_RESAMPLE_EXPORT void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride)\n{\n   st->out_stride = stride;\n}\n\nSPX_RESAMPLE_EXPORT void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride)\n{\n   *stride = st->out_stride;\n}\n\nSPX_RESAMPLE_EXPORT int speex_resampler_get_input_latency(SpeexResamplerState *st)\n{\n  return st->filt_len / 2;\n}\n\nSPX_RESAMPLE_EXPORT int speex_resampler_get_output_latency(SpeexResamplerState *st)\n{\n  return ((st->filt_len / 2) * st->den_rate + (st->num_rate >> 1)) / st->num_rate;\n}\n\nSPX_RESAMPLE_EXPORT int speex_resampler_skip_zeros(SpeexResamplerState *st)\n{\n   spx_uint32_t i;\n   for (i=0;i<st->nb_channels;i++)\n      st->last_sample[i] = st->filt_len/2;\n   return RESAMPLER_ERR_SUCCESS;\n}\n\nSPX_RESAMPLE_EXPORT int speex_resampler_reset_mem(SpeexResamplerState *st)\n{\n   spx_uint32_t i;\n   for (i=0;i<st->nb_channels*(st->filt_len-1);i++)\n      st->mem[i] = 0;\n   return RESAMPLER_ERR_SUCCESS;\n}\n\nSPX_RESAMPLE_EXPORT const char *speex_resampler_strerror(int err)\n{\n   switch (err)\n   {\n      case RESAMPLER_ERR_SUCCESS:\n         return \"Success.\";\n      case RESAMPLER_ERR_ALLOC_FAILED:\n         return \"Memory allocation failed.\";\n      case RESAMPLER_ERR_BAD_STATE:\n         return \"Bad resampler state.\";\n      case RESAMPLER_ERR_INVALID_ARG:\n         return \"Invalid argument.\";\n      case RESAMPLER_ERR_PTR_OVERLAP:\n         return \"Input and output buffers overlap.\";\n      default:\n         return \"Unknown error. Bad error code or strange version mismatch.\";\n   }\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/speex_resampler.h",
    "content": "/* Copyright (C) 2007 Jean-Marc Valin\n      \n   File: speex_resampler.h\n   Resampling code\n      \n   The design goals of this code are:\n      - Very fast algorithm\n      - Low memory requirement\n      - Good *perceptual* quality (and not best SNR)\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions are\n   met:\n\n   1. Redistributions of source code must retain the above copyright notice,\n   this list of conditions and the following disclaimer.\n\n   2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n   3. The name of the author may not be used to endorse or promote products\n   derived from this software without specific prior written permission.\n\n   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n   DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,\n   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\n   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n   POSSIBILITY OF SUCH DAMAGE.\n*/\n\n\n#ifndef SPEEX_RESAMPLER_H\n#define SPEEX_RESAMPLER_H\n\n#ifdef OUTSIDE_SPEEX\n\n/********* WARNING: MENTAL SANITY ENDS HERE *************/\n\n/* If the resampler is defined outside of Speex, we change the symbol names so that \n   there won't be any clash if linking with Speex later on. */\n\n/* #define RANDOM_PREFIX your software name here */\n#ifndef RANDOM_PREFIX\n#error \"Please define RANDOM_PREFIX (above) to something specific to your project to prevent symbol name clashes\"\n#endif\n\n#define CAT_PREFIX2(a,b) a ## b\n#define CAT_PREFIX(a,b) CAT_PREFIX2(a, b)\n      \n#define speex_resampler_init CAT_PREFIX(RANDOM_PREFIX,_resampler_init)\n#define speex_resampler_init_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_init_frac)\n#define speex_resampler_destroy CAT_PREFIX(RANDOM_PREFIX,_resampler_destroy)\n#define speex_resampler_process_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_float)\n#define speex_resampler_process_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_int)\n#define speex_resampler_process_interleaved_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_float)\n#define speex_resampler_process_interleaved_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_int)\n#define speex_resampler_set_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate)\n#define speex_resampler_get_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_get_rate)\n#define speex_resampler_set_rate_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate_frac)\n#define speex_resampler_get_ratio CAT_PREFIX(RANDOM_PREFIX,_resampler_get_ratio)\n#define speex_resampler_set_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_set_quality)\n#define speex_resampler_get_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_get_quality)\n#define speex_resampler_set_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_input_stride)\n#define speex_resampler_get_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_stride)\n#define speex_resampler_set_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_output_stride)\n#define speex_resampler_get_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_stride)\n#define speex_resampler_get_input_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_latency)\n#define speex_resampler_get_output_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_latency)\n#define speex_resampler_skip_zeros CAT_PREFIX(RANDOM_PREFIX,_resampler_skip_zeros)\n#define speex_resampler_reset_mem CAT_PREFIX(RANDOM_PREFIX,_resampler_reset_mem)\n#define speex_resampler_strerror CAT_PREFIX(RANDOM_PREFIX,_resampler_strerror)\n\n#define spx_int16_t short\n#define spx_int32_t int\n#define spx_uint16_t unsigned short\n#define spx_uint32_t unsigned int\n      \n#else /* OUTSIDE_SPEEX */\n\n#ifdef _BUILD_SPEEX\n# include \"speex_types.h\"\n#else\n# include <speex/speex_types.h>\n#endif\n\n#endif /* OUTSIDE_SPEEX */\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define SPEEX_RESAMPLER_QUALITY_MAX 10\n#define SPEEX_RESAMPLER_QUALITY_MIN 0\n#define SPEEX_RESAMPLER_QUALITY_DEFAULT 4\n#define SPEEX_RESAMPLER_QUALITY_VOIP 3\n#define SPEEX_RESAMPLER_QUALITY_DESKTOP 5\n\nenum {\n   RESAMPLER_ERR_SUCCESS         = 0,\n   RESAMPLER_ERR_ALLOC_FAILED    = 1,\n   RESAMPLER_ERR_BAD_STATE       = 2,\n   RESAMPLER_ERR_INVALID_ARG     = 3,\n   RESAMPLER_ERR_PTR_OVERLAP     = 4,\n   \n   RESAMPLER_ERR_MAX_ERROR\n};\n\nstruct SpeexResamplerState_;\ntypedef struct SpeexResamplerState_ SpeexResamplerState;\n\n/** Create a new resampler with integer input and output rates.\n * @param nb_channels Number of channels to be processed\n * @param in_rate Input sampling rate (integer number of Hz).\n * @param out_rate Output sampling rate (integer number of Hz).\n * @param quality Resampling quality between 0 and 10, where 0 has poor quality\n * and 10 has very high quality.\n * @return Newly created resampler state\n * @retval NULL Error: not enough memory\n */\nSpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, \n                                          spx_uint32_t in_rate, \n                                          spx_uint32_t out_rate, \n                                          int quality,\n                                          int *err);\n\n/** Create a new resampler with fractional input/output rates. The sampling \n * rate ratio is an arbitrary rational number with both the numerator and \n * denominator being 32-bit integers.\n * @param nb_channels Number of channels to be processed\n * @param ratio_num Numerator of the sampling rate ratio\n * @param ratio_den Denominator of the sampling rate ratio\n * @param in_rate Input sampling rate rounded to the nearest integer (in Hz).\n * @param out_rate Output sampling rate rounded to the nearest integer (in Hz).\n * @param quality Resampling quality between 0 and 10, where 0 has poor quality\n * and 10 has very high quality.\n * @return Newly created resampler state\n * @retval NULL Error: not enough memory\n */\nSpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, \n                                               spx_uint32_t ratio_num, \n                                               spx_uint32_t ratio_den, \n                                               spx_uint32_t in_rate, \n                                               spx_uint32_t out_rate, \n                                               int quality,\n                                               int *err);\n\n/** Destroy a resampler state.\n * @param st Resampler state\n */\nvoid speex_resampler_destroy(SpeexResamplerState *st);\n\n/** Resample a float array. The input and output buffers must *not* overlap.\n * @param st Resampler state\n * @param channel_index Index of the channel to process for the multi-channel \n * base (0 otherwise)\n * @param in Input buffer\n * @param in_len Number of input samples in the input buffer. Returns the \n * number of samples processed\n * @param out Output buffer\n * @param out_len Size of the output buffer. Returns the number of samples written\n */\nint speex_resampler_process_float(SpeexResamplerState *st, \n                                   spx_uint32_t channel_index, \n                                   const float *in, \n                                   spx_uint32_t *in_len, \n                                   float *out, \n                                   spx_uint32_t *out_len);\n\n/** Resample an int array. The input and output buffers must *not* overlap.\n * @param st Resampler state\n * @param channel_index Index of the channel to process for the multi-channel \n * base (0 otherwise)\n * @param in Input buffer\n * @param in_len Number of input samples in the input buffer. Returns the number\n * of samples processed\n * @param out Output buffer\n * @param out_len Size of the output buffer. Returns the number of samples written\n */\nint speex_resampler_process_int(SpeexResamplerState *st, \n                                 spx_uint32_t channel_index, \n                                 const spx_int16_t *in, \n                                 spx_uint32_t *in_len, \n                                 spx_int16_t *out, \n                                 spx_uint32_t *out_len);\n\n/** Resample an interleaved float array. The input and output buffers must *not* overlap.\n * @param st Resampler state\n * @param in Input buffer\n * @param in_len Number of input samples in the input buffer. Returns the number\n * of samples processed. This is all per-channel.\n * @param out Output buffer\n * @param out_len Size of the output buffer. Returns the number of samples written.\n * This is all per-channel.\n */\nint speex_resampler_process_interleaved_float(SpeexResamplerState *st, \n                                               const float *in, \n                                               spx_uint32_t *in_len, \n                                               float *out, \n                                               spx_uint32_t *out_len);\n\n/** Resample an interleaved int array. The input and output buffers must *not* overlap.\n * @param st Resampler state\n * @param in Input buffer\n * @param in_len Number of input samples in the input buffer. Returns the number\n * of samples processed. This is all per-channel.\n * @param out Output buffer\n * @param out_len Size of the output buffer. Returns the number of samples written.\n * This is all per-channel.\n */\nint speex_resampler_process_interleaved_int(SpeexResamplerState *st, \n                                             const spx_int16_t *in, \n                                             spx_uint32_t *in_len, \n                                             spx_int16_t *out, \n                                             spx_uint32_t *out_len);\n\n/** Set (change) the input/output sampling rates (integer value).\n * @param st Resampler state\n * @param in_rate Input sampling rate (integer number of Hz).\n * @param out_rate Output sampling rate (integer number of Hz).\n */\nint speex_resampler_set_rate(SpeexResamplerState *st, \n                              spx_uint32_t in_rate, \n                              spx_uint32_t out_rate);\n\n/** Get the current input/output sampling rates (integer value).\n * @param st Resampler state\n * @param in_rate Input sampling rate (integer number of Hz) copied.\n * @param out_rate Output sampling rate (integer number of Hz) copied.\n */\nvoid speex_resampler_get_rate(SpeexResamplerState *st, \n                              spx_uint32_t *in_rate, \n                              spx_uint32_t *out_rate);\n\n/** Set (change) the input/output sampling rates and resampling ratio \n * (fractional values in Hz supported).\n * @param st Resampler state\n * @param ratio_num Numerator of the sampling rate ratio\n * @param ratio_den Denominator of the sampling rate ratio\n * @param in_rate Input sampling rate rounded to the nearest integer (in Hz).\n * @param out_rate Output sampling rate rounded to the nearest integer (in Hz).\n */\nint speex_resampler_set_rate_frac(SpeexResamplerState *st, \n                                   spx_uint32_t ratio_num, \n                                   spx_uint32_t ratio_den, \n                                   spx_uint32_t in_rate, \n                                   spx_uint32_t out_rate);\n\n/** Get the current resampling ratio. This will be reduced to the least\n * common denominator.\n * @param st Resampler state\n * @param ratio_num Numerator of the sampling rate ratio copied\n * @param ratio_den Denominator of the sampling rate ratio copied\n */\nvoid speex_resampler_get_ratio(SpeexResamplerState *st, \n                               spx_uint32_t *ratio_num, \n                               spx_uint32_t *ratio_den);\n\n/** Set (change) the conversion quality.\n * @param st Resampler state\n * @param quality Resampling quality between 0 and 10, where 0 has poor \n * quality and 10 has very high quality.\n */\nint speex_resampler_set_quality(SpeexResamplerState *st, \n                                 int quality);\n\n/** Get the conversion quality.\n * @param st Resampler state\n * @param quality Resampling quality between 0 and 10, where 0 has poor \n * quality and 10 has very high quality.\n */\nvoid speex_resampler_get_quality(SpeexResamplerState *st, \n                                 int *quality);\n\n/** Set (change) the input stride.\n * @param st Resampler state\n * @param stride Input stride\n */\nvoid speex_resampler_set_input_stride(SpeexResamplerState *st, \n                                      spx_uint32_t stride);\n\n/** Get the input stride.\n * @param st Resampler state\n * @param stride Input stride copied\n */\nvoid speex_resampler_get_input_stride(SpeexResamplerState *st, \n                                      spx_uint32_t *stride);\n\n/** Set (change) the output stride.\n * @param st Resampler state\n * @param stride Output stride\n */\nvoid speex_resampler_set_output_stride(SpeexResamplerState *st, \n                                      spx_uint32_t stride);\n\n/** Get the output stride.\n * @param st Resampler state copied\n * @param stride Output stride\n */\nvoid speex_resampler_get_output_stride(SpeexResamplerState *st, \n                                      spx_uint32_t *stride);\n\n/** Get the latency introduced by the resampler measured in input samples.\n * @param st Resampler state\n */\nint speex_resampler_get_input_latency(SpeexResamplerState *st);\n\n/** Get the latency introduced by the resampler measured in output samples.\n * @param st Resampler state\n */\nint speex_resampler_get_output_latency(SpeexResamplerState *st);\n\n/** Make sure that the first samples to go out of the resamplers don't have \n * leading zeros. This is only useful before starting to use a newly created \n * resampler. It is recommended to use that when resampling an audio file, as\n * it will generate a file with the same length. For real-time processing,\n * it is probably easier not to use this call (so that the output duration\n * is the same for the first frame).\n * @param st Resampler state\n */\nint speex_resampler_skip_zeros(SpeexResamplerState *st);\n\n/** Reset a resampler so a new (unrelated) stream can be processed.\n * @param st Resampler state\n */\nint speex_resampler_reset_mem(SpeexResamplerState *st);\n\n/** Returns the English meaning for an error code\n * @param err Error code\n * @return English string\n */\nconst char *speex_resampler_strerror(int err);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/stack_alloc.h",
    "content": "/* Copyright (C) 2002 Jean-Marc Valin */\n/**\n   @file stack_alloc.h\n   @brief Temporary memory allocation on stack\n*/\n/*\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n\n   - Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n   - Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n   - Neither the name of the Xiph.org Foundation nor the names of its\n   contributors may be used to endorse or promote products derived from\n   this software without specific prior written permission.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR\n   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifndef STACK_ALLOC_H\n#define STACK_ALLOC_H\n\n#ifdef USE_ALLOCA\n# ifdef WIN32\n#  include <malloc.h>\n# else\n#  ifdef HAVE_ALLOCA_H\n#   include <alloca.h>\n#  else\n#   include <stdlib.h>\n#  endif\n# endif\n#endif\n\n/**\n * @def ALIGN(stack, size)\n *\n * Aligns the stack to a 'size' boundary\n *\n * @param stack Stack\n * @param size  New size boundary\n */\n\n/**\n * @def PUSH(stack, size, type)\n *\n * Allocates 'size' elements of type 'type' on the stack\n *\n * @param stack Stack\n * @param size  Number of elements\n * @param type  Type of element\n */\n\n/**\n * @def VARDECL(var)\n *\n * Declare variable on stack\n *\n * @param var Variable to declare\n */\n\n/**\n * @def ALLOC(var, size, type)\n *\n * Allocate 'size' elements of 'type' on stack\n *\n * @param var  Name of variable to allocate\n * @param size Number of elements\n * @param type Type of element\n */\n\n#ifdef ENABLE_VALGRIND\n\n#include <valgrind/memcheck.h>\n\n#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))\n\n#define PUSH(stack, size, type) (VALGRIND_MAKE_NOACCESS(stack, 1000),ALIGN((stack),sizeof(type)),VALGRIND_MAKE_WRITABLE(stack, ((size)*sizeof(type))),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type))))\n\n#else\n\n#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))\n\n#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type))))\n\n#endif\n\n#if defined(VAR_ARRAYS)\n#define VARDECL(var)\n#define ALLOC(var, size, type) type var[size]\n#elif defined(USE_ALLOCA)\n#define VARDECL(var) var\n#define ALLOC(var, size, type) var = alloca(sizeof(type)*(size))\n#else\n#define VARDECL(var) var\n#define ALLOC(var, size, type) var = PUSH(stack, size, type)\n#endif\n\n\n#endif\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/wav_io.c",
    "content": "/* Copyright (C) 2002 Jean-Marc Valin\n   File: wav_io.c\n   Routines to handle wav (RIFF) headers\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n\n   - Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n   - Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR\n   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifdef HAVE_CONFIG_H\n# include \"config.h\"\n#endif\n\n#include <stdio.h>\n#include <string.h>\n#include \"wav_io.h\"\n#include \"opus_header.h\"\n\n/* Adjust the stream->channel mapping to ensure the proper output order for\n   WAV files. */\nvoid adjust_wav_mapping(int mapping_family, int channels, unsigned char *stream_map)\n{\n   unsigned char new_stream_map[8];\n   int i;\n   /* If we aren't using one of the defined semantic channel maps, or we have\n      more channels than we know what to do with, use a default 1-1 mapping. */\n   if(mapping_family != 1 || channels > 8)\n      return;\n   for(i = 0; i < channels; i++)\n   {\n      new_stream_map[wav_permute_matrix[channels-1][i]] = stream_map[i];\n   }\n   memcpy(stream_map, new_stream_map, channels*sizeof(*stream_map));\n}\n\nstatic size_t fwrite_le32(opus_int32 i32, FILE *file)\n{\n   unsigned char buf[4];\n   buf[0]=(unsigned char)(i32&0xFF);\n   buf[1]=(unsigned char)(i32>>8&0xFF);\n   buf[2]=(unsigned char)(i32>>16&0xFF);\n   buf[3]=(unsigned char)(i32>>24&0xFF);\n   return fwrite(buf,4,1,file);\n}\n\nstatic size_t fwrite_le16(int i16, FILE *file)\n{\n   unsigned char buf[2];\n   buf[0]=(unsigned char)(i16&0xFF);\n   buf[1]=(unsigned char)(i16>>8&0xFF);\n   return fwrite(buf,2,1,file);\n}\n\nint write_wav_header(FILE *file, int rate, int mapping_family, int channels)\n{\n   int ret;\n   int extensible;\n\n   /* Multichannel files require a WAVEFORMATEXTENSIBLE header to declare the\n      proper channel meanings. */\n   extensible = mapping_family == 1 && 3 <= channels && channels <= 8;\n\n   ret = fprintf (file, \"RIFF\") >= 0;\n   ret &= fwrite_le32 (0x7fffffff, file);\n\n   ret &= fprintf (file, \"WAVEfmt \") >= 0;\n   ret &= fwrite_le32 (extensible ? 40 : 16, file);\n   ret &= fwrite_le16 (extensible ? 0xfffe : 1, file);\n   ret &= fwrite_le16 (channels, file);\n   ret &= fwrite_le32 (rate, file);\n   ret &= fwrite_le32 (2*channels*rate, file);\n   ret &= fwrite_le16 (2*channels, file);\n   ret &= fwrite_le16 (16, file);\n\n   if(extensible)\n   {\n      static const unsigned char ksdataformat_subtype_pcm[16]=\n      {\n        0x01, 0x00, 0x00, 0x00,\n        0x00, 0x00,\n        0x10, 0x00,\n        0x80, 0x00,\n        0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71\n      };\n      static const int wav_channel_masks[8] =\n      {\n         1,                      /* 1.0 mono */\n         1|2,                    /* 2.0 stereo */\n         1|2|4,                  /* 3.0 channel ('wide') stereo */\n         1|2|16|32,              /* 4.0 discrete quadrophonic */\n         1|2|4|16|32,            /* 5.0 */\n         1|2|4|8|16|32,          /* 5.1 */\n         1|2|4|8|256|512|1024,   /* 6.1 */\n         1|2|4|8|16|32|512|1024, /* 7.1 */\n      };\n      ret &= fwrite_le16 (22, file);\n      ret &= fwrite_le16 (16, file);\n      ret &= fwrite_le32 (wav_channel_masks[channels-1], file);\n      ret &= fwrite (ksdataformat_subtype_pcm, 16, 1, file);\n   }\n\n   ret &= fprintf (file, \"data\") >= 0;\n   ret &= fwrite_le32 (0x7fffffff, file);\n\n   return !ret ? -1 : extensible ? 40 : 16;\n}\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/wav_io.h",
    "content": "/* Copyright (C) 2002 Jean-Marc Valin \n   File: wav_io.h\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n   \n   - Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n   \n   - Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n   \n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR\n   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifndef WAV_IO_H\n#define WAV_IO_H\n\n#include <stdio.h>\n#include <opus_types.h>\n\n#if !defined(__LITTLE_ENDIAN__) && ( defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) )\n#define le_short(s) ((short) ((unsigned short) (s) << 8) | ((unsigned short) (s) >> 8))\n#define be_short(s) ((short) (s))\n#else\n#define le_short(s) ((short) (s))\n#define be_short(s) ((short) ((unsigned short) (s) << 8) | ((unsigned short) (s) >> 8))\n#endif \n\n/** Convert little endian */\nstatic inline opus_int32 le_int(opus_int32 i)\n{\n#if !defined(__LITTLE_ENDIAN__) && ( defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) )\n   opus_uint32 ui, ret;\n   ui = i;\n   ret =  ui>>24;\n   ret |= (ui>>8)&0x0000ff00;\n   ret |= (ui<<8)&0x00ff0000;\n   ret |= (ui<<24);\n   return ret;\n#else\n   return i;\n#endif\n}\n\nvoid adjust_wav_mapping(int mapping_family, int channels, unsigned char *stream_map);\n\nint write_wav_header(FILE *file, int rate, int mapping_family, int channels);\n\n#endif\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/wave_out.c",
    "content": "/* Copyright (c) 2002, John Edwards\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n\n   - Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n   - Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n   - Neither the name of the Xiph.org Foundation nor the names of its\n   contributors may be used to endorse or promote products derived from\n   this software without specific prior written permission.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR\n   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifdef HAVE_CONFIG_H\n# include \"config.h\"\n#endif\n\n/* Set TABS = 4 */\n/********************************************************************\n\n function: To provide playback of 16 bit PCM wave data in Win32\n           environments from decoded compressed files.\n\n ********************************************************************/\n\n#if defined WIN32 || defined _WIN32\n\n#include <string.h>\n#include <errno.h>\n#include \"wave_out.h\"\n\n#define MAXWAVESIZE     4294967040LU\n#define MAX_WAVEBLOCKS    32\n\n// This is modified for USE_WIN_AUDIO - ONLY 2002-02-27\n\n\nstatic CRITICAL_SECTION  cs;\nstatic HWAVEOUT          dev                    = NULL;\nstatic unsigned          ScheduledBlocks        = 0;\nstatic int               PlayedWaveHeadersCount = 0;          // free index\nstatic WAVEHDR*          PlayedWaveHeaders [MAX_WAVEBLOCKS];\n\nstatic int\nBox ( const char* msg )\n{\n\tMessageBox ( NULL, msg, \" \"PACKAGE\" \"VERSION\": Error Message . . .\", MB_OK | MB_ICONEXCLAMATION );\n\treturn -1;\n}\n\n\n/*\n *  This function registers already played WAVE chunks. Freeing is done by free_memory(),\n */\n\nstatic void CALLBACK\nwave_callback ( HWAVE hWave, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )\n{\n        (void) hWave;\n        (void) dwInstance;\n        (void) dwParam2;\n\tif ( uMsg == WOM_DONE ) {\n\t\tEnterCriticalSection ( &cs );\n\t\tPlayedWaveHeaders [PlayedWaveHeadersCount++] = (WAVEHDR*) dwParam1;\n\t\tLeaveCriticalSection ( &cs );\n\t}\n}\n\n\nstatic void\nfree_memory ( void )\n{\n\tWAVEHDR*  wh;\n\tHGLOBAL   hg;\n\n\tEnterCriticalSection ( &cs );\n\twh = PlayedWaveHeaders [--PlayedWaveHeadersCount];\n\tScheduledBlocks--;                               // decrease the number of USED blocks\n\tLeaveCriticalSection ( &cs );\n\n\twaveOutUnprepareHeader ( dev, wh, sizeof (WAVEHDR) );\n\n\thg = GlobalHandle ( wh -> lpData );       // Deallocate the buffer memory\n\tGlobalUnlock (hg);\n\tGlobalFree   (hg);\n\n\thg = GlobalHandle ( wh );                 // Deallocate the header memory\n\tGlobalUnlock (hg);\n\tGlobalFree   (hg);\n}\n\n\nInt\nSet_WIN_Params ( FILE_T   dummyFile ,\n                 Ldouble  SampleFreq,\n                 Uint     BitsPerSample,\n                 Uint     Channels )\n{\n\tWAVEFORMATEX  outFormat;\n\tUINT          deviceID = WAVE_MAPPER;\n\n\t(void) dummyFile;\n\n\tif ( waveOutGetNumDevs () == 0 )\n\t\treturn Box ( \"No audio device present.\" );\n\n\toutFormat.wFormatTag      = WAVE_FORMAT_PCM;\n\toutFormat.wBitsPerSample  = BitsPerSample;\n\toutFormat.nChannels       = Channels;\n\toutFormat.nSamplesPerSec  = (unsigned long)(SampleFreq + 0.5);\n\toutFormat.nBlockAlign     = (outFormat.wBitsPerSample + 7) / 8 * outFormat.nChannels;\n\toutFormat.nAvgBytesPerSec = outFormat.nSamplesPerSec * outFormat.nBlockAlign;\n\n\tswitch ( waveOutOpen ( &dev, deviceID, &outFormat, (DWORD)wave_callback, 0, CALLBACK_FUNCTION ) )\n\t{\n\t\tcase MMSYSERR_ALLOCATED:   return Box ( \"Device is already open.\" );\n\t\tcase MMSYSERR_BADDEVICEID: return Box ( \"The specified device is out of range.\" );\n\t\tcase MMSYSERR_NODRIVER:    return Box ( \"There is no audio driver in this system.\" );\n\t\tcase MMSYSERR_NOMEM:       return Box ( \"Unable to allocate sound memory.\" );\n\t\tcase WAVERR_BADFORMAT:     return Box ( \"This audio format is not supported.\" );\n\t\tcase WAVERR_SYNC:          return Box ( \"The device is synchronous.\" );\n\t\tdefault:                   return Box ( \"Unknown media error.\" );\n\t\tcase MMSYSERR_NOERROR:     break;\n\t}\n\n\twaveOutReset ( dev );\n\tInitializeCriticalSection ( &cs );\n\tSetPriorityClass ( GetCurrentProcess (), HIGH_PRIORITY_CLASS );\n\treturn 0;\n}\n\n\nint\nWIN_Play_Samples ( const void* data, size_t len )\n{\n\tHGLOBAL    hg;\n\tHGLOBAL    hg2;\n\tLPWAVEHDR  wh;\n\tvoid*      allocptr;\n\n\tdo {\n\t\twhile ( PlayedWaveHeadersCount > 0 )                // free used blocks ...\n\t\t\tfree_memory ();\n\n\t\tif ( ScheduledBlocks < sizeof(PlayedWaveHeaders)/sizeof(*PlayedWaveHeaders) ) // wait for a free block ...\n\t\t\tbreak;\n\t\tSleep (26);\n\t} while (1);\n\n\tif ( (hg2 = GlobalAlloc ( GMEM_MOVEABLE, len )) == NULL )   // allocate some memory for a copy of the buffer\n\t\treturn Box ( \"GlobalAlloc failed.\" );\n\n\tallocptr = GlobalLock (hg2);\n\tCopyMemory ( allocptr, data, len );                         // Here we can call any modification output functions we want....\n\n\tif ( (hg = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof (WAVEHDR))) == NULL ) // now make a header and WRITE IT!\n\t\treturn -1;\n\n\twh                   = GlobalLock (hg);\n\twh -> dwBufferLength = len;\n\twh -> lpData         = allocptr;\n\n\tif ( waveOutPrepareHeader ( dev, wh, sizeof (WAVEHDR)) != MMSYSERR_NOERROR ) {\n\t\tGlobalUnlock (hg);\n\t\tGlobalFree   (hg);\n\t\treturn -1;\n\t}\n\n\tif ( waveOutWrite ( dev, wh, sizeof (WAVEHDR)) != MMSYSERR_NOERROR ) {\n\t\tGlobalUnlock (hg);\n\t\tGlobalFree   (hg);\n\t\treturn -1;\n\t}\n\n\tEnterCriticalSection ( &cs );\n\tScheduledBlocks++;\n\tLeaveCriticalSection ( &cs );\n\n\treturn len;\n}\n\n\nint\nWIN_Audio_close ( void )\n{\n\tif ( dev != NULL ) {\n\n\t\twhile ( ScheduledBlocks > 0 ) {\n\t\t\tSleep (ScheduledBlocks);\n\t\t\twhile ( PlayedWaveHeadersCount > 0 )         // free used blocks ...\n\t\t\t\tfree_memory ();\n\t\t}\n\n\t\twaveOutReset (dev);      // reset the device\n\t\twaveOutClose (dev);      // close the device\n\t\tdev = NULL;\n\t}\n\n\tDeleteCriticalSection ( &cs );\n\tScheduledBlocks = 0;\n\treturn 0;\n}\n\n#endif\n\n/* end of wave_out.c */\n"
  },
  {
    "path": "SGM_android/SmartGlassesManager/third_party/opus_tools/src/src/wave_out.h",
    "content": "/* Copyright (c) 2002, John Edwards\r\n\r\n   Redistribution and use in source and binary forms, with or without\r\n   modification, are permitted provided that the following conditions\r\n   are met:\r\n\r\n   - Redistributions of source code must retain the above copyright\r\n   notice, this list of conditions and the following disclaimer.\r\n\r\n   - Redistributions in binary form must reproduce the above copyright\r\n   notice, this list of conditions and the following disclaimer in the\r\n   documentation and/or other materials provided with the distribution.\r\n\r\n   - Neither the name of the Xiph.org Foundation nor the names of its\r\n   contributors may be used to endorse or promote products derived from\r\n   this software without specific prior written permission.\r\n\r\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r\n   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r\n   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR\r\n   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r\n   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r\n   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\r\n   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r\n   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r\n   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n*/\r\n\r\n//    WAVE_OUT.H - Necessary stuff for WIN_AUDIO\r\n\r\n#ifndef WAVE_OUT_H\r\n#define WAVE_OUT_H\r\n\r\n#include <stdio.h>\r\n#include <windows.h>\r\n#ifdef __MINGW32__\r\n#include <mmsystem.h>\r\n#endif\r\n\r\n//// constants /////////////////////////////////////////////////////\r\n\r\n#define SAMPLE_SIZE            16\r\n#define FILE_T                 FILE*\r\n#define INVALID_FILEDESC       NULL\r\n\r\n//// Simple types //////////////////////////////////////////////////\r\n\r\ntypedef signed   int        Int;        // at least -32767...+32767, fast type\r\ntypedef unsigned int        Uint;       // at least 0...65535, fast type\r\ntypedef long double         Ldouble;    // most exact floating point format\r\n\r\n//// procedures/functions //////////////////////////////////////////\r\n// wave_out.c\r\nInt        Set_WIN_Params             ( FILE_T dummyFile , Ldouble SampleFreq, Uint BitsPerSample, Uint Channels);\r\nint        WIN_Play_Samples           ( const void* buff, size_t len );\r\nint        WIN_Audio_close            ( void );\r\n\r\n#endif /* WAVE_OUT_H */\r\n"
  },
  {
    "path": "SGM_android/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\nbuildscript {\n    ext.kotlinVersion = '1.6.21'\n    ext.kotlin_version = '1.6.21'\n    ext.sdkGroupId = \"com.activelook\"\n    ext.sdkVersionCode = 442\n    ext.sdkVersionName = '4.4.3'\n\n    repositories {\n        google()\n        mavenCentral()\n//        jcenter()\n    }\n    dependencies {\n        classpath \"com.android.tools.build:gradle:8.0.2\"\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion\"\n    }\n}\n\nplugins {\n    id 'com.android.application' version '8.0.2' apply false\n    id 'com.android.library' version '8.0.2' apply false\n    id 'com.google.protobuf' version '0.9.2' apply false\n}\n\next {\n    roomVersion = '2.2.3'\n    archLifecycleVersion = '2.2.0-rc03'\n    coreTestingVersion = '2.1.0'\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}"
  },
  {
    "path": "SGM_android/build_all.sh",
    "content": "# Set up a logging file.\nLOG_FILE_NAME=build_log.txt\nrm -f \"${LOG_FILE_NAME}\"\ntouch \"${LOG_FILE_NAME}\"\nLOG_FILE=$(readlink -f \"${LOG_FILE_NAME}\")\n\n# Build Ogg and Opus libs.\ncd app/third_party/build\necho \"Building third party dependencies...\"\necho \"  Downloading and building Ogg and Opus libraries. This may take a minute or two.\"\n#echo \"  See ${LOG_FILE} for logs.\"\necho \"  See stdout for logs.\"\nchmod 755 build_all.sh\n./build_all.sh #> \"${LOG_FILE}\" 2>&1\nif [ $? -eq 0 ]; then\n  echo -e \"\\e[32m  Dependencies successfully built.\\e[0m\"\n  cd ../../..\nelse\n  #echo -e \"\\e[31m  Dependencies did not build successfully. See ${LOG_FILE} for errors.\\e[0m\"\n  echo -e \"\\e[31m  Dependencies did not build successfully. See output above for errors.\\e[0m\"\n  cd ../../..\n  exit 1\nfi\n\n# Tell gradle where the Android SDK is located.\necho sdk.dir=\"${ANDROID_SDK_PATH}\" > local.properties\n\n# Build the app.\necho \"Building Live Transcribe Speech Engine demo app...\"\ngradle wrapper #>> \"${LOG_FILE}\" 2>&1\n./gradlew assembleDebug --stacktrace #>> \"${LOG_FILE}\" 2>&1\nif [ $? -eq 0 ]; then\n  echo -e \"\\e[32m  Demo app successfully built.\\e[0m\"\nelse\n  #echo -e \"\\e[31m  Demo app did not build successfully. See ${LOG_FILE} for errors.\\e[0m\"\n  echo -e \"\\e[31m  Demo app did not build successfully. See output above for errors.\\e[0m\"\n  exit 1\nfi\n"
  },
  {
    "path": "SGM_android/build_log.txt",
    "content": ""
  },
  {
    "path": "SGM_android/gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.0.2-bin.zip\nnetworkTimeout=10000\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists"
  },
  {
    "path": "SGM_android/gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n# AndroidX package structure to make it clearer which packages are bundled with the\n# Android operating system, and which are packaged with your app\"s APK\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\nandroid.useAndroidX=true\n# Automatically convert third-party libraries to use AndroidX\nandroid.enableJetifier=true\nLIFECYCLE_VERSION=2.2.0\nROOM_VERSION=2.2.3\n\n\n"
  },
  {
    "path": "SGM_android/gradlew",
    "content": "#!/usr/bin/env sh\n\n#\n# Copyright 2015 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif [ \"$cygwin\" = \"true\" -o \"$msys\" = \"true\" ] ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=`expr $i + 1`\n    done\n    case $i in\n        0) set -- ;;\n        1) set -- \"$args0\" ;;\n        2) set -- \"$args0\" \"$args1\" ;;\n        3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=`save \"$@\"`\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "SGM_android/gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n\r\n@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto execute\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto execute\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %*\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "SGM_android/settings.gradle",
    "content": "pluginManagement {\n    repositories {\n        google()\n        mavenCentral()\n        gradlePluginPortal()\n    }\n}\ndependencyResolutionManagement {\n    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)\n    repositories {\n        google()\n        mavenCentral()\n        maven { url 'https://jitpack.io' }\n    }\n}\nrootProject.name = \"Smart Glasses Manager\"\ninclude ':SmartGlassesManager'\n\ninclude ':AugmentOSLib'\nproject(':AugmentOSLib').projectDir = new File(rootProject.projectDir, '../AugmentOS/augmentos_android_library/AugmentOSLib')"
  },
  {
    "path": "SGM_iOS/SGM/.gitignore",
    "content": ".DS_Store\n/.build\n/Packages\nxcuserdata/\nDerivedData/\n.swiftpm/configuration/registries.json\n.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata\n.netrc\n"
  },
  {
    "path": "SGM_iOS/SGM/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "SGM_iOS/SGM/Package.resolved",
    "content": "{\n  \"originHash\" : \"ac288556adfccd52466f89d2dda6bdbf275ca563ae24422c4135c4a213814a62\",\n  \"pins\" : [\n    {\n      \"identity\" : \"ultralitesdk-releases-ios\",\n      \"kind\" : \"remoteSourceControl\",\n      \"location\" : \"https://github.com/Vuzix/UltraliteSDK-releases-iOS\",\n      \"state\" : {\n        \"branch\" : \"main\",\n        \"revision\" : \"c7bd39808f36dc3831843283b11d7f61097d67bb\"\n      }\n    }\n  ],\n  \"version\" : 3\n}\n"
  },
  {
    "path": "SGM_iOS/SGM/Package.swift",
    "content": "// swift-tools-version: 5.10\n// The swift-tools-version declares the minimum version of Swift required to build this package.\n\nimport PackageDescription\n\nlet package = Package(\n    name: \"SGM\",\n    platforms: [.iOS(\"14.0\")],\n    products: [\n        // Products define the executables and libraries a package produces, making them visible to other packages.\n        .library(\n            name: \"SGM\",\n            targets: [\"SGM\"]),\n    ],\n    dependencies: [\n        .package(name: \"UltraliteSDK\", url: \"https://github.com/Vuzix/UltraliteSDK-releases-iOS\", branch: \"main\"),\n    ],\n    targets: [\n        // Targets are the basic building blocks of a package, defining a module or a test suite.\n        // Targets can depend on other targets in this package and products from dependencies.\n        .target(\n            name: \"SGM\",\n            dependencies: [\"UltraliteSDK\"],\n            path: \"Sources\"),\n        .testTarget(\n            name: \"SGMTests\",\n            dependencies: [\"SGM\"]),\n    ]\n)\n"
  },
  {
    "path": "SGM_iOS/SGM/Sources/SGM/SGM.swift",
    "content": "//\n//  SGM.swift\n//  SGM_iOS\n//\n//  Created by illo on 3/23/24.\n//\n\nimport CoreBluetooth\nimport Foundation\nimport UltraliteSDK\n\npublic class SGM: NSObject, CBCentralManagerDelegate {\n    \n    public static let shared = SGM()\n    \n    private var isActive: Bool = false\n    \n    private var displayTimeout: Int = 60\n    private var maximumNumTaps: Int = 1\n    \n    let ultraliteLeftSidePixelBuffer = 40\n    \n    private var isConnectedListener: BondListener<Bool>?\n    \n    private var textHandle: Int?\n    private var tapTextHandle: Int?\n    \n    var centralManager: CBCentralManager?\n    \n    var scanCallback: ((CBPeripheral) -> Void)?\n    \n    public func centralManagerDidUpdateState(_ central: CBCentralManager) {\n        print(\"CentralManager is initialized\")\n\n        switch central.state{\n        case CBManagerState.unauthorized:\n            print(\"The app is not authorized to use Bluetooth low energy.\")\n        case CBManagerState.poweredOff:\n            print(\"Bluetooth is currently powered off.\")\n        case CBManagerState.poweredOn:\n            print(\"Bluetooth is currently powered on and available to use.\")\n            let scanResult: UltraliteManager.BluetoothScanResult = UltraliteManager.shared.startScan(callback: { (peripheral: CBPeripheral) -> () in\n                if let callback = self.scanCallback {\n                    callback(peripheral)\n                }\n            })\n            print(\"scanResult: \\(scanResult)\")\n        default:break\n        }\n    }\n    \n    func startControl() {\n        if !isActive {\n            let startControlGranted: Bool? = UltraliteManager.shared.currentDevice?.requestControl(layout: .canvas, timeout: displayTimeout, hideStatusBar: true)\n            print(\"startControlGranted: \\(startControlGranted ?? false)\")\n        }\n    }\n    \n    public func scan(callback: @escaping ((CBPeripheral) -> Void)) {\n        scanCallback = callback\n        if let device = UltraliteManager.shared.currentDevice, device.isConnected.value == true {\n            // we have a device and it's connected\n            print(\"we have a device and it's connected\")\n        } else if UltraliteManager.shared.currentDevice != nil {\n            // we have a device but it isn't connected\n            print(\"we have a device but it isn't connected\")\n        } else {\n            print(\"No device\")\n            centralManager = CBCentralManager.init(delegate: self, queue: nil, options: [:])\n        }\n    }\n    \n    public func link(peripheral: CBPeripheral) {\n        UltraliteManager.shared.link(device: peripheral, callback: { (ultralite: Ultralite?) -> Void in\n            print(\"ultralite?.getName(): \\(String(describing: ultralite?.getName()))\")\n        })\n    }\n    \n    public func displayReferenceCardSimple(title: String, body: String) {\n        guard let device = UltraliteManager.shared.currentDevice else {\n            return\n        }\n        \n        startControl()\n        \n        device.canvas.clear()\n        \n        _ = device.canvas.createText(text: title, textAlignment: .auto, textColor: .white, anchor: .topLeft, xOffset: ultraliteLeftSidePixelBuffer, yOffset: 120, isVisible: true, width: 640 - ultraliteLeftSidePixelBuffer, height: -1, wrapMode: .wrap)\n        _ = device.canvas.createText(text: body, textAlignment: .auto, textColor: .white, anchor: .midLeft, xOffset: ultraliteLeftSidePixelBuffer, yOffset: 0, isVisible: true, width: 640 - ultraliteLeftSidePixelBuffer, height: -1, wrapMode: .wrap)\n        \n        device.canvas.commit()\n    }\n    \n}\n\n"
  },
  {
    "path": "SGM_iOS/SGM/Tests/SGMTests/SGMTests.swift",
    "content": "import XCTest\n@testable import SGM\n\nfinal class SGMTests: XCTestCase {\n    func testExample() throws {\n        // XCTest Documentation\n        // https://developer.apple.com/documentation/xctest\n\n        // Defining Test Cases and Test Methods\n        // https://developer.apple.com/documentation/xctest/defining_test_cases_and_test_methods\n    }\n}\n"
  },
  {
    "path": "android_smart_glasses_frontend/README.md",
    "content": "This is the thin client that supports Android-based smart glasses. Install this on your smart glasses, connect your glasses to your phone via the Android smart phone app, and it should all work.\n\nmain/ is the main Android application to run on the ASG.\n\nOpen main in Android studio and build + run + upload + edit in Android Studio.\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/.gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/caches\n/.idea/libraries\n/.idea/modules.xml\n/.idea/workspace.xml\n/.idea/navEditor.xml\n/.idea/assetWizardSettings.xml\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n.cxx\nlocal.properties\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/.gitignore",
    "content": "/build"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/build.gradle",
    "content": "plugins {\n    id 'com.android.application'\n}\n\nrepositories {\n    maven { url 'https://jitpack.io' }\n    flatDir {\n        dirs 'libs'\n    }\n}\n\nandroid {\n    namespace \"com.wearableintelligencesystem.androidsmartglasses\"\n    compileSdkVersion 29\n//    buildToolsVersion \"30.0.3\"\n    useLibrary 'org.apache.http.legacy'\n\n    defaultConfig {\n        applicationId \"com.wearableintelligencesystem.androidsmartglasses\"\n        minSdkVersion 26\n        targetSdkVersion 29\n        versionCode 2\n        versionName \"1.3\"\n\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n        }\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    android {\n        buildFeatures {\n            buildConfig = true\n        }\n    }\n}\n\ndependencies {\n\n    //fragments\n    def fragment_version = \"1.2.0\"\n    def fragment_nav_version = \"2.2.0\"\n    implementation \"androidx.fragment:fragment:$fragment_version\"\n    implementation \"androidx.navigation:navigation-fragment:$fragment_nav_version\"\n    implementation \"androidx.navigation:navigation-ui:$fragment_nav_version\"\n    implementation \"androidx.navigation:navigation-runtime:$fragment_nav_version\"\n\n    implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'\n    implementation \"androidx.appcompat:appcompat:1.1.0\"\n    implementation \"androidx.annotation:annotation:1.1.0\"\n    implementation 'com.android.support.constraint:constraint-layout:2.0.4'\n    testImplementation 'junit:junit:4.+'\n    androidTestImplementation 'com.android.support.test:runner:1.0.2'\n    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'\n    implementation 'com.squareup.picasso:picasso:2.71828'\n    implementation 'com.intellij:annotations:+@jar'\n    implementation \"org.java-websocket:Java-WebSocket:1.5.2\"\n    implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'\n\n    // Because RxAndroid releases are few and far between, it is recommended you also\n    // explicitly depend on RxJava's latest version for bug fixes and new features.\n    // (see https://github.com/ReactiveX/RxJava/releases for latest 3.x.x version)\n    implementation 'io.reactivex.rxjava3:rxjava:3.0.0'\n\n    implementation \"androidx.constraintlayout:constraintlayout:2.1.2\"\n\n    implementation 'com.squareup.okhttp3:okhttp:3.2.0'\n}\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/androidTest/java/com/example/wearableintelligencesystemandroidsmartglasses/ExampleInstrumentedTest.java",
    "content": "package com.example.androidsmartglasses;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();\n        assertEquals(\"com.example.wearableaidisplaymoverio\", appContext.getPackageName());\n    }\n}"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.wearableintelligencesystem.androidsmartglasses\">\n\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>\n    <uses-permission android:name=\"android.permission.SYSTEM_ALERT_WINDOW\"/>\n    <uses-permission android:name=\"android.permission.RECORD_AUDIO\" />\n    <uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>\n    <uses-permission android:name=\"android.permission.android.permission.BROADCAST_STICKY\"/>\n    <uses-permission android:name=\"android.permission.FOREGROUND_SERVICE\" />\n    <uses-permission android:name=\"android.permission.BLUETOOTH\" />\n    <uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\" />\n    <uses-permission android:name=\"android.permission.WAKE_LOCK\"/>\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/wis_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/wis_launcher\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/Theme.WearableAiDisplayMoverio\">\n        <activity android:name=\"com.wearableintelligencesystem.androidsmartglasses.MainActivity\"\n            android:exported=\"true\"\n            >\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n        <service\n            android:name=\"com.wearableintelligencesystem.androidsmartglasses.WearableAiService\"\n            android:label=\"WearableAiService\" >\n        </service>\n        <service android:name=\"com.wearableintelligencesystem.androidsmartglasses.sensors.MuseService\" android:enabled=\"true\"/>\n\n        <service android:name=\"com.wearableintelligencesystem.androidsmartglasses.archive.AudioService\" android:enabled=\"true\" android:exported=\"true\"></service>\n\n    </application>\n\n</manifest>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/assets/autocite_references.csv",
    "content": "id,name,year,authours,link,keyword_list\n0,\"As We May Think\",1945,\"Vannevar Bush\",\"https://www.ias.ac.in/article/fulltext/reso/005/11/0094-0103\",\"memex;mimics;mimic system;extended memory;PKMS;pk mess;pk a mess;pk amis\"\n1,\"Wearable Affective Memory Augmentation\",2020,\"Cayden Pierce;Steve Mann\",\"https://arxiv.org/pdf/2112.01584.pdf\",\"affective memory;memory augmentation\"\n2,\"Augmenting human intellect: A conceptual framework\",1962,\"Douglas Engelbart\",\"https://books.google.com/books?hl=en&lr=&id=eg1sDQAAQBAJ&oi=fnd&pg=PA313&dq=engelbart&ots=vq76F-pLGk&sig=IlRExIG6j4G2Y3W7vnekkDauOCQ\",\"augmented intelligence;vim editor;invention of the mouse;extending human intelligence;symbol manipulation\"\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/ASPClientSocket.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses;\n\nimport android.content.Context;\n\nimport com.wearableintelligencesystem.androidsmartglasses.archive.GlboxClientSocket;\nimport com.wearableintelligencesystem.androidsmartglasses.comms.MessageTypes;\nimport com.wearableintelligencesystem.androidsmartglasses.comms.WebSocketManager;\n\nimport android.content.Intent;\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport android.os.Looper;\nimport android.util.Base64;\nimport android.util.Log;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.net.Socket;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.util.Random;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingQueue;\n\nimport io.reactivex.rxjava3.disposables.Disposable;\nimport io.reactivex.rxjava3.subjects.PublishSubject;\n\n//singleton clientsocket class for connecting o ASP\npublic class ASPClientSocket {\n    public static boolean killme = false;\n\n    private static Handler handler;\n\n    public static String TAG = \"WearableAiAsg_AspClientSocket\";\n    //data observable we can send data through\n    private static PublishSubject<JSONObject> dataObservable;\n    private static Disposable dataSubscriber;\n\n    //our websocket connection to the ASP\n    private static WebSocketManager aspWebSocketManager;\n    private static Disposable webSocketSub;\n\n    private static int socketTimeout = 10000;\n\n    //observables to receive data from websocket\n    private static PublishSubject<JSONObject> webSocketObservable;\n\n    //broadcast intent string\n    //broadcast intent string\n    public final static String ACTION_RECEIVE_MESSAGE = \"com.example.wearableaidisplaymoverio.ACTION_RECEIVE_MESSAGE\";\n    public final static String EXTRAS_MESSAGE = \"com.example.wearableaidisplaymoverio.EXTRAS_MESSAGE\";\n    public final static String EYE_CONTACT_5_MESSAGE = \"com.example.wearableaidisplaymoverio.EYE_CONTACT_5\";\n    public final static String EYE_CONTACT_30_MESSAGE = \"com.example.wearableaidisplaymoverio.EYE_CONTACT_30\";\n    public final static String EYE_CONTACT_300_MESSAGE = \"com.example.wearableaidisplaymoverio.EYE_CONTACT_300\";\n    public final static String FACIAL_EMOTION_5_MESSAGE = \"com.example.wearableaidisplaymoverio.FACIAL_EMOTION_5\";\n    public final static String FACIAL_EMOTION_30_MESSAGE = \"com.example.wearableaidisplaymoverio.FACIAL_EMOTION_30\";\n    public final static String FACIAL_EMOTION_300_MESSAGE = \"com.example.wearableaidisplaymoverio.FACIAL_EMOTION_300\";\n\n    public final static String ACTION_UI_DATA = \"ACTION_UI_DATA\";\n    public final static String RAW_MESSAGE_JSON_STRING = \"RAW_MESSAGE_JSON_STRING\";\n\n    public final static String ACTION_AFFECTIVE_MEM_TRANSCRIPT_LIST = \"com.example.wearableaidisplaymoverio.ACTION_AFFECTIVE_MEM_TRANSCRIPT_LIST\";\n    public final static String AFFECTIVE_MEM_TRANSCRIPT_LIST = \"com.example.wearableaidisplaymoverio.AFFECTIVE_MEM_TRANSCRIPT_LIST\";\n\n    public final static String ACTION_AFFECTIVE_SEARCH_QUERY = \"com.example.wearableaidisplaymoverio.ACTION_AFFECTIVE_SEARCH_QUERY\";\n    public final static String AFFECTIVE_SEARCH_QUERY_RESULT = \"com.example.wearableaidisplaymoverio.AFFECTIVE_SEARCH_QUERY_RESULT\";\n\n    //singleton instance\n    private static ASPClientSocket clientsocket;\n    //socket data\n    static Thread SocketThread = null;\n    static Thread ReceiveThread = null;\n    static Thread SendThread = null;\n    static Thread WebSocketThread = null;\n    static private DataOutputStream output;\n\n    //socket message ids\n    static final byte [] heart_beat_id = {0x19, 0x20}; //id for heart beat\n    static final byte [] ack_id = {0x13, 0x37};\n\n    //static private BufferedReader input;\n    static private DataInputStream input;\n    static String SERVER_IP = \"0.0.0.0\"; //gets updated\n    static int SERVER_PORT = 4567;\n    private static int mConnectState = 0;\n\n    private static boolean gotAck = false;\n\n    //our actual socket connection object\n    private static Socket socket;\n\n    //remember how many packets we have in our buffer\n    private static int packets_in_buf = 0;\n\n    //queue of data to send through the socket\n    private static BlockingQueue<byte []> data_queue;\n    private static BlockingQueue<String> type_queue;\n    private static int queue_size = 50;\n    private static int image_buf_size = 0;\n\n    //we need a reference to the context of whatever called this class so we can send broadcast updates on receving new info\n    private static Context mContext;\n\n    private boolean socketStarted = false;\n    private static boolean webSocketStarted = false;\n    private boolean audioSocketStarted = false;\n\n    private ASPClientSocket(Context context){\n        //create send queue and a thread to handle sending\n        data_queue = new ArrayBlockingQueue<byte[]>(queue_size);\n        type_queue = new ArrayBlockingQueue<String>(queue_size);\n\n        //service context set \n        mContext = context;\n    }\n\n    public static ASPClientSocket getInstance(Context c){\n        if (clientsocket == null){\n            clientsocket = new ASPClientSocket(c);\n        }\n        return clientsocket;\n    }\n\n    public static void setIp(String ip){\n        SERVER_IP = ip;\n        if (aspWebSocketManager != null) {\n            aspWebSocketManager.setNewIp(ip);\n        }\n    }\n\n    public static ASPClientSocket getInstance(){\n        if (clientsocket == null){\n            return null;\n        }\n        return clientsocket;\n    }\n\n    public void startSocket(){\n        socketStarted = true;\n        //start first socketThread\n        if (socket == null) {\n            mConnectState = 1;\n            Log.d(TAG, \"startSocket starting\");\n            SocketThread = new Thread(new SocketThread());\n            SocketThread.start();\n\n            //setup handler to handle keeping connection alive, all subsequent start of SocketThread\n            //start a new handler thread to send heartbeats\n            HandlerThread thread = new HandlerThread(\"HeartBeater\");\n            thread.start();\n            handler = new Handler(thread.getLooper());\n            final int delay = 1000;\n            final int min_delay = 3000;\n            final int max_delay = 4000;\n            Random rand = new Random();\n            handler.postDelayed(new Runnable() {\n                public void run() {\n                    heartBeat();\n                    //random delay for heart beat so as to disallow synchronized failure between client and server\n                    int random_delay = rand.nextInt((max_delay - min_delay) + 1) + min_delay;\n//                    Log.d(TAG, \"Run next heart beat in n seconds, n = \" + random_delay);\n                    handler.postDelayed(this, random_delay);\n                }\n            }, delay);\n        }\n    }\n\n    private void heartBeat(){\n        //check if we are still connected\n        //if not , reconnect,\n        //we don't need to actively send heart beats from the client, as it's assumed that we are ALWAYS streaming data. Later, if we have periods of time where no data is sent, we will want to send a heart beat perhaps. but the client doesn't really need to, we just need to check if we are still connected\n        if (mConnectState == 0) {\n            updateUi();\n            restartSocket();\n        }\n    }\n\n    public static void restartSocket() {\n        Log.d(TAG, \"Restarting socket\");\n        mConnectState = 1;\n        if (socket != null && (!socket.isClosed())){\n            try {\n                if (output != null) {\n                    output.close();\n                }\n                if (input != null) {\n                    input.close();\n                }\n                socket.close();\n            } catch (IOException e) {\n                System.out.println(\"FAILED TO CLOSE SOCKET, SOMETHING IS WRONG\");\n            }\n        }\n\n\n//        //kill threads\n//        stopThread(SendThread);\n//        stopThread(ReceiveThread);\n\n        //restart socket thread\n        SocketThread = new Thread(new SocketThread());\n        SocketThread.start();\n    }\n\n    public static void stopThread(Thread thread){\n        if(thread!=null){\n            thread.interrupt();\n            thread = null;\n        }\n    }\n\n    public static  byte[] my_int_to_bb_be(int myInteger){\n        return ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(myInteger).array();\n    }\n\n    public void sendBytes(byte[] id, byte [] data, String type){\n        //only try to send data if the socket is connected state\n        if (mConnectState != 2){\n            System.out.println(\"MCONNECTED IS FALSE IN sendBytes, returning\");\n            return;\n        }\n\n        //handle different types differently\n        if (type == \"image\"){\n            image_buf_size++;\n        }\n        //first, send hello\n        byte [] hello = {0x01, 0x02, 0x03};\n        //then send length of body\n        byte[] len;\n        if (data != null) {\n             len = my_int_to_bb_be(data.length);\n        } else {\n            len = my_int_to_bb_be(0);\n        }\n        //then send id of message type\n        byte [] msg_id = id;\n        //then send data\n        byte [] body = data;\n        //then send end tag - eventually make this unique to the image\n        byte [] goodbye = {0x3, 0x2, 0x1};\n        //combine those into a payload\n        ByteArrayOutputStream outputStream;\n        try {\n            outputStream = new ByteArrayOutputStream();\n            outputStream.write(hello);\n            outputStream.write(len);\n            outputStream.write(msg_id);\n            if (body != null) {\n                outputStream.write(body);\n            }\n            outputStream.write(goodbye);\n        } catch (IOException e){\n            mConnectState = 0;\n            return;\n        }\n        byte [] payload = outputStream.toByteArray();\n\n        //send it in a background thread\n        //new Thread(new SendThread(payload)).start();\n        boolean try_send;\n        if (type == \"image\"){\n            if (data_queue.size() < (queue_size / 2)){ //if our queue is over half full, don't keep adding images to queue\n                try_send = true;\n            } else {\n                try_send = false;\n            }\n        } else { //if not an image, try to send anyway\n            try_send = true;\n        }\n\n        //add the data to the send queue\n        if (try_send) {\n            try {\n                data_queue.add(payload);\n                type_queue.add(type);\n            } catch (IllegalStateException e) {\n                Log.d(TAG, \"Queue is full, skipping this one\");\n            }\n        }\n    }\n\n    public int getConnected(){\n        return mConnectState;\n    }\n\n    static class SocketThread implements Runnable {\n        public void run() {\n            try {\n                if (killme){\n                    return;\n                }\n                System.out.println(\"TRYING TO CONNECT AspClient Socket on IP: \" + SERVER_IP + \" and port: \" + SERVER_PORT);\n                socket = new Socket();\n                socket.setSoTimeout(5000);\n                socket.connect(new InetSocketAddress(SERVER_IP, SERVER_PORT), socketTimeout);\n                Log.d(TAG, \"CONNECTED!\");\n                output = new DataOutputStream(socket.getOutputStream());\n                //input = new BufferedReader(new InputStreamReader(socket.getInputStream()));\n                input = new DataInputStream(new DataInputStream(socket.getInputStream()));\n                mConnectState = 2;\n\n                //update UI so user knows we're connected\n                updateUi();\n\n                //make the threads that will send and receive\n                if (ReceiveThread == null) { //if the thread is null, make a new one (the first one)\n                    ReceiveThread = new Thread(new ReceiveThread());\n                    ReceiveThread.start();\n                } else if (!ReceiveThread.isAlive()) { //if the thread is not null but it's dead, let it join then start a new one\n                    Log.d(TAG, \"IN SocketThread, WAITING FOR RECEIVETHREAD JOING\");\n                    try {\n                        ReceiveThread.join(); //make sure socket thread has joined before throwing off a new one\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                    Log.d(TAG, \"receive JOINED\");\n                    ReceiveThread = new Thread(new ReceiveThread());\n                    ReceiveThread.start();\n                }\n                if (SendThread == null) { //if the thread is null, make a new one (the first one)\n                    SendThread = new Thread(new SendThread());\n                    SendThread.start();\n                } else if (!SendThread.isAlive()) { //if the thread is not null but it's dead, let it join then start a new one\n                    Log.d(TAG, \"IN SocketThread, WAITING FOR send THREAD JOING\");\n                    try {\n                        SendThread.join(); //make sure socket thread has joined before throwing off a new one\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                    Log.d(TAG, \"send JOINED\");\n                    SendThread =  new Thread(new SendThread());\n                    SendThread.start();\n                }\n            } catch (IOException e) {\n                Log.d(TAG, \"Connection Refused on socket\");\n                e.printStackTrace();\n                mConnectState = 0;\n            }\n        }\n    }\n\n    public static int my_bb_to_int_be(byte [] byteBarray){\n        return ByteBuffer.wrap(byteBarray).order(ByteOrder.BIG_ENDIAN).getInt();\n    }\n\n    public boolean getConnectState(){\n        if (mConnectState != 2){\n            return false;\n        } else {\n            return true;\n        }\n    }\n\n    static class ReceiveThread implements Runnable {\n        @Override\n        public void run() {\n            while (true) {\n                if (killme){\n                    return;\n                }\n                if (mConnectState != 2){\n                    System.out.println(\"MCONNECTED IS FALSE IN REEIVE THREAD, BREAKING\");\n                    break;\n                }\n                byte b1, b2;\n                byte [] raw_data = null;\n                byte goodbye1, goodbye2, goodbye3;\n                //just read in data here\n                try {\n                    byte hello1 = input.readByte(); // read hello of incoming message\n                    byte hello2 = input.readByte(); // read hello of incoming message\n                    byte hello3 = input.readByte(); // read hello of incoming message\n\n                    //make sure header is verified\n                    if (hello1 != 0x01 || hello2 != 0x02 || hello3 != 0x03){\n                        Log.d(TAG, \"Socket hello header broken, restarting socket\");\n                        break;\n                    }\n                    //length of body\n                    int body_len = input.readInt();\n\n                    //read in message id bytes\n                    b1 = input.readByte();\n                    b2 = input.readByte();\n\n                    //read in message body (if there is one)\n                    if (body_len > 0){\n                        raw_data = new byte[body_len];\n                        input.readFully(raw_data, 0, body_len); // read the body\n                    }\n\n                    goodbye1 = input.readByte(); // read goodbye of incoming message\n                    goodbye2 = input.readByte(); // read goodbye of incoming message\n                    goodbye3 = input.readByte(); // read goodbye of incoming message\n                } catch (IOException e) {\n                    e.printStackTrace();\n                    mConnectState = 0;\n                    break;\n                }\n\n                //make sure footer is verified\n                if (goodbye1 != 0x03 || goodbye2 != 0x02 || goodbye3 != 0x01) {\n                    Log.d(TAG, \"Socket stream - footer broken, restarting socket\");\n                    break;\n                }\n\n                //then process the data\n                if ((b1 == ack_id[0]) && (b2 == ack_id[1])){ //got ack response\n                    gotAck = true;\n                } else if ((b1 == heart_beat_id[0]) && (b2 == heart_beat_id[1])) { //heart beat check if alive\n                    //got heart beat, respond with heart beat\n                    clientsocket.sendBytes(heart_beat_id, null, \"heartbeat\");\n                } else {\n                    System.out.println(\"BAD SIGNAL, RECONNECT\");\n                    mConnectState = 0;\n                    break;\n                }\n            }\n            mConnectState = 0;\n        }\n    }\n    static class SendThread implements Runnable {\n        SendThread() {\n        }\n        @Override\n        public void run() {\n            //clear queue so we don't have a buildup of images\n            data_queue.clear();\n            type_queue.clear();\n            while (true) {\n                if (killme){\n                    return;\n                }\n                if (packets_in_buf > 5) { //if 5 packets in buffer (NOT QUEUE, BUF NETWORK BUFFER), restart socket\n                    break;\n                }\n                byte[] data;\n                String type;\n                try {\n                    data = data_queue.take(); //block until there is something we can pull out to send\n                    type = type_queue.take();\n                } catch (InterruptedException e){\n                    e.printStackTrace();\n                    break;\n                }\n                try {\n                    output.write(data);           // write the message\n                } catch (java.io.IOException e) {\n                    e.printStackTrace();\n                    break;\n                }\n\n                //handle different types of sends differently\n                if (type == \"image\"){\n                    image_buf_size--;\n                }\n            }\n            mConnectState = 0;\n        }\n    }\n\n    private void parseData(JSONObject data){\n        try {\n            String typeOf = data.getString(MessageTypes.MESSAGE_TYPE_LOCAL);\n\n            //the first bit does a bunch of if statement. The new, better way of doing things is our syncing of data across ASP and ASG with MessageTypes shared class. Now, we just pass a JSON string through to the UI if it's a MessageType that it needs to see, and let the UI deal with how to parse/handle it\n            String [] uiMessages = new String[] {MessageTypes.NATURAL_LANGUAGE_QUERY, MessageTypes.REFERENCE_CARD_SIMPLE_VIEW, MessageTypes.REFERENCE_CARD_TEXT_WALL_VIEW, MessageTypes.REFERENCE_CARD_IMAGE_VIEW, MessageTypes.ACTION_SWITCH_MODES, MessageTypes.VOICE_COMMAND_STREAM_EVENT, MessageTypes.SCROLLING_TEXT_VIEW_START, MessageTypes.SCROLLING_TEXT_VIEW_STOP};\n            for (String uiMessage : uiMessages){\n               if (typeOf.equals(uiMessage)){\n                   final Intent intent = new Intent();\n                   intent.setAction(ASPClientSocket.ACTION_UI_DATA);\n                   intent.putExtra(RAW_MESSAGE_JSON_STRING, data.toString());\n                   mContext.sendBroadcast(intent); //eventually, we won't need to use the activity context, as our service will have its own context to send from\n\n                   //new method\n                   final Intent nintent = new Intent();\n                   nintent.setAction(typeOf);\n                   nintent.putExtra(RAW_MESSAGE_JSON_STRING, data.toString());\n                   mContext.sendBroadcast(nintent); //eventually, we won't need to use the activity context, as our service will have its own context to send from\n               }\n            }\n\n            //manual parsing, kept here until someone updates the ui to handle like above\n            if (typeOf.equals(MessageTypes.SCROLLING_TEXT_VIEW_INTERMEDIATE )) {\n                String intermediate_transcript = data.getString(MessageTypes.SCROLLING_TEXT_VIEW_TEXT);\n                final Intent intent = new Intent();\n                intent.putExtra(MessageTypes.SCROLLING_TEXT_VIEW_TEXT, intermediate_transcript);\n                intent.setAction(MessageTypes.SCROLLING_TEXT_VIEW_INTERMEDIATE);\n                mContext.sendBroadcast(intent); //eventually, we won't need to use the activity context, as our service will have its own context to send from\n            } else if (typeOf.equals(MessageTypes.SCROLLING_TEXT_VIEW_FINAL)) {\n                String final_transcript = data.getString(MessageTypes.SCROLLING_TEXT_VIEW_TEXT);\n                final Intent intent = new Intent();\n                intent.putExtra(MessageTypes.SCROLLING_TEXT_VIEW_TEXT, final_transcript);\n                intent.setAction(MessageTypes.SCROLLING_TEXT_VIEW_FINAL);\n                mContext.sendBroadcast(intent); //eventually, we won't need to use the activity context, as our service will have its own context to send from\n            }\n        } catch (JSONException e){\n            e.printStackTrace();\n        }\n    }\n\n    public void setObservable(PublishSubject observable){\n        dataObservable = observable;\n        //dataSubscriber = dataObservable.subscribe(i -> parseData(i));\n        dataSubscriber = dataObservable.subscribe(i -> parseData(i));\n    }\n\n    public static void startWebSocket(){\n        webSocketStarted = true;\n        WebSocketThread = new Thread(new WebSocketThread());\n        WebSocketThread.start();\n    }\n\n    static class WebSocketThread implements Runnable {\n        public void run() {\n            //start a thread to hold the websocket connection to ASP\n            aspWebSocketManager = new WebSocketManager(SERVER_IP, \"8887\");\n            aspWebSocketManager.setObservable(dataObservable);\n            aspWebSocketManager.setSourceName(\"asg_web_socket\"); //should be pulled from R.string\n            aspWebSocketManager.run(); //start socket which will auto reconnect on disconnect\n        }\n    }\n\n    public boolean getSocketStarted(){\n        return socketStarted;\n    }\n\n    public boolean getWebSocketStarted(){\n        return webSocketStarted;\n    }\n\n    public boolean getAudioSocketStarted(){\n        return audioSocketStarted;\n    }\n\n    private static void updateUi() {\n        boolean connected = false;\n        if (mConnectState == 2){\n            connected = true;\n        }\n        //tell WearableAI service new info that the ui needs\n        try {\n            JSONObject uiUpdate = new JSONObject();\n            uiUpdate.put(MessageTypes.MESSAGE_TYPE_LOCAL, MessageTypes.UI_UPDATE_ACTION);\n            uiUpdate.put(MessageTypes.PHONE_CONNECTION_STATUS, connected);\n            dataObservable.onNext(uiUpdate);\n        } catch (JSONException e){\n            e.printStackTrace();\n        }\n    }\n\n    public static void destroy(){\n        killme = true;\n\n        aspWebSocketManager.destroy();\n        handler.removeCallbacksAndMessages(null);\n\n        try {\n            SendThread.join();\n            ReceiveThread.join();\n            SocketThread.join();\n        } catch (InterruptedException e){\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/AudioSystem.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.media.AudioFormat;\nimport android.media.AudioManager;\nimport android.media.AudioRecord;\nimport android.util.Base64;\nimport android.util.Log;\n\nimport com.wearableintelligencesystem.androidsmartglasses.comms.MessageTypes;\nimport com.wearableintelligencesystem.androidsmartglasses.sensors.AudioChunkCallback;\nimport com.wearableintelligencesystem.androidsmartglasses.sensors.BluetoothMic;\nimport com.wearableintelligencesystem.androidsmartglasses.R;\nimport com.wearableintelligencesystem.androidsmartglasses.utils.AES;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.nio.ByteBuffer;\nimport java.util.concurrent.BlockingQueue;\n\nimport io.reactivex.rxjava3.subjects.PublishSubject;\n\npublic class AudioSystem {\n    private static String TAG = \"WearableAi_AudioSystem\";\n\n\n    //data observable we can send data through\n    private static PublishSubject<JSONObject> dataObservable;\n\n    //encryption key - TEMPORARILY HARD CODED - change to local storage, user can set\n    private String secretKey;\n\n    private static boolean firstConnect = false;\n\n    private long lastAudioUpdate = 0;\n    private int audioInterval = 3000;\n\n    // the audio recording options\n    private static final int RECORDING_RATE = 16000;\n    private static final int CHANNEL = AudioFormat.CHANNEL_IN_MONO;\n    private static final int FORMAT = AudioFormat.ENCODING_PCM_16BIT;\n\n    // the audio recorder\n    private AudioRecord recorder;\n    private AudioManager mAudioManager;\n    // the minimum buffer size needed for audio recording\n    private static int BUFFER_SIZE = AudioRecord.getMinBufferSize(RECORDING_RATE, CHANNEL, FORMAT);\n    // are we currently sending audio data\n    private boolean currentlySendingAudio = false;\n\n    //queue of data to send through the socket\n    private static BlockingQueue<byte []> data_queue;\n\n    private static int queue_size = 1024;\n\n    private Context context;\n\n    public AudioSystem(Context context){\n        secretKey = context.getResources().getString(R.string.key);\n        this.context = context;\n    }\n\n    public void startStreaming(){\n        //follow this order for speed\n        //start audio from bluetooth headset\n        BluetoothMic blutoothAudio = new BluetoothMic(context, new AudioChunkCallback(){\n            @Override\n            public void onSuccess(ByteBuffer chunk){\n                receiveChunk(chunk);\n            }\n        });\n    }\n\n    enum BluetoothState {\n        AVAILABLE, UNAVAILABLE\n    }\n\n    private final BroadcastReceiver bluetoothStateReceiver = new BroadcastReceiver() {\n\n        private BluetoothState bluetoothState = BluetoothState.UNAVAILABLE;\n\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1);\n            switch (state) {\n                case AudioManager.SCO_AUDIO_STATE_CONNECTED:\n                    Log.i(TAG, \"Bluetooth HFP Headset is connected\");\n                    handleBluetoothStateChange(BluetoothState.AVAILABLE);\n                    break;\n                case AudioManager.SCO_AUDIO_STATE_CONNECTING:\n                    Log.i(TAG, \"Bluetooth HFP Headset is connecting\");\n                    handleBluetoothStateChange(BluetoothState.UNAVAILABLE);\n                case AudioManager.SCO_AUDIO_STATE_DISCONNECTED:\n                    Log.i(TAG, \"Bluetooth HFP Headset is disconnected\");\n                    handleBluetoothStateChange(BluetoothState.UNAVAILABLE);\n                    break;\n                case AudioManager.SCO_AUDIO_STATE_ERROR:\n                    Log.i(TAG, \"Bluetooth HFP Headset is in error state\");\n                    handleBluetoothStateChange(BluetoothState.UNAVAILABLE);\n                    break;\n            }\n        }\n\n        private void handleBluetoothStateChange(BluetoothState state) {\n            if (bluetoothState == state) {\n                return;\n            }\n\n            bluetoothState = state;\n        }\n    };\n\n    public byte [] encryptBytes(byte [] input){\n        byte [] encryptedBytes = AES.encrypt(input, secretKey) ;\n        return encryptedBytes;\n    }\n\n\n    public byte [] decryptBytes(byte [] input) {\n        byte [] decryptedBytes = AES.decrypt(input, secretKey) ;\n        return decryptedBytes;\n    }\n\n    public void sendBytes(byte [] data) {\n        try {\n            JSONObject audioChunkJson = new JSONObject();\n            String encodedData = Base64.encodeToString(data, Base64.DEFAULT);\n            audioChunkJson.put(MessageTypes.MESSAGE_TYPE_LOCAL, MessageTypes.AUDIO_CHUNK_DECRYPTED);\n            audioChunkJson.put(MessageTypes.AUDIO_DATA, encodedData);\n            dataObservable.onNext(audioChunkJson);\n        } catch (JSONException e){\n            e.printStackTrace();\n        }\n    }\n\n    private void receiveChunk(ByteBuffer chunk){\n        byte[] audio_bytes = chunk.array();\n        //byte[] encrypted_audio_bytes = encryptBytes(audio_bytes);\n        sendBytes(audio_bytes);\n    }\n\n    private void activateBluetoothSco() {\n        if (!mAudioManager.isBluetoothScoAvailableOffCall()) {\n            Log.e(TAG, \"SCO is not available, recording with bluetooth is not possible\");\n            return;\n        }\n\n        if (!mAudioManager.isBluetoothScoOn()) {\n            mAudioManager.startBluetoothSco();\n        }\n    }\n\n\n    public void setObservable(PublishSubject observable){\n        dataObservable = observable;\n    }\n\n}"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/ImageAdapter.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses;\n\nimport com.wearableintelligencesystem.androidsmartglasses.R;\nimport com.squareup.picasso.Callback;\nimport com.squareup.picasso.Picasso;\n\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.util.Log;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.BaseAdapter;\nimport android.widget.GridView;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\n\npublic class ImageAdapter extends BaseAdapter {\n    public String TAG = \"ImageAdapter_WearableAiDisplay\";\n    private Context mContext;\n    public int imageTotal = 50;\n    public int selected_position = -1;\n    public static String[] mThumbIds = {\n            \"https://cdn.vox-cdn.com/thumbor/xb-heShdGq4G32_R1-c8E9FpyQw=/0x0:1694x866/1200x800/filters:focal(712x298:982x568)/cdn.vox-cdn.com/uploads/chorus_image/image/63097414/Screen_Shot_2019_02_22_at_3.13.37_PM.0.png\",\n            \"https://cdn.vox-cdn.com/thumbor/xb-heShdGq4G32_R1-c8E9FpyQw=/0x0:1694x866/1200x800/filters:focal(712x298:982x568)/cdn.vox-cdn.com/uploads/chorus_image/image/63097414/Screen_Shot_2019_02_22_at_3.13.37_PM.0.png\",\n            \"https://pyxis.nymag.com/v1/imgs/2cf/110/24734fb560ea12fe59f08772e974a8ac7b-10-elon-musk-60-minutes.rsquare.w700.jpg\",\n            \"https://cdn.vox-cdn.com/thumbor/xb-heShdGq4G32_R1-c8E9FpyQw=/0x0:1694x866/1200x800/filters:focal(712x298:982x568)/cdn.vox-cdn.com/uploads/chorus_image/image/63097414/Screen_Shot_2019_02_22_at_3.13.37_PM.0.png\",\n            \"https://pyxis.nymag.com/v1/imgs/2cf/110/24734fb560ea12fe59f08772e974a8ac7b-10-elon-musk-60-minutes.rsquare.w700.jpg\",\n            \"https://cdn.vox-cdn.com/thumbor/xb-heShdGq4G32_R1-c8E9FpyQw=/0x0:1694x866/1200x800/filters:focal(712x298:982x568)/cdn.vox-cdn.com/uploads/chorus_image/image/63097414/Screen_Shot_2019_02_22_at_3.13.37_PM.0.png\",\n            \"https://pyxis.nymag.com/v1/imgs/2cf/110/24734fb560ea12fe59f08772e974a8ac7b-10-elon-musk-60-minutes.rsquare.w700.jpg\",\n    };\n\n    public ImageAdapter(Context c) {\n        mContext = c;\n    }\n\n    public int getCount() {\n        return imageTotal;\n    }\n\n    @Override\n    public String getItem(int position) {\n        return mThumbIds[position];\n    }\n\n    public long getItemId(int position) {\n        return position;\n    }\n\n    public View getView(int position, View convertView, ViewGroup parent) {\n        ImageView imageView;\n        if (convertView == null) {\n            imageView = new ImageView(mContext);\n            imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);\n            imageView.setLayoutParams(new GridView.LayoutParams(156, 146)); //these are specific to the vuzix blade 480p display, will have to make this more responsive as we expand to more hardware - cayden\n            imageView.setBackgroundColor(Color.TRANSPARENT);\n            imageView.setPadding(3, 3, 3, 3);\n        } else {\n            imageView = (ImageView) convertView;\n        }\n        String url = getItem(position);\n        Log.d(TAG, \"Image URL picasso: \" + url);\n        Picasso.get() //with(mContext)\n                .load(url)\n                .placeholder(R.drawable.loader)\n                .fit()\n                .centerCrop().into(imageView, new Callback() {\n\n            @Override\n            public void onSuccess() {\n                Log.d(TAG, \"IMAGE PULLED SUCCESS\");\n            }\n\n            @Override\n            public void onError(Exception e) {\n                Log.d(TAG,\"Image load failed\");\n                e.printStackTrace();\n            }\n        });\n        return imageView;\n    }\n}"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/MainActivity.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses;\n\nimport android.Manifest;\nimport android.app.ActivityManager;\nimport android.content.BroadcastReceiver;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.ServiceConnection;\nimport android.content.pm.PackageManager;\nimport android.graphics.Color;\nimport android.graphics.drawable.Drawable;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.IBinder;\nimport android.os.PowerManager;\nimport android.os.StrictMode;\nimport android.text.method.ScrollingMovementMethod;\nimport android.util.Log;\nimport android.view.KeyEvent;\nimport android.view.View;\nimport android.view.WindowManager;\nimport android.widget.Button;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.core.app.ActivityCompat;\nimport androidx.core.content.ContextCompat;\nimport androidx.navigation.NavController;\nimport androidx.navigation.fragment.NavHostFragment;\n\nimport com.wearableintelligencesystem.androidsmartglasses.BuildConfig;\nimport com.wearableintelligencesystem.androidsmartglasses.R;\nimport com.github.mikephil.charting.charts.PieChart;\nimport com.wearableintelligencesystem.androidsmartglasses.archive.GlboxClientSocket;\nimport com.wearableintelligencesystem.androidsmartglasses.comms.MessageTypes;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Date;\n\n\npublic class MainActivity extends AppCompatActivity {\n    public WearableAiService mService;\n    public boolean mBound = false;\n\n    public static String TAG = \"WearableAiDisplay_MainActivity\";\n\n    public boolean binding = false; //should we be binding to the service?\n\n    public long commandResolveTime = 8000;\n    public long searchEngineResultTimeout = 12000;\n\n    //local ID strings for UI updating\n    public final static String ACTION_UI_UPDATE = \"com.example.wearableaidisplaymoverio.UI_UPDATE\";\n    public final static String ACTION_TEXT_REFERENCE = \"com.example.wearableaidisplaymoverio.ACTION_TEXT_REFERENCE\";\n    public final static String PHONE_CONN_STATUS_UPDATE = \"com.example.wearableaidisplaymoverio.PHONE_CONN_STATUS_UPDATE\";\n    public final static String WIFI_CONN_STATUS_UPDATE = \"com.example.wearableaidisplaymoverio.WIFI_CONN_STATUS_UPDATE\";\n    public final static String BATTERY_CHARGING_STATUS_UPDATE = \"com.example.wearableaidisplaymoverio.BATTERY_CHARGIN_STATUS_UPDATE\";\n    public final static String BATTERY_LEVEL_STATUS_UPDATE = \"com.example.wearableaidisplaymoverio.BATTERY_LEVEL_STATUS_UPDATE\";\n    public final static String VOICE_TEXT_RESPONSE = \"VOICE_TEXT_RESPONSE\";\n    public final static String VOICE_TEXT_RESPONSE_TEXT = \"VOICE_TEXT_RESPONSE_TEXT\";\n\n    //text list ui\n    ArrayList<String> textListHolder = new ArrayList<>();\n    TextView textListView;\n\n    //text list ui\n    private String textBlockHolder = \"\";\n    TextView textBlockView;\n\n    //save current mode\n    String curr_mode = \"\";\n\n    //HUD ui\n    private TextView mClockTextView;\n    private boolean clockRunning = false;\n    private ImageView mWifiStatusImageView;\n    private ImageView mPhoneStatusImageView;\n    private ImageView mBatteryStatusImageView;\n\n    //device status\n    private TextView mBatteryStatusTextView;\n    boolean phoneConnected = false;\n    boolean wifiConnected;\n    boolean batteryFull;\n    float batteryLevel;\n    boolean batteryCharging = false;\n\n    private Handler uiHandler;\n    private Handler clockHandler;\n    private Handler navHandler;\n\n    private NavController navController;\n\n    TextView modeStatus;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        Log.d(TAG, \"onCreate running\");\n\n        super.onCreate(savedInstanceState);\n\n        //help us find potential issues in dev\n        if (BuildConfig.DEBUG){\n            StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()\n                    .detectAll()\n                    .penaltyLog()\n                    .build());\n        }\n\n        //hide top bar\n        getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);\n\n        //setup ui handler\n        uiHandler = new Handler();\n\n        //setup clock handler\n        clockHandler = new Handler();\n\n        //setup nav handler\n        navHandler = new Handler();\n\n        //set main view\n        setContentView(R.layout.activity_main);\n        modeStatus = findViewById(R.id.mode_hud);\n\n        //setup the nav bar\n//        Log.d(TAG, getSupportFragmentManager().toString());\n//        Log.d(TAG, getSupportFragmentManager().getFragments().toString());\n////        NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);\n//        NavHostFragment navHostFragment = (NavHostFragment) NavHostFragment.findNavController();\n//        Log.d(TAG, navHostFragment.toString());\n//        navController = navHostFragment.getNavController();\n        NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);\n        navController = navHostFragment.getNavController();\n\n        //setup main view\n        Log.d(TAG, \"onCreate switchMode\");\n        switchMode(MessageTypes.MODE_HOME);\n\n        //setup permissions\n        if (ContextCompat.checkSelfPermission(this,\n                Manifest.permission.RECORD_AUDIO)\n                != PackageManager.PERMISSION_GRANTED) {\n            ActivityCompat.requestPermissions(this,\n                    new String[]{Manifest.permission.RECORD_AUDIO},\n                    1234);\n        } else {\n            //create the WearableAI service if it isn't already running\n            startWearableAiService();\n        }\n\n    }\n\n    //handle permissions\n    @Override\n    public void onRequestPermissionsResult(int requestCode,\n                                           String permissions[], int[] grantResults) {\n        switch (requestCode) {\n            case 1234: {\n                // If request is cancelled, the result arrays are empty.\n                if (grantResults.length > 0\n                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {\n                    Log.d(\"TAG\", \"User granted audio permissions.\");\n                    startWearableAiService();\n                } else {\n                    Log.d(\"TAG\", \"permission denied by user\");\n                }\n                return;\n            }\n        }\n    }\n\n    private void turnOffScreen(){\n        screenBrightnessControl(0);\n    }\n\n    private void turnOnScreen(){\n        screenBrightnessControl(-1);\n    }\n\n    private void screenBrightnessControl(float brightness){\n        //turn screen brightness to 0;\n        WindowManager.LayoutParams params = getWindow().getAttributes();\n        params.screenBrightness = brightness;\n        getWindow().setAttributes(params);\n    }\n\n    private void setupHud(){\n        //setup clock\n        if (! clockRunning) {\n            clockRunning = true;\n            clockHandler.post(new Runnable() {\n                public void run() {\n                    // Default time format for current locale, with respect (on API 22+) to user's 12/24-hour\n                    // settings. I couldn't find any simple way to respect it back to API 14.\n                    //String prettyTime = DateFormat.getTimeInstance(DateFormat.SHORT).format(new Date()) + \"-\" + DateFormat.getDateInstance(DateFormat.SHORT).format(new Date());\n                    String prettyTime = new SimpleDateFormat(\"h:mm a\").format(new Date());\n                    mClockTextView = (TextView) findViewById(R.id.clock_text_view);\n                    if (mClockTextView != null) {\n                        mClockTextView.setText(prettyTime);\n                    }\n                    clockHandler.postDelayed(this, 1000);\n                }\n            });\n        } else{\n            //do just one update so user doesn't have to wait\n            String prettyTime = new SimpleDateFormat(\"h:mm a\").format(new Date());\n            mClockTextView = (TextView) findViewById(R.id.clock_text_view);\n            if (mClockTextView != null) {\n                mClockTextView.setText(prettyTime);\n            }\n        }\n\n        //setup wifi status\n        updateWifiHud();\n\n        //setup phone connect status\n        updatePhoneHud();\n\n        //setup battery connect status\n        updateBatteryHud();\n    }\n\n    private void updateWifiHud(){\n        mWifiStatusImageView = (ImageView) findViewById(R.id.wifi_image_view);\n\n        if (mWifiStatusImageView == null){\n            return;\n        }\n        //wifiConnected = WifiUtils.checkWifiOnAndConnected(this); //check wifi status - don't need now that we have listener in service\n        Drawable wifiOnDrawable = this.getDrawable(R.drawable.ic_wifi_on);\n        Drawable wifiOffDrawable = this.getDrawable(R.drawable.ic_wifi_off);\n        if (wifiConnected) {\n            mWifiStatusImageView.setImageDrawable(wifiOnDrawable);\n        } else {\n            mWifiStatusImageView.setImageDrawable(wifiOffDrawable);\n        }\n    }\n\n    private void updatePhoneHud(){\n        mPhoneStatusImageView = (ImageView) findViewById(R.id.phone_status_image_view);\n        if (mPhoneStatusImageView == null){\n            return;\n        }\n        Drawable phoneOnDrawable = this.getDrawable(R.drawable.ic_phone_connected);\n        Drawable phoneOffDrawable = this.getDrawable(R.drawable.ic_phone_disconnected);\n        if (phoneConnected) {\n            mPhoneStatusImageView.setImageDrawable(phoneOnDrawable);\n        } else {\n            mPhoneStatusImageView.setImageDrawable(phoneOffDrawable);\n        }\n    }\n\n    private void updateBatteryHud(){\n        //set the icon\n        mBatteryStatusImageView = (ImageView) findViewById(R.id.battery_status_image_view);\n        if (mBatteryStatusImageView == null){\n            return;\n        }\n        Drawable batteryFullDrawable = this.getDrawable(R.drawable.ic_full_battery);\n        Drawable batteryFullChargingDrawable = this.getDrawable(R.drawable.ic_full_battery_charging);\n        Drawable batteryLowDrawable = this.getDrawable(R.drawable.ic_low_battery);\n        Drawable batteryLowChargingDrawable = this.getDrawable(R.drawable.ic_low_battery_charging);\n        if (batteryFull) {\n            if (batteryCharging) {\n                mBatteryStatusImageView.setImageDrawable(batteryFullChargingDrawable);\n            } else {\n                mBatteryStatusImageView.setImageDrawable(batteryFullDrawable);\n            }\n        } else {\n            if (batteryCharging) {\n                mBatteryStatusImageView.setImageDrawable(batteryLowChargingDrawable);\n            } else {\n                mBatteryStatusImageView.setImageDrawable(batteryLowDrawable);\n            }\n        }\n\n        //set the text\n        mBatteryStatusTextView = (TextView) findViewById(R.id.battery_percentage_text_view);\n        mBatteryStatusTextView.setText((int)batteryLevel + \"%\");\n    }\n\n    private void switchMode(String mode) {\n        curr_mode = mode;\n        String modeDisplayName = \"...\";\n\n        //clear any previous ui intentions\n        uiHandler.removeCallbacksAndMessages(null);\n\n        if (mode != MessageTypes.MODE_BLANK){\n            turnOnScreen();\n        }\n\n        switch (mode) {\n            case MessageTypes.MODE_BLANK:\n                blankUi();\n                modeDisplayName = \"Blank\";\n                break;\n            case MessageTypes.MODE_LANGUAGE_TRANSLATE:\n                navController.navigate(R.id.nav_language_translate);\n                modeDisplayName = \"Lang.Trans.\";\n                break;\n            case MessageTypes.MODE_OBJECT_TRANSLATE:\n                navController.navigate(R.id.nav_object_translate);\n                modeDisplayName = \"Obj.Trans.\";\n                break;\n            case MessageTypes.MODE_TEXT_LIST:\n                setupTextList();\n                modeDisplayName = \"TextList\";\n                break;\n            case MessageTypes.MODE_TEXT_BLOCK:\n                setupTextBlock();\n                modeDisplayName = \"TextBlock\";\n                break;\n//            case MessageTypes.MODE_REFERENCE_GRID:\n//                setContentView(R.layout.image_gridview);\n//                modeDisplayName = \"Ref.Grid\";\n//                break;\n//            case MessageTypes.MODE_SOCIAL_MODE:\n//                setupSocialIntelligenceUi();\n//                modeDisplayName = \"Social\";\n//                break;\n            case MessageTypes.MODE_HOME:\n                navController.navigate(R.id.nav_home_prompt);\n                modeDisplayName = \"Home\";\n                break;\n            case MessageTypes.MODE_LIVE_LIFE_CAPTIONS:\n                navController.navigate(R.id.nav_live_life_captions);\n                modeDisplayName = \"ScrollingText\";\n                break;\n            case MessageTypes.MODE_CONVERSATION_MODE:\n                navController.navigate(R.id.nav_convo_mode);\n                modeDisplayName = \"Convo\";\n                break;\n            case MessageTypes.MODE_SEARCH_ENGINE_RESULT:\n                modeDisplayName = \"Card\";\n            break;\n        }\n\n        //set new mode status\n        modeStatus.setText(modeDisplayName);\n\n        //registerReceiver(mComputeUpdateReceiver, makeComputeUpdateIntentFilter());\n    }\n\n    //generic way to set the current enumerated list of strings and display them, scrollably, on the main UI\n    private void setupTextList() {\n        //live life captions mode gui setup\n        setContentView(R.layout.text_list);\n\n        //setup the text list view\n        textListView = (TextView) findViewById(R.id.text_list);\n        textListView.setText(\"\");\n        for (int i = 0; i < textListHolder.size(); i++) {\n            textListView.append(Integer.toString(i+1) + \": \" + textListHolder.get(i) + \"\\n\");\n        }\n        textListView.setPadding(10, 0, 10, 0);\n        textListView.setMovementMethod(new ScrollingMovementMethod());\n        textListView.setSelected(true);\n    }\n\n    //generic way to set the current single string, scrollably, on the main UI\n    private void setupTextBlock() {\n        //live life captions mode gui setup\n        setContentView(R.layout.text_block);\n\n        //setup the text list view\n        textBlockView = (TextView) findViewById(R.id.text_block);\n        textBlockView.setText(textBlockHolder);\n        textBlockView.setPadding(10, 0, 10, 0);\n        textBlockView.setMovementMethod(new ScrollingMovementMethod());\n        textBlockView.setSelected(true);\n    }\n\n    private void blankUi() {\n        turnOffScreen();\n    }\n\n    @Override\n    public void onResume() {\n        super.onResume();\n\n        setupHud();\n\n        registerReceiver(mComputeUpdateReceiver, makeComputeUpdateIntentFilter());\n\n        if (binding) {\n            bindWearableAiService();\n        }\n    }\n\n    private void teardownHud() {\n        uiHandler.removeCallbacksAndMessages(null);\n        clockHandler.removeCallbacksAndMessages(null);\n        clockRunning = false;\n    }\n\n    @Override\n    public void onPause() {\n        super.onPause();\n\n        teardownHud();\n\n        if (binding) {\n            unbindWearableAiService();\n        }\n\n        //unregister receiver\n        unregisterReceiver(mComputeUpdateReceiver);\n    }\n\n    private static IntentFilter makeComputeUpdateIntentFilter() {\n        final IntentFilter intentFilter = new IntentFilter();\n        intentFilter.addAction(GlboxClientSocket.COMMAND_SWITCH_MODE);\n        intentFilter.addAction(GlboxClientSocket.ACTION_WIKIPEDIA_RESULT);\n        intentFilter.addAction(GlboxClientSocket.ACTION_TRANSLATION_RESULT);\n        intentFilter.addAction(GlboxClientSocket.ACTION_VISUAL_SEARCH_RESULT);\n        intentFilter.addAction(GlboxClientSocket.ACTION_AFFECTIVE_SUMMARY_RESULT);\n        intentFilter.addAction(MessageTypes.FACE_SIGHTING_EVENT);\n\n        intentFilter.addAction(ASPClientSocket.ACTION_AFFECTIVE_MEM_TRANSCRIPT_LIST);\n        intentFilter.addAction(ASPClientSocket.ACTION_AFFECTIVE_SEARCH_QUERY);\n\n        intentFilter.addAction(ACTION_UI_UPDATE);\n        intentFilter.addAction(ASPClientSocket.ACTION_UI_DATA);\n\n        return intentFilter;\n    }\n\n    private final BroadcastReceiver mComputeUpdateReceiver = new BroadcastReceiver() {\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            final String action = intent.getAction();\n            if (ASPClientSocket.ACTION_UI_DATA.equals(action)) {\n                Log.d(TAG, \"THIS SHIT: \" + action.toString());\n                try {\n                    JSONObject data = new JSONObject(intent.getStringExtra(ASPClientSocket.RAW_MESSAGE_JSON_STRING));\n                    String typeOf = data.getString(MessageTypes.MESSAGE_TYPE_LOCAL);\n                    Log.d(TAG, typeOf);\n                    if (typeOf.equals(MessageTypes.SEARCH_ENGINE_RESULT)){\n                        showSearchEngineResults(data);\n                    } else if (typeOf.equals(MessageTypes.REFERENCE_CARD_SIMPLE_VIEW)){\n                        showReferenceCardSimpleView(data);\n                    } else if (typeOf.equals(MessageTypes.REFERENCE_CARD_TEXT_WALL_VIEW)){\n                        showTextWallView(data);\n                    } else if (typeOf.equals(MessageTypes.REFERENCE_CARD_IMAGE_VIEW)){\n                        Log.d(TAG, \"GOT IMAGE REFERENCE VIEW REQUEST\");\n                        showReferenceCardImageView(data);\n                    } else if (typeOf.equals(MessageTypes.ACTION_SWITCH_MODES)){\n                        //parse out the name of the mode\n                        String modeName = data.getString(MessageTypes.NEW_MODE);\n                        //switch to that mode\n                        Log.d(TAG, \"ACTION_SWITCH_MODES switchMode\");\n                        switchMode(modeName);\n                    } else if (typeOf.equals(MessageTypes.SCROLLING_TEXT_VIEW_START)){\n                        Log.d(TAG, \"GOT SCROLL START, Switching\");\n                        switchMode(MessageTypes.MODE_LIVE_LIFE_CAPTIONS);\n                    } else if (typeOf.equals(MessageTypes.SCROLLING_TEXT_VIEW_STOP)){\n                        Log.d(TAG, \"GOT SCROLL STOP, Switching\");\n                        switchMode(MessageTypes.MODE_HOME);\n                    } else if (typeOf.equals(MessageTypes.VOICE_COMMAND_STREAM_EVENT)) {\n                        Log.d(TAG, \"GOT VOICE COMMAND STREAM EVENT\");\n                        showVoiceCommandInterface(data);\n                    }\n                } catch(JSONException e){\n                        e.printStackTrace();\n                }\n            } else if (ACTION_UI_UPDATE.equals(action)) {\n//                Log.d(TAG, \"GOT ACTION_UI_UPDATE\");\n                if (intent.hasExtra(PHONE_CONN_STATUS_UPDATE)) {\n                    phoneConnected = intent.getBooleanExtra(PHONE_CONN_STATUS_UPDATE, false);\n                    updatePhoneHud();\n                }\n                if (intent.hasExtra(BATTERY_CHARGING_STATUS_UPDATE)){\n                    batteryCharging = intent.getBooleanExtra(BATTERY_CHARGING_STATUS_UPDATE, false);\n                    updateBatteryHud();\n                }\n                if (intent.hasExtra(BATTERY_LEVEL_STATUS_UPDATE)){\n                    batteryLevel = intent.getFloatExtra(BATTERY_LEVEL_STATUS_UPDATE, 100f);\n                    if (batteryLevel > 30f) {\n                        batteryFull = true;\n                    } else {\n                        batteryFull = false;\n                    }\n                    updateBatteryHud();\n                }\n                if (intent.hasExtra(WIFI_CONN_STATUS_UPDATE)){\n                    wifiConnected = intent.getBooleanExtra(WIFI_CONN_STATUS_UPDATE, false);\n                    updateWifiHud();\n                }\n            }\n        }\n    };\n\n    //disable the back button\n    @Override\n    public void onBackPressed() {\n        //do nothing\n    }\n\n    /** Defines callbacks for service binding, passed to bindService() */\n    private ServiceConnection connection = new ServiceConnection() {\n\n        @Override\n        public void onServiceConnected(ComponentName className,\n                                       IBinder service) {\n            // We've bound to LocalService, cast the IBinder and get LocalService instance\n            WearableAiService.LocalBinder binder = (WearableAiService.LocalBinder) service;\n            mService = binder.getService();\n            mBound = true;\n\n            //get update of ui information\n            mService.requestUiUpdate();\n            Log.d(TAG, \"onServiceConnected complete\");\n        }\n\n        @Override\n        public void onServiceDisconnected(ComponentName arg0) {\n            mBound = false;\n        }\n    };\n\n    @Override\n    public boolean onKeyUp(int keyCode, KeyEvent event) {\n        Log.d(TAG, \"got keycode\");\n        Log.d(TAG, Integer.toString(keyCode));\n        //broadcast to child fragments that this happened\n        final Intent nintent = new Intent();\n        nintent.setAction(MessageTypes.SG_TOUCHPAD_EVENT);\n        nintent.putExtra(MessageTypes.SG_TOUCHPAD_KEYCODE, keyCode);\n        this.sendBroadcast(nintent);\n\n        switch (keyCode) {\n            case KeyEvent.KEYCODE_ENTER:\n                Log.d(TAG, \"keycode _ enter felt\");\n                return super.onKeyUp(keyCode, event);\n            case KeyEvent.KEYCODE_DEL:\n                Log.d(TAG, \"keycode DEL entered - this means go back home\");\n                navHandler.removeCallbacksAndMessages(null);\n                switchMode(MessageTypes.MODE_HOME);\n                return super.onKeyUp(keyCode, event);\n            default:\n                return super.onKeyUp(keyCode, event);\n        }\n    }\n\n    // Note  from authour - From what I've seen you don't need the wake-lock or wifi-lock below for the audio-recorder to persist through screen-off.\n    // However, to be on the safe side you might want to activate them anyway. (and/or if you have other functions that need them)\n    private PowerManager.WakeLock wakeLock_partial = null;\n    public void StartPartialWakeLock() {\n        if (wakeLock_partial != null && wakeLock_partial.isHeld()) return;\n        Log.i(\"vmain\", \"Starting partial wake-lock.\");\n        final PowerManager pm = (PowerManager) this.getApplicationContext().getSystemService(Context.POWER_SERVICE);\n        wakeLock_partial = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, \"com.myapp:partial_wake_lock\");\n        wakeLock_partial.acquire();\n    }\n\n    public void bindWearableAiService(){\n        // Bind to that service\n        Intent intent = new Intent(this, WearableAiService.class);\n        bindService(intent, connection, Context.BIND_AUTO_CREATE);\n    }\n\n    public void unbindWearableAiService() {\n        // Unind to that service\n        unbindService(connection);\n    }\n\n    private void showReferenceCard(String title, String body, String imgUrl, long timeout){\n        //navHandler.removeCallbacksAndMessages(null);\n        uiHandler.removeCallbacksAndMessages(null);\n        String lastMode = curr_mode;\n\n        //show the reference\n        Bundle args = new Bundle();\n        args.putString(\"title\", title);\n        args.putString(\"body\", body);\n        args.putString(\"img_url\", imgUrl);\n        //quickly go home then to result, because if we go straight to the result, it will fail to display results if the nav_reference page is already loaded - this is a hack\n//        switchMode(MessageTypes.MODE_HOME);\n        navController.navigate(R.id.nav_reference, args);\n\n        //for now, show for n seconds and then return to llc\n        uiHandler.postDelayed(new Runnable() {\n            public void run() {\n                Log.d(TAG, \"showReferenceCard switchMode\");\n                switchMode(MessageTypes.MODE_HOME);\n            }\n        }, timeout);\n    }\n\n    private void showSearchEngineResults(JSONObject data) {\n        try {\n            //parse out the response object - one result for now\n            JSONObject search_engine_result = new JSONObject(data.getString(MessageTypes.SEARCH_ENGINE_RESULT_DATA));\n\n            //get content\n            String title = search_engine_result.getString(\"title\");\n            String summary = search_engine_result.getString(\"body\");\n\n            //pull image from web and display in imageview\n            String img_url = null;\n            if (search_engine_result.has(\"image\")) {\n                img_url = search_engine_result.getString(\"image\");\n            }\n\n            Log.d(TAG, \"Running search engine result\");\n            Log.d(TAG, title);\n            Log.d(TAG, summary);\n            switchMode(MessageTypes.MODE_SEARCH_ENGINE_RESULT);\n            showReferenceCard(title, summary, img_url, searchEngineResultTimeout);\n        } catch (JSONException e) {\n            Log.d(TAG, e.toString());\n            e.printStackTrace();\n        }\n    }\n\n    private void showReferenceCardSimpleView(JSONObject data) {\n        try {\n            //get content\n            String title = data.getString(MessageTypes.REFERENCE_CARD_SIMPLE_VIEW_TITLE);\n            String body = data.getString(MessageTypes.REFERENCE_CARD_SIMPLE_VIEW_BODY);\n\n            Log.d(TAG, \"Running reference card simple view\");\n            Log.d(TAG, title);\n            Log.d(TAG, body);\n            switchMode(MessageTypes.MODE_SEARCH_ENGINE_RESULT);\n            showReferenceCard(title, body, null, searchEngineResultTimeout);\n        } catch (JSONException e) {\n            Log.d(TAG, e.toString());\n        }\n    }\n\n    private void showTextWallView(JSONObject data) {\n        try {\n            //get content\n            String text = data.getString(MessageTypes.REFERENCE_CARD_TEXT_WALL_TEXT);\n\n            Log.d(TAG, \"Running text wall card simple view\");\n            Log.d(TAG, text);\n            switchMode(MessageTypes.MODE_SEARCH_ENGINE_RESULT);\n\n            uiHandler.removeCallbacksAndMessages(null);\n            String lastMode = curr_mode;\n\n            //show the reference\n            Bundle args = new Bundle();\n            args.putString(\"text\", text);\n            //quickly go home then to result, because if we go straight to the result, it will fail to display results if the nav_reference page is already loaded - this is a hack\n    //        switchMode(MessageTypes.MODE_HOME);\n            navController.navigate(R.id.nav_text_wall, args);\n\n            //for now, show for n seconds and then return to llc\n//            uiHandler.postDelayed(new Runnable() {\n//                public void run() {\n//                    Log.d(TAG, \"showReferenceCard switchMode\");\n//                    switchMode(MessageTypes.MODE_HOME);\n//                }\n//            }, timeout);\n        } catch (JSONException e) {\n            Log.d(TAG, e.toString());\n        }\n    }\n\n    private void showReferenceCardImageView(JSONObject data) {\n        try {\n            //get content\n            String title = data.getString(MessageTypes.REFERENCE_CARD_IMAGE_VIEW_TITLE);\n            String body = data.getString(MessageTypes.REFERENCE_CARD_IMAGE_VIEW_BODY);\n            String imgUrl = data.getString(MessageTypes.REFERENCE_CARD_IMAGE_VIEW_IMG_URL);\n\n            Log.d(TAG, \"Running reference card image view\");\n            Log.d(TAG, title);\n            Log.d(TAG, body);\n            switchMode(MessageTypes.MODE_SEARCH_ENGINE_RESULT);\n            showReferenceCard(title, body, imgUrl, searchEngineResultTimeout);\n        } catch (JSONException e) {\n            Log.d(TAG, e.toString());\n        }\n    }\n\n    //start, stop, handle the service\n    public void stopWearableAiService() {\n        Log.d(TAG, \"Stopping WearableAI service\");\n        unbindWearableAiService();\n        binding = false;\n\n        if (!isMyServiceRunning(WearableAiService.class)) return;\n        Intent stopIntent = new Intent(this, WearableAiService.class);\n        stopIntent.setAction(WearableAiService.ACTION_STOP_FOREGROUND_SERVICE);\n        startService(stopIntent);\n    }\n\n    public void sendWearableAiServiceMessage(String message) {\n        if (!isMyServiceRunning(WearableAiService.class)) return;\n        Intent messageIntent = new Intent(this, WearableAiService.class);\n        messageIntent.setAction(message);\n        Log.d(TAG, \"Sending WearableAi Service this message: \" + message);\n        startService(messageIntent);\n    }\n\n    public void startWearableAiService() {\n        Log.d(TAG, \"Starting wearableAiService\");\n        binding = true;\n        if (isMyServiceRunning(WearableAiService.class)) return;\n        Intent startIntent = new Intent(this, WearableAiService.class);\n        startIntent.setAction(WearableAiService.ACTION_START_FOREGROUND_SERVICE);\n        startService(startIntent);\n    }\n\n    //check if service is running\n    private boolean isMyServiceRunning(Class<?> serviceClass) {\n        ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);\n        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {\n            if (serviceClass.getName().equals(service.service.getClassName())) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private void showVoiceCommandInterface(JSONObject data){\n        try{\n            String voiceInputType = data.getString(MessageTypes.VOICE_COMMAND_STREAM_EVENT_TYPE);\n            Log.d(TAG, voiceInputType);\n\n            //if it told us to cancel the stream\n\n            if (voiceInputType.equals(MessageTypes.CANCEL_EVENT_TYPE)) {\n                Log.d(TAG, \"CANCEL_EVENT_TYPE switchMode\");\n                switchMode(MessageTypes.MODE_HOME);\n            } else if (voiceInputType.equals(MessageTypes.TEXT_RESPONSE_EVENT_TYPE)){ //if it was a wake word\n                String commandResponseDisplayString = data.getString(MessageTypes.COMMAND_RESPONSE_DISPLAY_STRING);\n\n                //send a broadcast to our fragment showing the command result\n                final Intent nintent = new Intent();\n                nintent.setAction(VOICE_TEXT_RESPONSE);\n                nintent.putExtra(VOICE_TEXT_RESPONSE_TEXT, commandResponseDisplayString);\n                sendBroadcast(nintent); //eventually, we won't need to use the activity context, as our service will have its own context to send from\n\n                //reset ui so user has time to read answer\n                //clear any previous ui intentions\n                uiHandler.removeCallbacksAndMessages(null);\n                uiHandler.postDelayed(new Runnable() {\n                    @Override\n                    public void run() {\n                        Log.d(TAG, \"TEXT_RESPONSE_EVENT_TYPE switchMode\");\n                        switchMode(MessageTypes.MODE_HOME);\n                    }\n                }, commandResolveTime);\n            } else if (voiceInputType.equals(MessageTypes.WAKE_WORD_EVENT_TYPE)){ //if it was a wake word\n                JSONArray commandList = new JSONArray(data.getString(MessageTypes.VOICE_COMMAND_LIST));\n                showPostWakeWordInterface(data.getString(MessageTypes.INPUT_WAKE_WORD), commandList);\n            } else if (voiceInputType.equals(MessageTypes.COMMAND_EVENT_TYPE)){ //if it was a wake word\n                String argumentExpect = data.getString(MessageTypes.VOICE_ARG_EXPECT_TYPE);\n                if (argumentExpect.equals(MessageTypes.VOICE_ARG_EXPECT_NATURAL_LANGUAGE)) {\n                    showPostCommandInterface(data.getString(MessageTypes.INPUT_WAKE_WORD), data.getString(MessageTypes.INPUT_VOICE_COMMAND_NAME));\n                }\n            } else if (voiceInputType.equals(MessageTypes.REQUIRED_ARG_EVENT_TYPE)){ //if it's a required argument we need to show a prompt for\n                JSONArray argsList = new JSONArray(data.getString(MessageTypes.ARG_OPTIONS));\n                showRequiredArgumentInterface(data.getString(MessageTypes.ARG_NAME), argsList);\n            } else if (voiceInputType.equals(MessageTypes.RESOLVE_EVENT_TYPE)){\n                boolean status = data.getBoolean(MessageTypes.COMMAND_RESULT);\n                String commandResponseDisplayString = data.getString(MessageTypes.COMMAND_RESPONSE_DISPLAY_STRING);\n                showCommandResolve(status, commandResponseDisplayString);\n            }\n        } catch (JSONException e){\n            e.printStackTrace();\n        }\n    }\n\n    private void showPostWakeWordInterface(String wakeWord, JSONArray commandOptions){\n        //show the reference\n        Bundle args = new Bundle();\n        args.putString(MessageTypes.VOICE_COMMAND_LIST, commandOptions.toString());\n        args.putString(MessageTypes.INPUT_WAKE_WORD, wakeWord);\n        uiHandler.removeCallbacksAndMessages(null);\n        navController.navigate(R.id.nav_wake_word_post, args);\n    }\n\n    private void showRequiredArgumentInterface(String argName, JSONArray argOptions){\n        Bundle args = new Bundle();\n        args.putString(MessageTypes.ARG_OPTIONS, argOptions.toString());\n        args.putString(MessageTypes.ARG_NAME, argName);\n        uiHandler.removeCallbacksAndMessages(null);\n        navController.navigate(R.id.nav_required_args, args);\n    }\n\n    private void showPostCommandInterface(String wakeWord, String selectedCommand){\n        Bundle args = new Bundle();\n        args.putString(MessageTypes.INPUT_WAKE_WORD, wakeWord);\n        args.putString(MessageTypes.INPUT_VOICE_COMMAND_NAME, selectedCommand);\n        uiHandler.removeCallbacksAndMessages(null);\n        navController.navigate(R.id.nav_command_post, args);\n    }\n\n    private void showCommandResolve(boolean success, String message){\n        //clear any previous ui intentions\n        uiHandler.removeCallbacksAndMessages(null);\n\n        //show the reference\n        Bundle args = new Bundle();\n        args.putBoolean(\"success\", success);\n        args.putString(\"message\", message);\n        navController.navigate(R.id.nav_command_resolve, args);\n\n        uiHandler.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n\n                Log.d(TAG, \"showCommandResolve switch mode\");\n                switchMode(MessageTypes.MODE_HOME);\n            }\n        }, commandResolveTime);\n    }\n}\n\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/WearableAiService.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses;\n\nimport android.app.ActivityManager;\nimport android.app.Notification;\nimport android.app.NotificationChannel;\nimport android.app.NotificationManager;\nimport android.app.PendingIntent;\nimport android.app.Service;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.graphics.Color;\nimport android.os.AsyncTask;\nimport android.os.BatteryManager;\nimport android.os.Binder;\nimport android.os.Environment;\nimport android.os.IBinder;\nimport android.os.PowerManager;\nimport android.os.SystemClock;\nimport android.util.Log;\n\nimport androidx.core.app.NotificationCompat;\n\nimport com.wearableintelligencesystem.androidsmartglasses.R;\nimport com.wearableintelligencesystem.androidsmartglasses.archive.GlboxClientSocket;\nimport com.wearableintelligencesystem.androidsmartglasses.comms.MessageTypes;\nimport com.wearableintelligencesystem.androidsmartglasses.comms.WifiStatusCallback;\nimport com.wearableintelligencesystem.androidsmartglasses.comms.WifiUtils;\nimport com.wearableintelligencesystem.androidsmartglasses.sensors.BluetoothScanner;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.DatagramPacket;\nimport java.net.DatagramSocket;\nimport java.net.InetAddress;\n\nimport io.reactivex.rxjava3.disposables.Disposable;\nimport io.reactivex.rxjava3.exceptions.UndeliverableException;\nimport io.reactivex.rxjava3.plugins.RxJavaPlugins;\nimport io.reactivex.rxjava3.subjects.PublishSubject;\n\n//handles all of the background stuff like\n    //-socket connection to ASP\n    //-socket connection to GLBox\n    //-receiving data from both ASP and GLBox\n    //-whatever else we need in the background\npublic class WearableAiService extends Service {\n    public static final String ACTION_START_FOREGROUND_SERVICE = \"ACTION_START_FOREGROUND_SERVICE\";\n    public static final String ACTION_STOP_FOREGROUND_SERVICE = \"ACTION_STOP_FOREGROUND_SERVICE\";\n\n    public static boolean killme = false;\n\n    // Binder given to clients\n    private final IBinder binder = new LocalBinder();\n\n    //device status\n    boolean phoneConnected = false;\n    boolean wifiConnected;\n    float batteryPercentage;\n    boolean batteryIsCharging;\n\n    //ASP socket\n    ASPClientSocket asp_client_socket;\n    String asp_address;\n    String asp_adv_key = \"WearableAiCyborg\";\n\n    //GLBOX socket\n    GlboxClientSocket glbox_client_socket;\n    String glbox_address = \"3.23.98.82\";\n\n    //id of packet\n    static final byte[] img_id = {0x01, 0x10}; //id for images\n\n    //settings\n    private String router = \"web\";\n\n    //tag\n    private String TAG = \"WearableAiDisplay\";\n\n    public int PORT_NUM = 8891;\n    public DatagramSocket socket;\n\n    private Context mContext;\n\n    Thread adv_thread;\n\n    //observables to send data around app\n    PublishSubject<JSONObject> dataObservable;\n    private Disposable dataSubscriber;\n\n    //bluetooth sensors\n    private BluetoothScanner mBluetoothScanner;\n\n    //audio system\n    AudioSystem audioSystem;\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n\n        //set the error handler for rxjava\n        RxJavaPlugins.setErrorHandler(throwable -> {\n            throwable.printStackTrace();\n            if (throwable instanceof  UndeliverableException){\n                Log.d(TAG, \"Got RXJAVA error UndeliverableException.... carrying on.\");\n            }\n        }); // nothing or some logging\n\n        dataObservable = PublishSubject.create();\n        dataSubscriber = dataObservable.subscribe(i -> handleDataStream(i));\n\n        //setup our connection to the ASP\n        asp_client_socket = ASPClientSocket.getInstance(this);\n        asp_client_socket.setObservable(dataObservable);\n\n        //first we have to listen for the UDP broadcast from the compute module so we know the IP address to connect to. Once we get that , we will connect to it on a socket and starting sending pictures\n        //this will start the asp socket when ASP address is received and ASP is not connected. If ASP socket already running, it will update the ASP address (useful when ASP IP changes, like on new wifi)\n        Thread adv_thread = new Thread(new ReceiveAdvThread());\n        adv_thread.start();\n\n        //setup audio streaming\n        audioSystem = new AudioSystem(this);\n        audioSystem.setObservable(dataObservable);\n        audioSystem.startStreaming();\n\n        mContext = this;\n\n        //start sensor scan\n//        mBluetoothScanner = new BluetoothScanner(this);\n//        mBluetoothScanner.startScan();\n\n        //register for battery information\n        this.registerReceiver(this.mBatInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));\n\n        //register for wifi information\n        IntentFilter wifiFilter = new IntentFilter();\n        wifiFilter.addAction(\"android.net.conn.CONNECTIVITY_CHANGE\");\n        WifiStatusCallback wifiConnectCallback = new WifiStatusCallback() {\n            @Override\n            public void onSuccess(boolean connected) {\n                wifiConnected = connected;\n                if (!wifiConnected){ //if wifi connects, then phone must disconnect too - ACTUALLY not true on all phone, some bounce off and on, but websocket stays up\n//                    phoneConnected = false;\n                }\n                updateUi();\n            }\n        };\n        this.registerReceiver(new WifiUtils.WifiReceiver(wifiConnectCallback), wifiFilter);\n    }\n\n    class ReceiveAdvThread extends Thread {\n        public void run() {\n            receiveUdpBroadcast();\n        }\n    }\n\n    class StartGlbox extends Thread {\n        public void run() {\n            glbox_starter();\n        }\n    }\n\n\n    public void receiveUdpBroadcast() {\n        try {\n            //Keep a socket open to listen to all the UDP trafic that is destined for this port\n            socket = new DatagramSocket(PORT_NUM, InetAddress.getByName(\"0.0.0.0\"));\n            socket.setBroadcast(true);\n\n            while (!killme) {\n                //Receive a packet\n                byte[] recvBuf = new byte[64];\n                DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);\n                socket.receive(packet);\n\n                //Packet received\n                String data = new String(packet.getData()).trim();\n                if (data.equals(asp_adv_key)) {\n                    asp_address = packet.getAddress().getHostAddress();\n                    asp_client_socket.setIp(asp_address);\n                    asp_comms_starter();\n                }\n                int hundos = 5; //how many hundredths of a second to wait, we split it up so we don't get stuck when the app is closed/killed\n                for (int i = 0; i < hundos; i++){\n                    SystemClock.sleep(100); //this is how we delay the loop from running too fast, there is probably a better way, but setting up a hanlder failed with no error, so this works for now\n                    if (killme){\n                        break;\n                    }\n                }\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n            Log.d(TAG, \"Exception: \" + e);\n        }\n    }\n\n    public void asp_comms_starter() {\n        //start the web socket to communicate with ASP, to replace TCP socket below\n        if (!asp_client_socket.getWebSocketStarted()) {\n            asp_client_socket.startWebSocket();\n        }\n\n        //start comms to ASP\n        if (!asp_client_socket.getSocketStarted()) {\n            asp_client_socket.startSocket();\n        }\n    }\n\n\n    public void glbox_starter() {\n        startGlboxSocket();\n    }\n\n    @Override\n    public void onDestroy() {\n        killme = true;\n        dataSubscriber.dispose();\n        asp_client_socket.destroy();\n\n        try {\n            adv_thread.join();\n        } catch(InterruptedException e){\n            e.printStackTrace();\n        }\n\n        super.onDestroy();\n    }\n\n    public class LocalBinder extends Binder {\n        WearableAiService getService() {\n            // Return this instance of LocalService so clients can call public methods\n            return WearableAiService.this;\n        }\n    }\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        return binder;\n    }\n\n    private void startMyOwnForeground(){\n\n    }\n\n    //service stuff\n    private Notification updateNotification() {\n\n        String NOTIFICATION_CHANNEL_ID = \"com.wearableintelligencesystem.main_notify_channel\";\n        String channelName = \"SmartGlassesManager\";\n        NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_NONE);\n        chan.setLightColor(Color.BLUE);\n        chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);\n        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);\n        assert manager != null;\n        manager.createNotificationChannel(chan);\n\n        Context context = getApplicationContext();\n        PendingIntent action = PendingIntent.getActivity(context,\n                0, new Intent(context, MainActivity.class),\n                PendingIntent.FLAG_CANCEL_CURRENT); // Flag indicating that if the described PendingIntent already exists, the current one should be canceled before generating a new one.\n\n        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);\n        Notification notification = notificationBuilder.setOngoing(true)\n                .setSmallIcon(R.drawable.elon)\n                .setContentTitle(\"Wearable Intelligence System\")\n                .setContentText(\"Running...\")\n                .setContentIntent(action)\n                .setPriority(NotificationManager.IMPORTANCE_MIN)\n                .setCategory(Notification.CATEGORY_SERVICE)\n                .setOngoing(true).build();\n\n        return notification;\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        if (intent != null){\n            String action = intent.getAction();\n            switch (action) {\n                case ACTION_START_FOREGROUND_SERVICE:\n                    // start the service in the foreground\n                    startForeground(1234, updateNotification());\n                    break;\n                case ACTION_STOP_FOREGROUND_SERVICE:\n                    stopForeground(true);\n                    stopSelf();\n                    break;\n            }\n        }\n\n        return START_NOT_STICKY;\n    }\n\n    private void startGlboxSocket() {\n        //create client socket and setup socket\n        System.out.println(\"STARTING GLBOX SOCKET\");\n        glbox_client_socket = GlboxClientSocket.getInstance(this);\n        glbox_client_socket.setObservable(dataObservable);\n        glbox_client_socket.setIp(glbox_address);\n        glbox_client_socket.startSocket();\n    }\n\n    private File getDir() {\n        File sdDir = Environment\n                .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);\n        return new File(sdDir, \"CameraAPIDemo\");\n    }\n\n    //check if service is running\n    private boolean isMyServiceRunning(Class<?> serviceClass) {\n        ActivityManager manager = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);\n        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {\n            if (serviceClass.getName().equals(service.service.getClassName())) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private BroadcastReceiver mBatInfoReceiver = new BroadcastReceiver(){\n        @Override\n        public void onReceive(Context ctxt, Intent intent) {\n            // Are we charging / charged?\n            int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);\n            batteryIsCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || status == BatteryManager.BATTERY_STATUS_FULL;\n\n            //what is the charge level?\n            int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);\n            int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);\n            batteryPercentage = level * 100 / (float)scale;\n//            Log.d(TAG, \"BATTERY PERCENTAGE IS: \" + batteryPercentage);\n//            Log.d(TAG, \"BATTERY IS charging: \" + batteryIsCharging);\n            updateUi();\n        }\n    };\n\n    private void updateUi() {\n        //send to main ui\n        final Intent intent = new Intent();\n        intent.setAction(MainActivity.ACTION_UI_UPDATE);\n        intent.putExtra(MainActivity.BATTERY_LEVEL_STATUS_UPDATE, batteryPercentage);\n        intent.putExtra(MainActivity.BATTERY_CHARGING_STATUS_UPDATE, batteryIsCharging);\n        intent.putExtra(MainActivity.WIFI_CONN_STATUS_UPDATE, wifiConnected);\n        intent.putExtra(MainActivity.PHONE_CONN_STATUS_UPDATE, phoneConnected);\n        mContext.sendBroadcast(intent); //eventually, we won't need to use the activity context, as our service will have its own context to send from\n    }\n\n    public void requestUiUpdate(){\n        updateUi();\n    }\n\n    private void handleDataStream(JSONObject data){\n        try {\n            String dataType = data.getString(MessageTypes.MESSAGE_TYPE_LOCAL);\n            if (dataType.equals(MessageTypes.UI_UPDATE_ACTION)){\n                if (data.has(MessageTypes.PHONE_CONNECTION_STATUS)){\n                    phoneConnected = data.getBoolean(MessageTypes.PHONE_CONNECTION_STATUS);\n                    updateUi();\n                }\n            }\n        } catch (JSONException e) {\n            e.printStackTrace();\n        }\n    }\n\n    //wake up the screen\n    private void wakeupScreen() {\n        new AsyncTask<Void, Void, Exception>() {\n            @Override\n            protected Exception doInBackground(Void... params) {\n                try {\n                    Log.d(TAG, \"WAITING TO TURN ON SCREEN\");\n                    try {\n                        Thread.sleep(10000); // turn on duration\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                    Log.d(TAG, \"TURNING ON SCREEN\");\n                    PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);\n                    PowerManager.WakeLock fullWakeLock = powerManager.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), \"WIS:Loneworker-FULL WAKE LOCK\");\n                    fullWakeLock.acquire(); // turn on\n                    try {\n                        Thread.sleep(5000); // turn on duration\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                    Log.d(TAG, \"RELEASING SCREEN\");\n                    fullWakeLock.release();\n                } catch (Exception e) {\n                    return e;\n                }\n                return null;\n            }\n        }.execute();\n    }\n\n}\n\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/archive/AudioService.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.archive;\n\nimport android.app.NotificationChannel;\nimport android.app.NotificationManager;\nimport android.app.Service;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.media.AudioFormat;\nimport android.media.AudioManager;\nimport android.media.AudioRecord;\nimport android.media.AudioTrack;\nimport android.media.MediaRecorder;\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport android.os.IBinder;\nimport android.util.Log;\n\nimport com.wearableintelligencesystem.androidsmartglasses.sensors.AudioChunkCallback;\nimport com.wearableintelligencesystem.androidsmartglasses.sensors.BluetoothMic;\nimport com.wearableintelligencesystem.androidsmartglasses.utils.AES;\nimport com.wearableintelligencesystem.androidsmartglasses.R;\n\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.net.Socket;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.util.Random;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingQueue;\n\npublic class AudioService extends Service {\n    public static final String ACTION_START_COMMS = \"ACTION_START_COMMS\";\n    public static final String ACTION_NEW_IP = \"ACTION_NEW_IP\";\n\n    //encryption key - TEMPORARILY HARD CODED - change to local storage, user can set\n    private String secretKey;\n\n    private static boolean firstConnect = false;\n\n    private static int socketTimeout = 10000;\n\n    private long lastAudioUpdate = 0;\n    private int audioInterval = 3000;\n\n    // Binder given to clients\n    private final IBinder binder = new AudioService.LocalBinder();\n\n    public static final String CHANNEL_ID = \"AudioServiceChannel\";\n\n    //socket info\n    //static String SERVER_IP = \"3.23.98.82\";\n    static String SERVER_IP;\n    static int SERVER_PORT = 4449;\n    private static int mConnectState = 0;\n\n    private static String TAG = \"WearableAi_AudioService\";\n\n\n    // the audio recording options\n    private static final int RECORDING_RATE = 16000;\n    private static final int CHANNEL = AudioFormat.CHANNEL_IN_MONO;\n    private static final int FORMAT = AudioFormat.ENCODING_PCM_16BIT;\n\n    // the audio recorder\n    private AudioRecord recorder;\n    private AudioManager mAudioManager;\n    // the minimum buffer size needed for audio recording\n    private static int BUFFER_SIZE = AudioRecord.getMinBufferSize(RECORDING_RATE, CHANNEL, FORMAT);\n    // are we currently sending audio data\n    private boolean currentlySendingAudio = false;\n\n    //socket data\n    static Thread SocketThread = null;\n    static Thread SendThread = null;\n    static private DataOutputStream output;\n\n    //our actual socket connection object\n    private static Socket socket;\n\n    //remember how many packets we have in our buffer\n    private static int packets_in_buf = 0;\n\n    //queue of data to send through the socket\n    private static BlockingQueue<byte []> data_queue;\n//    private static BlockingQueue<String> type_queue;\n    private static int queue_size = 1024;\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n\n        if (intent != null){\n            String action = intent.getAction();\n            switch (action) {\n                case ACTION_START_COMMS:\n                    SERVER_IP = intent.getExtras().getString(\"address_to_send\");\n\n                    // do heavy work on a background thread\n                    //StartRecorder();\n\n                    //follow this order for speed\n                    //start audio from bluetooth headset\n                    BluetoothMic blutoothAudio = new BluetoothMic(this, new AudioChunkCallback(){\n                        @Override\n                        public void onSuccess(ByteBuffer chunk){\n                            receiveChunk(chunk);\n                        }\n                    });\n\n                    //start the socket thread which will send the raw audio data\n                    startSocket();\n                    break;\n                case ACTION_NEW_IP:\n                    String newIp = intent.getExtras().getString(\"address_to_send\");\n                    SERVER_IP = newIp;\n            }\n        }\n\n        return START_NOT_STICKY;\n    }\n\n    enum BluetoothState {\n        AVAILABLE, UNAVAILABLE\n    }\n\n    private final BroadcastReceiver bluetoothStateReceiver = new BroadcastReceiver() {\n\n        private BluetoothState bluetoothState = BluetoothState.UNAVAILABLE;\n\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1);\n            switch (state) {\n                case AudioManager.SCO_AUDIO_STATE_CONNECTED:\n                    Log.i(TAG, \"Bluetooth HFP Headset is connected\");\n                    handleBluetoothStateChange(BluetoothState.AVAILABLE);\n                    break;\n                case AudioManager.SCO_AUDIO_STATE_CONNECTING:\n                    Log.i(TAG, \"Bluetooth HFP Headset is connecting\");\n                    handleBluetoothStateChange(BluetoothState.UNAVAILABLE);\n                case AudioManager.SCO_AUDIO_STATE_DISCONNECTED:\n                    Log.i(TAG, \"Bluetooth HFP Headset is disconnected\");\n                    handleBluetoothStateChange(BluetoothState.UNAVAILABLE);\n                    break;\n                case AudioManager.SCO_AUDIO_STATE_ERROR:\n                    Log.i(TAG, \"Bluetooth HFP Headset is in error state\");\n                    handleBluetoothStateChange(BluetoothState.UNAVAILABLE);\n                    break;\n            }\n        }\n\n        private void handleBluetoothStateChange(BluetoothState state) {\n            if (bluetoothState == state) {\n                return;\n            }\n\n            bluetoothState = state;\n        }\n    };\n\n    @Override\n    public void onCreate(){\n        super.onCreate();\n\n        secretKey = getResources().getString(R.string.key);\n\n        //setup data\n        //create send queue and a thread to handle sending\n        data_queue = new ArrayBlockingQueue<byte[]>(queue_size);\n\n        //use bluetooth microphone if available\n//        registerReceiver(bluetoothStateReceiver, new IntentFilter(\n//                AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED));\n\n//        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);\n//        activateBluetoothSco();\n//        mAudioManager.setBluetoothScoOn(true);\n//        mAudioManager.startBluetoothSco();\n//\n//        mAudioManager.setSpeakerphoneOn(false);\n//        mAudioManager.setMode(mAudioManager.MODE_NORMAL);\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n    }\n\n    private void createNotificationChannel() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            NotificationChannel serviceChannel = new NotificationChannel(\n                    CHANNEL_ID,\n                    \"Foreground Service Channel\",\n                    NotificationManager.IMPORTANCE_DEFAULT\n            );\n\n            NotificationManager manager = getSystemService(NotificationManager.class);\n            manager.createNotificationChannel(serviceChannel);\n        }\n    }\n\n    //SOCKET stuff\n    public void startSocket(){\n        //start first socketThread\n        if (socket == null) {\n            mConnectState = 1;\n            Log.d(TAG, \"starting AudioService socket\");\n            SocketThread = new Thread(new AudioService.SocketThread());\n            SocketThread.start();\n\n            //setup handler to handle keeping connection alive, all subsequent start of SocketThread\n            //start a new handler thread to send heartbeats\n            HandlerThread thread = new HandlerThread(\"HeartBeater_AudioService\");\n            thread.start();\n            Handler handler = new Handler(thread.getLooper());\n            final int delay = 3000;\n            final int min_delay = 3000;\n            final int max_delay = 4000;\n            Random rand = new Random();\n            handler.postDelayed(new Runnable() {\n                public void run() {\n                    heartBeat();\n                    //random delay for heart beat so as to disallow synchronized failure between client and server\n                    int random_delay = rand.nextInt((max_delay - min_delay) + 1) + min_delay;\n                    handler.postDelayed(this, random_delay);\n                }\n            }, delay);\n        }\n    }\n\n    //heart beat checker - check if we have received a heart rate\n    private void heartBeat(){\n        //check if we are still connected.\n        //if not , reconnect,\n        //we don't need to actively send heart beats from the client, as it's assumed that we are ALWAYS streaming data. Later, if we have periods of time where no data is sent, we will want to send a heart beat perhaps. but the client doesn't really need to, we just need to check if we are still connected\n        if (firstConnect && mConnectState == 0) { //check if firstConnect, cuz we shouldn't restart if we never connected yet in the first place\n            restartSocket();\n        }\n\n//        //or, if haven't been receiving heart beats, restart socket\n//        if (mConnectState == 2) {\n//            if ((System.currentTimeMillis() - lastHeartbeatTime) > (heartbeatInterval * heartbeatPanicX)) {\n//                Log.d(TAG, \"DIDN'T RECEIVE HEART BEATS, RESTARTING SOCKET\");\n//                mConnectState = 0;\n//                restartSocket();\n//            }\n//        }\n    }\n\n\n    public static void restartSocket() {\n        Log.d(TAG, \"Restarting socket\");\n        mConnectState = 1;\n        if (socket != null && (!socket.isClosed())) {\n            try {\n                output.close();\n                socket.close();\n            } catch (IOException e) {\n                System.out.println(\"FAILED TO CLOSE SOCKET, SOMETHING IS WRONG\");\n            }\n        }\n\n        //restart socket thread\n        Log.d(TAG, \"starting socket\");\n        SocketThread = new Thread(new AudioService.SocketThread());\n        SocketThread.start();\n    }\n\n    public byte [] encryptBytes(byte [] input){\n        byte [] encryptedBytes = AES.encrypt(input, secretKey) ;\n//        String encryptedString = AES.encrypt(originalString, secretKey) ;\n//        String decryptedString = AES.decrypt(encryptedString, secretKey) ;\n//\n//        System.out.println(originalString);\n//        System.out.println(encryptedString);\n//        System.out.println(decryptedString);\n        return encryptedBytes;\n    }\n\n\n    public byte [] decryptBytes(byte [] input) {\n        byte [] decryptedBytes = AES.decrypt(input, secretKey) ;\n        return decryptedBytes;\n    }\n\n//    public void sendBytes(byte [] data){\n//        //only try to send data if the socket is connected state\n//        if (mConnectState != 2){\n//            return;\n//        }\n//\n//        //combine those into a payload\n//        ByteArrayOutputStream outputStream;\n//        try {\n//            outputStream = new ByteArrayOutputStream();\n//            outputStream.write(data);\n//        } catch (IOException e){\n//            mConnectState = 0;\n//            return;\n//        }\n//        byte [] payload = outputStream.toByteArray();\n//\n//        //send it in a background thread\n//        try {\n//            data_queue.add(payload);\n//        } catch (IllegalStateException e) {\n//            e.printStackTrace();\n//            Log.d(TAG, \"Queue is full, skipping this one\");\n//        }\n//    }\n\n    public void sendBytes(byte [] data) {\n    }\n\n    static class SocketThread implements Runnable {\n        public void run() {\n            try {\n                System.out.println(\"TRYING TO CONNECT AudioService server at IP: \" + SERVER_IP);\n                socket = new Socket();\n                socket.setSoTimeout(5000);\n                socket.connect(new InetSocketAddress(SERVER_IP, SERVER_PORT), socketTimeout);\n                System.out.println(\"AudioService server CONNECTED!\");\n                output = new DataOutputStream(socket.getOutputStream());\n                mConnectState = 2;\n                firstConnect = true;\n                //make the thread that will send\n                if (SendThread == null) { //if the thread is null, make a new one (the first one)\n                    SendThread = new Thread(new AudioService.SendThread());\n                    SendThread.start();\n                } else if (!SendThread.isAlive()) { //if the thread is not null but it's dead, let it join then start a new one\n                    Log.d(TAG, \"IN SocketThread, WAITING FOR send THREAD JOING\");\n                    try {\n                        SendThread.join(); //make sure socket thread has joined before throwing off a new one\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                    Log.d(TAG, \"send JOINED\");\n                    SendThread = new Thread(new AudioService.SendThread());\n                    SendThread.start();\n                }\n            } catch (IOException e) {\n                Log.d(TAG, \"Connection Refused on socket or timeout occured\");\n                e.printStackTrace();\n                mConnectState = 0;\n            }\n        }\n    }\n\n    static class SendThread implements Runnable {\n        SendThread() {\n        }\n        @Override\n        public void run() {\n            if (mConnectState != 2){\n                System.out.println(\"MCONNECTED IS FALSE IN AudioService SendThread, returning\");\n                return;\n            }\n            //clear queue so we don't have a buildup of data\n            data_queue.clear();\n            while (true) {\n                if (packets_in_buf > 20) { //if 20 packets in buffer (NOT QUEUE, BUF NETWORK BUFFER), restart socket\n                    break;\n                }\n                byte[] data;\n                try {\n                    data = data_queue.take(); //block until there is something we can pull out to send\n                } catch (InterruptedException e){\n                    e.printStackTrace();\n                    break;\n                }\n                try {\n                    output.write(data);           // write the message\n                } catch (java.io.IOException e) {\n                    e.printStackTrace();\n                    break;\n                }\n            }\n            mConnectState = 0;\n        }\n    }\n\n\n    //AUDIO stuff\n//    NOTE - we are now using bluetoothMic class to get SCO mic or local mic, not using the below AudioRecorder\n    public void StartRecorder() {\n        Log.i(TAG, \"Starting the audio stream\");\n        currentlySendingAudio = true;\n        startStreaming();\n    }\n    public void StopRecorder() {\n        Log.i(TAG, \"Stopping the audio stream\");\n        currentlySendingAudio = false;\n        recorder.release();\n    }\n\n    private void receiveChunk(ByteBuffer chunk){\n        if (mConnectState == 2) {\n            byte[] audio_bytes = chunk.array();\n\n            byte[] encrypted_audio_bytes = encryptBytes(audio_bytes);\n\n            sendBytes(encrypted_audio_bytes);\n        }\n    }\n\n    private void startStreaming() {\n        Log.i(TAG, \"Starting the background thread (in this foreground service) to read the audio data\");\n\n        Thread streamThread = new Thread(() -> {\n            try {\n                Log.d(TAG, \"Creating the buffer of size \" + BUFFER_SIZE);\n                int rate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_SYSTEM);\n                int bufferSize = AudioRecord.getMinBufferSize(RECORDING_RATE, CHANNEL, FORMAT);\n                short[] buffer = new short[bufferSize];\n\n                android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO);\n                recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, RECORDING_RATE, CHANNEL, FORMAT, BUFFER_SIZE * 10);\n                //recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, rate, CHANNEL, FORMAT, bufferSize);\n\n                Log.d(TAG, \"Creating the AudioRecord\");\n\n\n                Log.d(TAG, \"AudioRecord recording...\");\n                recorder.startRecording();\n\n                while (currentlySendingAudio == true) {\n                    // read the data into the buffer\n                    int readSize = recorder.read(buffer, 0, buffer.length);\n\n                    if ((System.currentTimeMillis() - lastAudioUpdate) > audioInterval){\n                        Log.d(TAG, \"SENDING AUDIO\");\n                        lastAudioUpdate = System.currentTimeMillis();\n                    }\n\n                    //convert short array to byte array\n                    ByteBuffer b_buffer = ByteBuffer.allocate(buffer.length * 2);\n                    b_buffer.order(ByteOrder.LITTLE_ENDIAN);\n                    b_buffer.asShortBuffer().put(buffer);\n                    byte[] audio_bytes = b_buffer.array();\n\n                    byte [] encrypted_audio_bytes = encryptBytes(audio_bytes);\n                    byte [] decrypted_audio_bytes = decryptBytes(encrypted_audio_bytes);\n\n                    sendBytes(encrypted_audio_bytes);\n                }\n\n                Log.d(TAG, \"AudioRecord finished recording\");\n            } catch (Exception e) {\n                Log.e(TAG, \"Exception: \" + e);\n            }\n        });\n\n\n\n        // start the thread\n        streamThread.start();\n    }\n\n\n    public class LocalBinder extends Binder {\n        AudioService getService() {\n            // Return this instance of LocalService so clients can call public methods\n            return AudioService.this;\n        }\n    }\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        return binder;\n    }\n\n    private void activateBluetoothSco() {\n        if (!mAudioManager.isBluetoothScoAvailableOffCall()) {\n            Log.e(TAG, \"SCO is not available, recording with bluetooth is not possible\");\n            return;\n        }\n\n        if (!mAudioManager.isBluetoothScoOn()) {\n            mAudioManager.startBluetoothSco();\n        }\n    }\n}"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/archive/GlboxClientSocket.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.archive;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Environment;\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport android.util.Log;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.net.Socket;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.charset.StandardCharsets;\nimport android.util.Base64;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.Random;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingQueue;\n\nimport io.reactivex.rxjava3.disposables.Disposable;\nimport io.reactivex.rxjava3.subjects.PublishSubject;\n\n//singleton clientsocket class for connecting to ASP\npublic class GlboxClientSocket {\n    //data observable we can send data through\n    private static PublishSubject<JSONObject> dataObservable;\n    private static Disposable dataSubscriber;\n\n    //broadcast intent string\n    public final static String ACTION_RECEIVE_TEXT = \"com.example.wearableaidisplaymoverio.ACTION_RECEIVE_TEXT\";\n//    public final static String EXTRAS_MESSAGE = \"com.example.wearableaidisplaymoverio.EXTRAS_MESSAGE\";\n    public final static String FINAL_REGULAR_TRANSCRIPT = \"com.example.wearableaidisplaymoverio.FINAL_REGULAR_TRANSCRIPT\";\n    public final static String INTERMEDIATE_REGULAR_TRANSCRIPT = \"com.example.wearableaidisplaymoverio.INTERMEDIATE_REGULAR_TRANSCRIPT\";\n    public final static String COMMAND_RESPONSE = \"com.example.wearableaidisplaymoverio.COMMAND_RESPONSE\";\n    public final static String WIKIPEDIA_RESULT = \"com.example.wearableaidisplaymoverio.WIKIPEDIA_RESULT\";\n    public final static String ACTION_WIKIPEDIA_RESULT = \"com.example.wearableaidisplaymoverio.ACTION_WIKIPEDIA_RESULT\";\n    public final static String TRANSLATION_RESULT = \"com.example.wearableaidisplaymoverio.TRANSLATION_RESULT\";\n    public final static String VISUAL_SEARCH_RESULT = \"com.example.wearableaidisplaymoverio.VISUAL_SEARCH_RESULT\";\n    public final static String AFFECTIVE_SUMMARY_RESULT = \"com.example.wearableaidisplaymoverio.AFFECTIVE_SUMMARY_RESULT\";\n    public final static String ACTION_TRANSLATION_RESULT = \"com.example.wearableaidisplaymoverio.ACTION_TRANSLATION_RESULT\";\n    public final static String ACTION_VISUAL_SEARCH_RESULT = \"com.example.wearableaidisplaymoverio.ACTION_VISUAL_SEARCH_RESULT\";\n    public final static String ACTION_AFFECTIVE_SUMMARY_RESULT = \"com.example.wearableaidisplaymoverio.ACTION_AFFECTIVE_SUMMARY_RESULT\";\n\n    public final static String COMMAND_SWITCH_MODE = \"com.example.wearableaidisplaymoverio.COMMAND_SWITCH_MODE\";\n    public final static String COMMAND_ARG = \"com.example.wearableaidisplaymoverio.COMMAND_ARG\";\n    //public final static String COMMAND_RESPONSE_TEXT = \"com.example.wearableaidisplaymoverio.COMMAND_RESPONSE_TEXT\";\n//    public final static String EYE_CONTACT_30_MESSAGE = \"com.example.wearableaidisplaymoverio.EYE_CONTACT_30\";\n//    public final static String EYE_CONTACT_300_MESSAGE = \"com.example.wearableaidisplaymoverio.EYE_CONTACT_300\";\n//    public final static String FACIAL_EMOTION_5_MESSAGE = \"com.example.wearableaidisplaymoverio.FACIAL_EMOTION_5\";\n//    public final static String FACIAL_EMOTION_30_MESSAGE = \"com.example.wearableaidisplaymoverio.FACIAL_EMOTION_30\";\n//    public final static String FACIAL_EMOTION_300_MESSAGE = \"com.example.wearableaidisplaymoverio.FACIAL_EMOTION_300\";\n\n    public static String TAG = \"WearableAiDisplayMoverio\";\n    //singleton instance\n    private static GlboxClientSocket clientsocket;\n    //socket data\n    static Thread SocketThread = null;\n    static Thread ReceiveThread = null;\n    static Thread SendThread = null;\n    static private DataOutputStream output;\n    //ids of message types\n    //socket message ids\n    //metrics\n    static final byte [] intermediate_transcript_cid = {0xC, 0x01};\n    static final byte [] final_transcript_cid = {0xC, 0x02};\n    static final byte [] switch_mode_cid = {0xC, 0x03};\n    static final byte [] command_response_cid = {0xC, 0x04};\n    static final byte [] wikipedia_result_cid = {0xC, 0x05};\n    static final byte [] translation_result_cid = {0xC, 0x06};\n    static final byte [] visual_search_images_result_cid = {0xC, 0x07};\n    static final byte [] affective_summary_result_cid = {0xC, 0x08};\n\n    static final byte [] social_mode_id = {0xF, 0x00};\n    static final byte [] llc_mode_id = {0xF, 0x01};\n    static final byte [] blank_mode_id = {0xF, 0x02};\n    static final byte [] translate_mode_id = {0xF, 0x03};\n    static final byte [] visual_search_mode_viewfind_id = {0xF, 0x04};\n\n    static final byte [] affective_conversation_message = {0xD, 0x01};\n//    static final byte [] eye_contact_info_id_30 = {0x12, 0x02};\n//    static final byte [] eye_contact_info_id_300 = {0x12, 0x03};\n//    static final byte [] facial_emotion_info_id_5 = {0x13, 0x01};\n//    static final byte [] facial_emotion_info_id_30 = {0x13, 0x02};\n//    static final byte [] facial_emotion_info_id_300 = {0x13, 0x03};\n//\n//    static final byte [] img_id = {0x01, 0x10}; //id for images\n    static final byte [] heart_beat_id = {0x19, 0x20}; //id for heart beat\n//    static final byte [] ack_id = {0x13, 0x37};\n\n    //static private BufferedReader input;\n    static private DataInputStream input;\n    static String SERVER_IP = \"0.0.0.0\"; //gets updated\n    static int SERVER_PORT = 8989;\n    private static int mConnectState = 0;\n\n    //handle heart beat stuff\n    private static long lastHeartbeatTime;\n    private static int heartbeatInterval = 3000; //milliseconds\n    private static int heartbeatPanicX = 3; // number of intervals before we reset connection\n    static Thread HeartbeatThread = null;\n\n    private static boolean gotAck = false;\n\n    //our actual socket connection object\n    private static Socket socket;\n\n    //remember how many packets we have in our buffer\n    private static int packets_in_buf = 0;\n\n    //queue of data to send through the socket\n    private static BlockingQueue<byte []> data_queue;\n    private static BlockingQueue<String> type_queue;\n    private static int queue_size = 50;\n    private static int image_buf_size = 0;\n\n    //we need a reference to the context of whatever called this class so we can send broadcast updates on receving new info\n    private static Context mContext;\n\n    private GlboxClientSocket(Context context){\n        //create send queue and a thread to handle sending\n        data_queue = new ArrayBlockingQueue<byte[]>(queue_size);\n        type_queue = new ArrayBlockingQueue<String>(queue_size);\n\n        //service context set\n        mContext = context;\n    }\n\n    public static GlboxClientSocket getInstance(Context c){\n        if (clientsocket == null){\n            clientsocket = new GlboxClientSocket(c);\n        }\n        return clientsocket;\n    }\n\n    public static void setIp(String ip){\n        SERVER_IP = ip;\n    }\n\n    public static GlboxClientSocket getInstance(){\n        if (clientsocket == null){\n            return null;\n        }\n        return clientsocket;\n    }\n\n    public void startSocket(){\n        //start first socketThread\n        if (socket == null) {\n            mConnectState = 1;\n            Log.d(TAG, \"onCreate starting\");\n            Log.d(TAG, \"starting socket\");\n            SocketThread = new Thread(new SocketThread());\n            SocketThread.start();\n\n            //setup handler to handle keeping connection alive, all subsequent start of SocketThread\n            //start a new handler thread to send heartbeats\n            HandlerThread thread = new HandlerThread(\"HeartBeater\");\n            thread.start();\n            Handler handler = new Handler(thread.getLooper());\n            final int delay = 3000;\n            final int min_delay = 3000;\n            final int max_delay = 4000;\n            Random rand = new Random();\n            handler.postDelayed(new Runnable() {\n                public void run() {\n                    heartBeat();\n                    //random delay for heart beat so as to disallow synchronized failure between client and server\n                    int random_delay = rand.nextInt((max_delay - min_delay) + 1) + min_delay;\n                    handler.postDelayed(this, random_delay);\n                }\n            }, delay);\n        }\n    }\n\n    //heart beat checker - check if we have received a heart rate\n    private void heartBeat(){\n        //check if we are still connected.\n        //if not , reconnect,\n        //we don't need to actively send heart beats from the client, as it's assumed that we are ALWAYS streaming data. Later, if we have periods of time where no data is sent, we will want to send a heart beat perhaps. but the client doesn't really need to, we just need to check if we are still connected\n        if (mConnectState == 0) {\n            restartSocket();\n        }\n\n        //or, if haven't been receiving heart beats, restart socket\n        if (mConnectState == 2) {\n            if ((System.currentTimeMillis() - lastHeartbeatTime) > (heartbeatInterval * heartbeatPanicX)) {\n                Log.d(TAG, \"DIDN'T RECEIVE HEART BEATS, RESTARTING SOCKET\");\n                mConnectState = 0;\n                restartSocket();\n            }\n        }\n    }\n\n    public static void restartSocket() {\n        Log.d(TAG, \"Restarting socket\");\n        mConnectState = 1;\n        if (socket != null && (!socket.isClosed())){\n            try {\n                output.close();\n                input.close();\n                socket.close();\n            } catch (IOException e) {\n                System.out.println(\"FAILED TO CLOSE SOCKET, SOMETHING IS WRONG\");\n            }\n        }\n\n\n//        //kill threads\n//        stopThread(SendThread);\n//        stopThread(ReceiveThread);\n\n        //restart socket thread\n        Log.d(TAG, \"starting socket\");\n        SocketThread = new Thread(new SocketThread());\n        SocketThread.start();\n    }\n\n    public static void stopThread(Thread thread){\n        if(thread!=null){\n            thread.interrupt();\n            thread = null;\n        }\n    }\n\n    public static  byte[] my_int_to_bb_be(int myInteger){\n        return ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(myInteger).array();\n    }\n\n//    public void sendBytes(byte[] id, byte [] data, String type){\n//        //handle different types differently\n//        if (type == \"image\"){\n//            image_buf_size++;\n//        }\n//        //first, send hello\n//        byte [] hello = {0x01, 0x02, 0x03};\n//        //then send length of body\n//        byte[] len;\n//        if (data != null) {\n//            len = my_int_to_bb_be(data.length);\n//        } else {\n//            len = my_int_to_bb_be(0);\n//        }\n//        //then send id of message type\n//        byte [] msg_id = id;\n//        //then send data\n//        byte [] body = data;\n//        //then send end tag - eventually make this unique to the image\n//        byte [] goodbye = {0x3, 0x2, 0x1};\n//        //combine those into a payload\n//        ByteArrayOutputStream outputStream;\n//        try {\n//            outputStream = new ByteArrayOutputStream();\n//            outputStream.write(hello);\n//            outputStream.write(len);\n//            outputStream.write(msg_id);\n//            if (body != null) {\n//                outputStream.write(body);\n//            }\n//            outputStream.write(goodbye);\n//        } catch (IOException e){\n//            mConnectState = 0;\n//            return;\n//        }\n//        byte [] payload = outputStream.toByteArray();\n//\n//        //send it in a background thread\n//        //new Thread(new SendThread(payload)).start();\n//        boolean try_send;\n//        if (type == \"image\"){\n//            if (data_queue.size() < (queue_size / 2)){ //if our queue is over half full, don't keep adding images to queue\n//                try_send = true;\n//            } else {\n//                try_send = false;\n//            }\n//        } else { //if not an image, try to send anyway\n//            try_send = true;\n//        }\n//\n//        //add the data to the send queue\n//        if (try_send) {\n//            try {\n//                data_queue.add(payload);\n//                type_queue.add(type);\n//            } catch (IllegalStateException e) {\n//                Log.d(TAG, \"Queue is full, skipping this one\");\n//            }\n//        }\n//    }\n    public void sendBytes(byte[] id, byte [] data, String type){\n        //only try to send data if the socket is connected state\n        if (mConnectState != 2){\n            System.out.println(\"MCONNECTED IS FALSE IN sendBytes, returning\");\n            return;\n        }\n\n        //handle different types differently\n        if (type == \"image\"){\n            image_buf_size++;\n        }\n        //first, send hello\n        byte [] hello = {0x01, 0x02, 0x03};\n        //then send length of body\n        byte[] len;\n        if (data != null) {\n            len = my_int_to_bb_be(data.length);\n        } else {\n            len = my_int_to_bb_be(0);\n        }\n        //then send id of message type\n        byte [] msg_id = id;\n        //then send data\n        byte [] body = data;\n        //then send end tag - eventually make this unique to the image\n        byte [] goodbye = {0x3, 0x2, 0x1};\n        //combine those into a payload\n        ByteArrayOutputStream outputStream;\n        try {\n            outputStream = new ByteArrayOutputStream();\n            outputStream.write(hello);\n            outputStream.write(len);\n            outputStream.write(msg_id);\n            if (body != null) {\n                outputStream.write(body);\n            }\n            outputStream.write(goodbye);\n        } catch (IOException e){\n            mConnectState = 0;\n            return;\n        }\n        byte [] payload = outputStream.toByteArray();\n\n        //send it in a background thread\n        //new Thread(new SendThread(payload)).start();\n        boolean try_send;\n        if (type == \"image\"){\n            if (data_queue.size() < (queue_size / 2)){ //if our queue is over half full, don't keep adding images to queue\n                try_send = true;\n            } else {\n                try_send = false;\n            }\n        } else { //if not an image, try to send anyway\n            try_send = true;\n        }\n\n        //add the data to the send queue\n        if (try_send) {\n            try {\n                data_queue.add(payload);\n                type_queue.add(type);\n            } catch (IllegalStateException e) {\n                Log.d(TAG, \"Queue is full, skipping this one\");\n            }\n        }\n    }\n\n\n    //returns how many images are in the buffer\n    public int getImageBuf(){\n        return image_buf_size;\n    }\n\n    public int getConnected(){\n        return mConnectState;\n    }\n\n    static class SocketThread implements Runnable {\n        public void run() {\n            try {\n                System.out.println(\"TRYING TO CONNECT GLBOX\");\n                socket = new Socket(SERVER_IP, SERVER_PORT);\n                lastHeartbeatTime = System.currentTimeMillis();\n                System.out.println(\"GLBOX CONNECTED!\");\n                output = new DataOutputStream(socket.getOutputStream());\n                //input = new BufferedReader(new InputStreamReader(socket.getInputStream()));\n                input = new DataInputStream(new DataInputStream(socket.getInputStream()));\n                mConnectState = 2;\n                //make the threads that will send and receive\n                if (ReceiveThread == null) { //if the thread is null, make a new one (the first one)\n                    ReceiveThread = new Thread(new ReceiveThread());\n                    ReceiveThread.start();\n                } else if (!ReceiveThread.isAlive()) { //if the thread is not null but it's dead, let it join then start a new one\n                    Log.d(TAG, \"IN SocketThread, WAITING FOR receive THREAD JOING\");\n                    try {\n                        ReceiveThread.join(); //make sure socket thread has joined before throwing off a new one\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                    Log.d(TAG, \"receive JOINED\");\n                    ReceiveThread = new Thread(new ReceiveThread());\n                    ReceiveThread.start();\n                }\n                if (SendThread == null) { //if the thread is null, make a new one (the first one)\n                    SendThread = new Thread(new SendThread());\n                    SendThread.start();\n                } else if (!SendThread.isAlive()) { //if the thread is not null but it's dead, let it join then start a new one\n                    Log.d(TAG, \"IN SocketThread, WAITING FOR send THREAD JOING\");\n                    try {\n                        SendThread.join(); //make sure socket thread has joined before throwing off a new one\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                    Log.d(TAG, \"send JOINED\");\n                    SendThread =  new Thread(new SendThread());\n                    SendThread.start();\n                }\n            } catch (IOException e) {\n                Log.d(TAG, \"Connection Refused on socket\");\n                e.printStackTrace();\n                mConnectState = 0;\n            }\n        }\n    }\n\n    public static int my_bb_to_int_be(byte [] byteBarray){\n        return ByteBuffer.wrap(byteBarray).order(ByteOrder.BIG_ENDIAN).getInt();\n    }\n\n    static class ReceiveThread implements Runnable {\n        @Override\n        public void run() {\n            Log.d(TAG, \"GLBOX starting ReceiveThread\");\n            while (true) {\n                if (mConnectState != 2){\n                    System.out.println(\"MCONNECTED IS FALSE IN REEIVE THREAD, BREAKING\");\n                    break;\n                }\n\n//                try {\n//                    System.out.println(\"GLBOX PRETRANSCRIPT:\");\n\n//                    String transcript = readLine(input);\n//                    System.out.println(\"GLBOX TRANSCRIPT:\");\n//                    System.out.println(transcript);\n//                    final Intent intent = new Intent();\n//                    intent.putExtra(GlboxClientSocket.REGULAR_TRANSCRIPT, transcript);\n//                    intent.setAction(GlboxClientSocket.ACTION_RECEIVE_TEXT);\n//                    mContext.sendBroadcast(intent); //eventually, we won't need to use the activity context, as our service will have its own context to send from\n\n//                    Byte transcript = input.readByte();\n//                    System.out.println(\"GLBOX TRANSCRIPT:\");\n//                    System.out.println(Byte.toString(transcript));\n//                } catch (IOException e) {\n//                    System.out.println(\"IOException getting transcript string.\");\n//                    mConnectState = 0;\n//                    break;\n//                }\n\n                byte b1, b2;\n                byte [] raw_data = null;\n                byte goodbye1, goodbye2, goodbye3;\n                //just read in data here\n                try {\n                    byte hello1 = input.readByte(); // read hello of incoming message\n                    byte hello2 = input.readByte(); // read hello of incoming message\n                    byte hello3 = input.readByte(); // read hello of incoming message\n\n                    //make sure header is verified\n                    if (hello1 != 0x01 || hello2 != 0x02 || hello3 != 0x03){\n                        Log.d(TAG, \"Socket hello header broken, restarting socket\");\n                        break;\n                    } else {\n                    }\n                    //length of body\n                    int body_len = input.readInt();\n\n                    //read in message id bytes\n                    b1 = input.readByte();\n                    b2 = input.readByte();\n\n                    //read in message body (if there is one)\n                    if (body_len > 0){\n                        raw_data = new byte[body_len];\n                        input.readFully(raw_data, 0, body_len); // read the body\n                    }\n\n                    goodbye1 = input.readByte(); // read goodbye of incoming message\n                    goodbye2 = input.readByte(); // read goodbye of incoming message\n                    goodbye3 = input.readByte(); // read goodbye of incoming message\n                } catch (IOException e) {\n                    e.printStackTrace();\n                    mConnectState = 0;\n                    break;\n                }\n\n                //make sure footer is verified\n                if (goodbye1 != 0x03 || goodbye2 != 0x02 || goodbye3 != 0x01) {\n                    Log.d(TAG, \"Socket stream - footer broken, restarting socket\");\n                    break;\n                }\n\n                //then process the data\n                //if ((b1 == ack_id[0]) && (b2 == ack_id[1])) { //got ack response\n                if ((b1 == final_transcript_cid[0]) && (b2 == final_transcript_cid[1])) { //got ack response\n                    Log.d(TAG, \"final_transcript_cid received\");\n                    String final_transcript_json_string = new String(raw_data, StandardCharsets.UTF_8);\n                    JSONObject transcript_object;\n                    try {\n                        transcript_object = new JSONObject(final_transcript_json_string);\n                        final Intent intent = new Intent();\n                        intent.putExtra(GlboxClientSocket.FINAL_REGULAR_TRANSCRIPT, transcript_object.toString());\n                        intent.setAction(GlboxClientSocket.ACTION_RECEIVE_TEXT);\n                        dataObservable.onNext(transcript_object);\n                        mContext.sendBroadcast(intent); //eventually, we won't need to use the activity context, as our service will have its own context to send from\n                        Log.d(TAG, \"F. Transcript is: \" + transcript_object.toString());\n                    } catch (JSONException e) {\n                    }\n                } else if ((b1 == heart_beat_id[0]) && (b2 == heart_beat_id[1])) { //heart beat check if alive\n                    //got heart beat, respond with heart beat\n                    //clientsocket.sendBytes(heart_beat_id, null, \"heartbeat\");\n                    lastHeartbeatTime = System.currentTimeMillis();\n                } else if ((b1 == intermediate_transcript_cid[0]) && (b2 == intermediate_transcript_cid[1])) { //got ack response\n                    Log.d(TAG, \"intermediate_transcript_cid received\");\n                    String intermediate_transcript = new String(raw_data, StandardCharsets.UTF_8);\n                    final Intent intent = new Intent();\n                    intent.putExtra(GlboxClientSocket.INTERMEDIATE_REGULAR_TRANSCRIPT, intermediate_transcript);\n                    intent.setAction(GlboxClientSocket.ACTION_RECEIVE_TEXT);\n                    mContext.sendBroadcast(intent); //eventually, we won't need to use the activity context, as our service will have its own context to send from\n                    Log.d(TAG, \"I. Transcript is: \" + intermediate_transcript);\n                } else if ((b1 == switch_mode_cid[0]) && (b2 == switch_mode_cid[1])) { //got ack response\n                    Log.d(TAG, \"switch mode found\");\n                    Log.d(TAG, raw_data.toString());\n                    //the follow if block should be made WAY simpler ... just a dictionary or something\n                    if ((raw_data[0] == social_mode_id[0]) && (raw_data[1] == social_mode_id[1])) { //got ack response\n                        Log.d(TAG, \"SWITCHING TO SOCIAL MODE\");\n                        final Intent intent = new Intent();\n                        intent.setAction(GlboxClientSocket.COMMAND_SWITCH_MODE);\n                        intent.putExtra(GlboxClientSocket.COMMAND_ARG, \"social\");\n                        mContext.sendBroadcast(intent); //eventually, we won't need to use the activity context, as our service will have its own context to send from\n                    } else if ((raw_data[0] == llc_mode_id[0]) && (raw_data[1] == llc_mode_id[1])) { //got ack response\n                        Log.d(TAG, \"SWITCHING TO LLC MODE\");\n                        final Intent intent = new Intent();\n                        intent.setAction(GlboxClientSocket.COMMAND_SWITCH_MODE);\n                        intent.putExtra(GlboxClientSocket.COMMAND_ARG, \"llc\");\n                        mContext.sendBroadcast(intent); //eventually, we won't need to use the activity context, as our service will have its own context to send from\n                    } else if ((raw_data[0] == blank_mode_id[0]) && (raw_data[1] == blank_mode_id[1])) { //got ack response\n                        Log.d(TAG, \"BLANK TOGGLE\");\n                        final Intent intent = new Intent();\n                        intent.setAction(GlboxClientSocket.COMMAND_SWITCH_MODE);\n                        intent.putExtra(GlboxClientSocket.COMMAND_ARG, \"blank\");\n                        mContext.sendBroadcast(intent); //eventually, we won't need to use the activity context, as our service will have its own context to send from\n                    } else if ((raw_data[0] == translate_mode_id[0]) && (raw_data[1] == translate_mode_id[1])) { //got ack response\n                        Log.d(TAG, \"TRANSLATE MODE TOGGLE\");\n                        final Intent intent = new Intent();\n                        intent.setAction(GlboxClientSocket.COMMAND_SWITCH_MODE);\n                        intent.putExtra(GlboxClientSocket.COMMAND_ARG, \"translate\");\n                        mContext.sendBroadcast(intent); //eventually, we won't need to use the activity context, as our service will have its own context to send from\n                    } else if ((raw_data[0] == visual_search_mode_viewfind_id[0]) && (raw_data[1] == visual_search_mode_viewfind_id[1])) { //got ack response\n                        Log.d(TAG, \"VISUAL SEARCH MODE VIEWFIND TOGGLE\");\n                        final Intent intent = new Intent();\n                        intent.setAction(GlboxClientSocket.COMMAND_SWITCH_MODE);\n                        intent.putExtra(GlboxClientSocket.COMMAND_ARG, \"visualsearchviewfind\");\n                        mContext.sendBroadcast(intent); //eventually, we won't need to use the activity context, as our service will have its own context to send from\n                    }\n                } else if ((b1 == command_response_cid[0]) && (b2 == command_response_cid[1])) { //got command response\n                    Log.d(TAG, \"command_response_cid received\");\n                    String response_string = new String(raw_data, StandardCharsets.UTF_8);\n                    final Intent intent = new Intent();\n                    intent.putExtra(GlboxClientSocket.COMMAND_RESPONSE, response_string);\n                    intent.setAction(GlboxClientSocket.ACTION_RECEIVE_TEXT);\n                    mContext.sendBroadcast(intent); //eventually, we won't need to use the activity context, as our service will have its own context to send from\n                } else if ((b1 == wikipedia_result_cid [0]) && (b2 == wikipedia_result_cid [1])) { //got command response\n                    Log.d(TAG, \"wikipedia_result_cid received\");\n                    String wikipedia_result_json_string = new String(raw_data, StandardCharsets.UTF_8);\n                    JSONObject wikipedia_result_json;\n                    try {\n                        wikipedia_result_json = new JSONObject(wikipedia_result_json_string);\n                        //we have to pull out the image, decode it, save locally, and then send the location of that saved file, because an image is too big to communicate over IPC (Android Intent)\n                        String img_string = wikipedia_result_json.getString(\"image\");\n                        byte[] img_b64_bytes = img_string.getBytes(\"UTF-8\");\n                        byte[] img_bytes = Base64.decode(img_b64_bytes, Base64.DEFAULT);\n                        img_b64_bytes = null;\n                        File img_file = savePicture(img_bytes);\n                        String img_path = img_file.getAbsolutePath();\n                        wikipedia_result_json.remove(\"image\");\n                        wikipedia_result_json.put(\"image_path\", img_path);\n                        img_bytes = null;\n                        System.gc();\n\n                        final Intent intent = new Intent();\n                        intent.putExtra(GlboxClientSocket.WIKIPEDIA_RESULT, wikipedia_result_json.toString());\n                        intent.setAction(GlboxClientSocket.ACTION_WIKIPEDIA_RESULT);\n                        mContext.sendBroadcast(intent);\n                    } catch( JSONException e){\n                        Log.d(TAG, e.toString());\n                    } catch (UnsupportedEncodingException e){\n                        Log.d(TAG, e.toString());\n                    }\n                } else if ((b1 == translation_result_cid[0]) && (b2 == translation_result_cid[1])) { //got command response\n                    Log.d(TAG, \"translation_result_cid received\");\n                    String translated_text_string = new String(raw_data, StandardCharsets.UTF_8);\n                    final Intent intent = new Intent();\n                    intent.putExtra(GlboxClientSocket.TRANSLATION_RESULT, translated_text_string);\n                    intent.setAction(GlboxClientSocket.ACTION_TRANSLATION_RESULT);\n                    mContext.sendBroadcast(intent);\n                } else if ((b1 == visual_search_images_result_cid[0]) && (b2 == visual_search_images_result_cid[1])) { //got command response\n                    Log.d(TAG, \"visual_search_images_result_cid received\");\n                    String str_data = new String(raw_data, StandardCharsets.UTF_8);\n                    final Intent intent = new Intent();\n                    intent.putExtra(GlboxClientSocket.VISUAL_SEARCH_RESULT, str_data);\n                    intent.setAction(GlboxClientSocket.ACTION_VISUAL_SEARCH_RESULT);\n                    mContext.sendBroadcast(intent);\n\n//                    String translated_text_string = new String(raw_data, StandardCharsets.UTF_8);\n//                    final Intent intent = new Intent();\n//                    intent.putExtra(GlboxClientSocket.TRANSLATION_RESULT, translated_text_string);\n//                    intent.setAction(GlboxClientSocket.ACTION_TRANSLATION_RESULT);\n//                    mContext.sendBroadcast(intent);\n                } else if ((b1 == affective_summary_result_cid[0]) && (b2 == affective_summary_result_cid[1])) { //got command response\n                    Log.d(TAG, \"affective_summary_result_cid received\");\n                    String str_data = new String(raw_data, StandardCharsets.UTF_8);\n                    final Intent intent = new Intent();\n                    intent.putExtra(GlboxClientSocket.AFFECTIVE_SUMMARY_RESULT, str_data);\n                    intent.setAction(GlboxClientSocket.ACTION_AFFECTIVE_SUMMARY_RESULT);\n                    mContext.sendBroadcast(intent);\n                }\n\n//                } else if ((b1 == heart_beat_id[0]) && (b2 == heart_beat_id[1])) { //heart beat check if alive\n//                    //got heart beat, respond with heart beat\n//                    clientsocket.sendBytes(heart_beat_id, null, \"heartbeat\");\n//                } else if ((b1 == eye_contact_info_id_5[0]) && (b2 == eye_contact_info_id_5[1])) { //we got a message with information to display\n//                    Log.d(TAG, \"eye contact info 5\");\n//                    String message = Integer.toString(my_bb_to_int_be(raw_data));\n//                    final Intent intent = new Intent();\n//                    intent.putExtra(GlboxClientSocket.EYE_CONTACT_5_MESSAGE, message);\n//                    intent.setAction(GlboxClientSocket.ACTION_RECEIVE_MESSAGE);\n//                    mContext.sendBroadcast(intent); //eventually, we won't need to use the activity context, as our service will have its own context to send from\n//                } else if ((b1 == eye_contact_info_id_30[0]) && (b2 == eye_contact_info_id_30[1])) { //we got a message with information to display\n//                    String message = Integer.toString(my_bb_to_int_be(raw_data));\n//                    final Intent intent = new Intent();\n//                    intent.putExtra(GlboxClientSocket.EYE_CONTACT_30_MESSAGE, message);\n//                    intent.setAction(GlboxClientSocket.ACTION_RECEIVE_MESSAGE);\n//                    mContext.sendBroadcast(intent); //eventually, we won't need to use the activity context, as our service will have its own context to send from\n//                } else if ((b1 == eye_contact_info_id_300[0]) && (b2 == eye_contact_info_id_300[1])) { //we got a message with information to display\n//                    String message = Integer.toString(my_bb_to_int_be(raw_data));\n//                    final Intent intent = new Intent();\n//                    intent.putExtra(GlboxClientSocket.EYE_CONTACT_300_MESSAGE, message);\n//                    intent.setAction(GlboxClientSocket.ACTION_RECEIVE_MESSAGE);\n//                    mContext.sendBroadcast(intent); //eventually, we won't need to use the activity context, as our service will have its own context to send from\n//                } else if ((b1 == facial_emotion_info_id_5[0]) && (b2 == facial_emotion_info_id_5[1])) {\n//                    String message = new String(raw_data);\n//                    final Intent intent = new Intent();\n//                    intent.putExtra(GlboxClientSocket.FACIAL_EMOTION_5_MESSAGE, message);\n//                    intent.setAction(GlboxClientSocket.ACTION_RECEIVE_MESSAGE);\n//                    mContext.sendBroadcast(intent); //eventually, we won't need to use the activity context, as our service will have its own context to send from\n//                }  else if ((b1 == facial_emotion_info_id_30[0]) && (b2 == facial_emotion_info_id_30[1])) {\n//                    String message = new String(raw_data);\n//                    final Intent intent = new Intent();\n//                    intent.putExtra(GlboxClientSocket.FACIAL_EMOTION_30_MESSAGE, message);\n//                    intent.setAction(GlboxClientSocket.ACTION_RECEIVE_MESSAGE);\n//                    mContext.sendBroadcast(intent); //eventually, we won't need to use the activity context, as our service will have its own context to send from\n//                }  else if ((b1 == facial_emotion_info_id_300[0]) && (b2 == facial_emotion_info_id_300[1])) {\n//                    String message = new String(raw_data);\n//                    final Intent intent = new Intent();\n//                    intent.putExtra(GlboxClientSocket.FACIAL_EMOTION_300_MESSAGE, message);\n//                    intent.setAction(GlboxClientSocket.ACTION_RECEIVE_MESSAGE);\n//                    mContext.sendBroadcast(intent); //eventually, we won't need to use the activity context, as our service will have its own context to send from\n//                } else {\n//                    System.out.println(\"BAD SIGNAL, RECONNECT\");\n//                    mConnectState = 0;\n//                    break;\n//                }\n            }\n            mConnectState = 0;\n        }\n    }\n\n    private static File getDir() {\n        File sdDir = Environment\n                .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);\n        return new File(sdDir, \"WearableAI_Cache\");\n    }\n\n    private static File savePicture(byte[] data){\n//        byte[] data = Base64.encodeToString(ata, Base64.DEFAULT).getBytes();\n        File pictureFileDir = getDir();\n\n        if (!pictureFileDir.exists() && !pictureFileDir.mkdirs()) {\n\n            Log.d(\"PHOTO_HANDLER\", \"Can't create directory to save image.\");\n            return null;\n\n        }\n\n        SimpleDateFormat dateFormat = new SimpleDateFormat(\"yyyymmddhhmmss\");\n        String date = dateFormat.format(new Date());\n        String photoFile = \"Picture_\" + date + \".jpg\";\n\n        String filename = pictureFileDir.getPath() + File.separator + photoFile;\n\n        File pictureFile = new File(filename);\n\n        try {\n            FileOutputStream fos = new FileOutputStream(pictureFile);\n            fos.write(data);\n            fos.close();\n            Log.d(TAG, \"File saved: \" + filename);\n        } catch (Exception error) {\n            Log.d(TAG, \"File\" + filename + \"not saved: \"\n                    + error.getMessage());\n        }\n        return pictureFile;\n    }\n\n    static class SendThread implements Runnable {\n        SendThread() {\n        }\n        @Override\n        public void run() {\n            if (mConnectState != 2){\n                System.out.println(\"MCONNECTED IS FALSE IN SendThread, returning\");\n                return;\n            }\n            //clear queue so we don't have a buildup of images\n            data_queue.clear();\n            type_queue.clear();\n            while (true) {\n                if (packets_in_buf > 5) { //if 5 packets in buffer (NOT QUEUE, BUF NETWORK BUFFER), restart socket\n                    break;\n                }\n                byte[] data;\n                String type;\n                try {\n                    data = data_queue.take(); //block until there is something we can pull out to send\n                    type = type_queue.take();\n                } catch (InterruptedException e){\n                    e.printStackTrace();\n                    break;\n                }\n                try {\n                    output.write(data);           // write the message\n                } catch (java.io.IOException e) {\n                    e.printStackTrace();\n                    break;\n                }\n\n                //handle different types of sends differently\n                if (type == \"image\"){\n                    image_buf_size--;\n                }\n            }\n            mConnectState = 0;\n        }\n    }\n\n    /** Reads UTF-8 character data; lines are terminated with '\\n' */\n    public static String readLine(DataInputStream in) throws IOException {\n        ByteArrayOutputStream buffer = new ByteArrayOutputStream();\n        while (true) {\n            int b = in.readByte();\n            if (b < 0) {\n                throw new IOException(\"Data truncated\");\n            }\n            if (b == 0x0A) {\n                break;\n            }\n            buffer.write(b);\n        }\n        return new String(buffer.toByteArray(), \"UTF-8\");\n    }\n\n\n    public void setObservable(PublishSubject<JSONObject> observable){\n        dataObservable = observable;\n        dataSubscriber = dataObservable.subscribe(i -> parseData(i));\n    }\n\n    private void parseData(JSONObject data){\n        Log.d(TAG, \"Parsing data\");\n        try {\n            String typeOf = data.getString(\"type\");\n            if (typeOf.equals(\"affective_conversation\")) {\n                Log.d(TAG, data.toString());\n                sendBytes(affective_conversation_message, data.toString().getBytes(), \"message\");\n            }\n        } catch (JSONException e){\n            e.printStackTrace();\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/archive/SendImage.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.archive;\n\nimport android.os.AsyncTask;\nimport android.util.Base64;\n\nimport com.wearableintelligencesystem.androidsmartglasses.ASPClientSocket;\n\nimport org.apache.http.HttpResponse;\nimport org.apache.http.NameValuePair;\nimport org.apache.http.client.ClientProtocolException;\nimport org.apache.http.client.HttpClient;\nimport org.apache.http.client.entity.UrlEncodedFormEntity;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.impl.client.DefaultHttpClient;\nimport org.apache.http.message.BasicNameValuePair;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\n//deprecated, we use sockets instead of http to send stuff... this may be useful in future to send image to backend from moverio\nclass SendImage extends AsyncTask<byte [], Void, Void> {\n\n    private final String urlServer = \"http://192.168.1.165:45678\";\n    ASPClientSocket clientsocket;\n\n    @Override\n    protected Void doInBackground(byte []... data){\n        //grab reference to the open socket connection\n        uploadImage(data[0]);\n        return null;\n    }\n\n    private void uploadImage(byte[] data) {\n        System.out.println(\"DATA IN uploadImage start IS : \" + data[0] + data[1]);\n        System.out.println(\"DATA IN uploadImage end IS : \" + data[data.length - 2] + data[data.length - 1]);\n        //convert image to string to send in post json\n        String encodedImage = Base64.encodeToString(data, Base64.DEFAULT);\n\n        //get current time that the image is sent\n        Date utcDate=new Date(); utcDate.setTime(System.currentTimeMillis()); long currentTime = utcDate.getTime();\n\n\n        // Create a new HttpClient and Post Header\n        HttpClient httpclient = new DefaultHttpClient();\n        HttpPost httppost = new HttpPost(urlServer);\n\n        try {\n            // Add your data\n            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);\n            nameValuePairs.add(new BasicNameValuePair(\"timestamp\", Long.toString(currentTime)));\n            nameValuePairs.add(new BasicNameValuePair(\"image\", encodedImage));\n            httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));\n\n            // Execute HTTP Post Request\n            HttpResponse response = httpclient.execute(httppost);\n\n        } catch (ClientProtocolException e) {\n            // TODO Auto-generated catch block\n        } catch (IOException e) {\n            // TODO Auto-generated catch block\n        }\n\n    }\n\n}\n\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/comms/AsgWebSocketClient.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.comms;\n\n/*\n * Copyright (c) 2010-2020 Nathan Rajlich\n *\n *  Permission is hereby granted, free of charge, to any person\n *  obtaining a copy of this software and associated documentation\n *  files (the \"Software\"), to deal in the Software without\n *  restriction, including without limitation the rights to use,\n *  copy, modify, merge, publish, distribute, sublicense, and/or sell\n *  copies of the Software, and to permit persons to whom the\n *  Software is furnished to do so, subject to the following\n *  conditions:\n *\n *  The above copyright notice and this permission notice shall be\n *  included in all copies or substantial portions of the Software.\n *\n *  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n *  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n *  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n *  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n *  OTHER DEALINGS IN THE SOFTWARE.\n */\n\nimport android.util.Log;\n\nimport java.net.URI;\nimport java.nio.ByteBuffer;\nimport java.util.Map;\nimport org.java_websocket.client.WebSocketClient;\n\nimport org.java_websocket.drafts.Draft;\nimport org.java_websocket.handshake.ServerHandshake;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport io.reactivex.rxjava3.disposables.Disposable;\nimport io.reactivex.rxjava3.subjects.PublishSubject;\n\n/**\n * This example demonstrates how to create a websocket connection to a server. Only the most\n * important callbacks are overloaded.\n */\npublic class AsgWebSocketClient extends WebSocketClient {\n    private String TAG = \"WearableAI_WebSocketClient\";\n    private int connected = 0;\n    private URI serverURI;\n    private WebSocketManager webSocketManager;\n    public boolean killme = true; //shouldn't try to stay alive until we are born - i.e. one successful connect\n\n    //observables to send data around app\n    PublishSubject<JSONObject> dataObservable;\n    Disposable dataSubscriber;\n\n    private String mySourceName;\n\n    public AsgWebSocketClient(URI serverUri, Draft draft) {\n        super(serverUri, draft);\n\n    }\n\n    public void sendHeartBeat(){\n//        Log.d(TAG, \"send heartbeat\");\n        try {\n            JSONObject ping = new JSONObject();\n            ping.put(MessageTypes.MESSAGE_TYPE_LOCAL, MessageTypes.PING);\n            ping.put(\"ping\", \"ping\");\n            //send(ping.toString());\n        } catch (JSONException e){\n            e.printStackTrace();\n        }\n    }\n\n    public AsgWebSocketClient(WebSocketManager manager, URI serverURI) {\n        super(serverURI);\n        connected = 0;\n        webSocketManager = manager;\n        this.serverURI = serverURI;\n        setup();\n    }\n\n    public AsgWebSocketClient(URI serverUri, Map<String, String> httpHeaders) {\n        super(serverUri, httpHeaders);\n        setup();\n    }\n\n    private void setup(){\n        //dataObservable = PublishSubject.create();\n        mySourceName = \"web_socket\";\n    }\n\n    public void setObservable(PublishSubject<JSONObject> dataO){\n        dataObservable = dataO;\n    }\n\n    public void setSourceName(String name){\n        mySourceName = name;\n    }\n\n    public PublishSubject<JSONObject> getDataObservable(){\n        return dataObservable;\n    }\n\n    //stop this socket, the socket will NOT try to restart itself after this, so whoever calls this must handle restart, thus should only be called by WebSocketManager\n    public boolean stop(){\n        killme = true;\n        Log.d(TAG, \"Stopping Web socket\");\n        connected = 0;\n        if (! isClosed()) {\n            close();\n            getConnection().closeConnection(1000, \"closing\");\n//            try {\n//                closeBlocking();\n//                Log.d(TAG, \"Successfully closed\");\n//            } catch (InterruptedException e) {\n//                Log.d(TAG, \"Failed to close\");\n//                e.printStackTrace();\n//                return false;\n//            }\n        }\n        return true;\n    }\n\n    @Override\n    public void onOpen(ServerHandshake handshakedata) {\n        killme = false;\n        connected = 2;\n        Log.d(TAG, \"Web Socket CONNECTED\");\n        setConnectionLostTimeout(6);\n        startConnectionLostTimer();\n        dataSubscriber = dataObservable.subscribe(i -> parseData(i));\n        // if you plan to refuse connection based on ip or httpfields overload: onWebsocketHandshakeReceivedAsClient\n    }\n\n    @Override\n    public void onMessage(String message) {\n        try {\n//            Log.d(TAG, \"received: \" + message);\n            JSONObject json_message = new JSONObject(message);\n            json_message.put(\"local_source\", mySourceName); //ad our set name so rest of program knows the source of this message\n            dataObservable.onNext(json_message);\n        } catch (JSONException e){\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public void onMessage(ByteBuffer message) {\n    }\n\n    @Override\n    public void onClose(int code, String reason, boolean remote) {\n        Log.d(TAG, \"onClose called\");\n        connected = 0;\n        if (dataSubscriber != null) {\n            Log.d(TAG, \"dispose data subscriber\");\n            dataSubscriber.dispose();\n        }\n\n        if (!killme) {\n            Log.d(TAG, \"Ask manager to restart me\");\n            webSocketManager.onClose(); //tell manager that we are done and it should make a new socket to reconnect\n        }\n\n        // The codes are documented in class org.java_websocket.framing.CloseFrame\n        Log.d(TAG,\n                \"Connection closed by \" + (remote ? \"remote peer\" : \"us\") + \" Code: \" + code + \" Reason: \"\n                        + reason);\n        Log.d(TAG, \"onClose complete\");\n    }\n\n    @Override\n    public void onError(Exception ex) {\n        Log.d(TAG, \"Web Socket error!\");\n        ex.printStackTrace();\n        // if the error is fatal then onClose will be called additionally\n    }\n\n\n    public int getConnectionState(){\n//        ReadyState ready_state = getReadyState();\n//        if (ready_state == ReadyState.OPEN){\n//            return 2;\n//        } else if ((ready_state == ReadyState.CLOSING) || (ready_state == ReadyState.CLOSED)){\n//            return 1;\n//        } else {\n//            return 0;\n//        }\n        return connected;\n    }\n\n\n    //this to be moved into the ASPRepresentative class\n    private void parseData(JSONObject data){\n        try {\n            String typeOf = data.getString(MessageTypes.MESSAGE_TYPE_LOCAL);\n            if (typeOf.equals(MessageTypes.AUDIO_CHUNK_DECRYPTED)) {\n                //sendString(data.getString(MessageTypes.AUDIO_DATA));\n                sendJson(data);\n            } else if (typeOf.equals(MessageTypes.VISUAL_SEARCH_QUERY)) {\n                sendJson(data);\n            } else if (typeOf.equals(MessageTypes.POV_IMAGE)) {\n                sendJson(data);\n            }\n    } catch (JSONException e){\n            e.printStackTrace();\n        }\n    }\n\n    public void sendJson(JSONObject data){\n        String encodedData = data.toString();\n        sendString(encodedData);\n    }\n\n    public void sendString(String data){\n        if (connected == 2){\n            send(data);\n        } else {\n            Log.d(TAG, \"CANNOT SEND JSON, NOT CONNECTED\");\n        }\n    }\n\n}"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/comms/MessageTypes.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.comms;\n\npublic class MessageTypes {\n    //top level\n    public static final String MESSAGE_TYPE_LOCAL = \"MESSAGE_TYPE_LOCAL\";\n    public static final String TIMESTAMP = \"TIMESTAMP\";\n\n    //REFERENCE CARD VIEW\n    public static final String REFERENCE_CARD_SIMPLE_VIEW = \"REFERENCE_CARD_SIMPLE_VIEW\";\n    public static final String REFERENCE_CARD_TEXT_WALL_VIEW = \"REFERENCE_CARD_TEXT_WALL_VIEW\";\n    public static final String REFERENCE_CARD_SIMPLE_VIEW_TITLE = \"REFERENCE_CARD_SIMPLE_VIEW_TITLE\";\n    public static final String REFERENCE_CARD_SIMPLE_VIEW_BODY = \"REFERENCE_CARD_SIMPLE_VIEW_BODY\";\n\n    public static final String REFERENCE_CARD_IMAGE_VIEW = \"REFERENCE_CARD_IMAGE_VIEW\";\n    public static final String REFERENCE_CARD_IMAGE_VIEW_TITLE = \"REFERENCE_CARD_IMAGE_VIEW_TITLE\";\n    public static final String REFERENCE_CARD_IMAGE_VIEW_BODY = \"REFERENCE_CARD_IMAGE_VIEW_BODY\";\n    public static final String REFERENCE_CARD_TEXT_WALL_TEXT = \"REFERENCE_CARD_TEXT_WALL_TEXT\";\n    public static final String REFERENCE_CARD_IMAGE_VIEW_IMG_URL = \"REFERENCE_CARD_IMAGE_VIEW_IMG_URL\";\n\n    //SCROLLING TEXT VIEW\n    public static final String SCROLLING_TEXT_VIEW_START = \"SCROLLING_TEXT_VIEW_START\";\n    public static final String SCROLLING_TEXT_VIEW_FINAL = \"SCROLLING_TEXT_VIEW_FINAL\";\n    public static final String SCROLLING_TEXT_VIEW_INTERMEDIATE = \"SCROLLING_TEXT_VIEW_INTERMEDIATE\";\n    public static final String SCROLLING_TEXT_VIEW_TEXT = \"SCROLLING_TEXT_VIEW_TEXT\";\n    public static final String SCROLLING_TEXT_VIEW_STOP = \"SCROLLING_TEXT_VIEW_STOP\";\n\n    //DATA TYPES\n    public static final String POV_IMAGE = \"POV_IMAGE\";\n    public static final String JPG_BYTES_BASE64 = \"JPG_BYTES_BASE64\";\n\n    //specific message types (after MESSAGE_TYPE_*)\n    //TRANSCRIPTS\n    public static final String FINAL_TRANSCRIPT = \"FINAL_TRANSCRIPT\";\n    public static final String INTERMEDIATE_TRANSCRIPT = \"INTERMEDIATE_TRANSCRIPT\";\n    public static final String TRANSCRIPT_TEXT = \"TRANSCRIPT_TEXT\";\n    public static final String TRANSCRIPT_ID = \"TRANSCRIPT_ID\";\n\n    //VOICE COMMANDS\n    public static final String VOICE_COMMAND_RESPONSE = \"VOICE_COMMAND_RESPONSE\";\n    public static final String COMMAND_RESULT = \"COMMAND_RESULT\";\n    public static final String COMMAND_NAME = \"COMMAND_NAME\";\n    public static final String COMMAND_RESPONSE_DISPLAY_STRING = \"COMMAND_RESPONSE_DISPLAY_STRING\";\n    //voice command event\n    public static final String VOICE_COMMAND_STREAM_EVENT = \"VOICE_COMMAND_STREAM_EVENT\";\n    public static final String VOICE_COMMAND_STREAM_EVENT_TYPE = \"VOICE_COMMAND_STREAM_EVENT_TYPE\";\n    public static final String WAKE_WORD_EVENT_TYPE = \"WAKE_WORD_EVENT_TYPE\";\n    public static final String COMMAND_EVENT_TYPE = \"COMMAND_EVENT_TYPE\";\n    public static final String CANCEL_EVENT_TYPE = \"CANCEL_EVENT_TYPE\";\n    public static final String RESOLVE_EVENT_TYPE = \"RESOLVE_EVENT_TYPE\";\n    public static final String TEXT_RESPONSE_EVENT_TYPE = \"TEXT_RESPONSE_EVENT_TYPE\";\n    public static final String COMMAND_ARGS_EVENT_TYPE = \"COMMAND_ARGS_EVENT_TYPE\";\n    public static final String REQUIRED_ARG_EVENT_TYPE = \"REQUIRED_ARG_EVENT_TYPE\";\n    public static final String ARG_NAME = \"ARG_NAME\";\n    public static final String ARG_OPTIONS = \"ARG_OPTIONS\";\n    public static final String INPUT_VOICE_STRING = \"INPUT_VOICE_STRING\";\n    public static final String VOICE_ARG_EXPECT_TYPE = \"VOICE_ARG_EXPECT_TYPE\";\n    public static final String VOICE_ARG_EXPECT_NATURAL_LANGUAGE = \"VOICE_ARG_EXPECT_NATURAL_LANGUAGE\";\n    public static final String VOICE_COMMAND_LIST = \"VOICE_COMMAND_LIST\";\n    public static final String INPUT_WAKE_WORD = \"INPUT_WAKE_WORD\";\n    public static final String INPUT_VOICE_COMMAND_NAME = \"INPUT_VOICE_COMMAND_NAME\";\n\n    //AUTOCITER/WEARABLE-REFERENCER\n    public static final String AUTOCITER_START = \"AUTOCITER_START\";\n    public static final String AUTOCITER_STOP = \"AUTOCITER_STOP\";\n    public static final String AUTOCITER_PHONE_NUMBER = \"AUTOCITER_PHONE_NUMBER\";\n    public static final String AUTOCITER_POTENTIAL_REFERENCES = \"AUTOCITER_POTENTIAL_REFERENCES\";\n    public static final String AUTOCITER_REFERENCE_DATA = \"AUTOCITER_REFERENCE_DATA\";\n\n    //request user UI to display a list of possible choices to dipslay\n    public static final String REFERENCE_SELECT_REQUEST = \"REFERENCE_SELECT_REQUEST\";\n    public static final String REFERENCES = \"REFERENCES\";\n\n    //FACE/PERSON SIGHTING\n    public static final String FACE_SIGHTING_EVENT = \"FACE_SIGHTING_EVENT\";\n    public static final String FACE_NAME = \"FACE_NAME\";\n\n    //SMS\n    public static final String SMS_REQUEST_SEND = \"SMS_REQUEST_SEND\";\n    public static final String SMS_MESSAGE_TEXT = \"SMS_MESSAGE_TEXT\";\n    public static final String SMS_PHONE_NUMBER = \"SMS_PHONE_NUMBER\";\n\n    //AUDIO\n    //AUDIO\n    public static final String AUDIO_CHUNK_ENCRYPTED = \"AUDIO_CHUNK_ENCRYPTED\";\n    public static final String AUDIO_CHUNK_DECRYPTED = \"AUDIO_CHUNK_DECRYPTED\";\n    public static final String AUDIO_DATA = \"AUDIO_DATA\";\n\n\n    //COMMS\n    public static final String PING = \"PING\";\n\n    //UI\n    public static final String UI_UPDATE_ACTION = \"UI_UPDATE_ACTION\";\n    public static final String PHONE_CONNECTION_STATUS = \"PHONE_CONNECTION_STATUS\";\n\n//    //command responses to show\n//    public final static String NATURAL_LANGUAGE_QUERY = \"NATURAL_LANGUAGE_QUERY\";\n//    public final static String TEXT_RESPONSE = \"NATURAL_LANGUAGE_QUERY\";\n//    public final static String TEXT_QUERY = \"TEXT_QUERY\";\n//    public final static String VISUAL_SEARCH_RESULT = \"VISUAL_SEARCH_RESULT\";\n//    public final static String VISUAL_SEARCH_QUERY = \"VISUAL_SEARCH_QUERY\";\n//    public final static String VISUAL_SEARCH_IMAGE= \"VISUAL_SEARCH_IMAGE\";\n//    public final static String VISUAL_SEARCH_DATA = \"VISUAL_SEARCH_DATA\";\n//    public final static String SEARCH_ENGINE_RESULT = \"SEARCH_ENGINE_RESULT\";\n//    public final static String SEARCH_ENGINE_RESULT_DATA = \"SEARCH_ENGINE_RESULT_DATA\";\n//    public final static String TRANSLATION_RESULT = \"TRANSLATION_RESULT\";\n//    public final static String AFFECTIVE_SUMMARY_RESULT = \"AFFECTIVE_SUMMARY_RESULT\";\n//    public final static String COMMAND_SWITCH_MODE = \"COMMAND_SWITCH_MODE\";\n\n    //command responses to show\n    //Natural language\n    public final static String NATURAL_LANGUAGE_QUERY = \"NATURAL_LANGUAGE_QUERY\";\n    public final static String TEXT_QUERY = \"TEXT_QUERY\";\n    //visual search\n    public final static String VISUAL_SEARCH_RESULT = \"VISUAL_SEARCH_RESULT\"; //this is the ASG facing term\n    public final static String VISUAL_SEARCH_IMAGE= \"VISUAL_SEARCH_IMAGE\";\n    public final static String VISUAL_SEARCH_QUERY = \"VISUAL_SEARCH_QUERY\"; //this is the glbox facing term\n    public final static String VISUAL_SEARCH_DATA = \"VISUAL_SEARCH_DATA\"; //this is the payload\n    //search engine\n    public final static String SEARCH_ENGINE_QUERY = \"SEARCH_ENGINE_QUERY\";\n    public final static String SEARCH_ENGINE_RESULT = \"SEARCH_ENGINE_RESULT\";\n    public final static String SEARCH_ENGINE_RESULT_DATA = \"SEARCH_ENGINE_RESULT_DATA\";\n\n    //I/O\n    public final static String SG_TOUCHPAD_EVENT = \"SG_TOUCHPAD_EVENT\";\n    public final static String SG_TOUCHPAD_KEYCODE = \"SG_TOUCHPAD_KEYCODE\";\n\n    //translation\n    public final static String TRANSLATE_TEXT_QUERY = \"TRANSLATE_TEXT_QUERY\";\n    public final static String TRANSLATE_TEXT_DATA = \"TRANSLATE_TEXT_DATA\";\n    public final static String TRANSLATE_TEXT_RESULT = \"TRANSLATE_TEXT_RESULT\";\n    public final static String TRANSLATE_TEXT_RESULT_DATA = \"TRANSLATION_RESULT_DATA\";\n\n    //object translation\n    public final static String OBJECT_TRANSLATION_RESULT = \"OBJECT_TRANSLATION_RESULT\";\n    public final static String OBJECT_TRANSLATION_RESULT_DATA = \"OBJECT_TRANSLATION_RESULT_DATA\";\n\n    public final static String AFFECTIVE_SUMMARY_RESULT = \"AFFECTIVE_SUMMARY_RESULT\";\n    public final static String COMMAND_SWITCH_MODE = \"COMMAND_SWITCH_MODE\";\n\n    //control the current mode of the ASG\n    public final static String ACTION_SWITCH_MODES = \"ACTION_SWITCH_MODES\";\n    public final static String NEW_MODE = \"NEW_MODE\";\n    public final static String MODE_VISUAL_SEARCH = \"MODE_VISUAL_SEARCH\";\n    public final static String MODE_LIVE_LIFE_CAPTIONS = \"MODE_LIVE_LIFE_CAPTIONS\";\n    public final static String MODE_HOME = \"MODE_HOME\";\n    public final static String MODE_CONVERSATION_MODE = \"MODE_CONVERSATION_MODE\";\n    public final static String MODE_SOCIAL_MODE = \"MODE_SOCIAL_MODE\";\n    public final static String MODE_REFERENCE_GRID = \"MODE_REFERENCE_GRID\";\n    public final static String MODE_WEARABLE_FACE_RECOGNIZER = \"MODE_WEARABLE_FACE_RECOGNIZER\";\n    public final static String MODE_LANGUAGE_TRANSLATE = \"MODE_LANGUAGE_TRANSLATE\";\n    public final static String MODE_OBJECT_TRANSLATE = \"MODE_OBJECT_TRANSLATE\";\n    public final static String MODE_TEXT_LIST = \"MODE_TEXT_LIST\";\n    public final static String MODE_TEXT_BLOCK = \"MODE_TEXT_BLOCK\";\n    public final static String MODE_BLANK = \"MODE_BLANK\";\n    public final static String MODE_SEARCH_ENGINE_RESULT = \"MODE_SEARCH_ENGINE_RESULT\";\n\n}\n\n\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/comms/WebSocketManager.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.comms;\n\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport android.os.Looper;\nimport android.util.Log;\n\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.util.concurrent.TimeUnit;\n\nimport org.json.JSONObject;\n\nimport io.reactivex.rxjava3.subjects.PublishSubject;\n\npublic class WebSocketManager implements Runnable{\n    private boolean killme = false;\n\n    private String TAG = \"WearableAI_WebSocket_Reconnector\";\n    public AsgWebSocketClient ws;\n    private URI serverURI;\n\n    //data to save and pass to the socket\n    //observables to send data around app\n    PublishSubject<JSONObject> dataObservable;\n    String mySourceName;\n\n    private static Handler handler;\n    private static HandlerThread mHandlerThread;\n    private static int delay;\n    private static boolean firstRun = true;\n\n    public void setObservable(PublishSubject<JSONObject> dataO){\n        dataObservable = dataO;\n    }\n\n    public void setSourceName(String name){\n        mySourceName = name;\n    }\n\n    public int getConnectionState(){\n        if (ws != null) {\n            return ws.getConnectionState();\n        } else {\n            return 0;\n        }\n    }\n\n    public void sendJson(JSONObject data){\n//        Log.d(TAG, \"SENDING JSON FROM ASG WS\");\n        if (ws != null) {\n            ws.send(data.toString());\n        }\n    }\n\n    public WebSocketManager(String ip, String port){\n        //handler = new Handler();\n        //handler = new Handler(Looper.getMainLooper());\n        mHandlerThread = new HandlerThread(\"WebSocketHandler\");\n        mHandlerThread.start();\n        handler = new Handler(mHandlerThread.getLooper());\n        delay = 3500; // 1000 milliseconds == 1 second\n\n        if (port == null){\n            port = \"8887\";\n        }\n        //create new URI to connect with\n        try{\n            this.serverURI = new URI(\"ws://\" + ip + \":\" + port);\n        } catch (URISyntaxException e){\n            e.printStackTrace();\n        }\n\n        //start a heartbeat, which will try to send a heartbeat every n seconds iff the connection appears to be open. This will reveal if the other end has closed the connection and we weren't notified\n        handler.postDelayed(new Runnable() {\n            public void run() {\n                //if the ws doesn't exist or is not open, then the manager already knows we A) need to restart b) are starting, so don't send heart beat\n                if (ws != null) {\n                    if (ws.getConnectionState() == 2 && !ws.isClosed()) {\n//                        Log.d(TAG, \"tryna send heart beat\");\n                        ws.sendHeartBeat();\n//                        Log.d(TAG, \"done did send heart beat\");\n                    } else {\n//                        Log.d(TAG, \"not even gonna tryna send eart beat\");\n                    }\n                }\n                handler.postDelayed(this, 3000); //run again in delay milliseconds\n            }\n        }, delay);\n    }\n\n    public void setNewIp(String ip){\n        int prevPort = serverURI.getPort();\n        try {\n            this.serverURI = new URI(\"ws://\" + ip + \":\" + Integer.toString(prevPort));\n        } catch (URISyntaxException e){\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public void run() {\n        int currDelay;\n        if (firstRun){\n            Log.d(TAG, \"first run, so go fast\");\n            currDelay = 1;\n        } else {\n            currDelay = delay;\n        }\n        firstRun = false;\n        handler.postDelayed(new Runnable() {\n            public void run() {\n                boolean connected = false;\n                try {\n                    Log.d(TAG, \"Trying to connect...\");\n                    ws = new AsgWebSocketClient(WebSocketManager.this, serverURI);\n                    ws.setObservable(dataObservable);\n                    ws.setSourceName(mySourceName);\n                    ws.setReuseAddr(true);\n                    connected = ws.connectBlocking(2500, TimeUnit.MILLISECONDS); //add this so we don't get stuck trying to connect if the ip address updated\n                    Log.d(TAG, \"Web socket connected: \" + connected);\n                } catch (Exception e) {\n                    connected = false;\n                    e.printStackTrace();\n                }\n                if (!connected || ws.getConnectionState() == 0 || ws.isClosed()){\n                    ws.stop();\n                    handler.postDelayed(this, delay); //run again in delay milliseconds if we didn't successfully connect\n                }\n            }\n        }, currDelay);\n    }\n\n    protected void onClose(){\n        //reconnect\n        Runnable restarter = new Runnable() {\n            public void run() {\n                Log.d(TAG, \"Starting new run after onClose called...\");\n                runny();\n            }\n        };\n\n        //must put this on handler as onClose here is called by onClose in socket, and we need to make sure socket it done shutting down before restarting\n        handler.postDelayed(new Runnable() {\n            public void run() {\n                Log.d(TAG, \"WebSocketManager onClose called\");\n                boolean closed = ws.stop();\n                if (! closed){\n                    Log.d(TAG, \"WARNING: Old ws did not properly close\");\n                }\n                Log.d(TAG, \"onClose Stopped web socket\");\n                if (!killme) { //only restart if we aren't supposed to die yet\n                    handler.postDelayed(restarter, delay);\n                }\n            }\n        }, 100);\n    }\n\n    //this is because we need to delay this running, but there is a namespace overlap with run()\n    protected void runny(){\n        run();\n    }\n\n    public void destroy(){\n        killme = true;\n\n        //stop our heartbeat and connect loops\n        handler.removeCallbacksAndMessages(null);\n        mHandlerThread.quit();\n\n        //close the websocket\n        boolean closed = ws.stop();\n    }\n}"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/comms/WifiStatusCallback.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.comms;\n\npublic interface WifiStatusCallback{\n    void onSuccess(boolean connected);\n}\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/comms/WifiUtils.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.comms;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.ConnectivityManager;\nimport android.net.NetworkInfo;\nimport android.net.wifi.WifiInfo;\nimport android.net.wifi.WifiManager;\nimport android.util.Log;\n\npublic class WifiUtils {\n    public static String TAG = \"WearableAiAsg_WifiUtils\";\n\n    public static boolean checkWifiOnAndConnected(Context context) {\n        WifiManager wifiMgr = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);\n\n        if (wifiMgr.isWifiEnabled()) { // Wi-Fi adapter is ON\n\n            WifiInfo wifiInfo = wifiMgr.getConnectionInfo();\n\n            if( wifiInfo.getNetworkId() == -1 ){\n                return false; // Not connected to an access point\n            }\n            return true; // Connected to an access point\n        }\n        else {\n            return false; // Wi-Fi adapter is OFF\n        }\n    }\n\n    public static class WifiReceiver extends BroadcastReceiver {\n        private WifiStatusCallback callback;\n\n        public WifiReceiver(WifiStatusCallback callback){\n            //callback to send the network data to\n            this.callback = callback;\n        }\n\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            ConnectivityManager conMan = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);\n            NetworkInfo netInfo = conMan.getActiveNetworkInfo();\n            boolean connection = false;\n            if (netInfo != null && netInfo.getType() == ConnectivityManager.TYPE_WIFI) {\n                Log.d(\"WifiReceiver\", \"Have Wifi Connection\");\n                connection = true;\n            } else {\n                Log.d(\"WifiReceiver\", \"Don't have Wifi Connection\");\n                connection = false;\n            }\n            callback.onSuccess(connection);\n        }\n    };\n\n    public static void displayNetworkInfo(Context context) {\n        WifiManager mainWifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);\n        WifiInfo wifiInfo = mainWifi.getConnectionInfo();\n        String ssid = wifiInfo.getSSID();\n        int ip = wifiInfo.getIpAddress();\n        String message = \"Connection established.\\nSSID = \" + ssid + \"; IP Address = \" + ip;\n        Log.d(TAG, message);\n    }\n}\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/sensors/AudioChunkCallback.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.sensors;\n\nimport java.nio.ByteBuffer;\n\npublic interface AudioChunkCallback{\n    void onSuccess(ByteBuffer chunk);\n}\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/sensors/BluetoothMic.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.sensors;\n\n//thanks to https://github.com/aahlenst/android-audiorecord-sample/blob/master/src/main/java/com/example/audiorecord/BluetoothRecordActivity.java\n\n\nimport android.bluetooth.BluetoothDevice;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.media.AudioFormat;\nimport android.media.AudioManager;\nimport android.media.AudioRecord;\nimport android.media.MediaRecorder;\nimport android.os.CountDownTimer;\nimport android.os.Handler;\nimport android.util.Log;\n\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * Sample that demonstrates how to record from a Bluetooth HFP microphone using {@link AudioRecord}.\n */\npublic class BluetoothMic {\n\n    private static final String TAG = \"WearableAi_\" + BluetoothMic.class.getCanonicalName();\n\n    private static final int SAMPLING_RATE_IN_HZ = 16000;\n\n    private static final int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO;\n\n    private static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;\n\n    /**\n     * Factor by that the minimum buffer size is multiplied. The bigger the factor is the less\n     * likely it is that samples will be dropped, but more memory will be used. The minimum buffer\n     * size is determined by {@link AudioRecord#getMinBufferSize(int, int, int)} and depends on the\n     * recording settings.\n     */\n//    private final static float BUFFER_SIZE_SECONDS = 0.2f;\n    private final static float BUFFER_SIZE_SECONDS = 0.192f;\n    private static final int BUFFER_SIZE_FACTOR = 2;\n    private final int bufferSize;\n\n    private boolean bluetoothAudio = false; //are we using local audio or bluetooth audio?\n    private int retries = 0;\n    private int retryLimit = 3;\n\n    private Handler mHandler;\n\n    /**\n     * Size of the buffer where the audio data is stored by Android\n     */\n//    private static final int BUFFER_SIZE = AudioRecord.getMinBufferSize(SAMPLING_RATE_IN_HZ,\n//            CHANNEL_CONFIG, AUDIO_FORMAT) * BUFFER_SIZE_FACTOR;\n\n    /**\n     * Signals whether a recording is in progress (true) or not (false).\n     */\n    private final AtomicBoolean recordingInProgress = new AtomicBoolean(false);\n\n    private final BroadcastReceiver bluetoothStateReceiver = new BroadcastReceiver() {\n\n        private BluetoothState bluetoothState = BluetoothState.UNAVAILABLE;\n\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            String action = intent.getAction();\n            if (action.equals(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED)) {\n                int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1);\n                switch (state) {\n                    case AudioManager.SCO_AUDIO_STATE_CONNECTED:\n                        Log.i(TAG, \"Bluetooth HFP Headset is connected\");\n                        //handleBluetoothStateChange(BluetoothState.AVAILABLE);\n                        if (mIsStarting)\n                        {\n                            // When the device is connected before the application starts,\n                            // ACTION_ACL_CONNECTED will not be received, so call onHeadsetConnected here\n                            mIsStarting = false;\n                        }\n\n                        if (mIsCountDownOn)\n                        {\n                            mIsCountDownOn = false;\n                            mCountDown.cancel();\n                        }\n                        bluetoothAudio = true;\n                        startRecording();\n                        break;\n                    case AudioManager.SCO_AUDIO_STATE_CONNECTING:\n                        Log.i(TAG, \"Bluetooth HFP Headset is connecting\");\n                        handleBluetoothStateChange(BluetoothState.UNAVAILABLE);\n                    case AudioManager.SCO_AUDIO_STATE_DISCONNECTED:\n                        Log.i(TAG, \"Bluetooth HFP Headset is disconnected\");\n                        //handleBluetoothStateChange(BluetoothState.UNAVAILABLE);\n                        // Always receive SCO_AUDIO_STATE_DISCONNECTED on call to startBluetooth()\n                        // which at that stage we do not want to do anything. Thus the if condition.\n                        break;\n                    case AudioManager.SCO_AUDIO_STATE_ERROR:\n                        Log.i(TAG, \"Bluetooth HFP Headset is in error state\");\n                        handleBluetoothStateChange(BluetoothState.UNAVAILABLE);\n                        break;\n                }\n            } else if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)){\n                    Log.i(TAG, \"New bluetooth device is available\");\n                    handleNewBluetoothDevice();\n            } else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)){\n                Log.i(TAG, \"Bluetooth device was disconnected\");\n                handleDisconnectBluetoothDevice();\n            }\n    }\n\n    private void handleBluetoothStateChange(BluetoothState state) {\n            if (bluetoothState == state) {\n                return;\n            }\n\n            bluetoothState = state;\n            bluetoothStateChanged(state);\n        }\n\n        private void handleNewBluetoothDevice(){\n            //check if the new device is a headset, if so, connect\n            retries = 0; //reset retries as there is a new device\n//            if (!bluetoothAudio){\n//                activateBluetoothSco();\n//            }\n\n            // start bluetooth Sco audio connection.\n            // Calling startBluetoothSco() always returns faIL here,\n            // that why a count down timer is implemented to call\n            // startBluetoothSco() in the onTick.\n            audioManager.setMode(AudioManager.MODE_IN_CALL);\n            mIsCountDownOn = true;\n            mCountDown.start();\n        }\n\n        private void handleDisconnectBluetoothDevice() {\n            if (mIsCountDownOn)\n            {\n                mIsCountDownOn = false;\n                mCountDown.cancel();\n            }\n            bluetoothAudio = false;\n            deactivateBluetoothSco();\n            startRecording(); //if disconnected, now we should switch to recording on local mic\n        }\n    };\n\n    private AudioRecord recorder = null;\n\n    private AudioManager audioManager;\n    private boolean mIsCountDownOn = false;\n    private boolean mIsStarting = false;\n\n    private Thread recordingThread = null;\n\n    private Context mContext;\n\n    private AudioChunkCallback mChunkCallback;\n\n//    private Button startButton;\n//\n//    private Button stopButton;\n//\n//    private Button bluetoothButton;\n\n    public BluetoothMic(Context context, AudioChunkCallback chunkCallback) {\n        bufferSize = Math.round(SAMPLING_RATE_IN_HZ * BUFFER_SIZE_SECONDS);\n\n        // need for audio sco, see mBroadcastReceiver\n        mIsStarting = true;\n\n        //setup context\n        mContext = context;\n\n        mChunkCallback = chunkCallback;\n\n        //setup handler\n        mHandler = new Handler();\n\n        //listen for bluetooth HFP events\n        audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);\n        mContext.registerReceiver(bluetoothStateReceiver, new IntentFilter(\n                AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED));\n        mContext.registerReceiver(bluetoothStateReceiver,\n                new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED));\n        mContext.registerReceiver(bluetoothStateReceiver,\n                new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED));\n\n        //first, start recording on local microphone\n        bluetoothAudio = false;\n        startRecording();\n        //the, immediately try to startup the SCO connection\n        mIsCountDownOn = true;\n        mCountDown.start();\n    }\n\n    private void startRecording() {\n\n        //if alraedy recording, stop previous and start a new one\n        if (recorder != null) {\n            stopRecording();\n        }\n        if (bluetoothAudio) {\n            Log.d(TAG, \"Starting recording on Bluetooth Microphone\");\n        } else {\n            Log.d(TAG, \"Starting recording on local microphone\");\n        }\n\n        // Depending on the device one might has to change the AudioSource, e.g. to DEFAULT\n        // or VOICE_COMMUNICATION\n\n        recorder = new AudioRecord(MediaRecorder.AudioSource.VOICE_RECOGNITION,\n                SAMPLING_RATE_IN_HZ, CHANNEL_CONFIG, AUDIO_FORMAT, bufferSize * 2);\n\n        recorder.startRecording();\n\n        recordingInProgress.set(true);\n\n        recordingThread = new Thread(new RecordingRunnable(), \"Recording Thread\");\n        recordingThread.start();\n    }\n\n    private void stopRecording() {\n        Log.d(TAG, \"Stopping audio recording\");\n        if (null == recorder) {\n            return;\n        }\n\n        recordingInProgress.set(false);\n\n        recorder.stop();\n\n        recorder.release();\n\n        recorder = null;\n\n        recordingThread = null;\n    }\n\n    private void activateBluetoothSco() {\n        Log.d(TAG, \"Activating Bluetooth SCO\");\n\n        retries += 1;\n\n        if (!audioManager.isBluetoothScoAvailableOffCall()) {\n            Log.e(TAG, \"SCO ist not available, recording is not possible\");\n            return;\n        }\n\n        if (audioManager.isBluetoothScoOn()) {\n            audioManager.stopBluetoothSco();\n        }\n        audioManager.startBluetoothSco();\n    }\n\n    private void deactivateBluetoothSco(){\n        Log.d(TAG, \"Deactivating Bluetooth SCO\");\n        audioManager.stopBluetoothSco();\n    }\n\n    private void bluetoothStateChanged(BluetoothState state) {\n        Log.i(TAG, \"Bluetooth state changed to:\" + state);\n\n        if (BluetoothState.UNAVAILABLE == state && recordingInProgress.get()) {\n            bluetoothAudio = false;\n            stopRecording();\n            deactivateBluetoothSco();\n        } else if (BluetoothState.AVAILABLE == state && !recordingInProgress.get()){\n            bluetoothAudio = true;\n            startRecording();\n        } else if (BluetoothState.AVAILABLE == state && !bluetoothAudio){\n            bluetoothAudio = true;\n            startRecording();\n        }\n    }\n\n    private class RecordingRunnable implements Runnable {\n\n        @Override\n        public void run() {\n//            final ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER_SIZE);\n            short[] short_buffer = new short[bufferSize];\n            ByteBuffer b_buffer = ByteBuffer.allocate(short_buffer.length * 2);\n\n                while (recordingInProgress.get()) {\n//                    int result = recorder.read(buffer, BUFFER_SIZE);\n                    // read the data into the buffer\n                    int result = recorder.read(short_buffer, 0, short_buffer.length);\n                    if (result < 0) {\n                        Log.d(TAG, \"ERROR\");\n                    }\n                    //convert short array to byte array\n                    b_buffer.order(ByteOrder.LITTLE_ENDIAN);\n                    b_buffer.asShortBuffer().put(short_buffer);\n                    //send to audio system\n                    mChunkCallback.onSuccess(b_buffer);\n                    b_buffer.clear();\n                }\n        }\n\n        private String getBufferReadFailureReason(int errorCode) {\n            switch (errorCode) {\n                case AudioRecord.ERROR_INVALID_OPERATION:\n                    return \"ERROR_INVALID_OPERATION\";\n                case AudioRecord.ERROR_BAD_VALUE:\n                    return \"ERROR_BAD_VALUE\";\n                case AudioRecord.ERROR_DEAD_OBJECT:\n                    return \"ERROR_DEAD_OBJECT\";\n                case AudioRecord.ERROR:\n                    return \"ERROR\";\n                default:\n                    return \"Unknown (\" + errorCode + \")\";\n            }\n        }\n    }\n\n    enum BluetoothState {\n        AVAILABLE, UNAVAILABLE\n    }\n\n    /**\n     * Try to connect to audio headset in onTick.\n     */\n    private CountDownTimer mCountDown = new CountDownTimer(1000, 300)\n    {\n\n        @SuppressWarnings(\"synthetic-access\")\n        @Override\n        public void onTick(long millisUntilFinished)\n        {\n            // When this call is successful, this count down timer will be canceled.\n            audioManager.startBluetoothSco();\n\n            Log.d(TAG, \"\\nonTick start bluetooth Sco\"); //$NON-NLS-1$\n        }\n\n        @SuppressWarnings(\"synthetic-access\")\n        @Override\n        public void onFinish()\n        {\n            // Calls to startBluetoothSco() in onStick are not successful.\n            // Should implement something to inform user of this failure\n            mIsCountDownOn = false;\n            audioManager.setMode(AudioManager.MODE_NORMAL);\n\n            //if it fails after n tries, then we should start recording with local microphone\n            startRecording();\n\n            Log.d(TAG, \"\\nonFinish fail to connect to headset audio\"); //$NON-NLS-1$\n        }\n    };\n}\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/sensors/BluetoothScanner.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.sensors;\n\nimport android.bluetooth.BluetoothAdapter;\nimport android.bluetooth.BluetoothDevice;\nimport android.bluetooth.BluetoothManager;\nimport android.bluetooth.le.BluetoothLeScanner;\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.os.Handler;\nimport android.util.Log;\n\npublic class BluetoothScanner {\n    private String TAG = \"WearableAI_BluetoothScanner\";\n\n    private Muse myMuse;\n\n    private Context mContext;\n\n    public static String CLIENT_CHARACTERISTIC_CONFIG = \"00002902-0000-1000-8000-00805f9b34fb\";\n\n    private BluetoothAdapter mBluetoothAdapter;\n    private BluetoothLeScanner mBluetoothLeScanner;\n    private boolean mScanning;\n    private Handler mHandler;\n\n    private static final int REQUEST_ENABLE_BT = 1;\n    // Stops scanning after 10 seconds.\n    private static final long SCAN_PERIOD = 90000;\n\n    public BluetoothScanner(Context context){\n        mHandler = new Handler();\n        mContext = context;\n\n        // Use this check to determine whether BLE is supported on the device.  Then you can\n        // selectively disable BLE-related features.\n        if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {\n            Log.d(TAG, \"BLUETOOTH NOT AVAILABLE\");\n        }\n\n        // Initializes a Bluetooth adapter.  For API level 18 and above, get a reference to\n        // BluetoothAdapter through BluetoothManager.\n        final BluetoothManager bluetoothManager =\n                (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);\n        mBluetoothAdapter = bluetoothManager.getAdapter();\n        mBluetoothLeScanner =  mBluetoothAdapter.getBluetoothLeScanner();\n\n        // Ensures Bluetooth is enabled on the device.  If Bluetooth is not currently enabled,\n        // fire an intent to display a dialog asking the user to grant permission to enable it.\n        if (!mBluetoothAdapter.isEnabled()) {\n            Log.d(TAG, \"BLUETOOTH IS DISABLED ON DEVICE\");\n        }\n\n        // Checks if Bluetooth is supported on the device.\n        if (mBluetoothAdapter == null) {\n            Log.d(TAG, \"BLUETOOTH NOT AVAILABLE\");\n            return;\n        }\n    }\n\n    public void startScan(){\n        scanLeDevice(true);\n    }\n\n    public void stopScan(){\n        scanLeDevice(false);\n    }\n\n    private void scanLeDevice(final boolean enable) {\n        Log.d(TAG, \"Bluetooth scanning...\");\n        if (enable) {\n            // Stops scanning after a pre-defined scan period.\n            mHandler.postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    mScanning = false;\n                    mBluetoothAdapter.stopLeScan(mLeScanCallback);\n                }\n            }, SCAN_PERIOD);\n\n            mScanning = true;\n            mBluetoothAdapter.startLeScan(mLeScanCallback);\n        } else {\n            mScanning = false;\n            mBluetoothAdapter.stopLeScan(mLeScanCallback);\n            //mBluetoothLeScanner.stopSca\n        }\n    }\n\n    // Device scan callback.\n    private BluetoothAdapter.LeScanCallback mLeScanCallback =\n            new BluetoothAdapter.LeScanCallback() {\n                @Override\n                public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {\n                    Log.d(TAG, \"Found device: \" + device.getName());\n                    if (device.getName() != null && device.getName().toLowerCase().contains(\"muse\")){\n                        Log.d(TAG, \"FOUND MUSE: \" + device.getName());\n                        if (mScanning) {\n                            mBluetoothAdapter.stopLeScan(mLeScanCallback);\n                            mScanning = false;\n                            //below needs to happen in a new thread/handler\n                            myMuse = new Muse(mContext, device.getName(), device.getAddress());\n                            myMuse.run();\n                        }\n                    }\n                }\n            };\n}\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/sensors/Muse.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.sensors;\n\n//thanks to MuServe for code\n//https://github.com/CaydenPierce/MuServe\n\nimport static android.content.Context.BIND_AUTO_CREATE;\n\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.ServiceConnection;\nimport android.os.IBinder;\nimport android.util.Log;\n\npublic class Muse extends Thread {\n    private String TAG = \"WearableAI_MuseHandler\";\n    private Context mContext;\n\n    private MuseService mMuseService;\n    private String mDeviceName;\n    private String mDeviceAddress;\n\n    // Code to manage Service lifecycle.\n    private final ServiceConnection mServiceConnection = new ServiceConnection() {\n\n        @Override\n        public void onServiceConnected(ComponentName componentName, IBinder service) {\n            Log.d(TAG, \"Muse Service connected'\");\n            mMuseService = ((MuseService.LocalBinder) service).getService();\n\n            if (!mMuseService.initialize()) {\n                return;\n            }\n            // Automatically connects to the device upon successful start-up initialization.\n            mMuseService.connect(mDeviceAddress);\n        }\n\n        @Override\n        public void onServiceDisconnected(ComponentName componentName) {\n            //mMuseService = null;\n        }\n    };\n\n    public Muse(Context context, String name, String address){\n        mContext = context;\n        mDeviceAddress = address;\n        mDeviceName = name;\n\n    }\n\n    public void run(){\n        connect();\n    }\n\n    public void connect(){\n        Intent startIntent = new Intent(mContext, MuseService.class);\n        mContext.startService(startIntent);\n                /*\n                Intent bleService = new Intent(this, MuseService.class);\n                getApplicationContext().startForegroundService(bleService); //start up the service first so it stays alive after shutting down the app*/\n        Intent gattServiceIntent = new Intent(mContext, MuseService.class);\n        mContext.bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE); //then bind to the service so we can communicate with it\n        //mMuseService.connect(mDeviceAddress);\n    }\n\n    public void disconnect(){\n        mMuseService.disconnect();\n        mContext.unbindService(mServiceConnection);\n        Intent myService = new Intent(mContext, MuseService.class);\n        mContext.stopService(myService);\n    }\n\n    private static IntentFilter makeGattUpdateIntentFilter() {\n        final IntentFilter intentFilter = new IntentFilter();\n        intentFilter.addAction(MuseService.ACTION_GATT_CONNECTED);\n        intentFilter.addAction(MuseService.ACTION_GATT_DISCONNECTED);\n        intentFilter.addAction(MuseService.ACTION_GATT_SERVICES_DISCOVERED);\n        intentFilter.addAction(MuseService.ACTION_DATA_AVAILABLE);\n        return intentFilter;\n    }\n\n//    // Handles various events fired by the Service.\n//    // ACTION_GATT_CONNECTED: connected to a GATT server.\n//    // ACTION_GATT_DISCONNECTED: disconnected from a GATT server.\n//    // ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services.\n//    // ACTION_DATA_AVAILABLE: received data from the device.  This can be a result of read\n//    //                        or notification operations.\n//    private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {\n//        @Override\n//        public void onReceive(Context context, Intent intent) {\n//            final String action = intent.getAction();\n//            if (MuseService.ACTION_GATT_CONNECTED.equals(action)) {\n//                mConnected = true;\n//                updateConnectionState(R.string.connected);\n//                invalidateOptionsMenu();\n//            } else if (MuseService.ACTION_GATT_DISCONNECTED.equals(action)) {\n//                mConnected = false;\n//                updateConnectionState(R.string.disconnected);\n//                invalidateOptionsMenu();\n//                clearUI();\n//            } else if (MuseService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {\n//                // Show all the supported services and characteristics on the user interface.\n//                displayGattServices(mMuseService.getSupportedGattServices());\n//                mMuseService.museSetup();\n//            } else if (MuseService.ACTION_DATA_AVAILABLE.equals(action)) {\n//                displayData(intent.getStringExtra(MuseService.EXTRA_DATA));\n//            }\n//        }\n//    };\n\n}\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/sensors/MuseService.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.sensors;\n\n//thanks to MuServe for most code\n\n/*\n * Copyright (C) 2013 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport android.app.Notification;\nimport android.app.NotificationChannel;\nimport android.app.NotificationManager;\nimport android.app.PendingIntent;\nimport android.app.Service;\nimport android.bluetooth.BluetoothAdapter;\nimport android.bluetooth.BluetoothDevice;\nimport android.bluetooth.BluetoothGatt;\nimport android.bluetooth.BluetoothGattCallback;\nimport android.bluetooth.BluetoothGattCharacteristic;\nimport android.bluetooth.BluetoothGattDescriptor;\nimport android.bluetooth.BluetoothGattService;\nimport android.bluetooth.BluetoothManager;\nimport android.bluetooth.BluetoothProfile;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Binder;\nimport android.os.Handler;\nimport android.os.IBinder;\nimport android.os.Looper;\n//import android.support.v4.app.NotificationCompat;\n//import android.support.v4.app.NotificationCompat;\n\nimport android.util.Log;\n\nimport com.wearableintelligencesystem.androidsmartglasses.MainActivity;\nimport com.wearableintelligencesystem.androidsmartglasses.R;\n\nimport java.net.DatagramSocket;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.UUID;\nimport androidx.core.app.NotificationCompat;\n\n/**\n * Service for managing connection and data communication with a GATT server hosted on a\n * given Bluetooth LE device.\n */\npublic class MuseService extends Service {\n    private final static String TAG = \"WearableAI_MuseService\";\n\n    private BluetoothManager mBluetoothManager;\n    private BluetoothAdapter mBluetoothAdapter;\n    private String mBluetoothDeviceAddress;\n    private BluetoothGatt mBluetoothGatt;\n    private int mConnectionState = STATE_DISCONNECTED;\n\n    private boolean shouldStream=true;\n\n    private static final int STATE_DISCONNECTED = 0;\n    private static final int STATE_CONNECTING = 1;\n    private static final int STATE_CONNECTED = 2;\n\n    public final static String ACTION_GATT_CONNECTED =\n            \"com.example.bluetooth.le.ACTION_GATT_CONNECTED\";\n    public final static String ACTION_GATT_DISCONNECTED =\n            \"com.example.bluetooth.le.ACTION_GATT_DISCONNECTED\";\n    public final static String ACTION_GATT_SERVICES_DISCOVERED =\n            \"com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED\";\n    public final static String ACTION_DATA_AVAILABLE =\n            \"com.example.bluetooth.le.ACTION_DATA_AVAILABLE\";\n    public final static String EXTRA_DATA =\n            \"com.example.bluetooth.le.EXTRA_DATA\";\n\n    public final static UUID UUID_HEART_RATE_MEASUREMENT =\n            UUID.fromString(BluetoothScanner.CLIENT_CHARACTERISTIC_CONFIG);\n\n    //list of chars we want to write to\n    //sample are received in this order : 44, 41, 38, 32, 35\n    public String charStreamUUID = \"273e0001-4c4d-454d-96be-f03bac821358\"; //write preset to this\n\n    public Object [] charTP9UUID = {\"273e0003-4c4d-454d-96be-f03bac821358\", 44};\n    public Object [] charAF7UUID = {\"273e0004-4c4d-454d-96be-f03bac821358\", 41};\n    public Object [] charAF8UUID = {\"273e0005-4c4d-454d-96be-f03bac821358\", 38};\n    public Object [] charTP10UUID = {\"273e0006-4c4d-454d-96be-f03bac821358\", 32};\n    public Object [] charRightAuxUUID = {\"273e0007-4c4d-454d-96be-f03bac821358\", 35};\n\n    public Object [][] elecChars = {charAF7UUID, charAF8UUID, charRightAuxUUID, charTP9UUID, charTP10UUID};\n\n    public Boolean lock = false; //check if bluetooth writer/reader is locked before trying to read/write\n    public int attempts = 0; //number of attempts to keep retrying connection to bluetooth\n    public Boolean tryStill = false; //should we keep retrying to connect, this option is for \"Croc'ing\" - reconnecting on disconnec\n    private NotificationManager mNotificationManager; //manage notifications...\n    private final static String FOREGROUND_CHANNEL_ID = \"MuServeAppStreamerService\";\n    public DatagramSocket udpSocket; //creating the socket here... this should be moved to its own service for understandability and to expand this to TCP\n    String csvName;\n\n    @Override\n    public void onDestroy(){\n        Log.d(\"UUID\", \"destroying streamer service\");\n        tryStill = false;\n        stopForeground(true);\n        disconnect();\n        close();\n        this.stopSelf();\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);\n        //create socket connection\n//        try {\n//            udpSocket = new DatagramSocket(9999);\n//        } catch (Exception e){\n//            Log.e(\"UUID\", e.toString());\n//        }\n//        csvName = Long.toString(System.currentTimeMillis() / 1000);\n    }\n\n\n    private Notification prepareNotification() {\n        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O &&\n                mNotificationManager.getNotificationChannel(FOREGROUND_CHANNEL_ID) == null) {\n            // The user-visible name of the channel.\n            CharSequence name = \"Test\"; //getString(R.string.text_value_radio_notification);\n            int importance = NotificationManager.IMPORTANCE_DEFAULT;\n            NotificationChannel mChannel = new NotificationChannel(FOREGROUND_CHANNEL_ID, name, importance);\n            mChannel.enableVibration(false);\n            mNotificationManager.createNotificationChannel(mChannel);\n        }\n        Intent notificationIntent = new Intent(this, MainActivity.class);\n        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {\n            notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);\n        } else {\n            notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        }\n\n        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);\n\n        NotificationCompat.Builder lNotificationBuilder;\n        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {\n            lNotificationBuilder = new NotificationCompat.Builder(this, FOREGROUND_CHANNEL_ID);\n        } else {\n            lNotificationBuilder = new NotificationCompat.Builder(this);\n        }\n        lNotificationBuilder\n                .setContentTitle(\"Title\")\n                .setSmallIcon(R.drawable.ic_launcher_background)\n                .setOnlyAlertOnce(true)\n                .setOngoing(true)\n                .setAutoCancel(true)\n                .setContentIntent(pendingIntent);\n        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {\n            lNotificationBuilder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);\n        }\n        return lNotificationBuilder.build();\n\n    }\n\n\n    @Override\n    public int onStartCommand (Intent intent, int flags, int startId){\n        Log.d(\"UUID\", \"starting ble\");\n        if (intent == null) {\n            stopForeground(true);\n            stopSelf();\n            return START_NOT_STICKY;\n        }\n\n        startForeground(69696969, prepareNotification());\n        return START_NOT_STICKY;\n    }\n\n    // Implements callback methods for GATT events that the app cares about.  For example,\n    // connection change and services discovered.\n    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {\n        @Override\n        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {\n            String intentAction;\n            if (newState == BluetoothProfile.STATE_CONNECTED) {\n                //tryStill = false;\n                intentAction = ACTION_GATT_CONNECTED;\n                mConnectionState = STATE_CONNECTED;\n                broadcastUpdate(intentAction);\n                Log.i(\"UUID\", \"Connected to GATT server.\");\n                // Attempts to discover services after successful connection.\n                Log.i(\"UUID\", \"Attempting to start service discovery:\" +\n                        mBluetoothGatt.discoverServices());\n\n            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {\n                attempts++;\n                intentAction = ACTION_GATT_DISCONNECTED;\n                mConnectionState = STATE_DISCONNECTED;\n                Log.i(\"UUID\", \"Disconnected from GATT server.\");\n                if (tryStill.equals(true)) {\n                    oldConn(mBluetoothDeviceAddress);\n                    broadcastUpdate(intentAction);\n                }\n            }\n        }\n\n        @Override\n        public void onServicesDiscovered(BluetoothGatt gatt, int status) {\n            if (status == BluetoothGatt.GATT_SUCCESS) {\n                broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);\n                //run on handler so we don't block this callback\n                final Handler handler = new Handler(Looper.myLooper());\n                handler.post(new Runnable() {\n                    @Override\n                    public void run() {\n                        museSetup();\n                    }\n                });\n            } else {\n                Log.w(TAG, \"onServicesDiscovered received: \" + status);\n            }\n        }\n\n        @Override\n        public void onCharacteristicRead(BluetoothGatt gatt,\n                                         BluetoothGattCharacteristic characteristic,\n                                         int status) {\n            if (status == BluetoothGatt.GATT_SUCCESS) {\n                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);\n            }\n        }\n\n        @Override\n        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status){\n            Log.d(\"UUID\", \"Char write success\");\n            lock = false;\n        }\n\n        @Override\n        public void onDescriptorWrite (BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status){\n            lock = false;\n        }\n\n        @Override\n        public void onCharacteristicChanged(BluetoothGatt gatt,\n                                            BluetoothGattCharacteristic characteristic) {\n            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);\n            byte [] values = characteristic.getValue();\n            String currUuid = characteristic.getUuid().toString();\n            int handle = 0;\n            for (int i = 0; i < elecChars.length; i++){\n                if (elecChars[i][0].equals(currUuid)){\n                    handle = (int) elecChars[i][1];\n                }\n            }\n            Log.d(TAG, \"Handle: \" + handle + \", Values: \" + values);\n\n//            if(shouldStream) {\n//                Streamer streamer = new Streamer(getApplicationContext(), ipAddress, ipPortNum, id);\n//                Object[] obj = new Object[4];\n//                obj[0] = udpSocket;\n//                obj[1] = values;\n//                obj[2] = csvName;\n//                obj[3] = handle;\n//                streamer.execute(obj);\n//            }\n        }\n    };\n\n    private void broadcastUpdate(final String action) { final Intent intent = new Intent(action);\n        sendBroadcast(intent);\n    }\n\n    private void broadcastUpdate(final String action,\n                                 final BluetoothGattCharacteristic characteristic) {\n        final Intent intent = new Intent(action);\n\n        // This is special handling for the Heart Rate Measurement profile.  Data parsing is\n        // carried out as per profile specifications:\n        // http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml\n        if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {\n            int flag = characteristic.getProperties();\n            int format = -1;\n            if ((flag & 0x01) != 0) {\n                format = BluetoothGattCharacteristic.FORMAT_UINT16;\n                Log.d(TAG, \"Heart rate format UINT16.\");\n            } else {\n                format = BluetoothGattCharacteristic.FORMAT_UINT8;\n                Log.d(TAG, \"Heart rate format UINT8.\");\n            }\n            final int heartRate = characteristic.getIntValue(format, 1);\n            Log.d(TAG, String.format(\"Received heart rate: %d\", heartRate));\n            intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));\n        } else {\n            // For all other profiles, writes the data formatted in HEX.\n            final byte[] data = characteristic.getValue();\n            if (data != null && data.length > 0) {\n                final StringBuilder stringBuilder = new StringBuilder(data.length);\n                for(byte byteChar : data)\n                    stringBuilder.append(String.format(\"%02X \", byteChar));\n                intent.putExtra(EXTRA_DATA, new String(data) + \"\\n\" + stringBuilder.toString());\n            }\n        }\n        sendBroadcast(intent);\n    }\n\n    public class LocalBinder extends Binder {\n        MuseService getService() {\n            return MuseService.this;\n        }\n    }\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        return mBinder;\n    }\n\n    @Override\n    public boolean onUnbind(Intent intent) {\n        // After using a given device, you should make sure that BluetoothGatt.close() is called\n        // such that resources are cleaned up properly.  In this particular example, close() is\n        // invoked when the UI is disconnected from the Service.\n        //close();\n        return super.onUnbind(intent);\n    }\n\n    private final IBinder mBinder = new LocalBinder();\n\n    public void setShouldStream(boolean stream){\n        shouldStream=stream;\n    }\n\n    /**\n     * Initializes a reference to the local Bluetooth adapter.\n     *\n     * @return Return true if the initialization is successful.\n     */\n    public boolean initialize() {\n\n        // For API level 18 and above, get a reference to BluetoothAdapter through\n        // BluetoothManager.\n        if (mBluetoothManager == null) {\n            mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);\n            if (mBluetoothManager == null) {\n                Log.e(TAG, \"Unable to initialize BluetoothManager.\");\n                return false;\n            }\n        }\n\n        mBluetoothAdapter = mBluetoothManager.getAdapter();\n        if (mBluetoothAdapter == null) {\n            Log.e(TAG, \"Unable to obtain a BluetoothAdapter.\");\n            return false;\n        }\n\n        return true;\n    }\n\n    /**\n     * Connects to the GATT server hosted on the Bluetooth LE device.\n     *\n     * @param address The device address of the destination device.\n     *\n     * @return Return true if the connection is initiated successfully. The connection result\n     *         is reported asynchronously through the\n     *         {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}\n     *         callback.\n     */\n    public boolean connect(final String address) {\n        Boolean result;\n\n        if (mBluetoothAdapter == null || address == null) {\n            Log.w(TAG, \"BluetoothAdapter not initialized or unspecified address.\");\n            return false;\n        }\n\n        result = oldConn(address); //first try to connect with an old connection\n\n        if (result.equals(true)){\n            return true;\n        }\n\n        final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);\n        if (device == null) {\n            Log.w(TAG, \"Device not found.  Unable to connect.\");\n            return false;\n        }\n\n        // We want to directly connect to the device, so we are setting the autoConnect\n        // parameter to false.\n        mBluetoothGatt = device.connectGatt(this, false, mGattCallback);\n        Log.d(TAG, \"Trying to create a new connection.\");\n        mBluetoothDeviceAddress = address;\n        mConnectionState = STATE_CONNECTING;\n        attempts = 0; //set attempts to 0 so the callback will keep retrying connection (3 times)\n        tryStill = true;\n\n        return true;\n    }\n\n    public boolean oldConn(final String address){\n        // Previously connected device.  Try to reconnect.\n        if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)\n                && mBluetoothGatt != null) {\n            Log.d(TAG, \"Trying to use an existing mBluetoothGatt for connection.\");\n            if (mBluetoothGatt.connect()) {\n                mConnectionState = STATE_CONNECTING;\n                return true;\n            } else {\n                return false;\n            }\n        }\n        return false;\n    }\n\n    public void museSetup(){\n\n\n        //we have to setup the muse notifications and proper preset\n        List serve = getSupportedGattServices();\n        Log.d(\"UUID\", \"starting muse setup\");\n        for (int i = 0; i < serve.size(); i++){\n            BluetoothGattService currServe = (BluetoothGattService) serve.get(i);\n            discoverCharacteristics(currServe);\n            ArrayList chars = giveCharacteristics(currServe);\n            for (int j = 0; j < chars.size(); j++){\n                BluetoothGattCharacteristic currChar = (BluetoothGattCharacteristic) chars.get(j);\n                for (int k = 0; k < elecChars.length; k++){\n                    if (elecChars[k][0].equals(currChar.getUuid().toString())) {\n                        mBluetoothGatt.setCharacteristicNotification(currChar, true); //enable on android\n                        BluetoothGattDescriptor descriptor = currChar.getDescriptor(UUID.fromString(BluetoothScanner.CLIENT_CHARACTERISTIC_CONFIG));\n                        while (lock == true) {\n                            //spinning block\n                        }\n                        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);\n                        lock = true;\n                        Log.d(\"SUCCESS\", \"subscribe result: \" + Boolean.toString(mBluetoothGatt.writeDescriptor(descriptor))); //enable on muse\n                        Log.d(\"UUID\", \"subscribed to: \" + currChar.getUuid().toString());\n                    }\n                }\n                if (charStreamUUID.equals(currChar.getUuid().toString())){\n                    //write presets to this guy\n                    Log.d(\"UUID\", \"Writing presets to muse on uuid: \" + currChar.getUuid().toString());\n                    byte[] preset1 = new byte[]{(byte) 0x02, (byte) 0x64, (byte) 0x0a};\n                    byte[] preset2 = new byte[]{(byte) 0x04, (byte) 0x70, (byte) 0x32, (byte) 0x30, (byte) 0x0a};\n                    BluetoothGattDescriptor descriptor = currChar.getDescriptor(UUID.fromString(BluetoothScanner.CLIENT_CHARACTERISTIC_CONFIG));\n                    lock = true;\n                    currChar.setValue(preset2);\n                    Log.d(\"SUCCESS\", \"charStream: \" + Boolean.toString(mBluetoothGatt.writeCharacteristic(currChar))); //write preset1 to muse\n                    while (lock == true) {\n                        //spinning block\n                    }\n                    currChar.setValue(preset1);\n                    lock = true;\n                    Log.d(\"SUCCESS\", \"charStream: \" + Boolean.toString(mBluetoothGatt.writeCharacteristic(currChar))); //write preset2 to muse\n                }\n            }\n        }\n\n\n    }\n\n    /**\n     * Disconnects an existing connection or cancel a pending connection. The disconnection result\n     * is reported asynchronously through the\n     * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}\n     * callback.\n     */\n    public void disconnect() {\n        tryStill = false;\n        if (mBluetoothAdapter == null || mBluetoothGatt == null) {\n            Log.w(TAG, \"BluetoothAdapter not initialized\");\n            return;\n        }\n        close();\n    }\n\n    /**\n     * After using a given BLE device, the app must call this method to ensure resources are\n     * released properly.\n     */\n    public void close() {\n        if (mBluetoothGatt == null) {\n            return;\n        }\n        mBluetoothGatt.disconnect();\n        mBluetoothGatt.close();\n        mBluetoothGatt = null;\n        udpSocket.close();\n    }\n\n    /**\n     * Request a read on a given {@code BluetoothGattCharacteristic}. The read result is reported\n     * asynchronously through the {@code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)}\n     * callback.\n     *\n     * @param characteristic The characteristic to read from.\n     */\n    public void readCharacteristic(BluetoothGattCharacteristic characteristic) {\n        if (mBluetoothAdapter == null || mBluetoothGatt == null) {\n            Log.w(TAG, \"BluetoothAdapter not initialized\");\n            return;\n        }\n        mBluetoothGatt.readCharacteristic(characteristic);\n    }\n\n//    /**\n//     * Enables or disables notification on a give characteristic.\n//     *\n//     * @param characteristic Characteristic to act on.\n//     * @param enabled If true, enable notification.  False otherwise.\n//     */\n//    public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,\n//                                              boolean enabled) {\n//        if (mBluetoothAdapter == null || mBluetoothGatt == null) {\n//            Log.w(TAG, \"BluetoothAdapter not initialized\");\n//            return;\n//        }\n//        mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);\n//\n//        // This is specific to Heart Rate Measurement.\n//        if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {\n//            BluetoothGattDescriptor descriptor = characteristic.getDescriptor(\n//                    UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));\n//            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);\n//            mBluetoothGatt.writeDescriptor(descriptor);\n//        }\n//    }\n\n    /*public void setupMuse() {\n        if (mBluetoothAdapter == null || mBluetoothGatt == null) {\n            Log.w(TAG, \"BluetoothAdapter not initialized\");\n            return;\n        }\n        mBluetoothGatt.setCharacteristicNotification(characteristic, enabled); //enable on android\n        mBluetoothGatt.writeDescriptor(descriptor); //enable on muse\n\n    }*/\n\n    /**\n     * Retrieves a list of supported GATT services on the connected device. This should be\n     * invoked only after {@code BluetoothGatt#discoverServices()} completes successfully.\n     *\n     * @return A {@code List} of supported services.\n     */\n    public List<BluetoothGattService> getSupportedGattServices() {\n        if (mBluetoothGatt == null) {\n            Log.d(\"UUID\", \"it was null\");\n            return null;\n        }\n\n        return mBluetoothGatt.getServices();\n    }\n\n    private void discoverCharacteristics(BluetoothGattService service) {\n        for (BluetoothGattCharacteristic gattCharacteristic : service.getCharacteristics()) {\n            Log.d(TAG, \"Discovered UUID: \" + gattCharacteristic.getUuid());\n        }\n\n    }\n    private ArrayList<BluetoothGattCharacteristic> giveCharacteristics(BluetoothGattService service) {\n        ArrayList<BluetoothGattCharacteristic> chars = new ArrayList<BluetoothGattCharacteristic>();\n        for (BluetoothGattCharacteristic gattCharacteristic : service.getCharacteristics()) {\n            Log.d(TAG, \"Discovered UUID: \" + gattCharacteristic.getUuid());\n            chars.add(gattCharacteristic);\n        }\n\n        return chars;\n    }\n}\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/ui/ASGFragment.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.ui;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.Bundle;\nimport android.text.Html;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\nimport androidx.navigation.NavController;\nimport androidx.navigation.Navigation;\n\nimport com.wearableintelligencesystem.androidsmartglasses.R;\nimport com.wearableintelligencesystem.androidsmartglasses.ASPClientSocket;\nimport com.wearableintelligencesystem.androidsmartglasses.MainActivity;\nimport com.wearableintelligencesystem.androidsmartglasses.archive.GlboxClientSocket;\nimport com.wearableintelligencesystem.androidsmartglasses.comms.MessageTypes;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\npublic class ASGFragment extends Fragment {\n    protected String fragmentLabel;\n    protected NavController navController;\n\n    protected MainActivity mainActivity;\n\n    @Override\n    public void onResume(){\n        super.onResume();\n        getActivity().registerReceiver(myReceiver, makeComputeUpdateIntentFilter());\n    }\n\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        navController = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);\n        mainActivity = ((MainActivity)getActivity());\n    }\n\n    @Override\n    public void onPause(){\n        super.onPause();\n        getActivity().unregisterReceiver(myReceiver);\n    }\n\n    private BroadcastReceiver myReceiver = new BroadcastReceiver() {\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            onBroadcastReceive(context, intent);\n        }\n    };\n\n    protected void onBroadcastReceive(Context context, Intent intent){\n        //pass, should be overridden\n    }\n\n    public IntentFilter makeComputeUpdateIntentFilter() {\n        final IntentFilter intentFilter = new IntentFilter();\n        return intentFilter;\n    }\n\n}\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/ui/CommandPostUi.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.ui;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.Bundle;\nimport android.text.Editable;\nimport android.text.Html;\nimport android.text.TextUtils;\nimport android.text.TextWatcher;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.wearableintelligencesystem.androidsmartglasses.R;\nimport com.wearableintelligencesystem.androidsmartglasses.ASPClientSocket;\nimport com.wearableintelligencesystem.androidsmartglasses.archive.GlboxClientSocket;\nimport com.wearableintelligencesystem.androidsmartglasses.comms.MessageTypes;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\nimport org.w3c.dom.Text;\n\npublic class CommandPostUi extends ASGFragment {\n    private final String TAG = \"WearableAi_CommandPostUi\";\n\n    private TextView commandArgsTextView;\n    private TextView previousCommandString;\n\n    public CommandPostUi() {\n        fragmentLabel = \"Command Received\";\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container,\n                             Bundle savedInstanceState) {\n        // Inflate the layout for this fragment\n        return inflater.inflate(R.layout.command_post_fragment, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        super.onViewCreated(view, savedInstanceState);\n        previousCommandString = view.findViewById(R.id.main_title);\n        setupCommandArgsTextView(view);\n        //previousCommandString.setText(getArguments().getString(MessageTypes.INPUT_WAKE_WORD) + \" \" + getArguments().getString(MessageTypes.INPUT_VOICE_COMMAND_NAME));\n        previousCommandString.setText(\"Command: \" + getArguments().getString(MessageTypes.INPUT_VOICE_COMMAND_NAME));\n    }\n\n    @Override\n    public void onResume(){\n        super.onResume();\n        getActivity().registerReceiver(voiceArgsReceiver, makeComputeUpdateIntentFilter());\n    }\n\n    @Override\n    public void onPause(){\n        super.onPause();\n        getActivity().unregisterReceiver(voiceArgsReceiver);\n    }\n\n    private BroadcastReceiver voiceArgsReceiver = new BroadcastReceiver() {\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            try {\n                JSONObject data = new JSONObject(intent.getStringExtra(ASPClientSocket.RAW_MESSAGE_JSON_STRING));\n                String typeOf = data.getString(MessageTypes.MESSAGE_TYPE_LOCAL);\n                if (typeOf.equals(MessageTypes.VOICE_COMMAND_STREAM_EVENT)) {\n                    if (data.getString(MessageTypes.VOICE_COMMAND_STREAM_EVENT_TYPE).equals(MessageTypes.COMMAND_ARGS_EVENT_TYPE)) {\n                        String args = data.getString(MessageTypes.INPUT_VOICE_STRING);\n                        commandArgsTextView.setText(args);\n                    }\n                }\n            } catch (JSONException e){\n                e.printStackTrace();\n            }\n        }\n    };\n\n\n    private void setupCommandArgsTextView(View view){\n        commandArgsTextView = view.findViewById(R.id.command_args);\n\n        commandArgsTextView.addTextChangedListener(new TextWatcher() {\n            @Override\n            public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n\n            }\n\n            @Override\n            public void onTextChanged(CharSequence s, int start, int before, int count) {\n                UiUtils.scrollToBottom(commandArgsTextView);\n            }\n\n            @Override\n            public void afterTextChanged(Editable s) {\n\n            }\n        });\n        UiUtils.scrollToBottom(commandArgsTextView);\n    }\n\n    public IntentFilter makeComputeUpdateIntentFilter() {\n        final IntentFilter intentFilter = new IntentFilter();\n        intentFilter.addAction(MessageTypes.VOICE_COMMAND_STREAM_EVENT);\n\n        return intentFilter;\n    }\n\n}"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/ui/CommandResolveUi.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.ui;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.wearableintelligencesystem.androidsmartglasses.R;\nimport com.wearableintelligencesystem.androidsmartglasses.ASPClientSocket;\nimport com.wearableintelligencesystem.androidsmartglasses.MainActivity;\nimport com.wearableintelligencesystem.androidsmartglasses.comms.MessageTypes;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\npublic class CommandResolveUi extends ASGFragment {\n    private final String TAG = \"WearableAi_CommandResolveUi\";\n\n    private TextView voiceResponseTextView;\n\n    public CommandResolveUi() {\n        fragmentLabel = \"Command Resolved\";\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container,\n                             Bundle savedInstanceState) {\n        // Inflate the layout for this fragment\n        return inflater.inflate(R.layout.command_resolve_fragment, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        super.onViewCreated(view, savedInstanceState);\n\n        boolean success = getArguments().getBoolean(\"success\", false);\n        String message = getArguments().getString(\"message\", null);\n\n        TextView successTextView = view.findViewById(R.id.success_message);\n        voiceResponseTextView = view.findViewById(R.id.text_response_text_view);\n        TextView commandResponseStringTextView = view.findViewById(R.id.command_response_description);\n        commandResponseStringTextView.setText(message);\n\n        ImageView successImageView = view.findViewById(R.id.command_success_icon);\n\n        if(success){\n            successImageView.setImageResource(R.drawable.ic_command_success);\n            successTextView.setText(\"Success\");\n        }\n        else{\n            successImageView.setImageResource(R.drawable.ic_command_failed);\n            successTextView.setText(\"Failed\");\n        }\n    }\n\n    @Override\n    protected void onBroadcastReceive(Context context, Intent intent){\n        String voiceResponse = intent.getStringExtra(MainActivity.VOICE_TEXT_RESPONSE_TEXT);\n        updateVoiceResponse(voiceResponse);\n    }\n\n    private void updateVoiceResponse(String voiceResponse) {\n        voiceResponseTextView.setText(voiceResponse);\n    }\n\n    @Override\n    public IntentFilter makeComputeUpdateIntentFilter() {\n        final IntentFilter intentFilter = new IntentFilter();\n        intentFilter.addAction(MainActivity.VOICE_TEXT_RESPONSE);\n\n        return intentFilter;\n    }\n}\n\n\n\n\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/ui/ConvoModeUi.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.ui;\n\nimport android.content.BroadcastReceiver;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.Bundle;\nimport android.text.Html;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.content.ComponentName;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Button;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\nimport androidx.navigation.NavController;\nimport androidx.navigation.Navigation;\n\nimport com.wearableintelligencesystem.androidsmartglasses.R;\nimport com.wearableintelligencesystem.androidsmartglasses.ASPClientSocket;\nimport com.wearableintelligencesystem.androidsmartglasses.MainActivity;\nimport com.wearableintelligencesystem.androidsmartglasses.archive.GlboxClientSocket;\nimport com.wearableintelligencesystem.androidsmartglasses.comms.MessageTypes;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\npublic class ConvoModeUi extends ASGFragment {\n    private final String TAG = \"WearableAi_ConvoModeUIFragment\";\n\n    //convo mode ui\n    TextView convoModeContentTextView;\n\n    public ConvoModeUi() {\n        fragmentLabel = \"ConvoMode\";\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container,\n                             Bundle savedInstanceState) {\n        // Inflate the layout for this fragment\n        return inflater.inflate(R.layout.convo_mode_fragment, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        super.onViewCreated(view, savedInstanceState);\n\n        convoModeContentTextView = (TextView) getActivity().findViewById(R.id.references_text_view);\n    }\n\n    @Override\n    protected void onBroadcastReceive(Context context, Intent intent){\n        try {\n            JSONObject data = new JSONObject(intent.getStringExtra(ASPClientSocket.RAW_MESSAGE_JSON_STRING));\n            //parse out the name of the mode\n            JSONArray refsArr = new JSONArray(data.getString(MessageTypes.REFERENCES));\n            Log.d(TAG, \"We got references: \" + refsArr.toString());\n            showPotentialReferences(refsArr);\n        } catch (JSONException e){\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public IntentFilter makeComputeUpdateIntentFilter() {\n        final IntentFilter intentFilter = new IntentFilter();\n        intentFilter.addAction(MessageTypes.REFERENCE_SELECT_REQUEST);\n\n        return intentFilter;\n    }\n\n    private void showPotentialReferences(JSONArray refs) {\n            String refString = \"\";\n\n            try {\n                for (int i = 0; i < refs.length(); i++) {\n                    JSONObject ref = (JSONObject) refs.get(i);\n                    refString = refString + ref.getString(\"selector_char\") + \" - \" + ref.getString(\"title\") + '\\n';\n                }\n            } catch (JSONException e) {\n                e.printStackTrace();\n                return;\n            }\n            convoModeContentTextView.setText(refString);\n    }\n\n}\n\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/ui/HomePromptUi.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.ui;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\nimport androidx.navigation.NavController;\n\nimport com.wearableintelligencesystem.androidsmartglasses.R;\n\npublic class HomePromptUi extends Fragment {\n    private  final String TAG = \"WearableAi_HomePromptUIFragment\";\n\n    private final String fragmentLabel = \"HomePrompt\";\n\n    private NavController navController;\n\n    public HomePromptUi() {\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container,\n                             Bundle savedInstanceState) {\n        // Inflate the layout for this fragment\n        return inflater.inflate(R.layout.home_prompt_fragment, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n    }\n\n    @Override\n    public void onResume(){\n        super.onResume();\n    }\n\n    @Override\n    public void onPause(){\n        super.onPause();\n    }\n}\n\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/ui/LanguageTranslateUi.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.ui;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.Bundle;\nimport android.os.Message;\nimport android.text.Editable;\nimport android.text.Html;\nimport android.text.Spanned;\nimport android.text.TextUtils;\nimport android.text.TextWatcher;\nimport android.text.method.ScrollingMovementMethod;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\nimport androidx.navigation.NavController;\n\nimport com.wearableintelligencesystem.androidsmartglasses.R;\nimport com.wearableintelligencesystem.androidsmartglasses.ASPClientSocket;\nimport com.wearableintelligencesystem.androidsmartglasses.archive.GlboxClientSocket;\nimport com.wearableintelligencesystem.androidsmartglasses.comms.MessageTypes;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.ArrayList;\n\npublic class LanguageTranslateUi extends Fragment {\n    private  final String TAG = \"WearableAi_LanguageTranslateUIFragment\";\n\n    private final String fragmentLabel = \"Language Translate\";\n\n\n    //translate ui\n    ArrayList<Spanned> translateTextHolder = new ArrayList<>();\n    int translateTextHolderSizeLimit = 10; // how many lines maximum in the text holder\n    TextView translateText;\n\n    //scroll logic\n    boolean currentlyScrolling = false;\n\n    //update transcript logic\n    long lastIntermediateMillis = 0;\n    long intermediateTranscriptPeriod = 40; //milliseconds\n\n    public LanguageTranslateUi() {\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container,\n                             Bundle savedInstanceState) {\n        // Inflate the layout for this fragment\n        return inflater.inflate(R.layout.translate_mode_view, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        //live life captions mode gui setup\n        translateText = (TextView) getActivity().findViewById(R.id.translatetextview);\n        translateText.setMovementMethod(new ScrollingMovementMethod());\n        translateText.setText(getCurrentTranslateScrollText());\n\n        translateText.addTextChangedListener(new TextWatcher() {\n            @Override\n            public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n\n            }\n\n            @Override\n            public void onTextChanged(CharSequence s, int start, int before, int count) {\n                scrollToBottom(translateText);\n            }\n\n            @Override\n            public void afterTextChanged(Editable s) {\n\n            }\n        });\n        translateText.setText(getCurrentTranslateScrollText());\n        scrollToBottom(translateText);\n    }\n\n    @Override\n    public void onResume(){\n        super.onResume();\n        getActivity().registerReceiver(llcReceiver, makeComputeUpdateIntentFilter());\n    }\n\n    @Override\n    public void onPause(){\n        super.onPause();\n        getActivity().unregisterReceiver(llcReceiver);\n    }\n\n    private BroadcastReceiver llcReceiver = new BroadcastReceiver() {\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            final String action = intent.getAction();\n            if (MessageTypes.TRANSLATE_TEXT_RESULT.equals(action)) {\n                try {\n                    JSONObject data = new JSONObject(intent.getStringExtra(ASPClientSocket.RAW_MESSAGE_JSON_STRING));\n                    String translatedTextString = data.getString(MessageTypes.TRANSLATE_TEXT_RESULT_DATA);\n                    updateTranslatedText(translatedTextString);\n                } catch (JSONException e){\n                    e.printStackTrace();\n                }\n            }\n        }\n    };\n\n    private static IntentFilter makeComputeUpdateIntentFilter() {\n        final IntentFilter intentFilter = new IntentFilter();\n        intentFilter.addAction(MessageTypes.TRANSLATE_TEXT_RESULT);\n\n        return intentFilter;\n    }\n\n    private void scrollToBottom(TextView tv) {\n        if (!currentlyScrolling) {\n            tv.post(new Runnable() {\n                @Override\n                public void run() {\n                    currentlyScrolling = true;\n                    int lc = tv.getLineCount();\n                    if (lc == 0) {\n                        return;\n                    }\n                    tv.scrollTo(0, tv.getBottom());\n                    int scrollAmount = tv.getLayout().getLineTop(lc) - tv.getHeight();\n                    // if there is no need to scroll, scrollAmount will be <=0\n                    if (scrollAmount > 0)\n                        tv.scrollTo(0, scrollAmount);\n                    else\n                        tv.scrollTo(0, 0);\n                    currentlyScrolling = false;\n                }\n            });\n        }\n    }\n\n    private Spanned getCurrentTranslateScrollText() {\n        Spanned current_translate_scroll = Html.fromHtml(\"<div></div>\");\n        //limit textHolder to our maximum size\n        while ((translateTextHolder.size() - translateTextHolderSizeLimit) > 0){\n            translateTextHolder.remove(0);\n        }\n        for (int i = 0; i < translateTextHolder.size(); i++) {\n            //current_transcript_scroll = current_transcript_scroll + textHolder.get(i) + \"\\n\" + \"\\n\";\n            if (i == 0) {\n                current_translate_scroll = translateTextHolder.get(i);\n            } else {\n                current_translate_scroll = (Spanned) TextUtils.concat(current_translate_scroll, translateTextHolder.get(i));\n            }\n        }\n        return current_translate_scroll;\n    }\n\n\n    private void updateTranslatedText(String translationResultString){\n        translateTextHolder.add(Html.fromHtml(\"<p>\" + translationResultString + \"</p>\"));\n        translateText.setText(getCurrentTranslateScrollText());\n    }\n\n}\n\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/ui/LiveLifeCaptionsUi.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.ui;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.Bundle;\nimport android.os.Message;\nimport android.text.Editable;\nimport android.text.Html;\nimport android.text.Spanned;\nimport android.text.TextUtils;\nimport android.text.TextWatcher;\nimport android.text.method.ScrollingMovementMethod;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\nimport androidx.navigation.NavController;\n\nimport com.wearableintelligencesystem.androidsmartglasses.R;\nimport com.wearableintelligencesystem.androidsmartglasses.ASPClientSocket;\nimport com.wearableintelligencesystem.androidsmartglasses.archive.GlboxClientSocket;\nimport com.wearableintelligencesystem.androidsmartglasses.comms.MessageTypes;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.ArrayList;\n\npublic class LiveLifeCaptionsUi extends Fragment {\n    private  final String TAG = \"WearableAi_LiveLifeCaptionsUIFragment\";\n\n    private final String fragmentLabel = \"LiveLifeCaptions\";\n\n    private NavController navController;\n\n    //live life captions ui\n    ArrayList<Spanned> textHolder = new ArrayList<>();\n    int textHolderSizeLimit = 20; // how many lines maximum in the text holder\n    TextView liveLifeCaptionsText;\n\n    boolean currentlyScrolling = false;\n\n    long lastIntermediateMillis = 0;\n    long intermediateTranscriptPeriod = 40; //milliseconds\n\n    public LiveLifeCaptionsUi() {\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container,\n                             Bundle savedInstanceState) {\n        // Inflate the layout for this fragment\n        return inflater.inflate(R.layout.live_life_caption_text, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        liveLifeCaptionsText = (TextView) view.findViewById(R.id.livelifecaptionstextview);\n        liveLifeCaptionsText.setMovementMethod(new ScrollingMovementMethod());\n        liveLifeCaptionsText.setText(getCurrentTranscriptScrollText());\n\n        liveLifeCaptionsText.addTextChangedListener(new TextWatcher() {\n            @Override\n            public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n\n            }\n\n            @Override\n            public void onTextChanged(CharSequence s, int start, int before, int count) {\n                UiUtils.scrollToBottom(liveLifeCaptionsText);\n            }\n\n            @Override\n            public void afterTextChanged(Editable s) {\n\n            }\n        });\n\n        liveLifeCaptionsText.setText(getCurrentTranscriptScrollText());\n        UiUtils.scrollToBottom(liveLifeCaptionsText);\n        //navController = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);\n    }\n\n    @Override\n    public void onResume(){\n        super.onResume();\n        getActivity().registerReceiver(llcReceiver, makeComputeUpdateIntentFilter());\n    }\n\n    @Override\n    public void onPause(){\n        super.onPause();\n        getActivity().unregisterReceiver(llcReceiver);\n    }\n\n    private BroadcastReceiver llcReceiver = new BroadcastReceiver() {\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            Log.d(TAG, \"LLC called\");\n            Log.d(TAG, intent.toString());\n            String action = intent.getAction();\n            if (action.equals(MessageTypes.SCROLLING_TEXT_VIEW_FINAL)) {\n                try {\n                    String transcript = intent.getStringExtra(MessageTypes.SCROLLING_TEXT_VIEW_TEXT);\n//                    JSONObject transcript_object = new JSONObject(intent.getStringExtra(GlboxClientSocket.FINAL_REGULAR_TRANSCRIPT));\n////                        JSONObject nlp = transcript_object.getJSONObject(\"nlp\");\n////                        JSONArray nouns = nlp.getJSONArray(\"nouns\");\n                    JSONArray nouns = new JSONArray(); //for now, since we haven't implemented NLP on ASP, we just make this empty\n//                    String transcript = transcript_object.getString(MessageTypes.SCROLLING_TEXT_VIEW_TEXT);\n                    if ((nouns.length() == 0)) {\n                        textHolder.add(Html.fromHtml(\"<p>\" + transcript.trim() + \"</p>\"));\n                    } else {\n                        //add text to a string and highlight properly the things we want to highlight (e.g. proper nouns)\n                        String textBuilder = \"<p>\";\n                        int prev_end = 0;\n                        for (int i = 0; i < nouns.length(); i++) {\n                            String noun = nouns.getJSONObject(i).getString(\"noun\");\n                            int start = nouns.getJSONObject(i).getInt(\"start\");\n                            int end = nouns.getJSONObject(i).getInt(\"end\");\n\n                            //dont' drop the words before the first noun\n                            if (i == 0) {\n                                textBuilder = textBuilder + transcript.substring(0, start);\n                            } else { //add in the transcript between previous noun and this one\n                                textBuilder = textBuilder + transcript.substring(prev_end, start);\n                            }\n\n                            //add in current colored noun\n                            textBuilder = textBuilder + \"<font color='#00FF00'><u>\" + transcript.substring(start, end) + \"</u></font>\";\n\n                            //add in end of transcript if we just added the last noun\n                            if (i == (nouns.length() - 1)) {\n                                textBuilder = textBuilder + transcript.substring(end);\n                            }\n\n                            //set this noun end to be the previous noun end for next loop\n                            prev_end = end;\n                        }\n                        textBuilder = textBuilder + \"</p>\";\n                        textHolder.add(Html.fromHtml(textBuilder));\n                    }\n                    liveLifeCaptionsText.setText(getCurrentTranscriptScrollText());\n                } catch (JSONException e) {\n                    e.printStackTrace();\n                }\n            } else if (action.equals(MessageTypes.SCROLLING_TEXT_VIEW_INTERMEDIATE)) {\n                        //only update this transcript if it's been n milliseconds since the last intermediate update\n                        if ((System.currentTimeMillis() - lastIntermediateMillis) > intermediateTranscriptPeriod) {\n                            lastIntermediateMillis = System.currentTimeMillis();\n                            String intermediate_transcript = intent.getStringExtra(MessageTypes.SCROLLING_TEXT_VIEW_TEXT);\n                            liveLifeCaptionsText.setText(TextUtils.concat(getCurrentTranscriptScrollText(), Html.fromHtml(\"<p>\" + intermediate_transcript.trim() + \"</p>\")));\n                        }\n            } else if (intent.hasExtra(GlboxClientSocket.COMMAND_RESPONSE)) {\n                        String command_response_text = intent.getStringExtra(GlboxClientSocket.COMMAND_RESPONSE);\n                        //change newlines to <br/>\n                        command_response_text = command_response_text.replaceAll(\"\\n\", \"<br/>\");\n                        textHolder.add(Html.fromHtml(\"<p><font color='#00CC00'>\" + command_response_text.trim() + \"</font></p>\"));\n                        liveLifeCaptionsText.setText(getCurrentTranscriptScrollText());\n            } else {\n                Log.d(TAG, \"GOT SOMETHING ELSE\");\n            }\n\n        }\n    };\n\n    private static IntentFilter makeComputeUpdateIntentFilter() {\n        final IntentFilter intentFilter = new IntentFilter();\n        intentFilter.addAction(ASPClientSocket.ACTION_RECEIVE_MESSAGE);\n        intentFilter.addAction(GlboxClientSocket.ACTION_RECEIVE_TEXT);\n        intentFilter.addAction(MessageTypes.REFERENCE_SELECT_REQUEST);\n        intentFilter.addAction(MessageTypes.SCROLLING_TEXT_VIEW_FINAL);\n        intentFilter.addAction(MessageTypes.SCROLLING_TEXT_VIEW_INTERMEDIATE);\n\n        return intentFilter;\n    }\n\n    private Spanned getCurrentTranscriptScrollText() {\n        Spanned current_transcript_scroll = Html.fromHtml(\"<div></div>\");\n        //limit textHolder to our maximum size\n        while ((textHolder.size() - textHolderSizeLimit) > 0){\n            textHolder.remove(0);\n        }\n        for (int i = 0; i < textHolder.size(); i++) {\n            //current_transcript_scroll = current_transcript_scroll + textHolder.get(i) + \"\\n\" + \"\\n\";\n            if (i == 0) {\n                current_transcript_scroll = textHolder.get(i);\n            } else {\n                current_transcript_scroll = (Spanned) TextUtils.concat(current_transcript_scroll, textHolder.get(i));\n            }\n        }\n        return current_transcript_scroll;\n    }\n\n}\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/ui/ObjectTranslateUi.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.ui;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.util.Log;\nimport android.view.KeyEvent;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.wearableintelligencesystem.androidsmartglasses.R;\nimport com.wearableintelligencesystem.androidsmartglasses.ASPClientSocket;\nimport com.wearableintelligencesystem.androidsmartglasses.comms.MessageTypes;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\nimport org.w3c.dom.Text;\n\nimport java.util.List;\n\npublic class ObjectTranslateUi extends ASGFragment {\n    private final String TAG = \"WearableAi_ObjectTranslateUi\";\n\n    private TextView languageName;\n    private TextView nameOfObjectinSourceLanguage;\n    private TextView nameOfObjectInTargetLanguage;\n\n    public ObjectTranslateUi() {\n        fragmentLabel = \"Object Translate\";\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container,\n                             Bundle savedInstanceState) {\n        // Inflate the layout for this fragment\n        return inflater.inflate(R.layout.object_translate_mode_view, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        super.onViewCreated(view, savedInstanceState);\n\n        nameOfObjectinSourceLanguage = (TextView) view.findViewById(R.id.nameOfObjectinSourceLanguage);\n        nameOfObjectInTargetLanguage = (TextView) view.findViewById(R.id.nameOfObjectinTargetLanguage);\n        languageName = (TextView) view.findViewById(R.id.languageName);\n    }\n\n\n    @Override\n    protected void onBroadcastReceive(Context context, Intent intent){\n        Log.d(\"hereee\", \"kjbnkjb\");\n        final String action = intent.getAction();\n            try {\n                JSONObject data = new JSONObject(intent.getStringExtra(ASPClientSocket.RAW_MESSAGE_JSON_STRING));\n                String typeOf = data.getString(MessageTypes.MESSAGE_TYPE_LOCAL);\n                //preview object translation result data\n                if (typeOf.equals(MessageTypes.OBJECT_TRANSLATION_RESULT)) {\n                    showObjectTranslationResults((new JSONObject(data.getString(MessageTypes.OBJECT_TRANSLATION_RESULT_DATA))));\n                }\n            } catch (JSONException e){\n                e.printStackTrace();\n            }\n    }\n\n    @Override\n    public void onPause(){\n        super.onPause();\n    }\n\n    @Override\n    public void onResume(){\n        super.onResume();\n    }\n\n    private void showObjectTranslationResults(JSONObject objectTranslatedData){\n        //show the reference\n        try {\n            nameOfObjectinSourceLanguage.setText(objectTranslatedData.getString(\"source\"));\n            nameOfObjectInTargetLanguage.setText(objectTranslatedData.getString(\"target\"));\n            //languageName.setText(objectTranslatedData.getString(\"French\"));\n        } catch (JSONException e) {\n            e.printStackTrace();\n        }\n\n    }\n\n    @Override\n    public IntentFilter makeComputeUpdateIntentFilter() {\n        final IntentFilter intentFilter = new IntentFilter();\n        intentFilter.addAction(ASPClientSocket.ACTION_UI_DATA);\n\n        return intentFilter;\n    }\n}\n\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/ui/ReferenceUi.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.ui;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.text.method.ScrollingMovementMethod;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.wearableintelligencesystem.androidsmartglasses.R;\nimport com.squareup.picasso.Callback;\nimport com.squareup.picasso.OkHttp3Downloader;\nimport com.squareup.picasso.Picasso;\nimport com.wearableintelligencesystem.androidsmartglasses.ASPClientSocket;\nimport com.wearableintelligencesystem.androidsmartglasses.comms.MessageTypes;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\npublic class ReferenceUi extends ASGFragment {\n    private final String TAG = \"WearableAi_ReferenceUi\";\n\n    private String title;\n    private String body;\n    private String imgUrl;\n\n    //referenceCard ui\n    TextView referenceCardResultTitle;\n    TextView referenceCardResultSummary;\n    ImageView referenceCardResultImage;\n\n    public ReferenceUi() {\n        fragmentLabel = \"Reference\";\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        Log.d(TAG, \"onDestroy called\");\n    }\n\n    @Override\n    public void onDestroyView() {\n        super.onDestroyView();\n        Log.d(TAG, \"onDestroyView called\");\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container,\n                             Bundle savedInstanceState) {\n        // Inflate the layout for this fragment\n        Log.d(TAG, \"REFERENCE ON CREATE VIEW\");\n        return inflater.inflate(R.layout.reference_card, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        Log.d(TAG, \"REFERENCE ON VIEW CREATED\");\n        super.onCreate(savedInstanceState);\n        super.onViewCreated(view, savedInstanceState);\n\n        //get the passed in arguments\n        Handler h = new Handler();\n\n        h.postDelayed(new Runnable() {\n            public void run() {\n                title = getArguments().getString(\"title\", null);\n                body = getArguments().getString(\"body\", null);\n                imgUrl = getArguments().getString(\"img_url\", null);\n                Log.d(TAG, \"moi: \" + title);\n                Log.d(TAG, \"moi: \" + body);\n\n                //get the views\n                referenceCardResultTitle = (TextView) getActivity().findViewById(R.id.reference_card_result_title);\n                referenceCardResultSummary = (TextView) getActivity().findViewById(R.id.reference_card_result_summary);\n                referenceCardResultImage = (ImageView) getActivity().findViewById(R.id.reference_card_result_image);\n\n                //set the text\n                referenceCardResultTitle.setText(title);\n                referenceCardResultSummary.setText(body);\n                referenceCardResultSummary.setMovementMethod(new ScrollingMovementMethod());\n                referenceCardResultSummary.setSelected(true);\n                //        //pull the image from web and display\n                if (imgUrl != null) {\n                    Picasso.Builder builder = new Picasso.Builder(getActivity());\n                    builder.downloader(new OkHttp3Downloader(getActivity()));\n                    builder.build()\n                            .load(imgUrl.trim())\n                            .resize(400,0)\n                            .into(referenceCardResultImage, new Callback() {\n\n                                @Override\n                                public void onSuccess() {\n                                    Log.d(TAG, \"Picasso Image load success\");\n                                }\n\n                                @Override\n                                public void onError(Exception e) {\n                                    Log.e(\"Picasso\", \"Image load failed\");\n                                }\n                            });\n                }\n            }\n        }, 10);\n\n\n    }\n}\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/ui/RequiredArgsUi.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.ui;\n\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.wearableintelligencesystem.androidsmartglasses.R;\nimport com.wearableintelligencesystem.androidsmartglasses.comms.MessageTypes;\nimport com.wearableintelligencesystem.androidsmartglasses.ui.adapters.CommandListRecyclerViewAdapter;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\n\npublic class RequiredArgsUi extends ASGFragment {\n    private final String TAG = \"WearableAi_RequiredArgsUi\";\n\n    public RequiredArgsUi() {\n        fragmentLabel = \"RequiredArgs\";\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container,\n                             Bundle savedInstanceState) {\n        // Inflate the layout for this fragment\n        return inflater.inflate(R.layout.required_args_fragment, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        super.onViewCreated(view, savedInstanceState);\n\n        JSONArray argList = null;\n        try {\n            argList = new JSONArray(getArguments().getString(MessageTypes.ARG_OPTIONS));\n            CommandListRecyclerViewAdapter argListRecyclerViewAdapter;\n            RecyclerView argListRecyclerView = view.findViewById(R.id.args_list_recycler_view);\n            TextView mainTitle = view.findViewById(R.id.main_title);\n            mainTitle.setText(getArguments().getString(MessageTypes.ARG_NAME));\n            argListRecyclerView.setLayoutManager(new LinearLayoutManager(this.mainActivity));\n            argListRecyclerViewAdapter = new CommandListRecyclerViewAdapter(this.mainActivity, argList);\n            argListRecyclerView.setAdapter(argListRecyclerViewAdapter);\n            Log.d(TAG, argList.getString(0));\n        } catch (JSONException e) {\n            e.printStackTrace();\n        }\n    }\n}\n\n\n\n\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/ui/SelectableImageGridUi.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.ui;\n\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.os.Bundle;\nimport android.util.Base64;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.GridView;\nimport android.widget.ImageView;\nimport android.widget.Toast;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.wearableintelligencesystem.androidsmartglasses.R;\nimport com.wearableintelligencesystem.androidsmartglasses.ImageAdapter;\nimport com.wearableintelligencesystem.androidsmartglasses.MainActivity;\nimport com.wearableintelligencesystem.androidsmartglasses.comms.MessageTypes;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class SelectableImageGridUi extends ASGFragment {\n    private final String TAG = \"WearableAi_SelectableImageGrid\";\n\n    //visual search gridview ui\n    GridView gridviewImages;\n    ImageAdapter gridViewImageAdapter;\n    List<String> imageNames;\n    int imageDisplayLimit = 18;\n\n    //store information from visual search response\n    List<String> thumbnailImages;\n\n    public SelectableImageGridUi() {\n        fragmentLabel = \"Image Grid\";\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container,\n                             Bundle savedInstanceState) {\n        // Inflate the layout for this fragment\n        return inflater.inflate(R.layout.image_gridview, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        super.onViewCreated(view, savedInstanceState);\n\n        try {\n            JSONArray data = new JSONArray(getArguments().getString(\"images\", null));\n            showImages(data);\n        } catch (JSONException e){\n            e.printStackTrace();\n        }\n    }\n\n    private void selectImage(){\n        int pos = gridviewImages.getSelectedItemPosition();\n        String name = imageNames.get(pos);\n        Toast.makeText(mainActivity, name, Toast.LENGTH_LONG).show();\n    }\n\n    public void showImages(JSONArray data){\n        thumbnailImages = new ArrayList<String>();\n        imageNames = new ArrayList<String>();\n        try {\n            for (int i = 0; ((i < data.length()) && (i < imageDisplayLimit)); i++) {\n                //get thumnail image urls\n                String thumbnailUrl = data.getJSONObject(i).getString(\"thumbnailUrl\");\n                thumbnailImages.add(thumbnailUrl);\n\n                //get names of items\n                String name = data.getJSONObject(i).getString(\"name\");\n                imageNames.add(name);\n                Log.d(TAG, \"GOT IMAGE: \" + name);\n            }\n\n        } catch (JSONException e) {\n            Log.d(TAG, e.toString());\n        }\n\n        gridviewImages = (GridView) getActivity().findViewById(R.id.gridview);\n        gridViewImageAdapter = new ImageAdapter(getActivity());\n        String[] simpleThumbArray = new String[thumbnailImages.size()];\n        thumbnailImages.toArray(simpleThumbArray);\n        gridViewImageAdapter.imageTotal = simpleThumbArray.length;\n        gridViewImageAdapter.mThumbIds = simpleThumbArray;\n        gridviewImages.setDrawSelectorOnTop(false);\n        gridviewImages.setSelector(R.drawable.selector_image_gridview);\n        gridviewImages.setAdapter(gridViewImageAdapter);\n        gridviewImages.setOnItemClickListener(new AdapterView.OnItemClickListener() {\n            public void onItemClick(AdapterView<?> parent, View v,\n                                    int position, long id) {\n                Log.d(TAG, \"Selected position: \" + position);\n                selectImage();\n                gridViewImageAdapter.notifyDataSetChanged();\n            }\n        });\n    }\n}\n\n\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/ui/TextWallUi.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.ui;\n\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.text.method.ScrollingMovementMethod;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.squareup.picasso.Callback;\nimport com.squareup.picasso.OkHttp3Downloader;\nimport com.squareup.picasso.Picasso;\nimport com.wearableintelligencesystem.androidsmartglasses.R;\n\npublic class TextWallUi extends ASGFragment {\n    private final String TAG = \"WearableAi_TextWallUi\";\n\n    private String text;\n\n    //referenceCard ui\n    TextView textViewCardText;\n\n    public TextWallUi() {\n        fragmentLabel = \"TextWall\";\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        Log.d(TAG, \"onDestroy called\");\n    }\n\n    @Override\n    public void onDestroyView() {\n        super.onDestroyView();\n        Log.d(TAG, \"onDestroyView called\");\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container,\n                             Bundle savedInstanceState) {\n        // Inflate the layout for this fragment\n        Log.d(TAG, \"TEXT WALL ON CREATE VIEW\");\n        return inflater.inflate(R.layout.text_wall_card, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        Log.d(TAG, \"REFERENCE ON VIEW CREATED\");\n        super.onCreate(savedInstanceState);\n        super.onViewCreated(view, savedInstanceState);\n\n        //get the passed in arguments\n        Handler h = new Handler();\n\n        h.postDelayed(new Runnable() {\n            public void run() {\n                text = getArguments().getString(\"text\", null);\n                Log.d(TAG, \"text wall text: \" + text);\n\n                //get the views\n                textViewCardText = (TextView) getActivity().findViewById(R.id.text_wall_card_text);\n\n                //set the text\n                textViewCardText.setText(text);\n            }\n        }, 10);\n\n\n    }\n}\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/ui/UiUtils.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.ui;\n\nimport android.widget.TextView;\n\npublic class UiUtils {\n    public static void scrollToBottom(TextView tv) {\n            tv.post(new Runnable() {\n                @Override\n                public void run() {\n                    int lc = tv.getLineCount();\n                    if (lc == 0) {\n                        return;\n                    }\n                    tv.scrollTo(0, tv.getBottom());\n                    int scrollAmount = tv.getLayout().getLineTop(lc) - tv.getHeight();\n                    // if there is no need to scroll, scrollAmount will be <=0\n                    if (scrollAmount > 0)\n                        tv.scrollTo(0, scrollAmount);\n                    else\n                        tv.scrollTo(0, 0);\n                }\n            });\n        }\n}\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/ui/WakeWordPostUi.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.ui;\n\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.wearableintelligencesystem.androidsmartglasses.R;\nimport com.wearableintelligencesystem.androidsmartglasses.comms.MessageTypes;\nimport com.wearableintelligencesystem.androidsmartglasses.ui.adapters.CommandListRecyclerViewAdapter;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\n\npublic class WakeWordPostUi extends ASGFragment {\n    private final String TAG = \"WearableAi_WakeWordPostUi\";\n\n    public WakeWordPostUi() {\n        fragmentLabel = \"Wake Word Received\";\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container,\n                             Bundle savedInstanceState) {\n        // Inflate the layout for this fragment\n        return inflater.inflate(R.layout.wake_word_post_fragment, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        super.onViewCreated(view, savedInstanceState);\n\n        JSONArray commandList = null;\n        try {\n            commandList = new JSONArray(getArguments().getString(MessageTypes.VOICE_COMMAND_LIST));\n            CommandListRecyclerViewAdapter commandListRecyclerViewAdapter;\n            RecyclerView commandListRecyclerView = view.findViewById(R.id.command_list_recycler_view);\n//            TextView mainTitle = view.findViewById(R.id.main_title);\n//            mainTitle.setText(getArguments().getString(MessageTypes.INPUT_WAKE_WORD));\n            commandListRecyclerView.setLayoutManager(new LinearLayoutManager(this.mainActivity));\n            commandListRecyclerViewAdapter = new CommandListRecyclerViewAdapter(this.mainActivity, commandList);\n            commandListRecyclerView.setAdapter(commandListRecyclerViewAdapter);\n            Log.d(TAG, commandList.getString(0));\n        } catch (JSONException e) {\n            e.printStackTrace();\n        }\n    }\n}\n\n\n\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/ui/adapters/CommandListRecyclerViewAdapter.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.ui.adapters;\n\nimport android.content.Context;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.wearableintelligencesystem.androidsmartglasses.R;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\n\npublic class CommandListRecyclerViewAdapter extends RecyclerView.Adapter<CommandListRecyclerViewAdapter.ViewHolder> {\n\n    private JSONArray commandListData;\n    private LayoutInflater mInflater;\n    private ItemClickListener mClickListener;\n\n    // data is passed into the constructor\n    public CommandListRecyclerViewAdapter(Context context, JSONArray data) {\n        this.mInflater = LayoutInflater.from(context);\n        this.commandListData = data;\n    }\n\n    // inflates the row layout from xml when needed\n    @Override\n    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        View view = mInflater.inflate(R.layout.command_list_recyclerview_item, parent, false);\n        return new ViewHolder(view);\n    }\n\n    // binds the data to the TextView in each row\n    @Override\n    public void onBindViewHolder(ViewHolder holder, int position) {\n        String commandListName = null;\n        try {\n            commandListName = commandListData.getString(position);\n        } catch (JSONException e) {\n            e.printStackTrace();\n        }\n        holder.commandListItemNameTextView.setText(commandListName + \"...\");\n    }\n\n    // total number of rows\n    @Override\n    public int getItemCount() {\n        return commandListData.length();\n    }\n\n\n    // stores and recycles views as they are scrolled off screen\n    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {\n        TextView commandListItemNameTextView;\n\n        ViewHolder(View itemView) {\n            super(itemView);\n            commandListItemNameTextView = itemView.findViewById(R.id.command_list_item_name);\n            itemView.setOnClickListener(this);\n        }\n\n        @Override\n        public void onClick(View view) {\n            if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition());\n        }\n    }\n\n    // convenience method for getting data at click position\n    String getItem(int id) {\n        try {\n            return commandListData.getString(id);\n        } catch (JSONException e) {\n            e.printStackTrace();\n        }\n        return \"No Item Found\";\n    }\n\n    // allows clicks events to be caught\n    void setClickListener(ItemClickListener itemClickListener) {\n        this.mClickListener = itemClickListener;\n    }\n\n    // parent activity will implement this method to respond to click events\n    public interface ItemClickListener {\n        void onItemClick(View view, int position);\n    }\n}"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/java/com/wearableintelligencesystem/androidsmartglasses/utils/AES.java",
    "content": "package com.wearableintelligencesystem.androidsmartglasses.utils;\n\nimport android.util.Base64;\n\nimport java.io.UnsupportedEncodingException;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Arrays;\n\nimport javax.crypto.Cipher;\nimport javax.crypto.spec.SecretKeySpec;\n\npublic class AES {\n\n    private static SecretKeySpec secretKey;\n    private static byte[] key;\n\n    public static void setKey(String myKey)\n    {\n        MessageDigest sha = null;\n        try {\n            key = myKey.getBytes(\"UTF-8\");\n            sha = MessageDigest.getInstance(\"SHA-1\");\n            key = sha.digest(key);\n            key = Arrays.copyOf(key, 16);\n            secretKey = new SecretKeySpec(key, \"AES\");\n        }\n        catch (NoSuchAlgorithmException e) {\n            e.printStackTrace();\n        }\n        catch (UnsupportedEncodingException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static String encrypt(String strToEncrypt, String secret)\n    {\n        try\n        {\n            setKey(secret);\n            Cipher cipher = Cipher.getInstance(\"AES/ECB/PKCS7Padding\");\n            cipher.init(Cipher.ENCRYPT_MODE, secretKey);\n            return Base64.encodeToString(cipher.doFinal(strToEncrypt.getBytes(\"UTF-8\")), Base64.DEFAULT);\n        }\n        catch (Exception e)\n        {\n            System.out.println(\"Error while encrypting: \" + e.toString());\n        }\n        return null;\n    }\n\n    //bytes version\n    public static byte [] encrypt(byte [ ] bytesToEncrypt, String secret)\n    {\n        try\n        {\n            setKey(secret);\n            Cipher cipher = Cipher.getInstance(\"AES/ECB/PKCS7Padding\");\n            cipher.init(Cipher.ENCRYPT_MODE, secretKey);\n            return cipher.doFinal(bytesToEncrypt);\n        }\n        catch (Exception e)\n        {\n            System.out.println(\"Error while encrypting: \" + e.toString());\n        }\n        return null;\n    }\n\n    //String version\n    public static String decrypt(String strToDecrypt, String secret)\n    {\n        try\n        {\n            setKey(secret);\n            Cipher cipher = Cipher.getInstance(\"AES/ECB/PKCS7PADDING\");\n            cipher.init(Cipher.DECRYPT_MODE, secretKey);\n            return new String(cipher.doFinal(Base64.decode(strToDecrypt, Base64.DEFAULT)));\n        }\n        catch (Exception e)\n        {\n            System.out.println(\"Error while decrypting: \" + e.toString());\n        }\n        return null;\n    }\n\n    //bytes version\n    public static byte [] decrypt(byte [] bytesToDecrypt, String secret)\n    {\n        try\n        {\n            setKey(secret);\n            Cipher cipher = Cipher.getInstance(\"AES/ECB/PKCS7PADDING\");\n            cipher.init(Cipher.DECRYPT_MODE, secretKey);\n            return cipher.doFinal(bytesToDecrypt);\n        }\n        catch (Exception e)\n        {\n            System.out.println(\"Error while decrypting: \" + e.toString());\n        }\n        return null;\n    }\n}"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/drawable/circle_shape.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n\n    <solid\n        android:color=\"#50ffffff\"/>\n\n    <size\n        android:width=\"30dp\"\n        android:height=\"30dp\"/>\n</shape>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/drawable/ic_command_failed.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n  <path\n      android:pathData=\"M19.1,4.9C15.2,1 8.8,1 4.9,4.9C1,8.8 1,15.2 4.9,19.1C8.8,23 15.1,23 19,19.1C22.9,15.2 23,8.8 19.1,4.9V4.9ZM14.8,16.2L12,13.4L9.2,16.2L7.8,14.8L10.6,12L7.8,9.2L9.2,7.8L12,10.6L14.8,7.8L16.2,9.2L13.4,12L16.2,14.8L14.8,16.2V16.2Z\"\n      android:fillColor=\"#DE3636\"/>\n</vector>\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/drawable/ic_command_success.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"26dp\"\n    android:height=\"26dp\"\n    android:viewportWidth=\"26\"\n    android:viewportHeight=\"26\">\n  <path\n      android:pathData=\"M26,13C26,16.4478 24.6304,19.7544 22.1924,22.1924C19.7544,24.6304 16.4478,26 13,26C9.5522,26 6.2456,24.6304 3.8076,22.1924C1.3696,19.7544 0,16.4478 0,13C0,9.5522 1.3696,6.2456 3.8076,3.8076C6.2456,1.3696 9.5522,0 13,0C16.4478,0 19.7544,1.3696 22.1924,3.8076C24.6304,6.2456 26,9.5522 26,13ZM19.5487,8.0763C19.4327,7.9606 19.2945,7.8695 19.1424,7.8085C18.9903,7.7474 18.8275,7.7177 18.6637,7.721C18.4998,7.7244 18.3383,7.7607 18.1889,7.8279C18.0394,7.8951 17.905,7.9917 17.7937,8.112L12.1501,15.3026L8.749,11.8999C8.518,11.6846 8.2124,11.5674 7.8966,11.573C7.5809,11.5785 7.2797,11.7064 7.0564,11.9297C6.8331,12.153 6.7052,12.4543 6.6996,12.77C6.694,13.0858 6.8112,13.3913 7.0265,13.6224L11.3263,17.9237C11.4421,18.0394 11.58,18.1305 11.7318,18.1916C11.8836,18.2528 12.0462,18.2828 12.2098,18.2797C12.3735,18.2767 12.5348,18.2407 12.6843,18.174C12.8337,18.1072 12.9682,18.0111 13.0796,17.8913L19.5666,9.7825C19.7878,9.5526 19.9099,9.2451 19.9069,8.9261C19.9039,8.607 19.7759,8.3019 19.5504,8.0763H19.5487Z\"\n      android:fillColor=\"@color/green_icon\"/>\n</vector>\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/drawable/ic_full_battery.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"@dimen/headerIconWidth\"\n    android:height=\"@dimen/headerIconWidth\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n  <path\n      android:pathData=\"M16.67,4H15V2H9V4H7.33C6.9773,4 6.639,4.1401 6.3896,4.3896C6.1401,4.639 6,4.9773 6,5.33V20.67C6,21.4 6.6,22 7.33,22H16.67C17.0227,22 17.361,21.8599 17.6105,21.6105C17.8599,21.361 18,21.0227 18,20.67V5.33C18,4.6 17.4,4 16.67,4Z\"\n      android:fillColor=\"#ffffff\"/>\n</vector>\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/drawable/ic_full_battery_charging.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"@dimen/headerIconWidth\"\n    android:height=\"@dimen/headerIconWidth\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n  <path\n      android:pathData=\"M16.67,4H15V2H9V4H7.33C6.9773,4 6.639,4.1401 6.3896,4.3896C6.1401,4.639 6,4.9773 6,5.33V20.66C6,21.4 6.6,22 7.33,22H16.66C17.4,22 18,21.4 18,20.67V5.33C18,4.6 17.4,4 16.67,4ZM11,20V14.5H9L13,7V12.5H15\"\n      android:fillColor=\"#ffffff\"/>\n</vector>\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <path\n        android:fillColor=\"#3DDC84\"\n        android:pathData=\"M0,0h108v108h-108z\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M9,0L9,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,0L19,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,0L29,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,0L39,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,0L49,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,0L59,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,0L69,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,0L79,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M89,0L89,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M99,0L99,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,9L108,9\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,19L108,19\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,29L108,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,39L108,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,49L108,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,59L108,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,69L108,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,79L108,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,89L108,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,99L108,99\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,29L89,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,39L89,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,49L89,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,59L89,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,69L89,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,79L89,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,19L29,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,19L39,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,19L49,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,19L59,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,19L69,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,19L79,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n</vector>\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/drawable/ic_low_battery.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"@dimen/headerIconWidth\"\n    android:height=\"@dimen/headerIconWidth\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n  <path\n      android:pathData=\"M16,18H8V6H16V18ZM16.67,4H15V2H9V4H7.33C6.9773,4 6.639,4.1401 6.3896,4.3896C6.1401,4.639 6,4.9773 6,5.33V20.67C6,21.4 6.6,22 7.33,22H16.67C17.0227,22 17.361,21.8599 17.6105,21.6105C17.8599,21.361 18,21.0227 18,20.67V5.33C18,4.6 17.4,4 16.67,4Z\"\n      android:fillColor=\"#DE3636\"/>\n</vector>\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/drawable/ic_low_battery_charging.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"@dimen/headerIconWidth\"\n    android:height=\"@dimen/headerIconWidth\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n  <path\n      android:pathData=\"M23.05,11H20.05V4L15.05,14H18.05V22L23.05,11ZM12,18H4L4.05,6H12.05L12,18ZM12.72,4H11.05V2H5.05V4H3.38C3.0273,4 2.689,4.1401 2.4395,4.3896C2.1901,4.639 2.05,4.9773 2.05,5.33V20.67C2.05,21.4 2.65,22 3.38,22H12.72C13.45,22 14.05,21.4 14.05,20.67V5.33C14.05,4.9773 13.9099,4.639 13.6604,4.3896C13.411,4.1401 13.0727,4 12.72,4V4Z\"\n      android:fillColor=\"#DE3636\"/>\n</vector>\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/drawable/ic_mic_listening.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"@dimen/headerIconWidth\"\n    android:height=\"@dimen/headerIconWidth\"\n    android:viewportWidth=\"12\"\n    android:viewportHeight=\"12\">\n  <path\n      android:pathData=\"M6,6m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0\"\n      android:fillColor=\"#ffffff\"/>\n  <path\n      android:strokeWidth=\"1\"\n      android:pathData=\"M6,6m-5.5,0a5.5,5.5 0,1 1,11 0a5.5,5.5 0,1 1,-11 0\"\n      android:fillColor=\"#00000000\"\n      android:strokeColor=\"#ffffff\"/>\n</vector>\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/drawable/ic_phone_connected.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"@dimen/headerIconWidth\"\n    android:height=\"@dimen/headerIconWidth\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n  <path\n      android:pathData=\"M2,16V18C2.6566,18 3.3068,18.1293 3.9134,18.3806C4.5201,18.6319 5.0712,19.0002 5.5355,19.4645C5.9998,19.9288 6.3681,20.48 6.6194,21.0866C6.8707,21.6932 7,22.3434 7,23H9C9,21.1435 8.2625,19.363 6.9497,18.0503C5.637,16.7375 3.8565,16 2,16V16ZM2,20V23H5C5,22.2044 4.6839,21.4413 4.1213,20.8787C3.5587,20.3161 2.7957,20 2,20V20ZM2,12V14C4.387,14 6.6761,14.9482 8.364,16.636C10.0518,18.3239 11,20.6131 11,23H13C13,16.92 8.08,12 2,12ZM17,1H7C6.4696,1 5.9609,1.2107 5.5858,1.5858C5.2107,1.9609 5,2.4696 5,3V10.37C5.69,10.53 6.36,10.74 7,11V5H17V18H13.97C14.5,19.25 14.81,20.59 14.92,22H17C17.5304,22 18.0391,21.7893 18.4142,21.4142C18.7893,21.0391 19,20.5304 19,20V3C19,2.4696 18.7893,1.9609 18.4142,1.5858C18.0391,1.2107 17.5304,1 17,1Z\"\n      android:fillColor=\"#FFFFFF\"/>\n</vector>\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/drawable/ic_phone_disconnected.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"@dimen/headerIconWidth\"\n    android:height=\"@dimen/headerIconWidth\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n  <path\n      android:pathData=\"M2.38,1.73L1.11,3L5,6.89V21C5,21.5304 5.2107,22.0391 5.5858,22.4142C5.9608,22.7893 6.4696,23 7,23H17C17.5304,23 18.0391,22.7893 18.4142,22.4142C18.7893,22.0391 19,21.5304 19,21V20.89L20.84,22.73L22.11,21.46L2.38,1.73ZM17,19H7V8.89L17,18.89V19ZM17,5V13.8L19,15.8V3C19,2.4696 18.7893,1.9609 18.4142,1.5858C18.0391,1.2107 17.5304,1 17,1H7C6.28,1 5.6,1.37 5.24,2L8.24,5H17Z\"\n      android:fillColor=\"#DE3636\"/>\n</vector>\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/drawable/ic_wifi_off.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"@dimen/headerIconWidth\"\n    android:height=\"@dimen/headerIconWidth\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n  <path\n      android:pathData=\"M3.27,1.44L2,2.72L4.05,4.77C2.75,5.37 1.5,6.11 0.38,7C4.41,12.06 12,21.5 12,21.5L15.91,16.63L19.23,19.95L20.5,18.68L3.27,1.44ZM12,3C10.6,3 9.21,3.17 7.86,3.5L18.18,13.81C20,11.5 22.05,9 23.65,7C20.32,4.41 16.22,3 12,3Z\"\n      android:fillColor=\"#DE3636\"/>\n</vector>\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/drawable/ic_wifi_on.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"@dimen/headerIconWidth\"\n    android:height=\"@dimen/headerIconWidth\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n  <path\n      android:pathData=\"M12,3C7.79,3 3.7,4.41 0.38,7C4.41,12.06 7.89,16.37 12,21.5C16.08,16.42 20.24,11.24 23.65,7C20.32,4.41 16.22,3 12,3Z\"\n      android:fillColor=\"#ffffff\"/>\n</vector>\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/drawable/selector_image_gridview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:drawable=\"@color/yellow\" android:state_pressed=\"true\"/>\n    <item android:drawable=\"@color/yellow\" android:state_selected=\"true\"/>\n    <item android:drawable=\"@color/yellow\"/>\n\n</selector>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/drawable/wis_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector\n    android:height=\"108dp\"\n    android:width=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#3DDC84\"\n          android:pathData=\"M0,0h108v108h-108z\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M9,0L9,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,0L19,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M29,0L29,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M39,0L39,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M49,0L49,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M59,0L59,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M69,0L69,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M79,0L79,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M89,0L89,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M99,0L99,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,9L108,9\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,19L108,19\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,29L108,29\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,39L108,39\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,49L108,49\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,59L108,59\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,69L108,69\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,79L108,79\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,89L108,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,99L108,99\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,29L89,29\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,39L89,39\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,49L89,49\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,59L89,59\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,69L89,69\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,79L89,79\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M29,19L29,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M39,19L39,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M49,19L49,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M59,19L59,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M69,19L69,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M79,19L79,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n</vector>\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <path android:pathData=\"M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:endX=\"85.84757\"\n                android:endY=\"92.4963\"\n                android:startX=\"42.9492\"\n                android:startY=\"49.59793\"\n                android:type=\"linear\">\n                <item\n                    android:color=\"#44000000\"\n                    android:offset=\"0.0\" />\n                <item\n                    android:color=\"#00000000\"\n                    android:offset=\"1.0\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:fillColor=\"#FFFFFF\"\n        android:fillType=\"nonZero\"\n        android:pathData=\"M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z\"\n        android:strokeWidth=\"1\"\n        android:strokeColor=\"#00000000\" />\n</vector>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--<ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"-->\n<!--    xmlns:app=\"http://schemas.android.com/apk/res-auto\"-->\n<!--    xmlns:tools=\"http://schemas.android.com/tools\"-->\n<!--    android:layout_width=\"match_parent\"-->\n<!--    android:layout_height=\"match_parent\"-->\n<!--    android:paddingLeft=\"16dp\"-->\n<!--    android:paddingRight=\"16dp\"-->\n<!--    android:orientation=\"vertical\"-->\n<!--    android:background=\"@color/hud_bg\"-->\n<!--    android:gravity=\"top\">-->\n<androidx.constraintlayout.widget.ConstraintLayout\nandroid:layout_width=\"match_parent\"\nandroid:layout_height=\"match_parent\"\nxmlns:android=\"http://schemas.android.com/apk/res/android\"\nxmlns:app=\"http://schemas.android.com/apk/res-auto\"\nxmlns:tools=\"http://schemas.android.com/tools\"\nandroid:background=\"@color/hud_bg\"\n    >\n\n    <androidx.constraintlayout.widget.ConstraintLayout\n        android:id=\"@+id/constraintLayout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"@dimen/headerHeight\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\">\n\n        <ImageView\n            android:id=\"@+id/voice_prompt\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:adjustViewBounds=\"true\"\n            android:gravity=\"center\"\n            android:paddingEnd=\"2dp\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintStart_toStartOf=\"parent\"\n            app:srcCompat=\"@drawable/ic_mic_listening\"\n            app:layout_constraintTop_toTopOf=\"parent\" />\n\n        <TextView\n            android:id=\"@+id/mode_hud\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"center_vertical\"\n            android:paddingLeft=\"2dp\"\n            android:text=\"Live Captions\"\n            android:textColor=\"#FFFFFF\"\n            android:textSize=\"@dimen/mediumText\"\n            android:textStyle=\"bold\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintEnd_toStartOf=\"@+id/clock_text_view\"\n            app:layout_constraintHorizontal_bias=\"0.012\"\n            app:layout_constraintStart_toEndOf=\"@id/voice_prompt\"\n            app:layout_constraintTop_toTopOf=\"parent\" />\n\n        <TextView\n            android:id=\"@+id/battery_percentage_text_view\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"25%\"\n            android:padding=\"1dp\"\n            android:textColor=\"@color/white\"\n            android:textSize=\"@dimen/mediumText\"\n            android:gravity=\"center\"\n            app:layout_constraintEnd_toEndOf=\"parent\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\" />\n\n        <ImageView\n            android:id=\"@+id/battery_status_image_view\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:adjustViewBounds=\"true\"\n            android:gravity=\"center\"\n            android:maxHeight=\"48dp\"\n            android:minHeight=\"48dp\"\n            android:padding=\"1dp\"\n            android:paddingRight=\"8dp\"\n            app:layout_constraintEnd_toStartOf=\"@id/battery_percentage_text_view\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\" />\n        <ImageView\n            android:id=\"@+id/wifi_image_view\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:adjustViewBounds=\"true\"\n            android:gravity=\"center\"\n            android:padding=\"1dp\"\n            android:paddingRight=\"8dp\"\n            app:layout_constraintEnd_toStartOf=\"@id/battery_status_image_view\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\" />\n        <ImageView\n            android:id=\"@+id/phone_status_image_view\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:adjustViewBounds=\"true\"\n            android:gravity=\"center\"\n            android:padding=\"1dp\"\n            android:paddingRight=\"8dp\"\n            app:layout_constraintEnd_toStartOf=\"@id/wifi_image_view\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\" />\n        <TextView\n            android:id=\"@+id/clock_text_view\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginEnd=\"6dp\"\n            android:gravity=\"center\"\n            android:padding=\"1dp\"\n            android:paddingRight=\"8dp\"\n            android:textColor=\"@color/white\"\n            android:textSize=\"@dimen/mediumText\"\n            app:layout_constraintEnd_toStartOf=\"@id/phone_status_image_view\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\"\n            tools:text=\"12:30 PM\" />\n\n\n\n\n\n\n        <View\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"1dp\"\n            android:padding=\"1dp\"\n            app:layout_constraintEnd_toEndOf=\"parent\"\n            app:layout_constraintStart_toStartOf=\"parent\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            android:background=\"#99FFFFFF\"\n            />\n\n\n    </androidx.constraintlayout.widget.ConstraintLayout>\n\n    <androidx.fragment.app.FragmentContainerView\n        android:id=\"@+id/nav_host_fragment\"\n        android:layout_width=\"match_parent\"\n        app:navGraph=\"@navigation/nav_graph\"\n        app:defaultNavHost=\"true\"\n        android:name=\"androidx.navigation.fragment.NavHostFragment\"\n        android:layout_height=\"0dp\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/constraintLayout\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/layout/blank_screen.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\nxmlns:app=\"http://schemas.android.com/apk/res-auto\"\nxmlns:tools=\"http://schemas.android.com/tools\"\nandroid:layout_width=\"match_parent\"\nandroid:layout_height=\"match_parent\"\nandroid:paddingLeft=\"16dp\"\nandroid:paddingRight=\"16dp\"\nandroid:orientation=\"vertical\"\nandroid:background=\"@color/black\"\nandroid:gravity=\"top\">\n\n</RelativeLayout>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/layout/command_list_recyclerview_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:background=\"#000000\">\n    <TextView\n        android:id=\"@+id/command_list_item_name\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textSize=\"@dimen/smallText\"\n        android:includeFontPadding=\"false\"\n        tools:text = \"save speech...\"\n        android:textColor=\"@color/hud_text\"\n        android:textAlignment=\"center\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"/>\n\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/layout/command_post_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:background=\"@color/hud_bg\"\n    android:layout_height=\"match_parent\">\n\n    <ImageView\n        android:layout_width=\"26dp\"\n        android:layout_height=\"26dp\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:srcCompat=\"@drawable/ic_mic_listening\"\n        android:layout_marginTop=\"10dp\"\n        android:id=\"@+id/active_listening_icon\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"/>\n\n    <TextView\n        android:id=\"@+id/main_title\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        tools:text=\"Command: save speech\"\n        android:textSize=\"@dimen/largeText\"\n        android:textStyle=\"bold\"\n        android:textColor=\"@color/hud_text\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/active_listening_icon\" />\n\n\n    <TextView\n        android:id=\"@+id/args_prompt\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"12dp\"\n        android:text=\"Say command arguments:\"\n        android:textColor=\"@color/hud_text\"\n        android:textSize=\"@dimen/mediumText\"\n        android:textStyle=\"bold\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.501\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/main_title\" />\n\n    <TextView\n        android:id=\"@+id/command_args\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_marginTop=\"18dp\"\n        android:layout_marginBottom=\"8dp\"\n        android:scrollbars=\"vertical\"\n        android:textAlignment=\"center\"\n        android:textColor=\"@color/hud_text\"\n        android:textSize=\"@dimen/smallText\"\n        app:layout_constraintBottom_toTopOf=\"@id/finish_command_hint\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.0\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/args_prompt\"\n        app:layout_constraintVertical_bias=\"0.0\"\n        tools:text=\"args\" />\n\n    <TextView\n        android:id=\"@+id/finish_command_hint\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"Say 'finish command' when you are done.\"\n        android:textColor=\"@color/hud_text\"\n        android:textSize=\"@dimen/mediumText\"\n        android:textStyle=\"bold\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/command_args\"\n        app:layout_constraintVertical_bias=\"0.0\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/layout/command_resolve_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:background=\"@color/hud_bg\"\n    android:layout_height=\"match_parent\">\n\n    <ImageView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        android:layout_marginTop=\"30dp\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        android:id=\"@+id/command_success_icon\"\n        app:srcCompat = \"@drawable/ic_command_success\"\n        />\n    <TextView\n        android:id=\"@+id/success_message\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        tools:text=\"Command Resolve Fragment\"\n        android:textSize=\"14sp\"\n        android:textStyle=\"bold\"\n        android:textColor=\"@color/hud_text\"\n        android:layout_marginTop=\"20dp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        android:textAlignment=\"center\"\n        app:layout_constraintTop_toBottomOf=\"@id/command_success_icon\" />\n    <TextView\n        android:id=\"@+id/command_response_description\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        tools:text=\"Command Resolve Description Loremasdasdasdaskdjaksjdkajsdkjasdkjasdaljksdlajsdflaskdlaksd ipsum\"\n        android:textSize=\"14sp\"\n        android:textColor=\"@color/hud_text\"\n        android:layout_marginTop=\"6dp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        android:textAlignment=\"center\"\n        app:layout_constraintTop_toBottomOf=\"@id/success_message\" />\n\n    <TextView\n        android:id=\"@+id/text_response_text_view\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"36dp\"\n        android:textAlignment=\"center\"\n        android:textSize=\"14sp\"\n        android:textColor=\"@color/hud_text\"\n        tools:text=\"Command Resolve Description Loremasdasdasdaskdjaksjdkajsdkjasdkjasdaljksdlajsdflaskdlaksd ipsum\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.428\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/command_response_description\"\n        />\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/layout/convo_mode_fragment.xml",
    "content": "<androidx.constraintlayout.widget.ConstraintLayout\nandroid:layout_width=\"match_parent\"\nandroid:layout_height=\"match_parent\"\nxmlns:android=\"http://schemas.android.com/apk/res/android\"\nxmlns:app=\"http://schemas.android.com/apk/res-auto\"\nxmlns:tools=\"http://schemas.android.com/tools\"\nandroid:background=\"@color/hud_bg\"\n    >\n\n    <TextView\n        android:id=\"@+id/references_text_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:gravity=\"bottom\"\n        android:scrollbars=\"vertical\"\n        android:textColor=\"@color/white\"\n        android:textSize=\"12dp\"\n\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n\n\n\n\n        \n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"1.0\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        tools:text=\"THIS IS CONVO MODE BORK\" />\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/layout/home_prompt_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:background=\"@color/hud_bg\"\n    >\n\n    <TextView\n        android:id=\"@+id/home_screen_text_prompt\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:gravity=\"center\"\n        android:scrollbars=\"vertical\"\n        android:text=\"@string/home_screen_text_prompt\"\n        android:textAlignment=\"center\"\n        android:textColor=\"@color/white\"\n        android:textSize=\"@dimen/largeText\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"1.0\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/layout/image_gridview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<GridView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/gridview\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\"\n    android:numColumns=\"3\"\n    android:background=\"@color/black\"\n    android:verticalSpacing=\"3dp\"\n    android:horizontalSpacing=\"1dp\"\n    android:stretchMode=\"columnWidth\"\n    android:gravity=\"center\" />"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/layout/live_life_caption_text.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:background=\"@color/hud_bg\"\n    >\n\n    <TextView\n        android:id=\"@+id/livelifecaptionstextview\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:gravity=\"bottom\"\n        android:scrollbars=\"vertical\"\n        android:textColor=\"@color/white\"\n        android:textSize=\"@dimen/smallText\"\n        android:layout_marginBottom=\"@dimen/llcMarginBottom\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"1.0\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        tools:text=\"LIVE LIFE CAPTIONS \\n LIFE LIVE CAPTIONS \\n LIVE LIFE CAPTIONS\" />\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/layout/object_translate_mode_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:background=\"#00000000\">\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@android:color/black\"\n        android:orientation=\"vertical\">\n        <TextView\n            android:id=\"@+id/languageName\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentTop=\"true\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_marginTop=\"30dp\"\n            android:text=\"French\"\n            android:textColor=\"#FFFFFF\"\n            android:textSize=\"16sp\" />\n\n        <FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n            xmlns:tools=\"http://schemas.android.com/tools\"\n            android:id=\"@+id/container\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:alpha=\"0.0\"\n            android:visibility=\"visible\"\n            tools:context=\"org.tensorflow.demo.CameraActivity\" />\n\n\n    </RelativeLayout>\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        >\n\n        <View\n            android:layout_width=\"40dp\"\n            android:layout_height=\"40dp\"\n            android:elevation=\"12dp\"\n            android:background=\"@drawable/circle_shape\"\n            android:layout_centerInParent=\"true\" />\n\n        <TextView\n            android:id=\"@+id/nameOfObjectinTargetLanguage\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_above=\"@id/nameOfObjectinSourceLanguage\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_marginBottom=\"20dp\"\n            tools:text=\"Apple\"\n            android:textColor=\"#FFFFFF\"\n            android:textSize=\"22sp\" />\n\n        <TextView\n            android:id=\"@+id/nameOfObjectinSourceLanguage\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentBottom=\"true\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_marginBottom=\"50dp\"\n            tools:text=\"pomme\"\n            android:textColor=\"#FFFFFF\"\n            android:textSize=\"16sp\" />\n    </RelativeLayout>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/layout/old_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" >\n\n    <android.view.SurfaceView\n        android:id=\"@+id/preview\"\n        android:layout_width=\"211dp\"\n        android:layout_height=\"589dp\"></android.view.SurfaceView>\n\n    <TextView\n        android:id=\"@+id/textView\"\n        android:layout_width=\"131dp\"\n        android:layout_height=\"137dp\"\n        android:layout_alignParentTop=\"true\"\n        android:layout_alignParentRight=\"true\"\n        android:layout_alignParentBottom=\"true\"\n        android:text=\"AAAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBBBb CCCCCCCCCCCCCCCCCCCCCc CAYDEND\" />\n</RelativeLayout>\n\n<!--<?xml version=\"1.0\" encoding=\"utf-8\"?>-->\n<!--<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"-->\n<!--    android:layout_width=\"match_parent\"-->\n<!--    android:layout_height=\"match_parent\" >-->\n\n<!--    <Button-->\n<!--        android:id=\"@+id/captureFront\"-->\n<!--        android:layout_width=\"wrap_content\"-->\n<!--        android:layout_height=\"wrap_content\"-->\n<!--        android:layout_centerInParent=\"true\"-->\n<!--        android:onClick=\"onClick\"-->\n<!--        android:text=\"Make Photo\" />-->\n\n<!--</RelativeLayout>-->\n\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/layout/reference_card.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:orientation=\"vertical\"\n    android:background=\"@color/hud_bg\"\n    android:gravity=\"top\">\n\n    <LinearLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        >\n\n        <TextView\n            android:id=\"@+id/reference_card_result_title\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textColor=\"@color/hud_text\"\n            android:textSize=\"@dimen/largeText\"\n            android:textStyle=\"bold\"\n            tools:text=\"Example Wikipedia Result Title\"></TextView>\n\n    <ImageView\n        android:id=\"@+id/reference_card_result_image\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_horizontal\"\n        android:background=\"@color/black\"></ImageView>\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:scrollbars=\"vertical\"\n            tools:text=\"Example wikipedia results summary of the information that we receive from asking wikipedia about a certain person, place, or thing.\"\n            android:textColor=\"@color/hud_text\"\n            android:id=\"@+id/reference_card_result_summary\"\n            android:textSize=\"@dimen/smallText\"></TextView>\n    </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/layout/required_args_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:background=\"@color/hud_bg\"\n    android:layout_height=\"match_parent\">\n\n    <ImageView\n        android:layout_width=\"26dp\"\n        android:layout_height=\"26dp\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:srcCompat=\"@drawable/ic_mic_listening\"\n        android:layout_marginTop=\"50dp\"\n        android:id=\"@+id/active_listening_icon\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"/>\n\n    <TextView\n        android:id=\"@+id/main_title\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"Language\"\n        android:textSize=\"14sp\"\n        android:textStyle=\"bold\"\n        android:textColor=\"@color/hud_text\"\n        android:layout_marginTop=\"5dp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/active_listening_icon\" />\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/args_list_recycler_view\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@id/main_title\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/layout/social_intelligence_activity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:paddingLeft=\"16dp\"\n    android:paddingRight=\"16dp\"\n    android:orientation=\"vertical\"\n    android:background=\"@color/hud_bg\"\n    android:gravity=\"top\">\n\n    <!-- Include other widget or layout tags here. These are considered\n            \"child views\" or \"children\" of the linear layout -->\n\n    <LinearLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center\"\n        android:orientation=\"horizontal\">\n    <TextView\n        android:id=\"@+id/message\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"1\"\n        android:text=\"@string/waiting_message\"\n        android:textColor=\"@color/hud_text\"\n        android:textSize=\"32dp\" />\n    </LinearLayout>\n\n    <LinearLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center\"\n        android:orientation=\"horizontal\">\n\n<!--        <TextView-->\n<!--            android:id=\"@+id/facial_emotion_title\"-->\n<!--            android:layout_width=\"16dp\"-->\n<!--            android:layout_height=\"wrap_content\"-->\n<!--            android:layout_weight=\"1\"-->\n<!--            android:text=\"@string/title_facial_emotion\"-->\n<!--            android:textColor=\"@color/hud_text\"-->\n<!--            android:textSize=\"22dp\" />-->\n\n        <TextView\n            android:id=\"@+id/facial_emotion_metric_5\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:text=\"@string/data_loading\"\n            android:textColor=\"@color/hud_text\"\n            android:textSize=\"28dp\" />\n\n        <TextView\n            android:id=\"@+id/facial_emotion_metric_30\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:text=\"@string/data_loading\"\n            android:textColor=\"@color/hud_text\"\n            android:textSize=\"28dp\" />\n\n        <TextView\n            android:id=\"@+id/facial_emotion_metric\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:text=\"@string/data_loading\"\n            android:textColor=\"@color/hud_text\"\n            android:textSize=\"28dp\" />\n    </LinearLayout>\n\n    <LinearLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        android:gravity=\"center\">\n<!--        <TextView-->\n<!--            android:id=\"@+id/eye_contact_title\"-->\n<!--            android:layout_width=\"16dp\"-->\n<!--            android:layout_height=\"wrap_content\"-->\n<!--            android:layout_weight=\"1\"-->\n<!--            android:text=\"@string/title_eye_contact\"-->\n<!--            android:textColor=\"@color/hud_text\"-->\n<!--            android:textSize=\"22dp\" />-->\n\n        <TextView\n            android:id=\"@+id/eye_contact_metric_5\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:textColor=\"@color/hud_text\"\n            android:textSize=\"30dp\"\n            android:text=\"@string/data_loading\" />\n        <TextView\n            android:id=\"@+id/eye_contact_metric_30\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:textColor=\"@color/hud_text\"\n            android:textSize=\"30dp\"\n            android:text=\"@string/data_loading\" />\n        <TextView\n            android:id=\"@+id/eye_contact_metric\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:textColor=\"@color/hud_text\"\n            android:textSize=\"30dp\"\n            android:text=\"@string/data_loading\" />\n    </LinearLayout>\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        >\n        <com.github.mikephil.charting.charts.PieChart\n            android:id=\"@+id/stress_confidence_chart\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\" />\n    </RelativeLayout>\n<!--    <LinearLayout-->\n<!--        android:layout_width=\"wrap_content\"-->\n<!--        android:layout_height=\"wrap_content\">-->\n<!--            <Button-->\n<!--                android:id=\"@+id/toggle_camera_button\"-->\n<!--                android:layout_width=\"wrap_content\"-->\n<!--                android:layout_height=\"wrap_content\"-->\n<!--                android:textSize=\"32dp\"-->\n<!--                android:text=\"@string/cam_on\" />-->\n<!--    </LinearLayout>-->\n</LinearLayout>\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/layout/text_block.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:paddingLeft=\"16dp\"\n    android:paddingRight=\"16dp\"\n    android:orientation=\"vertical\"\n    android:background=\"@color/hud_bg\"\n    android:gravity=\"top\">\n\n\n\n    <TextView\n        android:id=\"@+id/text_block\"\n        android:layout_width=\"384dp\"\n        android:layout_height=\"705dp\"\n        android:text=\"\"\n        android:textSize=\"18dp\"\n        android:scrollbars = \"vertical\"\n        android:textColor=\"@color/white\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n</RelativeLayout>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/layout/text_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:paddingLeft=\"16dp\"\n    android:paddingRight=\"16dp\"\n    android:orientation=\"vertical\"\n    android:background=\"@color/hud_bg\"\n    android:gravity=\"top\">\n\n\n\n    <TextView\n        android:id=\"@+id/text_list\"\n    android:layout_width=\"384dp\"\n        android:layout_height=\"705dp\"\n        android:text=\"\"\n        android:textSize=\"18dp\"\n        android:scrollbars = \"vertical\"\n        android:textColor=\"@color/white\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n</RelativeLayout>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/layout/text_wall_card.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:orientation=\"vertical\"\n    android:background=\"@color/hud_bg\"\n    android:gravity=\"top\">\n\n    <LinearLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        >\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:scrollbars=\"vertical\"\n            tools:text=\"Example text wall results of the information that we receive from asking wikipedia about a certain person, place, or thing.\"\n            android:textColor=\"@color/hud_text\"\n            android:id=\"@+id/text_wall_card_text\"\n            android:textSize=\"@dimen/smallText\"></TextView>\n    </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/layout/translate_mode_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:background=\"@color/hud_bg\"\n    android:gravity=\"top\">\n\n\n\n    <TextView\n        android:id=\"@+id/translatetextview\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:text=\"\"\n        android:textSize=\"16dp\"\n        android:layout_marginBottom=\"-42dp\"\n        android:scrollbars = \"vertical\"\n        android:textColor=\"@color/white\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n</RelativeLayout>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/layout/viewfinder.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\nandroid:layout_height=\"match_parent\"\nandroid:orientation=\"vertical\"\nandroid:background=\"@color/hud_bg\"\nandroid:gravity=\"top\">\n\n    <ImageView\n        android:id=\"@+id/camera_viewfinder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        ></ImageView>\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/layout/wake_word_post_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:background=\"@color/hud_bg\"\n    android:layout_height=\"match_parent\">\n\n    <ImageView\n        android:layout_width=\"26dp\"\n        android:layout_height=\"26dp\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:srcCompat=\"@drawable/ic_mic_listening\"\n        android:layout_marginTop=\"30dp\"\n        android:id=\"@+id/active_listening_icon\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"/>\n\n\n    <TextView\n        android:id=\"@+id/main_title\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/post_wake_text\"\n        android:textSize=\"@dimen/largeText\"\n        android:textStyle=\"bold\"\n        android:textColor=\"@color/hud_text\"\n        android:layout_marginTop=\"5dp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/active_listening_icon\" />\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/command_list_recycler_view\"\n        app:layout_constraintTop_toBottomOf=\"@id/main_title\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"/>\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/layout/wearable_face_recognizer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:paddingLeft=\"16dp\"\n    android:paddingRight=\"16dp\"\n    android:orientation=\"vertical\"\n    android:background=\"@color/hud_bg\"\n    android:gravity=\"top\">\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"horizontal\">\n\n        <LinearLayout\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            >\n            <TextView\n                android:id=\"@+id/face_rec_title\"\n                android:layout_width=\"fill_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"Face detected!\\nName: Unknown\"\n                android:textColor=\"@color/hud_text\"\n                android:textSize=\"32dp\"></TextView>\n        </LinearLayout>\n\n    </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/mipmap-anydpi-v26/wis_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/wis_launcher_background\"/>\n    <foreground android:drawable=\"@mipmap/wis_launcher_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/mipmap-anydpi-v26/wis_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/wis_launcher_background\"/>\n    <foreground android:drawable=\"@mipmap/wis_launcher_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/navigation/nav_graph.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<navigation xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/nav_graph\"\n    app:startDestination=\"@id/nav_home_prompt\">\n\n    <fragment\n        android:id=\"@+id/nav_convo_mode\"\n        android:name=\"com.wearableintelligencesystem.androidsmartglasses.ui.ConvoModeUi\"\n        tools:layout=\"@layout/convo_mode_fragment\"\n        android:label=\"Convo Mode\" >\n    </fragment>\n\n\n    <fragment\n        android:id=\"@+id/nav_live_life_captions\"\n        android:name=\"com.wearableintelligencesystem.androidsmartglasses.ui.LiveLifeCaptionsUi\"\n        tools:layout=\"@layout/live_life_caption_text\"\n        android:label=\"Live Life Captions\" >\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/nav_home_prompt\"\n        android:name=\"com.wearableintelligencesystem.androidsmartglasses.ui.HomePromptUi\"\n        tools:layout=\"@layout/home_prompt_fragment\"\n        android:label=\"Home\" >\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/nav_reference\"\n        android:name=\"com.wearableintelligencesystem.androidsmartglasses.ui.ReferenceUi\"\n        tools:layout=\"@layout/reference_card\"\n        android:label=\"Reference\" >\n        <action\n            android:id=\"@+id/action_nav_reference_self\"\n            app:destination=\"@id/nav_reference\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/nav_text_wall\"\n        android:name=\"com.wearableintelligencesystem.androidsmartglasses.ui.TextWallUi\"\n        tools:layout=\"@layout/text_wall_card\"\n        android:label=\"Text Wall\" >\n        <action\n            android:id=\"@+id/action_nav_text_wall_self\"\n            app:destination=\"@id/nav_text_wall\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/nav_language_translate\"\n        android:name=\"com.wearableintelligencesystem.androidsmartglasses.ui.LanguageTranslateUi\"\n        tools:layout=\"@layout/translate_mode_view\"\n        android:label=\"Language Translate\" >\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/nav_object_translate\"\n        android:name=\"com.wearableintelligencesystem.androidsmartglasses.ui.ObjectTranslateUi\"\n        android:label=\"Object Translate\"\n        tools:layout=\"@layout/object_translate_mode_view\"></fragment>\n\n    <fragment\n        android:id=\"@+id/nav_image_grid\"\n        android:name=\"com.wearableintelligencesystem.androidsmartglasses.ui.SelectableImageGridUi\"\n        tools:layout=\"@layout/image_gridview\"\n        android:label=\"Image Gridview\" >\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/nav_command_post\"\n        android:name=\"com.wearableintelligencesystem.androidsmartglasses.ui.CommandPostUi\"\n        tools:layout=\"@layout/command_post_fragment\"\n        android:label=\"Command Recieved\" >\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/nav_wake_word_post\"\n        android:name=\"com.wearableintelligencesystem.androidsmartglasses.ui.WakeWordPostUi\"\n        tools:layout=\"@layout/wake_word_post_fragment\"\n        android:label=\"Wake Word Recieved\" >\n    </fragment>\n\n\n    <fragment\n        android:id=\"@+id/nav_command_resolve\"\n        android:name=\"com.wearableintelligencesystem.androidsmartglasses.ui.CommandResolveUi\"\n        tools:layout=\"@layout/command_resolve_fragment\"\n        android:label=\"Command Resolve\" >\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/nav_required_args\"\n        android:name=\"com.wearableintelligencesystem.androidsmartglasses.ui.RequiredArgsUi\"\n        tools:layout=\"@layout/required_args_fragment\"\n        android:label=\"Required Arguments\" >\n    </fragment>\n\n</navigation>\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"purple_200\">#FFBB86FC</color>\n    <color name=\"purple_500\">#FF6200EE</color>\n    <color name=\"purple_700\">#FF3700B3</color>\n    <color name=\"teal_200\">#FF03DAC5</color>\n    <color name=\"teal_700\">#FF018786</color>\n    <color name=\"black\">#FF000000</color>\n    <color name=\"white\">#DDFFFFFF</color>\n    <color name=\"yellow\">#FFFFFF00</color>\n    <color name=\"hud_text\">#FFFFFFFF</color>\n    <color name=\"hud_bg\">#FF000000</color>\n    <color name=\"white_transparent\">#33FFFFFF</color>\n    <color name=\"green_icon\">#FF66BB6A</color>\n    <color name=\"red_icon\">#FFE53935</color>\n    <color name=\"red_text\">#FFFFA9A5</color>\n    <color name=\"yellow_icon\">#FFFFEB3B</color>\n    <color name=\"gray\">#FFAAAAAA</color>\n</resources>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/values/dimensions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n<!--    <dimen name=\"largeText\">48dp</dimen>-->\n<!--    <dimen name=\"mediumText\">40dp</dimen>-->\n<!--    <dimen name=\"smallText\">34dp</dimen>-->\n<!--    <dimen name=\"headerIconWidth\">36dp</dimen>-->\n<!--    <dimen name=\"headerIconHeight\">36dp</dimen>-->\n<!--    -->\n    <dimen name=\"largeText\">30dp</dimen>\n    <dimen name=\"mediumText\">22dp</dimen>\n    <dimen name=\"smallText\">16dp</dimen>\n    <dimen name=\"headerIconWidth\">20dp</dimen>\n    <dimen name=\"headerIconHeight\">20dp</dimen>\n    <dimen name=\"headerHeight\">40dp</dimen>\n    <dimen name=\"llcMarginBottom\">0dp</dimen>\n</resources>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/values/key.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"key\">TEMPORARYKEY_CHANGETHISKEY</string>\n\n    <string name=\"app_name\">AA Wearable Intelligence System</string>\n    <string name=\"error_cannot_write\">Cannot write image captured by camera.</string>\n    <string name=\"error_cannot_open\">Cannot open camera.</string>\n    <string name=\"error_cannot_get_permission\">Camera permission not available.</string>\n    <string name=\"error_not_having_camera\">Your device does not have front camera.</string>\n    <string name=\"error_camera_permission_denied\">Camera permission denied.</string>\n    <string name=\"btn_tittle_capture_image\">Capture image</string>\n    <string name=\"waiting_message\">Waiting for data...</string>\n    <string name=\"title_eye_contact\">Eye Contact: </string>\n    <string name=\"title_facial_emotion\">Face Emo.: </string>\n    <string name=\"data_loading\">...</string>\n    <string name=\"cam_on\">START</string>\n    <string name=\"cam_off\">STOP</string>\n    <string name=\"asg_socket\">asg_socket</string>\n\n    <string name=\"post_wake_text\">Say a command:</string>\n    <string name=\"home_screen_text_prompt\">Say \\'hey computer\\'...</string>\n</resources>\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/values/themes.xml",
    "content": "<resources xmlns:tools=\"http://schemas.android.com/tools\">\n    <!-- Base application theme. -->\n    <style name=\"Theme.WearableAiDisplayMoverio\" parent=\"Theme.AppCompat.Light.NoActionBar\">\n        <!-- Primary brand color. -->\n        <item name=\"colorPrimary\">@color/purple_500</item>\n        <item name=\"colorPrimaryDark\">@color/purple_700</item>\n        <item name=\"colorAccent\">@color/teal_200</item>\n        <!-- Customize your theme here. -->\n    </style>\n</resources>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/main/res/values-night/themes.xml",
    "content": "<resources xmlns:tools=\"http://schemas.android.com/tools\">\n    <!-- Base application theme. -->\n    <style name=\"Theme.WearableAiDisplayMoverio\" parent=\"Theme.AppCompat.Light.NoActionBar\">\n        <!-- Primary brand color. -->\n        <item name=\"colorPrimary\">@color/purple_200</item>\n        <item name=\"colorPrimaryDark\">@color/purple_700</item>\n        <item name=\"colorAccent\">@color/teal_200</item>\n        <!-- Customize your theme here. -->\n    </style>\n</resources>"
  },
  {
    "path": "android_smart_glasses_frontend/main/app/src/test/java/com/example/wearableintelligencesystemandroidsmartglasses/ExampleUnitTest.java",
    "content": "package com.example.androidsmartglasses;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "android_smart_glasses_frontend/main/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\nbuildscript {\n    repositories {\n        google()\n        mavenCentral()\n        flatDir {\n            dirs 'libs'\n        }\n    }\n    dependencies {\n        classpath \"com.android.tools.build:gradle:8.0.1\"\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        mavenCentral()\n        //maven { url \"https://oss.jfrog.org/libs-snapshot\" }\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.0.2-bin.zip\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\nandroid.useAndroidX=true\n\nandroid.enableJetifier=true"
  },
  {
    "path": "android_smart_glasses_frontend/main/gradlew",
    "content": "#!/bin/sh\n\n#\n# Copyright © 2015-2021 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n#\n#   Gradle start up script for POSIX generated by Gradle.\n#\n#   Important for running:\n#\n#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is\n#       noncompliant, but you have some other compliant shell such as ksh or\n#       bash, then to run this script, type that shell name before the whole\n#       command line, like:\n#\n#           ksh Gradle\n#\n#       Busybox and similar reduced shells will NOT work, because this script\n#       requires all of these POSIX shell features:\n#         * functions;\n#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,\n#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;\n#         * compound commands having a testable exit status, especially «case»;\n#         * various built-in commands including «command», «set», and «ulimit».\n#\n#   Important for patching:\n#\n#   (2) This script targets any POSIX shell, so it avoids extensions provided\n#       by Bash, Ksh, etc; in particular arrays are avoided.\n#\n#       The \"traditional\" practice of packing multiple parameters into a\n#       space-separated string is a well documented source of bugs and security\n#       problems, so this is (mostly) avoided, by progressively accumulating\n#       options in \"$@\", and eventually passing that to Java.\n#\n#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,\n#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;\n#       see the in-line comments for details.\n#\n#       There are tweaks for specific operating systems such as AIX, CygWin,\n#       Darwin, MinGW, and NonStop.\n#\n#   (3) This script is generated from the Groovy template\n#       https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt\n#       within the Gradle project.\n#\n#       You can find Gradle at https://github.com/gradle/gradle/.\n#\n##############################################################################\n\n# Attempt to set APP_HOME\n\n# Resolve links: $0 may be a link\napp_path=$0\n\n# Need this for daisy-chained symlinks.\nwhile\n    APP_HOME=${app_path%\"${app_path##*/}\"}  # leaves a trailing /; empty if no leading path\n    [ -h \"$app_path\" ]\ndo\n    ls=$( ls -ld \"$app_path\" )\n    link=${ls#*' -> '}\n    case $link in             #(\n      /*)   app_path=$link ;; #(\n      *)    app_path=$APP_HOME$link ;;\n    esac\ndone\n\nAPP_HOME=$( cd \"${APP_HOME:-./}\" && pwd -P ) || exit\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=${0##*/}\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=maximum\n\nwarn () {\n    echo \"$*\"\n} >&2\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n} >&2\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"$( uname )\" in                #(\n  CYGWIN* )         cygwin=true  ;; #(\n  Darwin* )         darwin=true  ;; #(\n  MSYS* | MINGW* )  msys=true    ;; #(\n  NONSTOP* )        nonstop=true ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=$JAVA_HOME/jre/sh/java\n    else\n        JAVACMD=$JAVA_HOME/bin/java\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=java\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif ! \"$cygwin\" && ! \"$darwin\" && ! \"$nonstop\" ; then\n    case $MAX_FD in #(\n      max*)\n        MAX_FD=$( ulimit -H -n ) ||\n            warn \"Could not query maximum file descriptor limit\"\n    esac\n    case $MAX_FD in  #(\n      '' | soft) :;; #(\n      *)\n        ulimit -n \"$MAX_FD\" ||\n            warn \"Could not set maximum file descriptor limit to $MAX_FD\"\n    esac\nfi\n\n# Collect all arguments for the java command, stacking in reverse order:\n#   * args from the command line\n#   * the main class name\n#   * -classpath\n#   * -D...appname settings\n#   * --module-path (only if needed)\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif \"$cygwin\" || \"$msys\" ; then\n    APP_HOME=$( cygpath --path --mixed \"$APP_HOME\" )\n    CLASSPATH=$( cygpath --path --mixed \"$CLASSPATH\" )\n\n    JAVACMD=$( cygpath --unix \"$JAVACMD\" )\n\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    for arg do\n        if\n            case $arg in                                #(\n              -*)   false ;;                            # don't mess with options #(\n              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath\n                    [ -e \"$t\" ] ;;                      #(\n              *)    false ;;\n            esac\n        then\n            arg=$( cygpath --path --ignore --mixed \"$arg\" )\n        fi\n        # Roll the args list around exactly as many times as the number of\n        # args, so each arg winds up back in the position where it started, but\n        # possibly modified.\n        #\n        # NB: a `for` loop captures its iteration list before it begins, so\n        # changing the positional parameters here affects neither the number of\n        # iterations, nor the values presented in `arg`.\n        shift                   # remove old arg\n        set -- \"$@\" \"$arg\"      # push replacement arg\n    done\nfi\n\n# Collect all arguments for the java command;\n#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of\n#     shell script including quotes and variable substitutions, so put them in\n#     double quotes to make sure that they get re-expanded; and\n#   * put everything else in single quotes, so that it's not re-expanded.\n\nset -- \\\n        \"-Dorg.gradle.appname=$APP_BASE_NAME\" \\\n        -classpath \"$CLASSPATH\" \\\n        org.gradle.wrapper.GradleWrapperMain \\\n        \"$@\"\n\n# Use \"xargs\" to parse quoted args.\n#\n# With -n1 it outputs one arg per line, with the quotes and backslashes removed.\n#\n# In Bash we could simply go:\n#\n#   readarray ARGS < <( xargs -n1 <<<\"$var\" ) &&\n#   set -- \"${ARGS[@]}\" \"$@\"\n#\n# but POSIX shell has neither arrays nor command substitution, so instead we\n# post-process each arg (as a line of input to sed) to backslash-escape any\n# character that might be a shell metacharacter, then use eval to reverse\n# that process (while maintaining the separation between arguments), and wrap\n# the whole thing up as a single \"set\" statement.\n#\n# This will of course break if any of these variables contains a newline or\n# an unmatched quote.\n#\n\neval \"set -- $(\n        printf '%s\\n' \"$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\" |\n        xargs -n1 |\n        sed ' s~[^-[:alnum:]+,./:=@_]~\\\\&~g; ' |\n        tr '\\n' ' '\n    )\" '\"$@\"'\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto init\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:init\r\n@rem Get command-line arguments, handling Windows variants\r\n\r\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\r\n\r\n:win9xME_args\r\n@rem Slurp the command line arguments.\r\nset CMD_LINE_ARGS=\r\nset _SKIP=2\r\n\r\n:win9xME_args_slurp\r\nif \"x%~1\" == \"x\" goto execute\r\n\r\nset CMD_LINE_ARGS=%*\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "android_smart_glasses_frontend/main/settings.gradle",
    "content": "include ':app'\nrootProject.name = \"WearableIntelligenceSystemAndroidSmartGlasses\""
  },
  {
    "path": "example_smart_glasses_app/.gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/caches\n/.idea/libraries\n/.idea/modules.xml\n/.idea/workspace.xml\n/.idea/navEditor.xml\n/.idea/assetWizardSettings.xml\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n.cxx\nlocal.properties\n"
  },
  {
    "path": "example_smart_glasses_app/app/.gitignore",
    "content": "/build"
  },
  {
    "path": "example_smart_glasses_app/app/build.gradle",
    "content": "plugins {\n    id 'com.android.application'\n}\n\nandroid {\n    namespace 'com.teamopensmartglasses.example_smart_glasses_app'\n    compileSdk 33\n\n    defaultConfig {\n        applicationId \"com.teamopensmartglasses.example_smart_glasses_app\"\n        minSdk 31\n        targetSdk 33\n        versionCode 1\n        versionName \"1.0\"\n\n        testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n    }\n\n    packagingOptions {\n        exclude 'META-INF/proguard/androidx-annotations.pro'\n        resources {\n            excludes += '/META-INF/{AL2.0,LGPL2.1,DEPENDENCIES}'\n            excludes += '/META-INF/INDEX.LIST'\n        }\n    }\n\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n        }\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\next {\n    archLifecycleVersion = '2.2.0-rc03'\n}\n\ndependencies {\n\n    implementation 'androidx.appcompat:appcompat:1.6.1'\n    implementation 'com.google.android.material:material:1.5.0'\n    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'\n    testImplementation 'junit:junit:4.13.2'\n    androidTestImplementation 'androidx.test.ext:junit:1.1.5'\n    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'\n\n    //EventBus, greenrobot\n    implementation(\"org.greenrobot:eventbus:3.3.1\")\n\n    //navigation\n    implementation \"androidx.navigation:navigation-fragment:2.2.0\"\n    implementation \"androidx.navigation:navigation-ui:2.2.0\"\n    implementation \"androidx.navigation:navigation-runtime:2.2.0\"\n    implementation \"androidx.fragment:fragment:1.2.0\"\n\n    //Smart Glasses Manager\n    implementation project(path: ':smartglassesmanager')\n\n    // Lifecycle components\n    implementation \"androidx.lifecycle:lifecycle-extensions:$archLifecycleVersion\"\n    annotationProcessor \"androidx.lifecycle:lifecycle-compiler:$archLifecycleVersion\"\n    implementation \"com.google.guava:guava:28.1-android\"\n\n}"
  },
  {
    "path": "example_smart_glasses_app/app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile"
  },
  {
    "path": "example_smart_glasses_app/app/src/androidTest/java/com/teamopensmartglasses/example_smart_glasses_app/ExampleInstrumentedTest.java",
    "content": "package com.teamopensmartglasses.example_smart_glasses_app;\n\nimport android.content.Context;\n\nimport androidx.test.platform.app.InstrumentationRegistry;\nimport androidx.test.ext.junit.runners.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();\n        assertEquals(\"com.teamopensmartglasses.example_smart_glasses_app\", appContext.getPackageName());\n    }\n}"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <uses-permission android:name=\"android.permission.FOREGROUND_SERVICE\"/>\n\n    <application\n        android:allowBackup=\"true\"\n        android:dataExtractionRules=\"@xml/data_extraction_rules\"\n        android:fullBackupContent=\"@xml/backup_rules\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\"\n        tools:targetApi=\"31\">\n        <activity\n            android:name=\".MainActivity\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n\n        <service\n            android:name=\".SmartGlassesService\"\n            android:enabled=\"true\"\n            android:exported=\"false\">\n            <!-- Intent filters can be placed here if you want to expose the service to other apps -->\n        </service>\n    </application>\n\n</manifest>"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/java/com/teamopensmartglasses/example_smart_glasses_app/MainActivity.java",
    "content": "package com.teamopensmartglasses.example_smart_glasses_app;\n\nimport android.app.ActivityManager;\nimport android.content.BroadcastReceiver;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.ServiceConnection;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.util.Log;\n\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.appcompat.widget.Toolbar;\nimport androidx.navigation.NavController;\nimport androidx.navigation.fragment.NavHostFragment;\n\nimport com.google.android.material.bottomnavigation.BottomNavigationView;\nimport com.teamopensmartglasses.smartglassesmanager.comms.MessageTypes;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.ASR_FRAMEWORKS;\nimport com.teamopensmartglasses.smartglassesmanager.supportedglasses.AudioWearable;\nimport com.teamopensmartglasses.smartglassesmanager.supportedglasses.InmoAirOne;\nimport com.teamopensmartglasses.smartglassesmanager.supportedglasses.SmartGlassesDevice;\nimport com.teamopensmartglasses.smartglassesmanager.supportedglasses.TCLRayNeoXTwo;\nimport com.teamopensmartglasses.smartglassesmanager.supportedglasses.VuzixShield;\nimport com.teamopensmartglasses.smartglassesmanager.supportedglasses.VuzixUltralite;\nimport com.teamopensmartglasses.smartglassesmanager.utils.PermissionsUtils;\n\n/** This provides a simple UI for users to connect and setup their glasses. This activity launches the service which does all of the work to communicate with glasses and third party apps. **/\npublic class MainActivity extends AppCompatActivity {\n    private  final String TAG = \"SGM_ExampleApp_MainActivity\";\n\n    //the smart glasses we're currently connecting and communicating with\n    public SmartGlassesDevice selectedDevice;\n\n    //handle the foreground service which does all of the important stuff\n    public SmartGlassesService mService;\n    boolean mBound = false;\n\n    //handle permissions\n    PermissionsUtils permissionsUtils;\n\n    //UI - bottom nav bar\n    private BottomNavigationView bottomNavigation;\n    private NavController navController;\n\n    //list of glasses we support\n    public SmartGlassesDevice [] smartGlassesDevices;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mBound = false;\n\n        //setup action bar\n        Toolbar myToolbar = (Toolbar) findViewById(R.id.main_toolbar);\n        setSupportActionBar(myToolbar);\n\n        //set main view\n        setContentView(R.layout.activity_main);\n\n        //setup the available smart glasses we support\n        smartGlassesDevices = new SmartGlassesDevice[]{new VuzixShield(), new InmoAirOne(), new TCLRayNeoXTwo(), new VuzixUltralite(), new AudioWearable()};\n\n        //setup the nav bar\n        NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);\n        Log.d(TAG, getSupportFragmentManager().getFragments().toString());\n        navController = navHostFragment.getNavController();\n\n        //get permissions\n        permissionsUtils = new PermissionsUtils(this, TAG);\n        permissionsUtils.getSomePermissions();\n    }\n\n    private static IntentFilter makeMainServiceReceiverIntentFilter() {\n        final IntentFilter intentFilter = new IntentFilter();\n        intentFilter.addAction(MessageTypes.GLASSES_STATUS_UPDATE);\n\n        return intentFilter;\n    }\n\n    private final BroadcastReceiver mMainServiceReceiver = new BroadcastReceiver() {\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            final String action = intent.getAction();\n            if (MessageTypes.GLASSES_STATUS_UPDATE.equals(action)) {\n                int glassesConnectionState = intent.getIntExtra(MessageTypes.CONNECTION_GLASSES_STATUS_UPDATE, -1);\n                SmartGlassesDevice smartGlassesDevice = (SmartGlassesDevice) intent.getSerializableExtra(MessageTypes.CONNECTION_GLASSES_GLASSES_OBJECT);\n                updateGlassesConnectionState(glassesConnectionState, smartGlassesDevice);\n            }\n        }\n    };\n\n    public void updateGlassesConnectionState(int glassesConnectionState, SmartGlassesDevice smartGlassesDevice){\n        selectedDevice = smartGlassesDevice;\n        if (selectedDevice != null) {\n            selectedDevice.setConnectionState(glassesConnectionState);\n        }\n\n        //show connection page\n        if (glassesConnectionState == 2){\n            navController.navigate(R.id.nav_connected_to_smart_glasses);\n        }\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n\n        //register receiver that gets data from the service\n        registerReceiver(mMainServiceReceiver, makeMainServiceReceiverIntentFilter());\n\n        if (isMyServiceRunning(SmartGlassesService.class)) {\n            //bind to Smart Glasses service\n            bindSmartGlassesService();\n\n            //ask the service to send us information about the connection\n            if (mService != null) {\n                mService.sendUiUpdate();\n            }\n        }\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n\n        //unbind wearableAi service\n        unbindSmartGlassesService();\n\n        //unregister receiver\n        unregisterReceiver(mMainServiceReceiver);\n    }\n\n    public void stopSmartGlassesService() {\n        Log.d(TAG, \"Stopping SmartGlassesService\");\n        unbindSmartGlassesService();\n\n        if (!isMyServiceRunning(SmartGlassesService.class)) return;\n        Intent stopIntent = new Intent(this, SmartGlassesService.class);\n        stopIntent.setAction(SmartGlassesService.ACTION_STOP_FOREGROUND_SERVICE);\n        startService(stopIntent);\n    }\n\n    public void startSmartGlassesService() {\n        Log.d(TAG, \"Starting SmartGlassesService\");\n        if (isMyServiceRunning(SmartGlassesService.class)){\n            Log.i(TAG, \"SmartGlassesService already running, stopping...\");\n            stopSmartGlassesService();\n        }\n\n        Intent startIntent = new Intent(this, SmartGlassesService.class);\n        startIntent.setAction(SmartGlassesService.ACTION_START_FOREGROUND_SERVICE);\n        startService(startIntent);\n        bindSmartGlassesService();\n    }\n\n    //check if service is running\n    private boolean isMyServiceRunning(Class<?> serviceClass) {\n        ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);\n        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {\n            if (serviceClass.getName().equals(service.service.getClassName())) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    //handle bottom app bar navigation - if you want a multi-page app, this is ready to go\n//    private void setupBottomNavBar(){\n//        bottomNavigation = (BottomNavigationView) findViewById(R.id.bottom_nav_main_menu_nav);\n//        bottomNavigation.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {\n//            @Override\n//            public boolean onNavigationItemSelected(@NonNull MenuItem item) {\n//                //this has to be an if-else: https://stackoverflow.com/questions/21005205/what-causes-constant-expression-required-errors-for-the-generated-r-id-xxx-val\n//                int itemId = item.getItemId();\n//                if(R.id.memory_page == itemId){\n//                    Log.d(TAG, \"Clicked memory tools\");\n//                    navController.navigate(R.id.nav_memory_tools);\n//                } else if (R.id.smart_glasses_debug_page == itemId){\n//                    Log.d(TAG, \"Clicked smart glasses debug page\");\n//                    navController.navigate(R.id.nav_smart_glasses_debug);\n//                } else if (R.id.settings_page == itemId){\n//                    Log.d(TAG, \"Clicked settings page\");\n//                    navController.navigate(R.id.nav_settings);\n//                }\n//                return true;\n//            }\n//        });\n//    }\n\n    public void bindSmartGlassesService(){\n        // Bind to that service\n        if (!mBound){\n            Intent intent = new Intent(this, SmartGlassesService.class);\n            bindService(intent, wearableAiServiceConnection, Context.BIND_AUTO_CREATE);\n        }\n    }\n\n    public void unbindSmartGlassesService() {\n        // Bind to that service\n        if (mBound){\n            unbindService(wearableAiServiceConnection);\n            mBound = false;\n        }\n    }\n\n    /** Defines callbacks for service binding, passed to bindService() */\n    private ServiceConnection wearableAiServiceConnection = new ServiceConnection() {\n\n        @Override\n        public void onServiceConnected(ComponentName className,\n                                       IBinder service) {\n            // We've bound to LocalService, cast the IBinder and get LocalService instance\n            SmartGlassesService.LocalBinder wearableAiServiceBinder = (SmartGlassesService.LocalBinder) service;\n            mService = (SmartGlassesService) wearableAiServiceBinder.getService();\n            mBound = true;\n\n            //get update for UI\n            mService.sendUiUpdate();\n        }\n\n        @Override\n        public void onServiceDisconnected(ComponentName arg0) {\n            mBound = false;\n        }\n    };\n\n    //this should only be called after the Smart glasses Service is up and bound\n    public void connectSmartGlasses(SmartGlassesDevice device){\n        this.selectedDevice = device;\n\n        //check if the service is running. If not, we should start it first, so it doesn't die when we unbind\n        if (!isMyServiceRunning(SmartGlassesService.class)){\n            Log.e(TAG, \"Something went wrong, service should be started and bound.\");\n        } else {\n            mService.connectToSmartGlasses(device);\n        }\n    }\n\n    public boolean areSmartGlassesConnected(){\n        if (!isMyServiceRunning(SmartGlassesService.class)){\n            return false;\n        } else {\n            return (mService.getSmartGlassesConnectState() == 2);\n        }\n    }\n\n    public void changeAsrFramework(ASR_FRAMEWORKS asrFramework){\n        if (mService != null){\n            mService.changeChosenAsrFramework(asrFramework);\n        }\n    }\n}"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/java/com/teamopensmartglasses/example_smart_glasses_app/SmartGlassesService.java",
    "content": "package com.teamopensmartglasses.example_smart_glasses_app;\n\nimport org.greenrobot.eventbus.EventBus;\nimport org.greenrobot.eventbus.Subscribe;\n\nimport android.util.Log;\n\nimport com.teamopensmartglasses.smartglassesmanager.SmartGlassesAndroidService;\nimport com.teamopensmartglasses.smartglassesmanager.eventbusmessages.GlassesTapOutputEvent;\nimport com.teamopensmartglasses.smartglassesmanager.eventbusmessages.SmartRingButtonOutputEvent;\nimport com.teamopensmartglasses.smartglassesmanager.eventbusmessages.SpeechRecOutputEvent;\n\npublic class SmartGlassesService extends SmartGlassesAndroidService {\n    public String TAG = \"SmartGlassesExampleApp_Service\";\n\n    public SmartGlassesService(){\n        super(MainActivity.class,\n                \"example_smart_glasses_app\",\n                1837, //choose your own number here\n                \"Example Smart Glasses App\",\n                \"An example app for smart glasses\",\n                R.drawable.ic_launcher_foreground);\n\n        //register subscribers on EventBus\n        EventBus.getDefault().register(this);\n    }\n\n    @Subscribe\n    public void onTranscript(SpeechRecOutputEvent event) {\n        String text = event.text;\n        long time = event.timestamp;\n        boolean isFinal = event.isFinal;\n\n        if (isFinal) {\n            Log.d(TAG, \"Got a final transcript\");\n        } else {\n            Log.d(TAG, \"Got an intermediate transcript\");\n        }\n    }\n\n    @Subscribe\n    public void onSmartRingButtonEvent(SmartRingButtonOutputEvent event) {\n        int buttonId = event.buttonId;\n        long time = event.timestamp;\n\n        Log.d(TAG, \"Got an smart ring button event\");\n    }\n\n    @Subscribe\n    public void onGlassesTapSideEvent(GlassesTapOutputEvent event) {\n        int numTaps = event.numTaps;\n        boolean sideOfGlasses = event.sideOfGlasses;\n        long time = event.timestamp;\n        Log.d(TAG, \"Got an glasses tap event, number of taps is: \" + numTaps);\n    }\n\n    public void deinit(){\n        EventBus.getDefault().unregister(this);\n    }\n}\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/java/com/teamopensmartglasses/example_smart_glasses_app/ui/ConnectingToSmartGlassesUi.java",
    "content": "package com.teamopensmartglasses.example_smart_glasses_app.ui;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Button;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\nimport androidx.navigation.NavController;\nimport androidx.navigation.Navigation;\n\nimport com.teamopensmartglasses.example_smart_glasses_app.MainActivity;\nimport com.teamopensmartglasses.example_smart_glasses_app.R;\n\npublic class ConnectingToSmartGlassesUi extends Fragment {\n    private  final String TAG = \"WearableAi_ConnectingToSmartGlassesUIFragment\";\n\n    private final String fragmentLabel = \"Connecting to Smart Glasses\";\n\n    private NavController navController;\n\n    public ConnectingToSmartGlassesUi() {\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container,\n                             Bundle savedInstanceState) {\n        // Inflate the layout for this fragment\n        return inflater.inflate(R.layout.connecting_to_glasses_fragment, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        //setup the title\n        UiUtils.setupTitle(getActivity(), fragmentLabel);\n\n        navController = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);\n\n        final Button cancelConnectButton = view.findViewById(R.id.ok_glasses_connected_button);\n        cancelConnectButton.setOnClickListener(new View.OnClickListener() {\n            public void onClick(View v) {\n                // Code here executes on main thread after user presses button\n                ((MainActivity)getActivity()).stopSmartGlassesService();\n                navController.navigate(R.id.nav_settings);\n            }\n        });\n    }\n}"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/java/com/teamopensmartglasses/example_smart_glasses_app/ui/GlassesConnectedFragment.java",
    "content": "package com.teamopensmartglasses.example_smart_glasses_app.ui;\n\nimport android.graphics.drawable.Drawable;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Button;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\nimport androidx.navigation.NavController;\nimport androidx.navigation.Navigation;\n\nimport com.teamopensmartglasses.example_smart_glasses_app.MainActivity;\nimport com.teamopensmartglasses.example_smart_glasses_app.R;\nimport com.teamopensmartglasses.smartglassesmanager.supportedglasses.SmartGlassesDevice;\n\npublic class GlassesConnectedFragment extends Fragment {\n    private  final String TAG = \"WearableAi_GlassesConnectedFragment\";\n\n    private final String fragmentLabel = \"Connecting to Smart Glasses\";\n\n    private NavController navController;\n\n    public GlassesConnectedFragment() {\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container,\n                             Bundle savedInstanceState) {\n        // Inflate the layout for this fragment\n        return inflater.inflate(R.layout.glasses_connected_fragment, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        //setup the title\n        UiUtils.setupTitle(getActivity(), fragmentLabel);\n\n        navController = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);\n\n        //get the selected device\n        SmartGlassesDevice device = ((MainActivity)getActivity()).selectedDevice;\n        if (device == null){\n            return;\n        }\n\n        //setup the image view\n        ImageView connectedImageIv = (ImageView) view.findViewById(R.id.connected_glasses_image);\n        String uri = \"@drawable/\" + device.getDeviceIconName();  // where myresource (without the extension) is the file\n        int imageResource = view.getContext().getResources().getIdentifier(uri, null, view.getContext().getPackageName());\n        Drawable res = view.getContext().getResources().getDrawable(imageResource);\n        connectedImageIv.setImageDrawable(res);\n\n        //setup the message\n        TextView connectedMessageTv = (TextView) view.findViewById(R.id.glasses_connected_message_tv);\n        connectedMessageTv.setText(device.getDeviceModelName() + \" is now connected!\");\n\n        final Button okButton = view.findViewById(R.id.ok_glasses_connected_button);\n        okButton.setOnClickListener(new View.OnClickListener() {\n            public void onClick(View v) {\n                // Code here executes on main thread after user presses button\n                navController.navigate(R.id.nav_settings);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/java/com/teamopensmartglasses/example_smart_glasses_app/ui/SelectSmartGlassesUi.java",
    "content": "package com.teamopensmartglasses.example_smart_glasses_app.ui;\n\nimport android.app.AlertDialog;\nimport android.content.DialogInterface;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.Button;\nimport android.widget.ListView;\n\nimport androidx.fragment.app.Fragment;\nimport androidx.navigation.NavController;\nimport androidx.navigation.Navigation;\n\nimport com.teamopensmartglasses.example_smart_glasses_app.MainActivity;\nimport com.teamopensmartglasses.example_smart_glasses_app.R;\nimport com.teamopensmartglasses.smartglassesmanager.supportedglasses.SmartGlassesDevice;\n\nimport java.util.ArrayList;\n\npublic class SelectSmartGlassesUi extends Fragment {\n    public String TAG = \"WearableAi_SelectSmartGlassesUi\";\n\n    private final String fragmentLabel = \"Select Glasses to Connect...\";\n\n    private NavController navController;\n\n    //UI elements\n    private ListView glassesList;\n\n    public SelectSmartGlassesUi() {\n        // Required empty public constructor\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container,\n                             Bundle savedInstanceState) {\n\n        // Inflate the layout for this fragment\n        return inflater.inflate(R.layout.select_glasses_fragment, container, false);\n    }\n\n    @Override\n    public void onViewCreated(View view, Bundle savedInstanceState){\n        //setup titlebar\n        UiUtils.setupTitle(getActivity(), fragmentLabel);\n\n        //get the nav controller\n        navController = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);\n\n        //setup list of smart glasses\n        glassesList = view.findViewById(R.id.smart_glasses_list);\n\n        // on the below line we are initializing the adapter for our list view.\n        ArrayList<SmartGlassesDevice> glassesArrayList = new ArrayList<>();\n\n        //ArrayAdapter<String> glassesListAdapter = new ArrayAdapter<>(view.getContext(), android.R.layout.simple_list_item_activated_1, glassesArrayList);\n        SmartGlassesListAdapter glassesListAdapter = new SmartGlassesListAdapter(glassesArrayList, getContext());\n\n        //listen for list presses\n        glassesList.setOnItemClickListener(new AdapterView.OnItemClickListener()\n        {\n            @Override\n            public void onItemClick(AdapterView<?> adapter, View v, int position,\n                                    long arg3)\n            {\n                glassesListAdapter.setSelectedPosition(position);\n            }\n        });\n\n        // on below line we are setting adapter for our list view.\n        glassesList.setAdapter(glassesListAdapter);\n        for (SmartGlassesDevice device : ((MainActivity)getActivity()).smartGlassesDevices){\n            Log.d(TAG, device.getDeviceModelName());\n            glassesListAdapter.add(device);\n        }\n\n        //setup buttons\n        final Button cancelButton = view.findViewById(R.id.cancel_select_smart_glasses_button);\n        cancelButton.setOnClickListener(new View.OnClickListener() {\n            public void onClick(View v) {\n                // Code here executes on main thread after user presses button\n                navController.navigate(R.id.nav_settings);\n            }\n        });\n\n        final Button selectButton = view.findViewById(R.id.select_smart_glasses_button);\n        selectButton.setOnClickListener(new View.OnClickListener() {\n            public void onClick(View v) {\n                // Code here executes on main thread after user presses button\n                SmartGlassesDevice selectedDevice = glassesListAdapter.getSelectedDevice();\n                if (selectedDevice == null) {\n                    Log.d(TAG, \"Please choose a smart glasses device to continue.\");\n                    showNoGlassSelectedDialog();\n                } else if (!selectedDevice.getAnySupport()){\n                    Log.d(TAG, \"Glasses not yet supported, we're working on it.\");\n                    showUnsupportedGlassSelected();\n                } else {\n                    Log.d(TAG, \"Connecting to \" + selectedDevice.getDeviceModelName() + \"...\");\n                    navController.navigate(R.id.nav_connecting_to_smart_glasses);\n                    ((MainActivity)getActivity()).connectSmartGlasses(selectedDevice);\n                }\n            }\n        });\n    }\n\n    public void showNoGlassSelectedDialog(){\n        new AlertDialog.Builder(this.getContext()) .setIcon(android.R.drawable.ic_dialog_alert)\n                .setTitle(\"No Smart Glasses Selected\")\n                .setMessage(\"Please select a smart glasses model from the list to proceed, or press 'Cancel'.\")\n                .setPositiveButton(\"Ok\", new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                    }\n                }).show();\n    }\n\n    public void showUnsupportedGlassSelected(){\n        new AlertDialog.Builder(this.getContext()) .setIcon(android.R.drawable.ic_dialog_info)\n                .setTitle(\"Unsupported Smart Glasses Selected\")\n                .setMessage(\"We don't yet support those smart glasses, but we're working to add support for them. Please choose another pair of smart glasses from the list.\")\n                .setPositiveButton(\"Ok\", new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                    }\n                }).show();\n    }\n}\n\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/java/com/teamopensmartglasses/example_smart_glasses_app/ui/SettingsUi.java",
    "content": "package com.teamopensmartglasses.example_smart_glasses_app.ui;\n\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.text.Html;\nimport android.text.InputType;\nimport android.text.method.LinkMovementMethod;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Button;\nimport android.widget.CompoundButton;\nimport android.widget.EditText;\nimport android.widget.LinearLayout;\nimport android.widget.Switch;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.fragment.app.Fragment;\nimport androidx.navigation.NavController;\nimport androidx.navigation.Navigation;\n\nimport com.teamopensmartglasses.example_smart_glasses_app.MainActivity;\nimport com.teamopensmartglasses.example_smart_glasses_app.SmartGlassesService;\nimport com.teamopensmartglasses.smartglassesmanager.R;\nimport com.teamopensmartglasses.smartglassesmanager.speechrecognition.ASR_FRAMEWORKS;\n\npublic class SettingsUi extends Fragment {\n    private  final String TAG = \"WearableAi_SettingsUIFragment\";\n\n    private final String fragmentLabel = \"Example Smart Glasses App\";\n\n    private NavController navController;\n\n    //test card raw data\n    public String testCardImg = \"https://ichef.bbci.co.uk/news/976/cpsprodpb/7727/production/_103330503_musk3.jpg\";\n    public String testCardTitle = \"Test Card\";\n    public String testCardContent = \"This is an example of a reference card. This appears on your glasses after pressing the 'Send Test Card' button.\";\n\n    public SettingsUi() {\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container,\n                             Bundle savedInstanceState) {\n        // Inflate the layout for this fragment\n        return inflater.inflate(R.layout.settings_fragment, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        //setup the title\n        UiUtils.setupTitle(getActivity(), fragmentLabel);\n\n        navController = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);\n        Context mContext = this.getContext();\n\n        final Button killServiceButton = view.findViewById(R.id.kill_wearableai_service);\n//        if (((MainActivity)getActivity()).areSmartGlassesConnected()){\n//            killServiceButton.setEnabled(true);\n//        } else {\n//            killServiceButton.setEnabled(false);\n//        }\n        killServiceButton.setOnClickListener(new View.OnClickListener() {\n                public void onClick(View v) {\n                // Code here executes on main thread after user presses button\n                ((MainActivity)getActivity()).stopSmartGlassesService();\n            }\n        });\n\n        final Button connectSmartGlassesButton = view.findViewById(R.id.connect_smart_glasses);\n            connectSmartGlassesButton.setOnClickListener(new View.OnClickListener() {\n                public void onClick(View v) {\n                // Code here executes on main thread after user presses button\n                //check to first make sure that user isn't trying to enable google without providing API key\n                if (SmartGlassesService.getChosenAsrFramework(mContext) == ASR_FRAMEWORKS.GOOGLE_ASR_FRAMEWORK) {\n                    String apiKey = SmartGlassesService.getApiKey(mContext);\n                    if (apiKey == null || apiKey.equals(\"\")) {\n                        showNoGoogleAsrDialog();\n                        return;\n                    }\n                }\n\n                ((MainActivity)getActivity()).startSmartGlassesService();\n                navController.navigate(R.id.nav_select_smart_glasses);\n            }\n        });\n\n        final Button startHotspotButton = view.findViewById(R.id.start_hotspot);\n            startHotspotButton.setOnClickListener(new View.OnClickListener() {\n                public void onClick(View v) {\n                // Code here executes on main thread after user presses button\n                launchHotspotSettings();\n            }\n        });\n\n        // setup test card sender\n        final Button sendTestCardButton = view.findViewById(R.id.send_test_card_old);\n//        if (((MainActivity)getActivity()).areSmartGlassesConnected()){\n//            sendTestCardButton.setEnabled(true);\n//        } else {\n//            sendTestCardButton.setEnabled(false);\n//        }\n\n        sendTestCardButton.setOnClickListener(new View.OnClickListener() {\n            public void onClick(View v) {\n                // Code here executes on main thread after user presses button\n                sendTestCard();\n            }\n        });\n\n        final Button setGoogleApiKeyButton = view.findViewById(R.id.google_api_change);\n        final Switch switchGoogleAsr = view.findViewById(R.id.google_asr_switch);\n\n        //find out the current ASR state, remember it\n        ASR_FRAMEWORKS asrFramework = SmartGlassesService.getChosenAsrFramework(mContext);\n        switchGoogleAsr.setChecked(asrFramework == ASR_FRAMEWORKS.GOOGLE_ASR_FRAMEWORK);\n\n        setGoogleApiKeyButton.setEnabled(switchGoogleAsr.isChecked());\n        setGoogleApiKeyButton.setOnClickListener(new View.OnClickListener() {\n            public void onClick(View v) {\n                showAPIKeyDialog();\n            }\n        });\n\n        switchGoogleAsr.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {\n            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {\n                setGoogleApiKeyButton.setEnabled(isChecked);\n                //save explicitly as well as force change in case the service is down, we want this to be saved either way\n                if (isChecked) {\n                    SmartGlassesService.saveChosenAsrFramework(mContext, ASR_FRAMEWORKS.GOOGLE_ASR_FRAMEWORK);\n                    ((MainActivity)getActivity()).changeAsrFramework(ASR_FRAMEWORKS.GOOGLE_ASR_FRAMEWORK);\n                } else {\n                    SmartGlassesService.saveChosenAsrFramework(mContext, ASR_FRAMEWORKS.VOSK_ASR_FRAMEWORK);\n                    ((MainActivity)getActivity()).changeAsrFramework(ASR_FRAMEWORKS.VOSK_ASR_FRAMEWORK);\n                }\n            }\n        });\n    }\n\n    public void sendTestCard(){\n        Log.d(TAG, \"SENDING TEST CARD\");\n        ((MainActivity)getActivity()).mService.sendTestCard(testCardTitle, testCardContent, testCardImg);\n    }\n\n    //open hotspot settings\n    private void launchHotspotSettings(){\n        final Intent intent = new Intent(Intent.ACTION_MAIN, null);\n        intent.addCategory(Intent.CATEGORY_LAUNCHER);\n        final ComponentName cn = new ComponentName(\"com.android.settings\", \"com.android.settings.TetherSettings\");\n        intent.setComponent(cn);\n        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        startActivity( intent);\n    }\n\n    /** The API won't work without a valid API key. This prompts the user to enter one. */\n    private void showAPIKeyDialog() {\n        LinearLayout contentLayout =\n                (LinearLayout) getLayoutInflater().inflate(R.layout.api_key_message, null);\n        TextView linkView = contentLayout.findViewById(R.id.api_key_link_view);\n        linkView.setText(Html.fromHtml(getString(R.string.api_key_doc_link)));\n        linkView.setMovementMethod(LinkMovementMethod.getInstance());\n        EditText keyInput = contentLayout.findViewById(R.id.api_key_input);\n        keyInput.setInputType(InputType.TYPE_CLASS_TEXT);\n        keyInput.setText(SmartGlassesService.getApiKey(this.getContext()));\n\n        AlertDialog.Builder builder = new AlertDialog.Builder(this.getContext());\n        builder\n                .setTitle(getString(R.string.api_key_message))\n                .setView(contentLayout)\n                .setPositiveButton(\n                        getString(android.R.string.ok),\n                        (dialog, which) -> {\n                            SmartGlassesService.saveApiKey(this.getContext(), keyInput.getText().toString().trim());\n                        })\n                .show();\n    }\n\n    /** The API won't work without a valid API key. This prompts the user to enter one. */\n    private void showDefaultAppDialog() {\n        LinearLayout contentLayout =\n                (LinearLayout) getLayoutInflater().inflate(R.layout.default_app_dialog, null);\n        EditText keyInput = contentLayout.findViewById(R.id.default_app_input);\n        keyInput.setInputType(InputType.TYPE_CLASS_TEXT);\n    }\n\n    public void showNoGoogleAsrDialog(){\n        new android.app.AlertDialog.Builder(this.getContext()) .setIcon(android.R.drawable.ic_dialog_alert)\n                .setTitle(\"No Google API Key Provided\")\n                .setMessage(\"You have Google ASR enabled without an API key. Please turn off Google ASR or enter a valid API key.\")\n                .setPositiveButton(\"Ok\", new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                    }\n                }).show();\n    }\n\n}\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/java/com/teamopensmartglasses/example_smart_glasses_app/ui/SmartGlassesListAdapter.java",
    "content": "package com.teamopensmartglasses.example_smart_glasses_app.ui;\n\nimport android.content.Context;\nimport android.graphics.drawable.Drawable;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ArrayAdapter;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.teamopensmartglasses.smartglassesmanager.R;\nimport com.teamopensmartglasses.smartglassesmanager.supportedglasses.SmartGlassesDevice;\n\nimport java.util.ArrayList;\n\npublic class SmartGlassesListAdapter extends ArrayAdapter<SmartGlassesDevice> {\n    Context mContext;\n    private ArrayList<SmartGlassesDevice> glassesList;\n\n    private int selectedPosition = -1;\n\n    public SmartGlassesListAdapter(ArrayList<SmartGlassesDevice> glassesList, Context context) {\n        super(context, R.layout.smart_glasses_list_item, glassesList);\n        // TODO Auto-generated constructor stub\n\n        this.mContext = context;\n        this.glassesList = glassesList;\n    }\n\n    public int getSelectedPosition() {\n        return selectedPosition;\n    }\n\n    public void setSelectedPosition(int selectedPosition) {\n        this.selectedPosition = selectedPosition;\n    }\n\n    public SmartGlassesDevice getSelectedDevice(){\n        if (this.selectedPosition != -1) {\n            return this.glassesList.get(this.selectedPosition);\n        } else {\n            return null;\n        }\n    }\n\n    @Override\n    public View getView(int position, View convertView, ViewGroup parent) {\n        SmartGlassesDevice device = this.glassesList.get(position);\n        if (convertView == null) {\n            convertView = LayoutInflater.from(mContext).inflate(R.layout.smart_glasses_list_item, parent, false);\n        }\n        TextView tvGlassesName = (TextView)convertView.findViewById(R.id.glasses_name);\n        TextView tvGlassesSupport = (TextView)convertView.findViewById(R.id.glasses_support);\n        ImageView ivGlassesIcon = (ImageView) convertView.findViewById(R.id.glasses_icon);\n\n        //set device name\n        tvGlassesName.setText(device.getDeviceModelName());\n\n        //set device icon\n        String uri = \"@drawable/\" + device.getDeviceIconName();  // where myresource (without the extension) is the file\n        int imageResource = mContext.getResources().getIdentifier(uri, null, mContext.getPackageName());\n        Drawable res = mContext.getResources().getDrawable(imageResource);\n        ivGlassesIcon.setImageDrawable(res);\n\n        //set device supported\n        if (!device.getAnySupport()){\n            tvGlassesSupport.setText(\"Not supported.\");\n        } else if (!device.getFullSupport()){\n            tvGlassesSupport.setText(\"Partially supported.\");\n        } else {\n            tvGlassesSupport.setText(\"Fully Supported\");\n        }\n\n        return convertView;\n    }\n}"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/java/com/teamopensmartglasses/example_smart_glasses_app/ui/UiUtils.java",
    "content": "package com.teamopensmartglasses.example_smart_glasses_app.ui;\n\nimport android.app.Activity;\n\nimport androidx.appcompat.widget.Toolbar;\n\nimport com.teamopensmartglasses.example_smart_glasses_app.MainActivity;\nimport com.teamopensmartglasses.example_smart_glasses_app.R;\n\npublic class UiUtils {\n\n    //set app bar title\n    public static void setupTitle(Activity activity, String title) {\n        Toolbar toolbar = (Toolbar) activity.findViewById(R.id.main_toolbar);\n        ((MainActivity) activity).setSupportActionBar(toolbar);\n        ((MainActivity) activity).getSupportActionBar().setTitle(title);\n    }\n}\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <path\n        android:fillColor=\"#3DDC84\"\n        android:pathData=\"M0,0h108v108h-108z\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M9,0L9,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,0L19,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,0L29,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,0L39,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,0L49,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,0L59,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,0L69,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,0L79,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M89,0L89,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M99,0L99,108\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,9L108,9\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,19L108,19\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,29L108,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,39L108,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,49L108,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,59L108,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,69L108,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,79L108,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,89L108,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,99L108,99\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,29L89,29\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,39L89,39\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,49L89,49\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,59L89,59\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,69L89,69\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,79L89,79\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,19L29,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,19L39,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,19L49,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,19L59,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,19L69,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,19L79,89\"\n        android:strokeWidth=\"0.8\"\n        android:strokeColor=\"#33FFFFFF\" />\n</vector>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/drawable/outline_device_hub_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M17,16l-4,-4V8.82C14.16,8.4 15,7.3 15,6c0,-1.66 -1.34,-3 -3,-3S9,4.34 9,6c0,1.3 0.84,2.4 2,2.82V12l-4,4H3v5h5v-3.05l4,-4.2 4,4.2V21h5v-5h-4z\"/>\n</vector>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/drawable/outline_groups_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M4,13c1.1,0 2,-0.9 2,-2c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2C2,12.1 2.9,13 4,13zM5.13,14.1C4.76,14.04 4.39,14 4,14c-0.99,0 -1.93,0.21 -2.78,0.58C0.48,14.9 0,15.62 0,16.43V18l4.5,0v-1.61C4.5,15.56 4.73,14.78 5.13,14.1zM20,13c1.1,0 2,-0.9 2,-2c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2C18,12.1 18.9,13 20,13zM24,16.43c0,-0.81 -0.48,-1.53 -1.22,-1.85C21.93,14.21 20.99,14 20,14c-0.39,0 -0.76,0.04 -1.13,0.1c0.4,0.68 0.63,1.46 0.63,2.29V18l4.5,0V16.43zM16.24,13.65c-1.17,-0.52 -2.61,-0.9 -4.24,-0.9c-1.63,0 -3.07,0.39 -4.24,0.9C6.68,14.13 6,15.21 6,16.39V18h12v-1.61C18,15.21 17.32,14.13 16.24,13.65zM8.07,16c0.09,-0.23 0.13,-0.39 0.91,-0.69c0.97,-0.38 1.99,-0.56 3.02,-0.56s2.05,0.18 3.02,0.56c0.77,0.3 0.81,0.46 0.91,0.69H8.07zM12,8c0.55,0 1,0.45 1,1s-0.45,1 -1,1s-1,-0.45 -1,-1S11.45,8 12,8M12,6c-1.66,0 -3,1.34 -3,3c0,1.66 1.34,3 3,3s3,-1.34 3,-3C15,7.34 13.66,6 12,6L12,6z\"/>\n</vector>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/drawable/outline_memory_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M15,9L9,9v6h6L15,9zM13,13h-2v-2h2v2zM21,11L21,9h-2L19,7c0,-1.1 -0.9,-2 -2,-2h-2L15,3h-2v2h-2L11,3L9,3v2L7,5c-1.1,0 -2,0.9 -2,2v2L3,9v2h2v2L3,13v2h2v2c0,1.1 0.9,2 2,2h2v2h2v-2h2v2h2v-2h2c1.1,0 2,-0.9 2,-2v-2h2v-2h-2v-2h2zM17,17L7,17L7,7h10v10z\"/>\n</vector>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/drawable/outline_settings_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98 0,-0.34 -0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.09,-0.16 -0.26,-0.25 -0.44,-0.25 -0.06,0 -0.12,0.01 -0.17,0.03l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.06,-0.02 -0.12,-0.03 -0.18,-0.03 -0.17,0 -0.34,0.09 -0.43,0.25l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98 0,0.33 0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.09,0.16 0.26,0.25 0.44,0.25 0.06,0 0.12,-0.01 0.17,-0.03l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.06,0.02 0.12,0.03 0.18,0.03 0.17,0 0.34,-0.09 0.43,-0.25l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM17.45,11.27c0.04,0.31 0.05,0.52 0.05,0.73 0,0.21 -0.02,0.43 -0.05,0.73l-0.14,1.13 0.89,0.7 1.08,0.84 -0.7,1.21 -1.27,-0.51 -1.04,-0.42 -0.9,0.68c-0.43,0.32 -0.84,0.56 -1.25,0.73l-1.06,0.43 -0.16,1.13 -0.2,1.35h-1.4l-0.19,-1.35 -0.16,-1.13 -1.06,-0.43c-0.43,-0.18 -0.83,-0.41 -1.23,-0.71l-0.91,-0.7 -1.06,0.43 -1.27,0.51 -0.7,-1.21 1.08,-0.84 0.89,-0.7 -0.14,-1.13c-0.03,-0.31 -0.05,-0.54 -0.05,-0.74s0.02,-0.43 0.05,-0.73l0.14,-1.13 -0.89,-0.7 -1.08,-0.84 0.7,-1.21 1.27,0.51 1.04,0.42 0.9,-0.68c0.43,-0.32 0.84,-0.56 1.25,-0.73l1.06,-0.43 0.16,-1.13 0.2,-1.35h1.39l0.19,1.35 0.16,1.13 1.06,0.43c0.43,0.18 0.83,0.41 1.23,0.71l0.91,0.7 1.06,-0.43 1.27,-0.51 0.7,1.21 -1.07,0.85 -0.89,0.7 0.14,1.13zM12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z\"/>\n</vector>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/drawable/pretty_thin_border.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" android:shape=\"rectangle\" >\n    <!-- use this for transparent -->\n    <!-- <solid android:color=\"#00000000\" /> -->\n    <!-- use this for a background colour -->\n    <solid android:color=\"#FFF\" />\n    <stroke android:width=\"2dip\" android:color=\"#000000\" />\n</shape>"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/drawable/rounded_corner.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n<!--    <stroke-->\n<!--        android:width=\"1dp\"-->\n<!--        android:color=\"@color/colorPrimaryDark\" />-->\n\n    <solid android:color=\"#fafafa\" />\n\n    <padding\n        android:left=\"1dp\"\n        android:right=\"1dp\"\n        android:bottom=\"1dp\"\n        android:top=\"1dp\" />\n\n    <corners android:radius=\"5dp\" />\n</shape>"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/drawable/rounded_corners_bg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"#FFFFFF\"/>\n    <stroke android:width=\"3dp\" android:color=\"#B1BCBE\" />\n    <corners android:radius=\"10dp\"/>\n    <padding android:left=\"0dp\" android:top=\"0dp\" android:right=\"0dp\" android:bottom=\"0dp\" />\n</shape>"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/drawable/rounded_shadow_bg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <item\n        android:width=\"48dp\"\n        android:height=\"48dp\"\n        android:bottom=\"68dp\"\n        android:right=\"-20dp\">\n        <bitmap\n            android:gravity=\"bottom|right\"\n            android:src=\"@drawable/rounded_corners_bg\" />\n    </item>\n    <item\n        android:height=\"68dp\"\n        android:left=\"-20dp\"\n        android:bottom=\"-20dp\"\n        android:width=\"68dp\">\n        <bitmap\n            android:gravity=\"bottom|left\"\n            android:src=\"@android:drawable/dialog_holo_light_frame\" />\n    </item>\n</layer-list>"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/drawable/sgm_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector\n    android:height=\"108dp\"\n    android:width=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#3DDC84\"\n          android:pathData=\"M0,0h108v108h-108z\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M9,0L9,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,0L19,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M29,0L29,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M39,0L39,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M49,0L49,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M59,0L59,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M69,0L69,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M79,0L79,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M89,0L89,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M99,0L99,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,9L108,9\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,19L108,19\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,29L108,29\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,39L108,39\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,49L108,49\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,59L108,59\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,69L108,69\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,79L108,79\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,89L108,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,99L108,99\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,29L89,29\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,39L89,39\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,49L89,49\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,59L89,59\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,69L89,69\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,79L89,79\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M29,19L29,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M39,19L39,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M49,19L49,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M59,19L59,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M69,19L69,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M79,19L79,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n</vector>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/drawable/textview_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <gradient\n        android:angle=\"90\"\n        android:startColor=\"@android:color/holo_blue_light\"\n        android:centerColor=\"@android:color/transparent\"\n        android:endColor=\"@android:color/transparent\"\n        />\n\n</shape>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/drawable/wis_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector\n    android:height=\"108dp\"\n    android:width=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#3DDC84\"\n          android:pathData=\"M0,0h108v108h-108z\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M9,0L9,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,0L19,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M29,0L29,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M39,0L39,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M49,0L49,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M59,0L59,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M69,0L69,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M79,0L79,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M89,0L89,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M99,0L99,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,9L108,9\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,19L108,19\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,29L108,29\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,39L108,39\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,49L108,49\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,59L108,59\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,69L108,69\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,79L108,79\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,89L108,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,99L108,99\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,29L89,29\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,39L89,39\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,49L89,49\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,59L89,59\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,69L89,69\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,79L89,79\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M29,19L29,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M39,19L39,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M49,19L49,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M59,19L59,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M69,19L69,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M79,19L79,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n</vector>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/drawable/wis_launcher_transparent_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector\n    android:height=\"108dp\"\n    android:width=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#3DDC84\"\n          android:pathData=\"M0,0h108v108h-108z\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M9,0L9,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,0L19,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M29,0L29,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M39,0L39,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M49,0L49,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M59,0L59,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M69,0L69,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M79,0L79,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M89,0L89,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M99,0L99,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,9L108,9\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,19L108,19\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,29L108,29\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,39L108,39\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,49L108,49\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,59L108,59\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,69L108,69\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,79L108,79\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,89L108,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,99L108,99\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,29L89,29\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,39L89,39\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,49L89,49\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,59L89,59\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,69L89,69\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,79L89,79\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M29,19L29,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M39,19L39,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M49,19L49,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M59,19L59,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M69,19L69,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M79,19L79,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n</vector>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <path android:pathData=\"M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:endX=\"85.84757\"\n                android:endY=\"92.4963\"\n                android:startX=\"42.9492\"\n                android:startY=\"49.59793\"\n                android:type=\"linear\">\n                <item\n                    android:color=\"#44000000\"\n                    android:offset=\"0.0\" />\n                <item\n                    android:color=\"#00000000\"\n                    android:offset=\"1.0\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:fillColor=\"#FFFFFF\"\n        android:fillType=\"nonZero\"\n        android:pathData=\"M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z\"\n        android:strokeWidth=\"1\"\n        android:strokeColor=\"#00000000\" />\n</vector>"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:id=\"@+id/mainlayout\"\n    android:layout_height=\"match_parent\">\n\n    <com.google.android.material.appbar.AppBarLayout\n        android:id=\"@+id/appbarlayout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        android:fitsSystemWindows=\"true\"\n        app:liftOnScroll=\"true\">\n\n        <androidx.constraintlayout.widget.ConstraintLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            >\n\n            <ImageView\n                android:id=\"@+id/imageView2\"\n                android:layout_width=\"70dp\"\n                android:layout_height=\"35dp\"\n                android:src=\"@drawable/sgm_app_transparent_bg_white_text_icon\"\n                android:background=\"@android:color/transparent\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintStart_toStartOf=\"parent\"\n                app:layout_constraintTop_toTopOf=\"parent\"></ImageView>\n\n            <TextView\n                android:id=\"@+id/seperator\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:text=\"|\"\n                android:textAlignment=\"center\"\n                android:textColor=\"#FFFFFFFF\"\n                android:textSize=\"35dp\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintTop_toTopOf=\"parent\"\n                app:layout_constraintStart_toEndOf=\"@+id/imageView2\"></TextView>\n\n            <androidx.appcompat.widget.Toolbar\n                android:id=\"@+id/main_toolbar\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                app:contentInsetStart=\"7dp\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintStart_toEndOf=\"@+id/seperator\"\n                app:titleTextColor=\"@android:color/white\" />\n        </androidx.constraintlayout.widget.ConstraintLayout>\n    </com.google.android.material.appbar.AppBarLayout>\n\n    <androidx.fragment.app.FragmentContainerView\n        android:id=\"@+id/nav_host_fragment\"\n        android:name=\"androidx.navigation.fragment.NavHostFragment\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        app:defaultNavHost=\"true\"\n\n        app:layout_constraintTop_toBottomOf=\"@id/appbarlayout\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:navGraph=\"@navigation/nav_graph\" />\n\n<!--    <com.google.android.material.bottomnavigation.BottomNavigationView-->\n<!--        android:id=\"@+id/bottom_nav_main_menu_nav\"-->\n<!--        android:layout_width=\"match_parent\"-->\n<!--        android:layout_height=\"wrap_content\"-->\n<!--        app:layout_constraintTop_toBottomOf=\"@id/nav_host_fragment\"-->\n<!--        app:layout_constraintBottom_toBottomOf=\"parent\"-->\n<!--        app:menu=\"@menu/bottom_nav_main_menu\" />-->\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/layout/all_transcripts_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/mainlayout\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/phrase_wall\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"0dp\"\n        android:background=\"@color/colorMainBackground\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.0\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        tools:listitem=\"@layout/phrase_recyclerview_item\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/layout/api_key_message.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\"\n    android:padding=\"10dp\">\n\n  <TextView\n      android:id=\"@+id/api_key_link_view\"\n      android:layout_width=\"wrap_content\"\n      android:layout_height=\"wrap_content\"\n      android:clickable=\"true\" />\n\n  <EditText\n      android:id=\"@+id/api_key_input\"\n      android:layout_width=\"match_parent\"\n      android:layout_height=\"wrap_content\"\n      android:autofillHints=\"password\"\n      android:inputType=\"text\" />\n\n<!--  <TextView-->\n<!--      android:id=\"@+id/language_locale_view\"-->\n<!--      android:layout_width=\"wrap_content\"-->\n<!--      android:layout_height=\"wrap_content\"-->\n<!--      android:text=\"@string/select_language_message\" />-->\n\n<!--  <Spinner-->\n<!--      android:id=\"@+id/language_locale_spinner\"-->\n<!--      android:layout_width=\"match_parent\"-->\n<!--      android:layout_height=\"wrap_content\" />-->\n</LinearLayout>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/layout/connecting_to_glasses_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:id=\"@+id/textView4\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"5dp\"\n        android:text=\"Trying to Connect...\"\n        android:textColor=\"#4d4d4d\"\n        android:textSize=\"28dp\"\n        android:textStyle=\"bold\"\n        android:justificationMode=\"inter_word\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.498\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n\n    <ProgressBar\n        android:id=\"@+id/connected_glasses_image\"\n        style=\"?android:attr/progressBarStyleLarge\"\n        android:layout_width=\"195dp\"\n        android:layout_height=\"166dp\"\n        android:layout_marginTop=\"200dp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/textView4\"></ProgressBar>\n\n    <TextView\n        android:id=\"@+id/glasses_connected_message_tv\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"16dp\"\n        android:justificationMode=\"inter_word\"\n        android:text=\"Connecting to smart glasses...\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/connected_glasses_image\" />\n\n\n    <Button\n        android:id=\"@+id/ok_glasses_connected_button\"\n        android:layout_width=\"99dp\"\n        android:layout_height=\"66dp\"\n        android:layout_marginBottom=\"48dp\"\n        android:text=\"Cancel\"\n        app:backgroundTint=\"@color/red\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\" />\n\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/layout/default_app_dialog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\"\n    android:padding=\"10dp\">\n\n    <EditText\n        android:id=\"@+id/default_app_input\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:inputType=\"text\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/layout/export_data_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:id=\"@+id/textView3\"\n        android:layout_width=\"317dp\"\n        android:layout_height=\"78dp\"\n        android:layout_marginTop=\"116dp\"\n        android:text=\"Select date range of data to export:\"\n        android:textSize=\"24sp\"\n        android:textStyle=\"bold\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"></TextView>\n\n    <TextView\n        android:id=\"@+id/export_date_range_text_view\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"164dp\"\n        android:layout_marginEnd=\"28dp\"\n        android:textSize=\"20sp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/pick_date_button\"\n        tools:text=\"Jan 10 - Jan 15\" />\n\n    <TextView\n        android:id=\"@+id/textView7\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"164dp\"\n        android:text=\"Export Date Range: \"\n        android:textSize=\"20sp\"\n        app:layout_constraintEnd_toStartOf=\"@+id/export_date_range_text_view\"\n        app:layout_constraintHorizontal_bias=\"0.157\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/pick_date_button\" />\n\n    <Button\n        android:id=\"@+id/export_data_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"48dp\"\n        android:text=\"Export Data Now\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.48\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/textView7\"\n        app:layout_constraintVertical_bias=\"0.019\" />\n\n    <Button\n        android:id=\"@+id/pick_date_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:text=\"Select Date\"\n        android:textSize=\"18sp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.481\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/textView3\" />\n\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/layout/glasses_connected_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <TextView\n        android:id=\"@+id/textView4\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"5dp\"\n        android:text=\"Glasses Connected!\"\n        android:textColor=\"#4d4d4d\"\n        android:textSize=\"28dp\"\n        android:textStyle=\"bold\"\n        android:justificationMode=\"inter_word\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.498\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n\n    <ImageView\n        android:id=\"@+id/connected_glasses_image\"\n        android:layout_width=\"230dp\"\n        android:layout_height=\"230dp\"\n        android:layout_marginTop=\"200dp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/textView4\">\n        ></ImageView>\n\n    <TextView\n        android:id=\"@+id/glasses_connected_message_tv\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"16dp\"\n        android:justificationMode=\"inter_word\"\n        android:text=\"Glasses are connected!\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/connected_glasses_image\" />\n\n\n    <Button\n        android:id=\"@+id/ok_glasses_connected_button\"\n        android:layout_width=\"99dp\"\n        android:layout_height=\"66dp\"\n        android:layout_marginBottom=\"48dp\"\n        android:text=\"Ok\"\n        app:backgroundTint=\"@color/green\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\" />\n\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/layout/image_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginLeft=\"5dp\"\n    android:layout_marginRight=\"5dp\"\n    android:orientation=\"vertical\"\n    >\n\n    <ImageView\n        android:id=\"@+id/imageView\"\n        android:adjustViewBounds=\"true\"\n        android:layout_centerInParent=\"true\"\n        android:layout_width=\"350dp\"\n        android:layout_height=\"wrap_content\"\n        tools:srcCompat=\"@tools:sample/avatars\" />\n\n    <TextView\n        android:id=\"@+id/textView\"\n        android:layout_width=\"350dp\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"TextView\"\n        android:textAlignment=\"center\"\n        android:textSize=\"22dp\"\n        android:textStyle=\"bold\" />\n</LinearLayout>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/layout/main_ui_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"48dp\"\n        android:paddingTop=\"7dp\"\n        android:text=\"Intelligence Tools\"\n        android:textSize=\"35sp\"\n        android:textStyle=\"bold\"\n        app:layout_constraintBottom_toTopOf=\"@+id/memory_tools\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.496\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintVertical_bias=\"1.0\" />\n\n    <Button\n        android:id=\"@+id/memory_tools\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"84dp\"\n        android:text=\"Memory Tools\"\n        app:layout_constraintBottom_toTopOf=\"@+id/textView2\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.498\"\n        app:layout_constraintStart_toStartOf=\"parent\" />\n\n    <TextView\n        android:id=\"@+id/textView2\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"28dp\"\n        android:paddingTop=\"7dp\"\n        android:text=\"Settings\"\n        android:textSize=\"35sp\"\n        android:textStyle=\"bold\"\n        app:layout_constraintBottom_toTopOf=\"@+id/kill_wearableai_service\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\" />\n\n    <Button\n        android:id=\"@+id/kill_wearableai_service\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"40dp\"\n        android:text=\"Kill WearableAI Service\"\n        app:layout_constraintBottom_toTopOf=\"@+id/send_test_card_old\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\" />\n\n    <Button\n        android:id=\"@+id/send_test_card_old\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"40dp\"\n        android:text=\"Start WearableAI Service\"\n        app:layout_constraintBottom_toTopOf=\"@+id/start_hotspot\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\" />\n\n    <Button\n        android:id=\"@+id/start_hotspot\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"84dp\"\n        android:text=\"Start Wifi Hotspot\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\" />\n\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/layout/menu_item_exposed_dropdown.xml",
    "content": "<TextView\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:padding=\"16dp\"\n    android:ellipsize=\"end\"\n    android:maxLines=\"1\"\n    android:textAppearance=\"?attr/textAppearanceSubtitle1\"\n/>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/layout/phrase_context_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n\n    <TextView\n        android:id=\"@+id/image_header\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"POV Images\"\n        android:textSize=\"22sp\"\n        android:textStyle=\"bold\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.055\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n\n    <HorizontalScrollView\n        android:id=\"@+id/gallery_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_gravity=\"center\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.0\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/image_header\">\n\n        <LinearLayout\n            android:id=\"@+id/image_gallery\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"horizontal\" />\n    </HorizontalScrollView>\n\n    <TextView\n        android:id=\"@+id/map_header\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"2dp\"\n        android:text=\"Location\"\n        android:textSize=\"22sp\"\n        android:textStyle=\"bold\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.049\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/gallery_holder\" />\n\n    <ImageView\n        android:id=\"@+id/map_image_view\"\n        android:layout_width=\"383dp\"\n        android:layout_height=\"294dp\"\n        android:layout_marginTop=\"2dp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.497\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/map_header\"\n        tools:srcCompat=\"@drawable/elon\" />\n\n    <TextView\n        android:id=\"@+id/people_header\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"2dp\"\n        android:text=\"People\"\n        android:textSize=\"22sp\"\n        android:textStyle=\"bold\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.052\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/map_image_view\" />\n\n    <TextView\n        android:id=\"@+id/people_list\"\n        android:layout_width=\"381dp\"\n        android:layout_height=\"72dp\"\n        android:layout_marginTop=\"2dp\"\n        android:text=\"- person 1\\n-person 2\\n-person 3\"\n        android:textSize=\"18sp\"\n        android:textStyle=\"\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/people_header\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/layout/phrase_recyclerview_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_margin=\"0dp\"\n    android:background=\"@android:drawable/dialog_holo_light_frame\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n<TextView\n        android:id=\"@+id/textView\"\n        style=\"@style/phrase_title\"\n        android:textColor=\"@color/recyclertextcolor\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n</LinearLayout>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/layout/reference_card_recyclerview_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:background=\"@android:drawable/dialog_holo_light_frame\"\n    android:layout_height=\"wrap_content\">\n\n    <ImageView\n        android:id=\"@+id/image_image_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_margin=\"4dp\"\n        android:layout_height=\"140dp\"\n        tools:srcCompat=\"@drawable/elon\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_margin=\"4dp\"\n        style=\"@style/text_box\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n        <LinearLayout\n            android:orientation=\"vertical\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n            <TextView\n                android:id=\"@+id/title_text_view\"\n                style=\"@style/reference_title\"\n                android:layout_height=\"wrap_content\"\n                android:textAlignment=\"viewStart\"\n                android:textStyle=\"bold\"\n                tools:text=\"Title Here\" />\n\n            <TextView\n                android:id=\"@+id/start_date_text_view\"\n                style=\"@style/reference_date\"\n                android:layout_height=\"wrap_content\"\n                android:layout_width=\"match_parent\"\n                android:textStyle=\"bold\"\n                tools:text=\"Start: Jan 20, 1999\" />\n            <TextView\n                android:id=\"@+id/stop_date_text_view\"\n                style=\"@style/reference_date\"\n                android:layout_height=\"wrap_content\"\n                android:layout_width=\"match_parent\"\n                android:textStyle=\"bold\"\n                tools:text=\"End: Jan 20, 1999\" />\n        </LinearLayout>\n        <TextView\n            android:id=\"@+id/summary_text_view\"\n            style=\"@style/reference_summary\"\n            android:layout_height=\"wrap_content\"\n            android:layout_width=\"match_parent\"\n            android:textAlignment=\"viewStart\"\n            android:textStyle=\"bold\"\n            tools:text=\"I think that this is the way to go, it seems to fit what we may need\" />\n    </LinearLayout>\n\n</LinearLayout>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/layout/response_text_box.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\"\n    android:paddingRight=\"6dp\"\n    android:paddingLeft=\"6dp\"\n    android:paddingTop=\"12dp\">\n\n    <TextView\n        android:id=\"@+id/textView\"\n        android:layout_width=\"match_parent\"\n        android:padding=\"12dp\"\n        android:layout_height=\"wrap_content\"\n        android:textSize=\"30sp\"\n        android:hint=\"Text here my man.\"\n        android:background=\"@drawable/rounded_corner\"\n        android:textColor=\"#000000\"/>\n</LinearLayout>"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/layout/select_glasses_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\nxmlns:tools=\"http://schemas.android.com/tools\"\nandroid:layout_width=\"match_parent\"\nandroid:layout_height=\"match_parent\"\nxmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <TextView\n        android:id=\"@+id/textView6\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop =\"5dp\"\n        android:text=\"Select your smart glasses:\"\n        android:textColor=\"#4d4d4d\"\n        android:textSize=\"28dp\"\n        android:textStyle=\"bold\"\n        android:justificationMode=\"inter_word\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"></TextView>\n\n    <ListView\n        android:id=\"@+id/smart_glasses_list\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_marginRight=\"5dp\"\n        android:layout_marginLeft=\"5dp\"\n        android:layout_marginTop=\"75dp\"\n        android:layout_marginBottom=\"130dp\"\n        android:choiceMode=\"singleChoice\"\n        android:listSelector=\"@android:color/darker_gray\"\n        ></ListView>\n\n    <Button\n        android:id=\"@+id/select_smart_glasses_button\"\n        android:layout_width=\"99dp\"\n        android:layout_height=\"66dp\"\n        android:layout_marginRight =\"72dp\"\n        android:layout_marginBottom=\"48dp\"\n        android:text=\"Select\"\n        app:backgroundTint=\"@color/green\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/smart_glasses_list\" />\n\n    <Button\n        android:id=\"@+id/cancel_select_smart_glasses_button\"\n        android:layout_width=\"99dp\"\n        android:layout_height=\"66dp\"\n        android:layout_marginBottom=\"48dp\"\n        android:layout_marginLeft=\"72dp\"\n        android:text=\"Cancel\"\n        app:backgroundTint=\"@color/red\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/smart_glasses_list\" />\n\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/layout/settings_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <TextView\n        android:id=\"@+id/textView5\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"88dp\"\n        android:text=\"Wearable\"\n        android:textSize=\"32dp\"\n        android:textStyle=\"bold\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.498\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n\n    <Button\n        android:id=\"@+id/connect_smart_glasses\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"11dp\"\n        android:text=\"Start Wearable\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/textView5\" />\n\n    <Button\n        android:id=\"@+id/kill_wearableai_service\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"11dp\"\n        android:text=\"Stop Wearable\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/connect_smart_glasses\" />\n\n    <Button\n        android:id=\"@+id/send_test_card_old\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"11dp\"\n        android:text=\"Test Wearable\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/kill_wearableai_service\" />\n\n\n    <TextView\n        android:id=\"@+id/textView6\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"24dp\"\n        android:text=\"Settings\"\n        android:textSize=\"32dp\"\n        android:textStyle=\"bold\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/send_test_card_old\" />\n\n    <Button\n        android:id=\"@+id/start_hotspot\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"11dp\"\n        android:text=\"Start Wifi Hotspot\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHorizontal_bias=\"0.497\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/textView6\" />\n\n    <Switch\n        android:id=\"@+id/google_asr_switch\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"11dp\"\n        android:text=\"Google ASR\"\n        android:textSize=\"20dp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/start_hotspot\" />\n\n    <Button\n        android:id=\"@+id/google_api_change\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"11dp\"\n        android:text=\"Set Google API Key\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/google_asr_switch\" />\n\n\n    <!--    <Button-->\n<!--        android:id=\"@+id/start_live_captions\"-->\n<!--        android:layout_width=\"wrap_content\"-->\n<!--        android:layout_height=\"wrap_content\"-->\n<!--        android:layout_marginTop=\"25dp\"-->\n<!--        android:text=\"Start Live Captions\"-->\n<!--        app:layout_constraintEnd_toEndOf=\"parent\"-->\n<!--        app:layout_constraintStart_toStartOf=\"parent\"-->\n<!--        app:layout_constraintTop_toBottomOf=\"@+id/send_test_card_old\" />-->\n\n\n<!--    <Button-->\n<!--        android:id=\"@+id/trigger_tpa_command\"-->\n<!--        android:layout_width=\"wrap_content\"-->\n<!--        android:layout_height=\"wrap_content\"-->\n<!--        android:layout_marginTop=\"25dp\"-->\n<!--        android:text=\"Trigger Hello World Command\"-->\n<!--        app:layout_constraintEnd_toEndOf=\"parent\"-->\n<!--        app:layout_constraintStart_toStartOf=\"parent\"-->\n<!--        app:layout_constraintTop_toBottomOf=\"@+id/start_live_captions\" />-->\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/layout/smart_glasses_debug_fragment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n\n    <Button\n        android:id=\"@+id/send_test_card_old\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"388dp\"\n        android:text=\"Send Test Card to Glasses\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/layout/smart_glasses_list_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <ImageView\n        android:id=\"@+id/glasses_icon\"\n        android:layout_width=\"85dp\"\n        android:layout_height=\"65dp\"\n        android:padding=\"5dp\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n\n    <TextView\n        android:id=\"@+id/glasses_name\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:padding=\"2dp\"\n        android:text=\"Coolest Smart Glasses\"\n        android:layout_marginLeft=\"4dp\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\"\n        android:textColor=\"#4d4d4d\"\n        android:textStyle=\"bold\"\n        app:layout_constraintStart_toEndOf=\"@+id/glasses_icon\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n\n    <TextView\n        android:id=\"@+id/glasses_support\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginLeft=\"4dp\"\n        android:text=\"Fully Supported\"\n        app:layout_constraintStart_toEndOf=\"@+id/glasses_icon\"\n        app:layout_constraintTop_toBottomOf=\"@+id/glasses_name\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/menu/bottom_nav_main_menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  Copyright 2017 The Android Open Source Project\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n      http://www.apache.org/licenses/LICENSE-2.0\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <item\n        android:id=\"@+id/memory_page\"\n        android:enabled=\"true\"\n        android:icon=\"@drawable/outline_memory_white_24\"\n        android:title=\"Memory Tools\"/>\n    <item\n        android:id=\"@+id/smart_glasses_debug_page\"\n        android:enabled=\"true\"\n        android:icon=\"@drawable/outline_device_hub_white_24\"\n        android:title=\"Smart Glasses\"/>\n    <item\n        android:id=\"@+id/settings_page\"\n        android:enabled=\"true\"\n        android:icon=\"@drawable/outline_settings_white_24\"\n        android:title=\"Settings\"/>\n\n</menu>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/menu/memory_cache_menu.xml",
    "content": "<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item\n        android:id=\"@+id/name_cache\"\n        android:title=\"Name Cache\"\n        android:showAsAction=\"always\"/>\n</menu>"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n    <monochrome android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n    <monochrome android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/navigation/nav_graph.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<navigation xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/nav_graph\"\n    app:startDestination=\"@id/nav_settings\">\n\n    <fragment\n        android:id=\"@+id/nav_main_ui\"\n        android:name=\"com.teamopensmartglasses.example_smart_glasses_app.ui.MainUi\"\n        tools:layout=\"@layout/main_ui_fragment\"\n        android:label=\"Home Main Page\" >\n    </fragment>\n    <fragment\n        android:id=\"@+id/nav_smart_glasses_debug\"\n        android:name=\"com.teamopensmartglasses.example_smart_glasses_app.ui.SmartGlassesDebugUi\"\n        tools:layout=\"@layout/smart_glasses_debug_fragment\"\n        android:label=\"Smart Glasses + Debug\" >\n    </fragment>\n    <fragment\n        android:id=\"@+id/nav_settings\"\n        android:name=\"com.teamopensmartglasses.example_smart_glasses_app.ui.SettingsUi\"\n        tools:layout=\"@layout/settings_fragment\"\n        android:label=\"Example Smart Glasses App\" >\n    </fragment>\n    <fragment\n        android:id=\"@+id/nav_select_smart_glasses\"\n        android:name=\"com.teamopensmartglasses.example_smart_glasses_app.ui.SelectSmartGlassesUi\"\n        tools:layout=\"@layout/select_glasses_fragment\"\n        android:label=\"Select Smart Glasses\" >\n    </fragment>\n    <fragment\n        android:id=\"@+id/nav_connecting_to_smart_glasses\"\n        android:name=\"com.teamopensmartglasses.example_smart_glasses_app.ui.ConnectingToSmartGlassesUi\"\n        tools:layout=\"@layout/connecting_to_glasses_fragment\"\n        android:label=\"Connecting to Smart Glasses\" >\n    </fragment>\n    <fragment\n        android:id=\"@+id/nav_connected_to_smart_glasses\"\n        android:name=\"com.teamopensmartglasses.example_smart_glasses_app.ui.GlassesConnectedFragment\"\n        tools:layout=\"@layout/glasses_connected_fragment\"\n        android:label=\"Connected to Smart Glasses\" >\n    </fragment>\n    <fragment\n        android:id=\"@+id/nav_all_transcripts\"\n        android:name=\"com.teamopensmartglasses.example_smart_glasses_app.ui.AllTranscriptsUi\"\n        tools:layout=\"@layout/all_transcripts_fragment\"\n        android:label=\"All Transcripts\" >\n        <action\n            android:id=\"@+id/action_nav_memory_tools_to_nav_all_transcripts\"\n            app:destination=\"@id/nav_all_transcripts\" />\n    </fragment>\n    <fragment\n        android:id=\"@+id/nav_export_data\"\n        android:name=\"com.teamopensmartglasses.example_smart_glasses_app.ui.ExportDataUi\"\n        tools:layout=\"@layout/export_data_fragment\"\n        android:label=\"Export Data\" >\n    </fragment>\n    <fragment\n        android:id=\"@+id/nav_phrase_context\"\n        android:name=\"com.teamopensmartglasses.example_smart_glasses_app.ui.PhraseContextUi\"\n        tools:layout=\"@layout/phrase_context_fragment\"\n        android:label=\"Phrase Context\" >\n        <action\n            android:id=\"@+id/action_nav_all_transcripts_to_nav_phrase_context\"\n            app:destination=\"@id/nav_phrase_context\" />\n        <action\n            android:id=\"@+id/action_nav_mxt_cache_to_nav_phrase_context\"\n            app:destination=\"@id/nav_phrase_context\" />\n    </fragment>\n</navigation>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#960000</color>\n    <color name=\"colorPrimaryDark\">#560000</color>\n    <color name=\"colorAccent\">#970000</color>\n\n    <color name=\"buttonLabel\">#eeff41</color>\n\n    <color name=\"colorPhraseBackground\">#dfd8d8</color>\n    <color name=\"colorMainBackground\">#dfd8d8</color>\n    <color name=\"recyclertextcolor\">#222222</color>\n\n    <color name=\"red\">#DFBA0000</color>\n    <color name=\"green\">#FF009E00</color>\n    <color name=\"blue\">#FF0000AF</color>\n</resources>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/values/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  Copyright 2017 The Android Open Source Project\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n      http://www.apache.org/licenses/LICENSE-2.0\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n  -->\n\n<resources>\n    <dimen name=\"cat_card_demo_min_height\">200dp</dimen>\n    <dimen name=\"content_padding_top\">16dp</dimen>\n    <!-- Rich Media Demo Dimensions -->\n    <dimen name=\"cat_card_rich_media_demo_min_height\">148dp</dimen>\n    <dimen name=\"cat_card_single_spacing\">8dp</dimen>\n    <dimen name=\"cat_card_double_spacing\">16dp</dimen>\n    <dimen name=\"cat_card_triple_spacing\">24dp</dimen>\n    <dimen name=\"cat_card_content_padding\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">Smart Glasses Example App</string>\n    <string name=\"key\">TEMPORARYKEY_CHANGETHISKEY</string>\n    <string name=\"no_camera_access\" translatable=\"false\">Please grant camera permissions.</string>\n    <string name=\"medium_text\">text</string>\n    <string name=\"memory_hint\">Enter memory to save here</string>\n    <string name=\"tag_label\">Choose Tag</string>\n\n    <string-array name=\"exposed_dropdown_content\">\n        <item>Wearable</item>\n        <item>Engineering</item>\n        <item>Ideas</item>\n        <item>Personal</item>\n    </string-array>\n\n\n    <!-- Entering API key message. -->\n    <string name=\"api_key_message\">Enter G-Cloud API key</string>\n    <!-- API key document link. -->\n    <string name=\"api_key_doc_link\">See &lt;a href=\"https://cloud.google.com/docs/authentication/api-keys\">here&lt;/a> for more details.</string>\n    <!-- Selecting language message. -->\n    <string name=\"select_language_message\">Select language. See  &lt;a href=\"https://cloud.google.com/speech-to-text/docs/languages\">here&lt;/a> for more details.</string>\n    <string name=\"say_something\">Say something!</string>\n    <!-- Internal code use. -->\n    <string name=\"SHARED_PREF_KEY\">api_key</string>\n    <string name=\"DEFAULT_COMMAND_SHARED_PREF_KEY\">default_command_key</string>\n    <string name=\"DEFAULT_COMMAND_SET_SHARED_PREF_KEY\">default_command_set_key</string>\n\n    <string name=\"SHARED_PREF_ASR_KEY\">shared_pref_api_key</string>\n</resources>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.MaterialComponents.Light.NoActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n  <style name=\"phrase_title\">\n        <item name=\"android:layout_width\">match_parent</item>\n<!--        <item name=\"android:layout_marginBottom\">8dp</item>-->\n<!--        <item name=\"android:paddingLeft\">8dp</item>-->\n        <item name=\"android:layout_marginRight\">4dp</item>\n          <item name=\"android:layout_marginLeft\">4dp</item>\n      <!--        <item name=\"android:background\">@color/colorPhraseBackground</item>-->\n        <item name=\"android:textAppearance\">@android:style/TextAppearance.Large</item>\n    </style>\n\n\n    <style name=\"text_box\">\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_margin\">8dp</item>\n    </style>\n\n    <style name=\"reference_title\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_marginBottom\">2dp</item>\n        <item name=\"android:textAppearance\">@android:style/TextAppearance.Large</item>\n    </style>\n\n    <style name=\"reference_date\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_marginBottom\">2dp</item>\n        <item name=\"android:textAppearance\">@android:style/TextAppearance.Medium</item>\n    </style>\n\n    <style name=\"reference_summary\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_marginBottom\">2dp</item>\n        <item name=\"android:textAppearance\">@android:style/TextAppearance.Small</item>\n    </style>\n\n\n    <!-- bottom bar for facial recognition naming autocomplete -->\n    <style name=\"AppBottomSheetDialogTheme\" parent=\"Theme.Design.Light.BottomSheetDialog\">\n        <item name=\"bottomSheetStyle\">@style/AppModalStyle</item>\n        <item name=\"android:windowIsFloating\">false</item>\n        <item name=\"android:windowSoftInputMode\">adjustResize</item>\n    </style>\n\n    <style name=\"AppModalStyle\" parent=\"Widget.Design.BottomSheet.Modal\">\n        <item name=\"behavior_peekHeight\">400dp</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/xml/backup_rules.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n   Sample backup rules file; uncomment and customize as necessary.\n   See https://developer.android.com/guide/topics/data/autobackup\n   for details.\n   Note: This file is ignored for devices older that API 31\n   See https://developer.android.com/about/versions/12/backup-restore\n-->\n<full-backup-content>\n    <!--\n   <include domain=\"sharedpref\" path=\".\"/>\n   <exclude domain=\"sharedpref\" path=\"device.xml\"/>\n-->\n</full-backup-content>"
  },
  {
    "path": "example_smart_glasses_app/app/src/main/res/xml/data_extraction_rules.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n   Sample data extraction rules file; uncomment and customize as necessary.\n   See https://developer.android.com/about/versions/12/backup-restore#xml-changes\n   for details.\n-->\n<data-extraction-rules>\n    <cloud-backup>\n        <!-- TODO: Use <include> and <exclude> to control what is backed up.\n        <include .../>\n        <exclude .../>\n        -->\n    </cloud-backup>\n    <!--\n    <device-transfer>\n        <include .../>\n        <exclude .../>\n    </device-transfer>\n    -->\n</data-extraction-rules>"
  },
  {
    "path": "example_smart_glasses_app/app/src/test/java/com/teamopensmartglasses/example_smart_glasses_app/ExampleUnitTest.java",
    "content": "package com.teamopensmartglasses.example_smart_glasses_app;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "example_smart_glasses_app/build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        google()\n        mavenCentral() // Add this if your library depends on artifacts from Maven Central\n        // other repositories your library might need\n    }\n}\n\nplugins {\n    id 'com.android.application' version '8.0.2' apply false\n    id 'com.android.library' version '8.0.2' apply false\n}"
  },
  {
    "path": "example_smart_glasses_app/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Mon Jan 08 17:20:07 EST 2024\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.0-bin.zip\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "example_smart_glasses_app/gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n# AndroidX package structure to make it clearer which packages are bundled with the\n# Android operating system, and which are packaged with your app's APK\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\nandroid.useAndroidX=true\n# Enables namespacing of each library's R class so that its R class includes only the\n# resources declared in the library itself and none from the library's dependencies,\n# thereby reducing the size of the R class for that library\nandroid.nonTransitiveRClass=true"
  },
  {
    "path": "example_smart_glasses_app/gradlew",
    "content": "#!/usr/bin/env sh\n\n#\n# Copyright 2015 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif [ \"$cygwin\" = \"true\" -o \"$msys\" = \"true\" ] ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=`expr $i + 1`\n    done\n    case $i in\n        0) set -- ;;\n        1) set -- \"$args0\" ;;\n        2) set -- \"$args0\" \"$args1\" ;;\n        3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=`save \"$@\"`\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "example_smart_glasses_app/gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n\r\n@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto execute\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto execute\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %*\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "example_smart_glasses_app/settings.gradle",
    "content": "pluginManagement {\n    repositories {\n        google()\n        mavenCentral()\n        gradlePluginPortal()\n    }\n}\ndependencyResolutionManagement {\n    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)\n    repositories {\n        google()\n        mavenCentral()\n        maven { url \"https://jitpack.io\" } // if using settings.gradle\n    }\n}\nrootProject.name = \"example_smart_glasses_app\"\ninclude ':app'\n\ninclude ':internal'\ninclude ':smartglassesmanager'\nproject(':smartglassesmanager').projectDir = new File(rootProject.projectDir, '../SGM_android/SmartGlassesManager')\n"
  }
]