Repository: jamesonrader/CUE-Ultrasonic-Transmissions-Protocol
Branch: master
Commit: 387fae93ed09
Files: 99
Total size: 47.5 MB
Directory structure:
gitextract_94ypakwa/
├── .gitignore
├── Android/
│ ├── consumer/
│ │ ├── .gitignore
│ │ ├── app/
│ │ │ ├── .gitignore
│ │ │ ├── build.gradle
│ │ │ ├── proguard-rules.pro
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── cueaudio/
│ │ │ │ └── engine_consumer/
│ │ │ │ └── MainActivity.java
│ │ │ └── res/
│ │ │ ├── drawable/
│ │ │ │ ├── ic_clear.xml
│ │ │ │ ├── ic_launcher_background.xml
│ │ │ │ ├── ic_notification.xml
│ │ │ │ ├── ic_send.xml
│ │ │ │ ├── ic_start.xml
│ │ │ │ └── ic_stop.xml
│ │ │ ├── drawable-v24/
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ ├── layout/
│ │ │ │ └── activity_main.xml
│ │ │ ├── menu/
│ │ │ │ └── main.xml
│ │ │ ├── mipmap-anydpi-v26/
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ └── values/
│ │ │ ├── colors.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ ├── build.gradle
│ │ ├── config/
│ │ │ └── debug.keystore
│ │ ├── gradle/
│ │ │ └── wrapper/
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ │ ├── gradle.properties
│ │ ├── gradlew
│ │ ├── gradlew.bat
│ │ └── settings.gradle
│ └── engine.aar
├── License.md
├── README.md
├── doc/
│ ├── Android_README.md
│ ├── CUEEngine_JSON_Structure.md
│ ├── iOS_README.md
│ └── licenses/
│ └── 3rd_party/
│ ├── CREDITS-LIBC++.TXT
│ └── NOTICE
└── iOS/
├── consumer/
│ ├── consumer/
│ │ ├── AppDelegate.h
│ │ ├── AppDelegate.m
│ │ ├── Assets.xcassets/
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ ├── Base.lproj/
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ ├── ViewController.h
│ │ ├── ViewController.m
│ │ └── main.m
│ ├── consumer.xcodeproj/
│ │ └── project.pbxproj
│ └── engine.xcframework/
│ ├── Info.plist
│ ├── LICENSE/
│ │ └── 3rd_party/
│ │ ├── CREDITS-LIBC++.TXT
│ │ └── NOTICE
│ ├── ios-arm64/
│ │ └── engine.framework/
│ │ ├── Headers/
│ │ │ ├── AudioSession.h
│ │ │ ├── CUEEngine.h
│ │ │ ├── CUEErrno.h
│ │ │ └── CUETrigger.h
│ │ ├── Info.plist
│ │ ├── LICENSE/
│ │ │ └── 3rd_party/
│ │ │ ├── CREDITS-LIBC++.TXT
│ │ │ └── NOTICE
│ │ ├── Modules/
│ │ │ └── module.modulemap
│ │ └── engine
│ └── ios-x86_64-simulator/
│ └── engine.framework/
│ ├── Headers/
│ │ ├── AudioSession.h
│ │ ├── CUEEngine.h
│ │ ├── CUEErrno.h
│ │ └── CUETrigger.h
│ ├── Info.plist
│ ├── LICENSE/
│ │ └── 3rd_party/
│ │ ├── CREDITS-LIBC++.TXT
│ │ └── NOTICE
│ ├── Modules/
│ │ └── module.modulemap
│ └── engine
├── engine.framework/
│ ├── Headers/
│ │ ├── AudioSession.h
│ │ ├── CUEEngine.h
│ │ ├── CUEErrno.h
│ │ └── CUETrigger.h
│ ├── Info.plist
│ ├── LICENSE/
│ │ └── 3rd_party/
│ │ ├── CREDITS-LIBC++.TXT
│ │ └── NOTICE
│ ├── Modules/
│ │ └── module.modulemap
│ └── engine
└── engine.xcframework/
├── Info.plist
├── LICENSE/
│ └── 3rd_party/
│ ├── CREDITS-LIBC++.TXT
│ └── NOTICE
├── ios-arm64/
│ └── engine.framework/
│ ├── Headers/
│ │ ├── AudioSession.h
│ │ ├── CUEEngine.h
│ │ ├── CUEErrno.h
│ │ └── CUETrigger.h
│ ├── Info.plist
│ ├── LICENSE/
│ │ └── 3rd_party/
│ │ ├── CREDITS-LIBC++.TXT
│ │ └── NOTICE
│ ├── Modules/
│ │ └── module.modulemap
│ └── engine
└── ios-x86_64-simulator/
└── engine.framework/
├── Headers/
│ ├── AudioSession.h
│ ├── CUEEngine.h
│ ├── CUEErrno.h
│ └── CUETrigger.h
├── Info.plist
├── LICENSE/
│ └── 3rd_party/
│ ├── CREDITS-LIBC++.TXT
│ └── NOTICE
├── Modules/
│ └── module.modulemap
└── engine
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# macOS
.DS_Store
#iOS
xcshareddata/
iOS/consumer/build.vars
# xcode
xcuserdata
*.xcuserstate
project.xcworkspace
# Android
Android/wrapper/.cxx/
.gradle/
.idea/
*.iml
*google-services.json
build/
================================================
FILE: Android/consumer/.gitignore
================================================
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.externalNativeBuild
.idea/
================================================
FILE: Android/consumer/app/.gitignore
================================================
/build
================================================
FILE: Android/consumer/app/build.gradle
================================================
apply plugin: 'com.android.application'
//apply plugin: 'com.google.gms.google-services'
android {
compileSdkVersion 28
buildToolsVersion '28.0.3'
defaultConfig {
applicationId "com.cueaudio.engine_consumer"
minSdkVersion 19
targetSdkVersion 28
versionCode 1
versionName "1.0"
}
signingConfigs {
debug {
storeFile file(rootDir.path + '/config/debug.keystore')
storePassword "android"
keyAlias "androiddebugkey"
keyPassword "android"
}
}
buildTypes {
release {
minifyEnabled true
//signingConfig signingConfigs.debug
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
lintOptions {
abortOnError false
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.0.0'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.core:core:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
implementation (name: 'engine', ext: 'aar')
//implementation (name: 'engine', ext: 'aar')
// Import the Firebase BoM
implementation platform('com.google.firebase:firebase-bom:26.3.0')
// Add the dependency for the Firebase SDK for Google Analytics
// When using the BoM, don't specify versions in Firebase dependencies
implementation 'com.google.firebase:firebase-analytics'
}
================================================
FILE: Android/consumer/app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
================================================
FILE: Android/consumer/app/src/main/AndroidManifest.xml
================================================
================================================
FILE: Android/consumer/app/src/main/java/com/cueaudio/engine_consumer/MainActivity.java
================================================
package com.cueaudio.engine_consumer;
import android.app.Activity;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.textfield.TextInputEditText;
import com.google.android.material.textfield.TextInputLayout;
import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.appcompat.app.AppCompatActivity;
import android.text.Editable;
import android.text.InputType;
import android.text.Selection;
import android.text.TextWatcher;
import android.text.method.DigitsKeyListener;
import android.text.method.ScrollingMovementMethod;
import android.text.method.TextKeyListener;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
import com.cueaudio.engine.CUEEngine;
import com.cueaudio.engine.CUEReceiverCallbackInterface;
import com.cueaudio.engine.CUETrigger;
import com.cueaudio.engine.CUEEngineError;
import java.util.regex.Pattern;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "AndroidConsumer";
private static final int REQUEST_RECORD_AUDIO = 13;
private static final String API_KEY = "H7v7NMMNh6im735w331iLHtqnduxGCTL";
private static final int NOTIFICATION_ID = 1;
private TextView outputView;
private View clearOutput;
private Switch outputMode;
private View sendButton;
private Spinner spinner;
private TextInputLayout messageLayout;
private TextInputEditText messageInput;
private boolean isShown = false;
/**
* Used to validate the input.
*/
private Pattern inputMatcher = null;
private String[] hints;
private String[] regex;
private String[] errors;
private boolean restartListening = false;
private int getModeByPosition(int position) {
int realMode;
switch( position ) {
case 0:
case 1:
realMode = CUETrigger.MODE_TRIGGER;
break;
case 2:
case 3:
realMode = CUETrigger.MODE_MULTI_TRIGGER;
break;
case 4:
realMode = CUETrigger.MODE_LL;
break;
default:
realMode = CUETrigger.MODE_DATA;
break;
}
return realMode;
}
private boolean getTriggerAsNumberByPosition(int position) {
if( position == 1 || position == 3 )
return true;
else
return false;
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkPermission();
messageLayout = findViewById(R.id.message_layout);
messageInput = findViewById(R.id.message);
sendButton = findViewById(R.id.send);
outputView = findViewById(R.id.outputView);
outputMode = findViewById(R.id.output_mode);
clearOutput = findViewById(R.id.clear_output);
hints = getResources().getStringArray(R.array.message_hints);
regex = getResources().getStringArray(R.array.message_regex);
errors = getResources().getStringArray(R.array.message_errors);
spinner = findViewById(R.id.message_mode);
final ArrayAdapter adapter = ArrayAdapter.createFromResource(
this,
R.array.message_modes,
android.R.layout.simple_spinner_item
);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
selectMode(position);
}
@Override
public void onNothingSelected(AdapterView> parent) {
}
});
messageInput.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (s != null && s.toString().length() != 0 ) {
validateInput(s.toString());
}
}
});
outputView.setMovementMethod(new ScrollingMovementMethod());
sendButton.setEnabled(false);
sendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//noinspection ConstantConditions
final String input = messageInput.getText().toString();
final int position = spinner.getSelectedItemPosition();
int mode = getModeByPosition( position );
boolean triggerAsNumber = getTriggerAsNumberByPosition( position );
Log.v(TAG, String.format("triggerAsNumber %b", triggerAsNumber));
queueInput(input, mode, triggerAsNumber);
}
});
clearOutput.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
outputView.setText(null);
clearOutput.setVisibility(View.GONE);
}
});
}
@Override
protected void onStart() {
super.onStart();
isShown = true;
if (restartListening) {
CUEEngine.getInstance().startListening();
}
}
@Override
protected void onStop() {
restartListening = CUEEngine.getInstance().isListening();
CUEEngine.getInstance().stopListening();
isShown = false;
super.onStop();
}
private void selectMode(int position) {
refreshKeyboard(messageInput);
messageInput.setHint(hints[position]);
messageLayout.setHint(null);
inputMatcher = Pattern.compile(regex[position]);
int mode = getModeByPosition(position);
switch (mode) {
case CUETrigger.MODE_TRIGGER:
case CUETrigger.MODE_MULTI_TRIGGER:
case CUETrigger.MODE_LL:
messageInput.setInputType(InputType.TYPE_CLASS_NUMBER);
messageInput.setKeyListener(DigitsKeyListener.getInstance("0123456789."));
break;
case CUETrigger.MODE_DATA:
messageInput.setInputType(InputType.TYPE_CLASS_TEXT);
messageInput.setKeyListener(TextKeyListener.getInstance());
break;
}
//noinspection ConstantConditions
validateInput(messageInput.getText().toString());
}
private void validateInput(@NonNull String input) {
final boolean matches = inputMatcher.matcher(input).matches();
sendButton.setEnabled(matches);
if (!matches) {
final int position = spinner.getSelectedItemPosition();
// HACK: to prevent error message to be cut https://stackoverflow.com/a/55468225/322955
messageLayout.setError(null);
messageLayout.setError(errors[position]);
} else {
messageLayout.setError(null);
}
}
private void queueInput(@NonNull String input, int mode, boolean triggerAsNumber) {
int result;
switch (mode) {
case CUETrigger.MODE_TRIGGER:
if(triggerAsNumber) {
long number = Long.parseLong(input);
result = CUEEngine.getInstance().queueTriggerAsNumber(number);
if( result == CUEEngineError.TRIGGER_AS_NUMBER_MAX_NUMBER_EXCEEDED ) {
messageLayout.setError(
"Triggers as number can not exceed 461 for a CUEEngine g1 or 98611127 for a CUEEngine g2" );
} else if ( result < 0 ){
messageLayout.setError(
"Triggers as number sending: unknown error" );
}
} else {
result = CUEEngine.getInstance().queueTrigger(input);
if( result == CUEEngineError.NUMBER_OF_SYMBOLS_MISMATCH
|| result == CUEEngineError.INDEX_VALUE_EXCEEDED ) {
messageLayout.setError(
"Triggers must be of the format [0-461] for a CUEEngine generation 1 " +
"or [0-461].[0-461].[0-461] for a CUEEngine generation 2" );
} else if ( result < 0 ){
messageLayout.setError(
"Triggers as number sending: unknown error" );
}
}
break;
case CUETrigger.MODE_MULTI_TRIGGER:
if(triggerAsNumber) {
long number = Long.parseLong(input);
result = CUEEngine.getInstance().queueMultiTriggerAsNumber(number);
if( result == CUEEngineError.G1_QUEUE_MULTI_TRIGGER_UNSUPPORTED ) {
messageLayout.setError("Queue multi-trigger as number: unsupported for CUEEngine generation 1");
} else if( result == CUEEngineError.MULTI_TRIGGER_AS_NUMBER_MAX_NUMBER_EXCEEDED ) {
messageLayout.setError(
"Queue multi-trigger as number can not exceed 9724154565432383" );
} else if ( result < 0 ){
messageLayout.setError(
"Queue multi-trigger as number: unknown error" );
}
} else {
result = CUEEngine.getInstance().queueMultiTrigger(input);
if( result == CUEEngineError.G1_QUEUE_MULTI_TRIGGER_UNSUPPORTED ) {
messageLayout.setError("Queue multi-trigger: unsupported for CUEEngine generation 1");
} else if ( result < 0 ){
messageLayout.setError(
"Queue multi-trigger: unknown error" );
}
}
break;
case CUETrigger.MODE_LL:
result = CUEEngine.getInstance().queueLL(input);
if ( result == CUEEngineError.G1_QUEUE_LL_UNSUPPORTED ) {
messageLayout.setError(
"LL triggers sending is unsupported for engine generation 1");
} else if ( result == CUEEngineError.G2_QUEUE_LL_MODE_LL_ONLY_OR_MODE_BASIC_SHOULD_BE_SET ) {
messageLayout.setError(
"Can not queue ll: please set config mode to 'basic' or to 'll_only'" );
} else if ( result == CUEEngineError.G2_LL_IS_ON_IN_BASIC_CAN_NOT_QUEUE ) {
Toast.makeText(this,
"LL is already on in a config 'basic' mode, can not queue, please wait while it is off",
Toast.LENGTH_SHORT).show();
} else if( result < 0 ) {
messageLayout.setError("Queue ll: unknown error");
}
break;
case CUETrigger.MODE_DATA:
result = CUEEngine.getInstance().queueMessage(input);
if ( result == CUEEngineError.G1_QUEUE_MESSAGE_UNSUPPORTED ) {
messageLayout.setError("Queue message or data: unsupported for CUEEngine generation 1");
} else if ( result == CUEEngineError.G2_MESSAGE_STRING_SIZE_IN_BYTES_EXCEEDED ) {
messageLayout.setError("Text can't contain more then 512 bytes for G2");
} else if( result < 0 ) {
messageLayout.setError("Queue message: unknown error");
}
break;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
final boolean listening = CUEEngine.getInstance().isListening();
final Drawable startIcon = menu.findItem(R.id.menu_start).getIcon();
final Drawable stopIcon = menu.findItem(R.id.menu_stop).getIcon();
if (listening) {
DrawableCompat.setTint(startIcon, getResources().getColor(R.color.menu_active));
DrawableCompat.setTint(stopIcon, getResources().getColor(R.color.menu_inactive));
} else {
DrawableCompat.setTint(startIcon, getResources().getColor(R.color.menu_inactive));
DrawableCompat.setTint(stopIcon, getResources().getColor(R.color.menu_active));
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
final int id = item.getItemId();
switch (id) {
case R.id.menu_start:
enableListening(true);
return true;
case R.id.menu_stop:
enableListening(false);
return true;
}
return super.onOptionsItemSelected(item);
}
private void checkPermission() {
ActivityCompat.requestPermissions(
this,
new String[] { android.Manifest.permission.RECORD_AUDIO },
REQUEST_RECORD_AUDIO
);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
//check if permission was granted, and confirm that permission was mic access
boolean permCondition = requestCode == REQUEST_RECORD_AUDIO &&
grantResults.length == 1 &&
grantResults[0] == PackageManager.PERMISSION_GRANTED;
// permission is not granted yet
if (!permCondition) {
checkPermission();
return;
}
CUEEngine.getInstance().setupWithAPIKey(this, API_KEY);
CUEEngine.getInstance().setDefaultGeneration(2);
CUEEngine.getInstance().setReceiverCallback(new OutputListener());
enableListening(true);
final String config = CUEEngine.getInstance().getConfig();
Log.v(TAG, config);
CUEEngine.getInstance().setTransmittingEnabled(true);
}
private void onTriggerHeard(CUETrigger model) {
if (!isShown) {
showNotification(model.getRawIndices());
}
if (outputMode.isChecked()) {
outputView.append(model.toString());
} else {
outputView.append(model.toShortString());
}
outputView.append("\n");
outputView.append("\n");
clearOutput.setVisibility(View.VISIBLE);
long triggerNum = model.getTriggerAsNumber();
Log.i("triggerAsNumber: ", Long.toString(triggerNum));
// scroll to end
// https://stackoverflow.com/a/43290961
final Editable editable = (Editable) outputView.getText();
Selection.setSelection(editable, editable.length());
}
private void showNotification(@NonNull String message) {
final NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
final String channelId = getString(R.string.notification_channel_id);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
final CharSequence name = getString(R.string.notification_channel_name);
NotificationChannel channel = new NotificationChannel(
channelId,
name,
NotificationManager.IMPORTANCE_DEFAULT
);
//noinspection ConstantConditions
notificationManager.createNotificationChannel(channel);
}
final Intent intent = new Intent(this, MainActivity.class);
final PendingIntent pendingIntent = PendingIntent.getActivity(
this, 0, intent, 0
);
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(getText(R.string.notification_title))
.setContentText(message)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setSound(Settings.System.DEFAULT_NOTIFICATION_URI)
.setContentIntent(pendingIntent)
.setVibrate(new long[] { 1000, 1000, 1000 })
.setAutoCancel(true);
//noinspection ConstantConditions
notificationManager.notify(NOTIFICATION_ID, builder.build());
}
private void enableListening(boolean enable) {
if (enable) {
CUEEngine.getInstance().startListening();
} else {
CUEEngine.getInstance().stopListening();
}
supportInvalidateOptionsMenu();
}
private static void refreshKeyboard(@NonNull View view) {
final InputMethodManager imm =
(InputMethodManager) view.getContext().getSystemService(Activity.INPUT_METHOD_SERVICE);
//noinspection ConstantConditions
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
imm.showSoftInput(view, 0);
}
private class OutputListener implements CUEReceiverCallbackInterface {
@Override
public void run(@NonNull String json) {
final CUETrigger model = CUETrigger.parse(json);
runOnUiThread(new Runnable() {
@Override
public void run() {
onTriggerHeard(model);
}
});
}
}
}
================================================
FILE: Android/consumer/app/src/main/res/drawable/ic_clear.xml
================================================
================================================
FILE: Android/consumer/app/src/main/res/drawable/ic_launcher_background.xml
================================================
================================================
FILE: Android/consumer/app/src/main/res/drawable/ic_notification.xml
================================================
================================================
FILE: Android/consumer/app/src/main/res/drawable/ic_send.xml
================================================
================================================
FILE: Android/consumer/app/src/main/res/drawable/ic_start.xml
================================================
================================================
FILE: Android/consumer/app/src/main/res/drawable/ic_stop.xml
================================================
================================================
FILE: Android/consumer/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
================================================
================================================
FILE: Android/consumer/app/src/main/res/layout/activity_main.xml
================================================
================================================
FILE: Android/consumer/app/src/main/res/menu/main.xml
================================================
================================================
FILE: Android/consumer/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
================================================
================================================
FILE: Android/consumer/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
================================================
================================================
FILE: Android/consumer/app/src/main/res/values/colors.xml
================================================
#3F51B5#303F9F#FF4081@color/colorAccent#808080
================================================
FILE: Android/consumer/app/src/main/res/values/strings.xml
================================================
CUE ConsumerStart listeningStop listeningOutput ALL dataUltrasonic PayloadtriggersTriggers@string/app_name
Triggers must be of the format [0-461] for a CUEEngine generation 1
or [0-461].[0-461].[0-461] for a CUEEngine generation 2
Triggers as number must be of the format [0-98611127]Multi triggers must be of the format [0-461].[0-461].[0-461].[0-461].[0-461].[0-461]Multi-triggers as number must be of the format [0-9724154565432383]LL Triggers must be of the format [0-125].[0-125]...e.g. 1 or 1.2.340-986111271.2.3.4.5.60-97241545654323831.2.3.4.5....Hello World!TriggerNumberMultiTriggerNumMultiTrgLLData@string/message_error_trigger@string/message_error_number@string/message_error_multi_trigger@string/message_error_number_mt@string/message_error_ll@null@string/mode_trigger@string/mode_number@string/mode_multi_trigger@string/mode_number_mt@string/mode_ll@string/mode_data@string/message_hint_trigger@string/message_hint_number@string/message_hint_multi_trigger@string/message_hint_number_mt@string/message_hint_ll@string/message_hint_data^([0-9]|[1-9][0-9]|[1-3][0-9]{2}|4[0-5][0-9]|46[01])(\\.([0-9]|[1-9][0-9]|[1-3][0-9]{2}|4[0-5][0-9]|46[01]))*$^[0-9]+$^([0-9]|[1-9][0-9]|[1-3][0-9]{2}|4[0-5][0-9]|46[01])(\\.([0-9]|[1-9][0-9]|[1-3][0-9]{2}|4[0-5][0-9]|46[01])){5}$^[0-9]+$^([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-5])(\\.([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-5]))*$^.*$
================================================
FILE: Android/consumer/app/src/main/res/values/styles.xml
================================================
================================================
FILE: Android/consumer/build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.0'
classpath 'com.google.gms:google-services:4.3.4'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
flatDir {
dirs 'libs'
}
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
================================================
FILE: Android/consumer/gradle/wrapper/gradle-wrapper.properties
================================================
#Wed Aug 21 13:46:46 BST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
================================================
FILE: Android/consumer/gradle.properties
================================================
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
android.enableJetifier=true
android.useAndroidX=true
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
================================================
FILE: Android/consumer/gradlew
================================================
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
================================================
FILE: Android/consumer/gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
================================================
FILE: Android/consumer/settings.gradle
================================================
include ':app'
================================================
FILE: Android/engine.aar
================================================
[File too large to display: 22.9 MB]
================================================
FILE: License.md
================================================
For a better formatted version, see [HERE](./doc/licenses/License.pdf)
# End User License Agreement
This End User License Agreement (“Agreement”) is a binding agreement between you (“End User” or “you”) and CUE Audio, LLC, a Delaware limited liability company (“Company”). This Agreement governs your use of the Company’s software, whether incorporated into a mobile application, integrated into a third-party’s product, software or other medium, or provided on a stand-alone basis, including all related documentation (the “Product”). The Product is licensed, not sold, to you.
BY DOWNLOADING OR USING THE PRODUCT, YOU (A) ACKNOWLEDGE THAT YOU HAVE READ AND UNDERSTAND THIS AGREEMENT; (B) REPRESENT THAT YOU ARE OF LEGAL AGE TO ENTER INTO A BINDING AGREEMENT; AND (C) ACCEPT THIS AGREEMENT AND THE COMPANY’S PRIVACY POLICY AND AGREE THAT YOU ARE LEGALLY BOUND BY SUCH TERMS. IF YOU DO NOT AGREE TO THESE TERMS, DO NOT USE THE PRODUCT AND DELETE IT FROM YOUR MOBILE DEVICE.
License Grant. Subject to the terms of this Agreement, Company grants you a limited, non-exclusive, and nontransferable license to:
download, install, and use the Product for your personal, non-commercial use on a single mobile device owned or otherwise controlled by you (the “Mobile Device”) strictly in accordance with the Product’s documentation; and
on the Mobile Device, access, stream, and use the Content and Services (as defined in Section 5) made available in or otherwise accessible through the Product, strictly in accordance with this Agreement and the Privacy Policy applicable to such Content and Services as set forth in Section 5 (the “Privacy Policy”).
License Restrictions. You shall not:
copy the Product, except as expressly permitted by this license;
modify, translate, adapt, or otherwise create updates, upgrades, bug fixes, patches, other error corrections, and/or new features (“Updates”) or derivative works, whether or not patentable, of the Product;
reverse engineer, disassemble, decompile, decode, or otherwise attempt to derive or gain access to the source code of the Product or any part thereof;
remove, delete, alter, or obscure any trademarks or any copyright, trademark, patent, or other intellectual property or proprietary rights notices from the Product, or any copy thereof;
rent, lease, lend, sell, sublicense, assign, distribute, publish, transfer, or otherwise make available the Product, or any features or functionality of the Product, to any third party for any reason, including by making the Product available on a network where it is capable of being accessed by more than one device at any time; or
remove, disable, circumvent, or otherwise create or implement any workaround to any copy protection, rights management, or security features in or protecting the Product.
Reservation of Rights. You acknowledge and agree that the Product is provided under license, and not sold, to you. You do not acquire any ownership interest in the Product under this Agreement, or any other rights thereto other than to use the Product in accordance with the license granted, and subject to all terms, conditions, and restrictions, under this Agreement. Company and its licensors and service providers reserve and shall retain their entire right, title, and interest in and to the Product, including all copyrights, trademarks, and other intellectual property rights therein or relating thereto, subject to rights licensed and expressly granted to you in this Agreement. You agree to safeguard the Product from infringement, misappropriation, theft, misuse, or unauthorized access.
Collection and Use of Your Information. You acknowledge that when you download, install, or use the Product, Company may use automatic means (including, for example, cookies and web beacons) to collect information about your Mobile Device and about your use of the Product. You also may be required to provide certain information about yourself as a condition to downloading, installing, or using the Product or certain of its features or functionality, and the Product may provide you with opportunities to share information about yourself with others. You represent and warrant that all information you contribute or provide in connection with your use of the Product will be current, complete and accurate, and that you will update it as necessary to maintain its completeness and accuracy. If you choose, or are provided with, a user name, password, or any other piece of information as part of Company’s security procedures, you must treat such information as confidential, and you must not disclose it to any other person or entity, whether such disclosure is made by written or verbal communication, or via social media, blog, or other media-based platform. You also acknowledge that your account is personal to you and agree not to provide any other person with access to the Product or portions of the Product using your user name, password, or other security information. You agree to notify Company immediately of any unauthorized access to or use of your user name or password or any other breach of security. You are responsible for ensuring that you exit your account at the end of each session. You are responsible for the actions of anyone using your account, whether with or without your permission, and you may be held liable for any losses incurred by Company, its members, managers officers, directors, employees, agents, affiliates, successors, and assigns due to someone else’s use of your account, password, or other security information. You should use particular caution when accessing your account from a public or shared network so that others are not able to view or record your password or other personal information. All information Company collects through or in connection with this Product is subject to Company’s Privacy Policy as published at www.cueaudio.com/privacy. By downloading, installing, using, and providing information to or through this Product, you consent to all actions taken by Company with respect to your information in compliance with the Privacy Policy.
Content and Services. The Product may provide you with access to Company’s website located at https://www.cueaudio.com/ (the “Website”) and products and services accessible thereon, and certain features, functionality, and content accessible on or through the Product may be hosted on the Website (collectively, “Content and Services”). Your access to and use of such Content and Services are governed by the Website’s Privacy Policy, which is incorporated herein by this reference. Your access to and use of such Content and Services may require you to acknowledge your acceptance of such Privacy Policy and/or to register with the Website, and your failure to do so may restrict you from accessing or using certain of the Product’s features and functionality. Any violation of such Privacy Policy will also be deemed a violation of this Agreement.
Consent to Receive Email from Company. You may receive periodic email communications regarding the Product, updates or changes to the Product or this Agreement, or the functionality of the Product, which you cannot opt out of receiving. You may also receive periodic promotions and other offers or materials Company believes might be of interest to you. You can opt out of receiving these promotional messages at any time by (a) following the unsubscribe instructions contained in the email, newsletter, or promotion; or (b) changing the email preferences in your account.
Geographic Restrictions. Company does not represent or warrant that the Content and Services, the Product, or any part thereof, is appropriate or available for use in any particular jurisdiction. If you choose to access the Content and Services or the Product, you do so on your own initiative and at your own risk, and you are responsible for complying with all local laws, rules, and regulations. Company may limit the availability of the Content and Services or the Product, in whole or in part, to any person, geographic area, or jurisdiction that Company chooses, at any time and in the Company’s sole discretion. By using the Product and submitting any information, you consent to the transfer of such information, including personal information, to other countries, such as the United States, which may provide a different level of data security than in your country of residence.
Updates. Company may from time to time, in its sole discretion, develop and provide Updates for the Product (collectively, including related documentation, “Company Updates”). Company Updates may also modify or delete in their entirety certain features and functionality. You agree that Company has no obligation to provide any Company Updates or to continue to provide or enable any particular features or functionality. Based on your Mobile Device settings, when your Mobile Device is connected to the internet either:
the Product will automatically download and install all available Company Updates; or
you may receive notice of or be prompted to download and install available Company Updates.
You shall promptly download and install all Company Updates and acknowledge and agree that the Product or portions thereof may not properly operate should you fail to do so. You further agree that all Company Updates will be deemed part of the Product and be subject to all terms and conditions of this Agreement.
Third-Party Materials. The Product may display, include, or make available third-party content (including data, information, Products, and other products, services, and/or materials) or provide links to third-party websites or services, including through third-party advertising (“Third-Party Materials”). You acknowledge and agree that Company is not responsible for Third-Party Materials, including their accuracy, completeness, timeliness, validity, copyright compliance, legality, decency, quality, or any other aspect thereof. Company does not assume and will not have any liability or responsibility to you or any other person or entity for any Third-Party Materials. Third-Party Materials and links thereto are provided solely as a convenience to you, and you access and use them entirely at your own risk and subject to such third parties’ terms and conditions.
Term and Termination.
The term of Agreement commences when you download the Product and acknowledge your acceptance and will continue in effect until terminated by you or Company as set forth in this Section 10.
You may terminate this Agreement by permanently deleting the Product and all copies thereof from your Mobile Device.
Company may terminate this Agreement at any time without notice. Furthermore, Company may terminate this Agreement if it ceases to support the Product, which Company may do in its sole discretion. In addition, this Agreement will terminate immediately and automatically without any notice if you violate any of the terms and conditions of this Agreement.
Upon termination:
all rights granted to you under this Agreement will also terminate; and
you must cease all use of the Product and permanently delete all copies of the Product from your Mobile Device and account.
Termination will not limit any of Company’s rights or remedies at law or in equity.
Disclaimer of Warranties. THE PRODUCT IS PROVIDED TO YOU “AS IS” AND WITH ALL FAULTS AND DEFECTS WITHOUT WARRANTY OF ANY KIND. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW, COMPANY, ON ITS OWN BEHALF AND ON BEHALF OF ITS AFFILIATES AND ITS AND THEIR RESPECTIVE LICENSORS AND SERVICE PROVIDERS, EXPRESSLY DISCLAIMS ALL WARRANTIES, WHETHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO THE PRODUCT, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND NON-INFRINGEMENT, AND WARRANTIES THAT MAY ARISE OUT OF COURSE OF DEALING, COURSE OF PERFORMANCE, USAGE, OR TRADE PRACTICE. WITHOUT LIMITATION TO THE FOREGOING, COMPANY PROVIDES NO WARRANTY OR UNDERTAKING, AND MAKES NO REPRESENTATION OF ANY KIND THAT THE PRODUCT WILL MEET YOUR REQUIREMENTS, ACHIEVE ANY INTENDED RESULTS, BE COMPATIBLE, OR WORK WITH ANY OTHER SOFTWARE, PRODUCTS, SYSTEMS, OR SERVICES, OPERATE WITHOUT INTERRUPTION, MEET ANY PERFORMANCE OR RELIABILITY STANDARDS, OR BE ERROR-FREE, OR THAT ANY ERRORS OR DEFECTS CAN OR WILL BE CORRECTED.
SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY NOT APPLY TO YOU.
No Reliance on Information. The information provided on or through the Product or in connection with the Product is made available for your convenience and for general information purposes only and is subject to change without notice. COMPANY DOES NOT WARRANT THE ACCURACY, TIMELINESS, COMPLETENESS, OR USEFULNESS OF THIS INFORMATION OR THAT THE INFORMATION WILL SERVE YOUR PARTICULAR PURPOSES. ALL INFORMATION IS SUBJECT TO CHANGE. Any reliance you place on such information is strictly at your own risk. Company disclaims all liability and responsibility arising from any reliance placed on such information or materials by you, or by anyone who may be informed of any of its contents.
Limitation of Liability. TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL COMPANY OR ITS AFFILIATES, OR ANY OF ITS OR THEIR RESPECTIVE LICENSORS OR SERVICE PROVIDERS, HAVE ANY LIABILITY ARISING FROM OR RELATED TO YOUR USE OF OR INABILITY TO USE THE PRODUCT OR THE CONTENT AND SERVICES FOR:
PERSONAL INJURY, PROPERTY DAMAGE, LOST PROFITS, COST OF SUBSTITUTE GOODS OR SERVICES, LOSS OF DATA, LOSS OF GOODWILL, BUSINESS INTERRUPTION, COMPUTER FAILURE OR MALFUNCTION, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, INDIRECT, EXEMPLARY, SPECIAL, OR PUNITIVE DAMAGES.
DIRECT DAMAGES IN AMOUNTS THAT IN THE AGGREGATE EXCEED THE AMOUNT ACTUALLY PAID BY YOU FOR THE PRODUCT.
THE FOREGOING LIMITATIONS WILL APPLY WHETHER SUCH DAMAGES ARISE OUT OF BREACH OF CONTRACT, TORT (INCLUDING NEGLIGENCE), OR OTHERWISE AND REGARDLESS OF WHETHER SUCH DAMAGES WERE FORESEEABLE OR COMPANY WAS ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME JURISDICTIONS DO NOT ALLOW CERTAIN LIMITATIONS OF LIABILITY SO SOME OR ALL OF THE ABOVE LIMITATIONS OF LIABILITY MAY NOT APPLY TO YOU.
Indemnification. You agree to indemnify, defend, and hold harmless Company and its members, managers, officers, directors, employees, agents, affiliates, successors, and assigns from and against any and all losses, damages, liabilities, deficiencies, claims, actions, judgments, settlements, interest, awards, penalties, fines, costs, or expenses of whatever kind, including reasonable attorneys’ fees, arising from or relating to your use or misuse of the Product or your breach of this Agreement, including but not limited to the content you submit or make available through this Product.
Export Regulation. The Product may be subject to United States export control laws, including the United States Export Administration Act and its associated regulations. You shall not, directly or indirectly, export, re-export, or release the Product to, or make the Product accessible from, any jurisdiction or country to which export, re-export, or release is prohibited by law, rule, or regulation. You shall comply with all applicable federal laws, regulations, and rules, and complete all required undertakings (including obtaining any necessary export license or other governmental approval), prior to exporting, re-exporting, releasing, or otherwise using or accessing the Product outside the US.
Severability. If any provision of this Agreement is illegal or unenforceable under applicable law, the remainder of the provision will be amended to achieve as closely as possible the effect of the original term and all other provisions of this Agreement will continue in full force and effect.
Governing Law. This Agreement is governed by and construed in accordance with the internal laws of the State of Delaware without giving effect to any choice or conflict of law provision or rule. In the event of a direct conflict between the provisions of this Agreement and any mandatory provision of applicable law, the mandatory provision of applicable law will control; in all other events, the provisions of this Agreement will control.
Arbitration. You agree that any dispute, claim, or controversy between you and Company relating in any way to this Agreement or to your use of the Product (whether based in contract, tort, malpractice, negligence, misrepresentation, or any other legal theory, and whether the claims arise during or after the termination of the Agreement) will be resolved by mandatory binding individual arbitration. Arbitration is more informal than a lawsuit in court. There is no judge or jury, but instead an appointed arbitrator, usually with an experienced background in the area of the dispute. There may be more limited discovery than in court. An arbitrator can award the same damages and relief as a court (including attorney fees), except that the arbitrator may not award declaratory or injunctive relief to anyone but the parties to the arbitration. This arbitration provision will survive termination of the Agreement.
Either you or Company may demand and/or file arbitration proceedings. Arbitration between you and Company will be conducted under the then-current American Arbitration Association’s (“AAA”) Commercial Dispute Resolution Procedures and the Supplementary Procedures for Consumer Related Disputes (the “AAA Rules”). Arbitration will take place at a location to be agreed upon in Denver, Colorado, provided that if the claim is for $10,000 or less, you may request that the arbitration to be conducted be based on documents submitted to the Arbitrator or through a non-appearance based telephonic hearing; or by an in-person hearing as established by the AAA Rules. Your arbitration fees and costs will be subject to any limitations set forth in the AAA Rules with the remainder (if any) paid by Company.
In the event that Company makes any future change to this arbitration provision, you may reject any such change by sending written notice within thirty (30) days of the change and ceasing all use of the Product deleting the all copies of the Product from your Mobile Device within the same notice period.
Limitation of Time to File Claims. ANY CAUSE OF ACTION, CLAIM, OR DEMAND FOR ARBITRATION YOU MAY HAVE ARISING OUT OF OR RELATING TO THIS AGREEMENT OR THE PRODUCT MUST BE COMMENCED WITHIN ONE (1) YEAR AFTER THE CAUSE OF ACTION FIRST ACCRUES OTHERWISE SUCH CAUSE OF ACTION OR CLAIM WILL BE PERMANENTLY BARRED. If applicable law prohibits a one-year limitation period for asserting claims, any claim must be asserted within the shortest time period permitted by applicable law.
Entire Agreement. This Agreement and Company’s Privacy Policy constitute the entire agreement between you and Company with respect to the Product and supersede all prior or contemporaneous understandings and agreements, whether written or oral, with respect to the Product.
Waiver. No failure to exercise, and no delay in exercising, on the part of either party, any right or any power hereunder shall operate as a waiver thereof, nor shall any single or partial exercise of any right or power hereunder preclude further exercise of that or any other right hereunder. In the event of a conflict between this Agreement and any applicable purchase or other terms, the terms of this Agreement shall govern.
================================================
FILE: README.md
================================================
# High Reliability Acoustic Modem
## CUE Audio
CUE Audio provides an extremely reliable acoustic modem, permitting data exchange between any two devices with a microphone or speaker. CUE typically operates in the near-ultrasonic frequency band (17.5-19.5kHz) in order to be inaudible to the majority of people but detectable by commonplace microphones. Trusted by many of the world's largest brands and deployed on over nine million devices, with CUE you will have access to the world's most advanced acoustic modem.
Unlike alternative data-over-audio solution, which work only in quiet environments over short distances (a few cm to 3 meters), we've utilized this solution to successfully broadcasted ultrasonic signals in indoor/outdoor environments to crowds of 80,000+ stadium attendees, with a propagation distance of over 150 meters and negligible latency above the speed of sound.
##### Advantages include:
* No reliance on a data connection, including Wi-Fi, Bluetooth, or cellular service.
* Ability to imperceptibly transmit data through online videos, television broadcasts, or any other sound-based media.
* Enhancing the second-screen experience by allowing mobile devices to be informed of not only of what you are watching, but exactly how far along you are in the program. This also allows second-screens to respond to live events, such as touchdowns or breaking news.
* Enabling proximity-awareness in slow zones and dead spots using existing speaker infrastructure.
* Ability to synchronize devices to the nearest eighth of a second.
# Who’s using CUE Audio's library?
###### CUE Audio have been enjoyed by over 5,000,000 users across three continents. Past and current clients include:
# Technical Overview
[See PDF here](./doc/cue-technical-overview.pdf)
# Licensing
Please only use the included API Key for applications in development. The public API Key included in this demo is liable to break at any time. Before pushing a product into production, please make sure you have your own API Key by contacting . Learn more at .
# Example Use Cases
* Triggering commands on the smartphone through a television broadcast, online video, radio commercial, film and movies. Users can be rewarded for tuning in; products can be linked to during a featured commercial; coupons can be distributed, etc.
* Turn $10 household speakers into iBeacons. Any speaker emitting a unique fingerprint at regular intervals can be used to detect proximity and trigger events to achieve the same effect as traditional Bluetooth beacons.
* Location-based “push” notifications. Users can be segmented by proximity to various speakers.
* Smartphones in the same room or across the globe can be synchronized and given precisely timed commands in real-time, or minutes, hours, or even days after the trigger was detected.