Add support for remote control microphones.

GFRM210: ti-rcu-audio
TI supplies a RAS_lib to convert their proprietary
audio codec to PCM. Provide a daemon which Blue/Z
can send messages to, via a Unix domain socket in
abstract namespace "\0rc_audio_ti"

GFRM100: gfrm100-rcu-audio
Handle GFRM100 using HID RAW, watching for AUDIO_DATA
events as they fly by. The Broadcom BT chip in GFRM100
packages audio data as giant HID events, and handling
non-standard stuff like that is why HID RAW exists.
GFRM100 sends 16KHz PCM, no postprocessing is required.

ti-rcu-audio and gfrm100-rcu-audio package audio samples into
a protobuf defined in remote_control_audio.proto, and send it
to a Unix domain socket in abstract namespace "\0rcu_audio".

gfrm-voice-demo
In the real system, audio data will be handled by the TV
software as a continuous stream and uploaded to the speech
API as it arrives. For early testing, provide a gfrm-voice-demo
which records PCM data into WAV files.

Also:
Rename BUILD_IBEACON to BUILD_BLUETOOTH as we now
have a number of utilities to be built on Bluetooth
capable platforms: ibeacon, eddystone, ti-rcu-audio,
gfrm100-rcu-audio, gfrm-voice-demo.

Change-Id: I52da6a424dd4b69c3295544db2bbfd97f7bbc3ca
diff --git a/Makefile b/Makefile
index b0d99f0..1852f66 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@
 BUILD_SSDP?=y
 BUILD_DNSSD?=y
 BUILD_LOGUPLOAD?=   # default off: needs libgtest
-BUILD_IBEACON?=     # default off: needs bluetooth.h
+BUILD_BLUETOOTH?=     # default off: needs bluetooth.h
 BUILD_WAVEGUIDE?=y
 BUILD_DVBUTILS?=y
 BUILD_SYSMGR?=y
@@ -17,7 +17,7 @@
 BUILD_JSONPOLL?=n
 BUILD_PRESTERASTATS?=n
 export BUILD_HNVRAM BUILD_SSDP BUILD_DNSSD BUILD_LOGUPLOAD \
-	BUILD_IBEACON BUILD_WAVEGUIDE BUILD_DVBUTILS BUILD_SYSMGR \
+	BUILD_BLUETOOTH BUILD_WAVEGUIDE BUILD_DVBUTILS BUILD_SYSMGR \
 	BUILD_STATUTILS BUILD_CRYPTDEV BUILD_SIGNING BUILD_JSONPOLL \
 	BUILD_PRESTERASTATS BUILD_CACHE_WARMING
 
@@ -97,6 +97,10 @@
 DIRS+=ledpattern
 endif
 
+ifeq ($(BUILD_BLUETOOTH),y)
+DIRS+=rcu_audio
+endif
+
 PREFIX=/usr
 BINDIR=$(DESTDIR)$(PREFIX)/bin
 LIBDIR=$(DESTDIR)$(PREFIX)/lib
diff --git a/cmds/Makefile b/cmds/Makefile
index 24bc8a1..6c19ab8 100644
--- a/cmds/Makefile
+++ b/cmds/Makefile
@@ -76,7 +76,7 @@
 SCRIPT_TARGETS += castcheck
 endif
 
-ifeq ($(BUILD_IBEACON),y)
+ifeq ($(BUILD_BLUETOOTH),y)
 ARCH_TARGETS += ibeacon eddystone
 endif
 
diff --git a/rcu_audio/.gitignore b/rcu_audio/.gitignore
new file mode 100644
index 0000000..e08ad34
--- /dev/null
+++ b/rcu_audio/.gitignore
@@ -0,0 +1,4 @@
+ti-rcu-audio
+gfrm100-rcu-audio
+gfrm-voice-demo
+*.o
diff --git a/rcu_audio/Makefile b/rcu_audio/Makefile
new file mode 100644
index 0000000..71ef498
--- /dev/null
+++ b/rcu_audio/Makefile
@@ -0,0 +1,34 @@
+CC:=$(CROSS_COMPILE)gcc
+CPP:=$(CROSS_COMPILE)g++
+HOST_PROTOC ?= $(HOSTDIR)/usr/bin/protoc
+PREFIX=/usr
+BINDIR=$(DESTDIR)$(PREFIX)/bin
+CFLAGS += $(EXTRACFLAGS)
+LDFLAGS += $(EXTRALDFLAGS)
+
+BINARIES = ti-rcu-audio gfrm100-rcu-audio gfrm-voice-demo
+CHECKING = -Wall -Werror
+all: $(BINARIES)
+
+%.pb.cc: %.proto
+	echo "Building .pb.cc"
+	$(HOST_PROTOC) --cpp_out=. $<
+
+ti-rcu-audio: ti-rcu-audio.cc RAS_lib.c RAS_lib.h rcu-audio.h remote_control_audio.pb.cc rcu-utils.cc
+	$(CPP) -I. $(CHECKING) $(CFLAGS) ti-rcu-audio.cc RAS_lib.c remote_control_audio.pb.cc rcu-utils.cc -o $@ $(LDFLAGS) -lprotobuf-lite
+
+gfrm100-rcu-audio: gfrm100-rcu-audio.cc rcu-audio.h remote_control_audio.pb.cc rcu-utils.cc
+	$(CPP) -I. $(CHECKING) $(CFLAGS) gfrm100-rcu-audio.cc remote_control_audio.pb.cc rcu-utils.cc -o $@ $(LDFLAGS) -lprotobuf-lite
+
+gfrm-voice-demo: gfrm-voice-demo.cc rcu-audio.h remote_control_audio.pb.cc rcu-utils.cc
+	$(CPP) -I. $(CHECKING) $(CFLAGS) gfrm-voice-demo.cc remote_control_audio.pb.cc rcu-utils.cc -o $@ $(LDFLAGS) -lprotobuf-lite
+
+install:
+	mkdir -p $(BINDIR)
+	cp $(BINARIES) $(BINDIR)
+
+install-libs:
+	@echo "No libs to install."
+
+clean:
+	rm -f $(BINARIES) *.o
diff --git a/rcu_audio/RAS_lib.c b/rcu_audio/RAS_lib.c
new file mode 100755
index 0000000..cfb33df
--- /dev/null
+++ b/rcu_audio/RAS_lib.c
@@ -0,0 +1,332 @@
+/*
+* Copyright (c) [2015] Texas Instruments Incorporated
+*
+* All rights reserved not granted herein.
+* Limited License.
+*
+* Texas Instruments Incorporated grants a world-wide, royalty-free,
+* non-exclusive license under copyrights and patents it now or hereafter
+* owns or controls to make, have made, use, import, offer to sell and sell ("Utilize")
+* this software subject to the terms herein.  With respect to the foregoing patent
+*license, such license is granted  solely to the extent that any such patent is necessary
+* to Utilize the software alone.  The patent license shall not apply to any combinations which
+* include this software, other than combinations with devices manufactured by or for TI ("TI Devices").
+* No hardware patent is licensed hereunder.
+*
+* Redistributions must preserve existing copyright notices and reproduce this license (including the
+* above copyright notice and the disclaimer and (if applicable) source code license limitations below)
+* in the documentation and/or other materials provided with the distribution
+*
+* Redistribution and use in binary form, without modification, are permitted provided that the
+* following conditions are met:
+*
+*             * No reverse engineering, decompilation, or disassembly of this software is permitted
+*             	with respect to any software provided in binary form.
+*             * any redistribution and use are licensed by TI for use only with TI Devices.
+*             * Nothing shall obligate TI to provide you with source code for the software licensed
+*             	and provided to you in object code.
+*
+* If software source code is provided to you, modification and redistribution of the source code are
+* permitted provided that the following conditions are met:
+*
+*   * any redistribution and use of the source code, including any resulting derivative works, are
+*     licensed by TI for use only with TI Devices.
+*   * any redistribution and use of any object code compiled from the source code and any resulting
+*     derivative works, are licensed by TI for use only with TI Devices.
+*
+* Neither the name of Texas Instruments Incorporated nor the names of its suppliers may be used to
+* endorse or promote products derived from this software without specific prior written permission.
+*
+* DISCLAIMER.
+*
+* THIS SOFTWARE IS PROVIDED BY TI AND TI'S LICENSORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TI AND TI'S LICENSORS BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "RAS_lib.h"
+
+static int16 PV_Dec;
+static int8 SI_Dec;
+
+
+#define NULL	0
+#define PRED_CYPHER_CONST 0x3292
+#define STEP_CYPHER_CONST 0x5438
+
+#define HDR_NOT_SCRAMBLED 1
+
+
+static uint8 ras_pec_mode;
+static int16 per_buff[MAX_INPUT_BUF_SIZE*4];
+
+const uint16 codec_stepsize_Lut[89] =
+{
+  7,    8,    9,   10,   11,   12,   13,   14,
+  16,   17,   19,   21,   23,   25,   28,   31,
+  34,   37,   41,   45,   50,   55,   60,   66, 73,   80,   88,   97,  107,  118,  130,  143,
+  157,  173,  190,  209,  230,  253,  279,  307, 337,  371,  408,  449,  494,  544,  598,  658,
+  724,  796,  876,  963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
+  3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493,10442,11487,12635,13899,
+  15289,16818,18500,20350,22385,24623,27086,29794, 32767
+};
+
+const int8 codec_IndexLut[16] =
+{
+  -1, -1, -1, -1, 2, 4, 6, 8,
+  -1, -1, -1, -1, 2, 4, 6, 8
+};
+
+
+/**************************************************************************************************
+*
+* @fn          codec_DecodeSingle
+*
+* @brief       This routine decode a 4bits ADPCM sample to a uin16 PCM audio sample.
+*
+* @param       uint8 a 4 bits ADPCM sample
+*
+*
+* @return      the 16 bits PCM samples.
+*/
+static int16 codec_DecodeSingle(uint8 codec_4bits)
+{
+  int16 step = codec_stepsize_Lut[SI_Dec];
+  int16 cum_diff  = step>>3;
+
+	// DBG("step %d cum_diff %d\n", step, cum_diff);
+
+  SI_Dec += codec_IndexLut[codec_4bits];
+  if(SI_Dec<0) SI_Dec = 0; else if(SI_Dec>88) SI_Dec = 88;
+
+  if(codec_4bits&4)
+     cum_diff += step;
+  if(codec_4bits&2)
+     cum_diff += step>>1;
+  if(codec_4bits&1)
+     cum_diff += step>>2;
+
+   if(codec_4bits&8)
+   {
+     if (PV_Dec < (-32767+cum_diff))
+       (PV_Dec) = -32767;
+     else
+       PV_Dec -= cum_diff;
+   }
+   else
+   {
+     if (PV_Dec > (0x7fff-cum_diff))
+       (PV_Dec) = 0x7fff;
+     else
+     PV_Dec += cum_diff;
+   }
+  return PV_Dec;
+}
+
+/**************************************************************************************************
+ *
+ * @fn          codec_DecodeBuff
+ *
+ * @brief       This routine encode a buffer with ADPCM IMA.
+ *
+ * @param       int16* dst  pointer to buffer where decoding result will be copy
+ *              uint8* src  input buffer, size must be a multiple of 4 bytes
+ *              srcSize     Number of byte that will be generated by the encoder (4* (src buffer size in byte))
+ *
+ *
+ * @return      none
+ */
+static void codec_DecodeBuff(int16* dst, uint8* src, unsigned int srcSize,  int8 *si, int16 *pv)
+{
+
+  // calculate pointers to iterate output buffer
+  int16* out = dst;
+  int16* end = out+(srcSize>>1);
+	int16 temp;
+
+  PV_Dec = *pv;
+  SI_Dec = *si;
+
+  while(out<end)
+  {
+     // get byte from src
+     uint8 codec = *src;
+	// DBG("codec %04x\n", codec);
+     // *out++ = codec_DecodeSingle((codec&0xF));  // decode value and store it
+     temp = codec_DecodeSingle((codec&0xF));  // decode value and store it
+		// DBG("from low %04x\n", temp);
+		*out++ = temp;
+     codec >>= 4;  // use high nibble of byte
+     codec &= 0xF;  // use high nibble of byte
+     // *out++ = codec_DecodeSingle(codec);  // decode value and store it
+     temp = codec_DecodeSingle((codec));  // decode value and store it
+		// DBG("from high %04x\n", temp);
+		*out++ = temp;
+     ++src;        // move on a byte for next sample
+  }
+
+  *pv = PV_Dec;
+  *si = SI_Dec;
+}
+
+
+/**************************************************************************************************
+ *
+ * @fn      RAS_Init
+ *
+ * @brief   RemoTI Audio Subsystem, initialization function
+ *
+ * input parameters
+ *
+ * @param   pec_mode:    	Packet Error concealment algorithm to apply:
+ * 							RAS_NO_PEC(0): 		None (default)
+ * 							RAS_PEC_MODE1(1): 	Replace lost packets by last valid.
+ *
+ * output parameters
+ *codec_ima_DecodeBuff
+ * None.
+ *
+ * @return      .
+ * status.	0				SUCCESS
+ * 			-1				ERROR: INVALID PARAMETER
+ */
+uint8 RAS_Init( uint8 pec_mode )
+{
+	uint16 i;
+	if (pec_mode>RAS_PEC_MODE1) return -1;
+	ras_pec_mode = pec_mode;
+
+	for (i=0; i<(MAX_INPUT_BUF_SIZE*4);i++)
+		per_buff[i]=0;
+
+	return 0;
+}
+
+/**************************************************************************************************
+ *
+ * @fn      RAS_GetVersion
+ *
+ * @brief   RemoTI Audio Subsystem, retrieve software version
+ *
+ * input parameters
+ *
+ * none
+ *
+ * output parameters
+ *
+ * None.
+ *
+ * @return      .
+ * Software Version.	MSB	 Major revision number
+ *						LSB: Minor revision number
+ */
+uint16 RAS_GetVersion( void )
+{
+	return RAS_SOFTWARE_VERSION;
+}
+/**************************************************************************************************
+ *
+ * @fn      RAS_Decode
+ *
+ * @brief   RemoTI Audio Subsystem, decoding function. decode encoded audioframe to PCM samples.
+ *
+ * input parameters
+ *
+ * @param   option:    		decoding option. can be pure decoding, or packet lot concealment algorithm:
+ * 							RAS_PACKET_LOST(0)
+ * 							RAS_DECODE(1)
+ * @param   input: 			address of the buffer to decode, this buffer must include the 3 bytes header..
+ *
+ * @param   inputLength:  	length of the buffer to decode, excluding the 3 bytes header.
+ * 							cannot be greater than 128 (MAX_INPUT_BUF_SIZE);
+ *
+ * output parameters
+ *
+ * @param   output:     	buffer where the decoded PCM will be written. This buffer must be allocated by the caller.
+ * 							it must have a length of 4 times the inputLength variable
+ *
+ * @param   outputLenght:  	length of the decoded buffer.
+ * 							max possible value 512 (4*MAX_INPUT_BUF_SIZE);
+ *
+ *
+ * @return      .
+ * status.	0				SUCCESS
+ * 			-1				ERROR: INVALID PARAMETER
+ *
+ */
+uint8 RAS_Decode( uint8 option, uint8* input, uint16 inputLength, int16* output,uint16 *outputLenght )
+{
+    int8 step_index;
+    int16 predicted_value;
+    uint16 i;
+    static uint8 *rf_DataFrame;
+    *outputLenght = 0;
+
+	// DBG("RAS_Decode option %d input %04x inputLength %d output %04x outputLength %d\n", option, input, inputLength, output, outputLenght);
+
+    if ((output == NULL) || (inputLength > MAX_INPUT_BUF_SIZE)) return -1;
+
+#ifdef HDR_NOT_SCRAMBLED
+	predicted_value = (input [0] + ((input[1])<<8));
+    step_index = input [2] & 0xFF;
+#else
+    predicted_value = (int16)(((int16)((input[0])<<8))+((int16)(input [2] ))) ^ PRED_CYPHER_CONST;
+    step_index      = (input [1] & 0xFF) ^STEP_CYPHER_CONST;
+#endif
+
+    //extract Predicted value and step index from the header.
+    inputLength-=3;  //Remove Header Size
+    // check Option
+    switch(option)
+    {
+    	case RAS_PACKET_LOST:
+    	{
+    		switch (ras_pec_mode)
+    		{
+				case RAS_PEC_MODE1:
+					for (i=0; i<(inputLength*4);i++)
+						output[i] = per_buff[i];
+					break;
+		    	default:
+		    		break;
+    		}
+
+    	}
+    	break;
+
+    	case RAS_DECODE_TI_TYPE1:
+    	    if (input == NULL) return -1;
+    	    rf_DataFrame = input+3;
+    	    codec_DecodeBuff(output, rf_DataFrame, inputLength*4,  &step_index, &predicted_value);
+
+			//Save Frame for packet error concealment
+	   		switch (ras_pec_mode)
+			{
+				case RAS_PEC_MODE1:
+					for (i=0; i<(inputLength*4);i++)
+						per_buff[i] = output[i];
+					break;
+				default:
+					break;
+			}
+
+    		break;
+
+    	default:
+    		break;
+
+
+    }
+    *outputLenght = inputLength*4;
+    return 0;
+};
+
+
diff --git a/rcu_audio/RAS_lib.h b/rcu_audio/RAS_lib.h
new file mode 100755
index 0000000..e009902
--- /dev/null
+++ b/rcu_audio/RAS_lib.h
@@ -0,0 +1,195 @@
+/*
+* Copyright (c) [2015] Texas Instruments Incorporated
+*
+* All rights reserved not granted herein.
+* Limited License.
+*
+* Texas Instruments Incorporated grants a world-wide, royalty-free,
+* non-exclusive license under copyrights and patents it now or hereafter
+* owns or controls to make, have made, use, import, offer to sell and sell ("Utilize")
+* this software subject to the terms herein.  With respect to the foregoing patent
+*license, such license is granted  solely to the extent that any such patent is necessary
+* to Utilize the software alone.  The patent license shall not apply to any combinations which
+* include this software, other than combinations with devices manufactured by or for TI ("TI Devices").
+* No hardware patent is licensed hereunder.
+*
+* Redistributions must preserve existing copyright notices and reproduce this license (including the
+* above copyright notice and the disclaimer and (if applicable) source code license limitations below)
+* in the documentation and/or other materials provided with the distribution
+*
+* Redistribution and use in binary form, without modification, are permitted provided that the
+* following conditions are met:
+*
+*             * No reverse engineering, decompilation, or disassembly of this software is permitted
+*             	with respect to any software provided in binary form.
+*             * any redistribution and use are licensed by TI for use only with TI Devices.
+*             * Nothing shall obligate TI to provide you with source code for the software licensed
+*             	and provided to you in object code.
+*
+* If software source code is provided to you, modification and redistribution of the source code are
+* permitted provided that the following conditions are met:
+*
+*   * any redistribution and use of the source code, including any resulting derivative works, are
+*     licensed by TI for use only with TI Devices.
+*   * any redistribution and use of any object code compiled from the source code and any resulting
+*     derivative works, are licensed by TI for use only with TI Devices.
+*
+* Neither the name of Texas Instruments Incorporated nor the names of its suppliers may be used to
+* endorse or promote products derived from this software without specific prior written permission.
+*
+* DISCLAIMER.
+*
+* THIS SOFTWARE IS PROVIDED BY TI AND TI'S LICENSORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TI AND TI'S LICENSORS BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef RSA_LIB_H
+#define RSA_LIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#if !defined PACK_1
+#define PACK_1
+#endif
+
+
+#if defined(_MSC_VER) || defined(unix) || (defined(__ICC430__) && (__ICC430__==1))
+#pragma pack(1)
+#endif
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Defines
+
+#define MAX_INPUT_BUF_SIZE 		128
+
+#define RAS_PACKET_LOST 		0
+#define RAS_DECODE_TI_TYPE1		1
+
+#define RAS_NO_PEC		   		0
+#define RAS_PEC_MODE1   		1
+
+//RAS Software Version: v1.3
+#define RAS_SOFTWARE_VERSION	0x0103
+/////////////////////////////////////////////////////////////////////////////
+// Typedefs
+#ifndef int8
+typedef signed   char   int8;
+#endif
+
+#ifndef uint8
+typedef unsigned char   uint8;
+#endif
+
+#ifndef int16
+typedef signed   short  int16;
+#endif
+
+#ifndef uint16
+typedef unsigned short  uint16;
+#endif
+
+#ifndef int32
+typedef signed   int  int32;
+#endif
+
+#ifndef uint32
+typedef unsigned int  uint32;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// Global variable
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Function declarations
+/**************************************************************************************************
+ *
+ * @fn      RAS_GetVersion
+ *
+ * @brief   RemoTI Audio Subsystem, retrieve software version
+ *
+ * input parameters
+ *
+ * none
+ *
+ * output parameters
+ *
+ * None.
+ *
+ * @return      .
+ * Software Version.	MSB	 Major revision number
+ *						LSB: Minor revision number
+ */
+uint16 RAS_GetVersion( void );
+
+/**************************************************************************************************
+ *
+ * @fn      RAS_Init
+ *
+ * @brief   RemoTI Audio Subsystem, initialization function
+ *
+ * input parameters
+ *
+ * @param   pec_mode:    	Packet Error concealment algorithm to apply:
+ * 							RAS_NO_PEC(0): 		None (default)
+ * 							RAS_PEC_MODE1(1): 	Replace lost packets by last valid.
+ *
+ * output parameters
+ *
+ * None.
+ *
+ * @return      .
+ * status.	0				SUCCESS
+ * 			-1				ERROR: INVALID PARAMETER
+ */
+uint8 RAS_Init( uint8 pec_mode );
+
+
+/**************************************************************************************************
+ *
+ * @fn      RAS_Decode
+ *
+ * @brief   RemoTI Audio Subsystem, decoding function. decode encoded audioframe to PCM samples.
+ *
+ * input parameters
+ *
+ * @param   option:    		decoding option. can be pure decoding, or packet lot concealment algorithm:
+ * 							RAS_PACKET_LOST(0)
+ * 							RAS_DECODE(1)
+ * @param   input: 			address of the buffer to decode, this buffer must include the 3 bytes header..
+ *
+ * @param   inputLenght:  	length of the buffer to decode, excluding the 3 bytes header.
+ * 							cannot be greater than 128 (MAX_INPUT_BUF_SIZE);
+ *
+ * output parameters
+ *
+ * @param   output:     	buffer where the decoded PCM will be written. This buffer must be allocated by the caller.
+ * 							it must have a length of 4 times the inputLength variable
+ *
+ * @param   outputLenght:  	length of the decoded buffer.
+ * 							max possible value 512 (4*MAX_INPUT_BUF_SIZE);
+ *
+ *
+ * @return      .
+ * status.	0				SUCCESS
+ * 			-1				ERROR: INVALID PARAMETER
+ *
+ */
+uint8 RAS_Decode( uint8 option, uint8* input, uint16 inputLenght, int16* output,uint16 *outputLenght );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // RSA_LIB_H
diff --git a/rcu_audio/gfrm-voice-demo.cc b/rcu_audio/gfrm-voice-demo.cc
new file mode 100644
index 0000000..c097252
--- /dev/null
+++ b/rcu_audio/gfrm-voice-demo.cc
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _BSD_SOURCE
+#include <endian.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "rcu-audio.h"
+#include "remote_control_audio.pb.h"
+
+
+typedef struct WAV_hdr
+{
+  uint32_t chunk_id;
+  uint32_t chunk_size;
+  uint32_t format;
+
+  uint32_t subchunk1_id;
+  uint32_t subchunk1_size;
+  uint16_t audio_format;
+  uint16_t num_channels;
+  uint32_t sample_rate;
+  uint32_t byte_rate;
+  uint16_t block_align;
+  uint16_t bits_per_sample;
+
+  uint32_t subchunk2_id;
+  uint32_t subchunk2_size;
+} WAV_hdr_t;
+
+
+static int usage(const char *progname)
+{
+  fprintf(stderr, "usage: %s [-f outfile]\n, where:", progname);
+  fprintf(stderr, "\t-f outfile: file to write audio to in WAV format.\n");
+  exit(1);
+}
+
+
+int main(int argc, char **argv)
+{
+  mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP;
+  int fd;
+  struct sockaddr_un sun;
+  const char *outfile = "/tmp/audio.wav";
+  int outfd;
+  uint8_t buf[8192];
+  WAV_hdr_t hdr;
+  ssize_t len, totlen=0;
+  int c;
+  struct timeval tv;
+  const char *model = "UNKNOWN";
+
+  memset(buf, 0, sizeof(buf));
+  memset(&hdr, 0, sizeof(hdr));
+
+  while ((c = getopt(argc, argv, "f:")) != -1) {
+    switch (c) {
+      case 'f':
+        outfile = optarg;
+        break;
+      default:
+        usage(argv[0]);
+        break;
+    }
+  }
+
+  if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
+    perror("socket(AF_UNIX) RCU_AUDIO_PATH");
+    exit(1);
+  }
+  memset(&sun, 0, sizeof(sun));
+  sun.sun_family = AF_UNIX;
+  strncpy(&sun.sun_path[1], RCU_AUDIO_PATH, sizeof(sun.sun_path) - 2);
+  if (bind(fd, (const struct sockaddr *) &sun, sizeof(sun)) < 0) {
+    perror("bind(AF_UNIX) RCU_AUDIO_PATH");
+    exit(1);
+  }
+
+  if ((outfd = open(outfile, O_RDWR|O_CREAT|O_TRUNC, mode)) < 0) {
+    fprintf(stderr, "Unable to open %s for writing.\n", outfile);
+    exit(1);
+  }
+
+  if ((len = write(outfd, &hdr, sizeof(WAV_hdr_t))) != sizeof(WAV_hdr_t)) {
+    fprintf(stderr, "Incorrect size for WAV header: %zd != %zd\n",
+      len, sizeof(WAV_hdr_t));
+    exit(1);
+  }
+
+  tv.tv_sec = 0x7fffffff;
+  tv.tv_usec = 0;
+
+  while (1) {
+    fd_set rfds;
+
+    FD_ZERO(&rfds);
+    FD_SET(fd, &rfds);
+    if (select(fd + 1, &rfds, NULL, NULL, &tv) <= 0) {
+      /* No more data, close the output and exit. */
+      break;
+    }
+
+    len = read(fd, buf, sizeof(buf));
+    if (len > 0) {
+      rcaudio::AudioSamples samples;
+      const char *data;
+      ssize_t data_len;
+
+      if (!samples.ParseFromArray(buf, len)) {
+        if (pacing()) {
+          printf("failed to parse rcaudio::AudioSamples.\n");
+        }
+        continue;
+      }
+
+      if (samples.audio_format() != rcaudio::AudioSamples::PCM_16BIT_16KHZ) {
+        /* if we ever build a remote with a different format, we'll need
+         * to keep track of it here and adjust the WAV header to match. */
+        if (pacing()) {
+          fprintf(stderr, "unknown audio format %d\n", samples.audio_format());
+        }
+        continue;
+      }
+
+      switch (samples.remote_type()) {
+        case rcaudio::AudioSamples::GFRM210: model = "GFRM210"; break;
+        case rcaudio::AudioSamples::GFRM100: model = "GFRM100"; break;
+
+        case rcaudio::AudioSamples::UNDEFINED_REMOTE_TYPE:
+        default:
+          model = "UNKNOWN";
+          break;
+      }
+
+      data = samples.audio_samples().c_str();
+      data_len = samples.audio_samples().size();
+      totlen += data_len;
+      if (write(outfd, data, data_len) != data_len) {
+        fprintf(stderr, "short write!\n");
+        exit(1);
+      }
+    } else if (len == 0) {
+      break;
+    } else if (len < 0) {
+      perror("read");
+      exit(1);
+    }
+    tv.tv_sec = 2;
+    tv.tv_usec = 0;
+  }
+
+  /* print the remote control type to stdout, demo script uses it. */
+  puts(model);
+
+  lseek(outfd, 0, SEEK_SET);
+
+  #define BITS_PER_SAMPLE 16
+  #define SAMPLES_PER_SECOND  16000
+  /* http://soundfile.sapp.org/doc/WaveFormat/ */
+  hdr.chunk_id = htole32(0x46464952);  // "RIFF"
+  hdr.chunk_size = htole32(36 + totlen);
+  hdr.format = htole32(0x45564157);  // "WAVE"
+
+  hdr.subchunk1_id = htole32(0x20746d66);  // "fmt "
+  hdr.subchunk1_size = htole32(16);
+  hdr.audio_format = htole16(1);
+  hdr.num_channels = htole16(1);
+  hdr.sample_rate = htole32(SAMPLES_PER_SECOND);
+  hdr.byte_rate = htole32(SAMPLES_PER_SECOND * 1 * BITS_PER_SAMPLE/8);
+  hdr.block_align = htole16(1 * BITS_PER_SAMPLE/8);
+  hdr.bits_per_sample = htole16(BITS_PER_SAMPLE);
+
+  hdr.subchunk2_id = htole32(0x61746164);  // "data"
+  hdr.subchunk2_size = htole32(totlen);
+  if ((len = write(outfd, &hdr, sizeof(WAV_hdr_t))) != sizeof(WAV_hdr_t)) {
+    fprintf(stderr, "Incorrect size for WAV header: %zd != %zd\n",
+      len, sizeof(WAV_hdr_t));
+    exit(1);
+  }
+
+  exit(0);
+}
diff --git a/rcu_audio/gfrm100-rcu-audio.cc b/rcu_audio/gfrm100-rcu-audio.cc
new file mode 100644
index 0000000..6e55e93
--- /dev/null
+++ b/rcu_audio/gfrm100-rcu-audio.cc
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Derived from hid-example.c, license:
+ *
+ * Hidraw Userspace Example
+ *
+ * Copyright (c) 2010 Alan Ott <alan@signal11.us>
+ * Copyright (c) 2010 Signal 11 Software
+ *
+ * The code may be used by anyone for any purpose,
+ * and can serve as a starting point for developing
+ * applications using hidraw.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/hidraw.h>
+#include <linux/input.h>
+#include <linux/types.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "rcu-audio.h"
+#include "remote_control_audio.pb.h"
+
+
+int main(int argc, char **argv)
+{
+  int in = -1, out = -1, connected = 0;
+  const char *device;
+  struct sockaddr_un sun;
+  char name[16];
+  char address[64];
+
+  if (argc != 2) {
+    fprintf(stderr, "usage: %s /dev/hidraw#\n", argv[0]);
+    exit(1);
+  }
+  device = argv[1];
+
+  if ((in = open(device, O_RDWR)) < 0) {
+    perror("open /dev/hidraw");
+    exit(1);
+  }
+
+  memset(&sun, 0, sizeof(sun));
+  sun.sun_family = AF_UNIX;
+  strncpy(&sun.sun_path[1], RCU_AUDIO_PATH, sizeof(sun.sun_path) - 2);
+
+  if (ioctl(in, HIDIOCGRAWNAME(sizeof(name)), name) < 0) {
+    perror("HIDIOCGRAWNAME");
+    exit(1);
+  }
+  if (strcmp(name, "GFRM100") != 0) {
+    fprintf(stderr, "%s is not a GFRM100. Exiting.\n", device);
+    exit(0);
+  }
+
+  if (ioctl(in, HIDIOCGRAWPHYS(sizeof(address)), address) < 0) {
+    perror("HIDIOCGRAWPHYS");
+    exit(1);
+  }
+
+  /* this process will be started out of the hotplug script when a new
+   * remote appears. We either exit if not a GFRM100, or daemonize to
+   * let the hotplug script continue. */
+  if (daemon(0, 1)) {
+    perror("daemon()");
+    exit(1);
+  }
+
+  while (1) {
+    uint8_t data[2048];
+    size_t len = read(in, data, sizeof(data));
+
+    if (len < 0) {
+      fprintf(stderr, "GFRM100 has disconnected. Exiting.\n");
+      exit(0);
+    }
+
+    if (data[0] != 0xf7) {
+      /* Not an audio packet */
+      continue;
+    }
+
+    if (data[1] == 0x01 && len > 4) {
+      rcaudio::AudioSamples samples;
+      std::vector<uint8_t> pkt;
+
+      samples.set_rc_address(address);
+      samples.set_audio_format(rcaudio::AudioSamples::PCM_16BIT_16KHZ);
+      samples.set_remote_type(rcaudio::AudioSamples::GFRM100);
+
+      /*
+       * data[0] == 0xf7
+       * data[1] == 0x01
+       * data[2] and data[3] are a count of the number of samples.
+       * data[4] == first byte of audio data.
+       */
+      samples.set_audio_samples(data + 4, len - 4);
+
+      pkt.resize(samples.ByteSize());
+      samples.SerializeToArray(&pkt[0], samples.ByteSize());
+
+      if (out < 0) {
+        out = get_socket_or_die();
+      }
+
+      if (!connected) {
+        if (connect(out, (const struct sockaddr *) &sun, sizeof(sun)) == 0) {
+          connected = 1;
+        } else {
+          sleep(2);  /* rate limit how often we retry. */
+        }
+      }
+
+      if (connected) {
+        if (send(out, &pkt[0], pkt.size(), 0) != (ssize_t)pkt.size()) {
+          fprintf(stderr, "Audio send failed, will reconnect.\n");
+          close(out);
+          out = -1;
+          connected = 0;
+        }
+      }
+    }
+  }
+  return 0;
+}
diff --git a/rcu_audio/rcu-audio.h b/rcu_audio/rcu-audio.h
new file mode 100644
index 0000000..725ca10
--- /dev/null
+++ b/rcu_audio/rcu-audio.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RCU_AUDIO_H
+#define RCU_AUDIO_H
+
+#define RCU_AUDIO_PATH "rcu_audio"
+
+/* Return 1 if at least one second has passed since the
+ * last successful call to pacing(). */
+extern int pacing();
+
+/* Return an AF_UNIX socket, or die trying. */
+extern int get_socket_or_die();
+
+#endif  /* RCU_AUDIO_H */
diff --git a/rcu_audio/rcu-utils.cc b/rcu_audio/rcu-utils.cc
new file mode 100644
index 0000000..2bd1e41
--- /dev/null
+++ b/rcu_audio/rcu-utils.cc
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <unistd.h>
+
+static uint64_t monotime(void) {
+  struct timespec ts;
+  if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
+    perror("clock_gettime(CLOCK_MONOTONIC)");
+    exit(1);
+  } else {
+    return (ts.tv_sec * 1000000) + (ts.tv_nsec / 1000);
+  }
+}
+
+
+/* Return 1 if at least one second has passed since the
+ * last successful call to pacing(). */
+int pacing() {
+  static uint64_t last = 0;
+  uint64_t now = monotime();
+  int rc = 0;
+
+  if ((now - last) > 1000000) {
+    last = now;
+    rc = 1;
+  }
+
+  return rc;
+}
+
+
+int get_socket_or_die()
+{
+  int s;
+
+  if ((s = socket(AF_UNIX, SOCK_NONBLOCK | SOCK_DGRAM, 0)) < 0) {
+    perror("socket(AF_UNIX)");
+    exit(1);
+  }
+
+  return s;
+}
diff --git a/rcu_audio/remote_control_audio.proto b/rcu_audio/remote_control_audio.proto
new file mode 100644
index 0000000..3f6b767
--- /dev/null
+++ b/rcu_audio/remote_control_audio.proto
@@ -0,0 +1,25 @@
+syntax = "proto2";
+package rcaudio;
+option optimize_for = LITE_RUNTIME;
+
+message AudioSamples {
+  // A unique identifier for the remote control.
+  // For Bluetooth this will be the BDADDR like "00:11:22:33:44:55"
+  optional string rc_address = 1;
+
+  enum AudioFormat {
+    UNDEFINED_AUDIO_FORMAT = 0;
+    PCM_16BIT_16KHZ = 1;
+  }
+  optional AudioFormat audio_format = 2;
+
+  enum RemoteType {
+    UNDEFINED_REMOTE_TYPE = 0;
+    GFRM210 = 1;
+    GFRM100 = 2;
+  }
+  optional RemoteType remote_type = 3;
+
+  optional bytes audio_samples = 4;
+};
+
diff --git a/rcu_audio/ti-rcu-audio.cc b/rcu_audio/ti-rcu-audio.cc
new file mode 100644
index 0000000..76f1126
--- /dev/null
+++ b/rcu_audio/ti-rcu-audio.cc
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* Note: though this specific file is licensed under the Apache license,
+ * it exists in order to interface with the RAS_LIB.c implementation
+ * provided by TI which is not licensed under Apache. */
+
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "rcu-audio.h"
+#include "remote_control_audio.pb.h"
+#include "RAS_lib.h"
+
+#define TI_AUDIO_PATH "\0rc_audio_ti"
+
+int main(int argc, char **argv)
+{
+  int is = -1, os = -1, connected = 0;
+  struct sockaddr_un sun;
+  uint8 prev = 0;
+  int msgs = 0, missed = 0, errors = 0;
+
+  is = get_socket_or_die();
+  memset(&sun, 0, sizeof(sun));
+  sun.sun_family = AF_UNIX;
+  snprintf(sun.sun_path, sizeof(sun.sun_path), "%s", TI_AUDIO_PATH);
+  if (bind(is, (const struct sockaddr *) &sun, sizeof(sun)) < 0) {
+    perror("bind(AF_UNIX)");
+    exit(1);
+  }
+
+  memset(&sun, 0, sizeof(sun));
+  sun.sun_family = AF_UNIX;
+  strncpy(&sun.sun_path[1], RCU_AUDIO_PATH, sizeof(sun.sun_path) - 2);
+
+  while (1) {
+    uint8 ibuf[MAX_INPUT_BUF_SIZE + 6 + 1 + 4];
+    size_t ilen;
+
+    ilen = recv(is, ibuf, sizeof(ibuf), 0);
+    if (ilen < 23) {
+      /* end of an audio file, prepare for the next one */
+      printf("Finished audio stream; msgs = %d, missed = %d, errors = %d\n",
+          msgs, missed, errors);
+      msgs = missed = errors = 0;
+      RAS_Init(RAS_NO_PEC);
+    } else {
+      uint8_t remote_type = ibuf[6];
+      uint8 expected = (prev + 1) & 0x1f;
+      uint8 seqnum = (ibuf[7] >> 3) & 0x1f;
+      uint8 *data;
+      uint16 data_len;
+      int16 obuf[4 * MAX_INPUT_BUF_SIZE];
+      uint16 olen;
+
+      if (seqnum != expected) {
+        missed++;
+      }
+      prev = seqnum;
+      msgs++;
+
+      /*
+       * We skip over:
+       *   the first 6 bytes, which is the BDADDR of the remote.
+       *   the remote type byte (0 == GFRM210)
+       *   the sequence number byte
+       *
+       * The first three bytes of payload are some kind of RAS header.
+       * RAS_Decode() says the data pointer must include the three bytes
+       * of header, but the length must not include those 3 bytes.
+       * So the length is decremented by 6+1+1+3 for a total of 11.
+       */
+      data = &ibuf[6 + 1 + 1];
+      data_len = ilen - (6 + 1 + 1 + 3);
+      if (RAS_Decode(RAS_DECODE_TI_TYPE1, data, data_len, obuf, &olen) == 0) {
+        rcaudio::AudioSamples samples;
+        char bdaddr[18];
+        std::vector<uint8_t> pkt;
+
+        snprintf(bdaddr, sizeof(bdaddr),
+            "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+            ibuf[0], ibuf[1], ibuf[2], ibuf[3], ibuf[4], ibuf[5]);
+
+        samples.set_rc_address(bdaddr);
+        if (remote_type == 0) {
+          samples.set_audio_format(rcaudio::AudioSamples::PCM_16BIT_16KHZ);
+          samples.set_remote_type(rcaudio::AudioSamples::GFRM210);
+        } else {
+          samples.set_audio_format(rcaudio::AudioSamples::UNDEFINED_AUDIO_FORMAT);
+          samples.set_remote_type(rcaudio::AudioSamples::UNDEFINED_REMOTE_TYPE);
+        }
+        samples.set_audio_samples(obuf, olen);
+
+        pkt.resize(samples.ByteSize());
+        samples.SerializeToArray(&pkt[0], samples.ByteSize());
+
+        if (os < 0) {
+          os = get_socket_or_die();
+        }
+
+        if (!connected) {
+          if (connect(os, (const struct sockaddr *) &sun, sizeof(sun)) == 0) {
+            connected = 1;
+          } else {
+            sleep(2);  /* rate limit how often we try */
+          }
+        }
+
+        if (connected) {
+          if (send(os, &pkt[0], pkt.size(), 0) != (ssize_t)pkt.size()) {
+            fprintf(stderr, "Audio send failed, will reconnect.\n");
+            connected = 0;
+            close(os);
+            os = -1;
+          }
+        }
+      } else {
+        if (pacing()) {
+          printf("RAS_Decode(RAS_DECODE_TI_TYPE1) failed\n");
+        }
+        errors++;
+      }
+    }
+  }
+}