blob: 952e90f0806c83494325bf143d81cdf415c5e77a [file] [log] [blame]
/**************************************************************************************************
Filename: ti_audio.c
Description: audio over BLe, audio decoding app
Copyright 2013 Texas Instruments Incorporated. All rights reserved.
IMPORTANT: Your use of this Software is limited to those specific rights
granted under the terms of a software license agreement between the user
who downloaded the software, his/her employer (which must be your employer)
and Texas Instruments Incorporated (the "License"). You may not use this
Software unless you agree to abide by the terms of the License. The License
limits your use, and you acknowledge, that the Software may not be modified,
copied or distributed unless embedded on a Texas Instruments microcontroller
or used solely and exclusively in conjunction with a Texas Instruments radio
frequency transceiver, which is integrated into your product. Other than for
the foregoing purpose, you may not use, reproduce, copy, prepare derivative
works of, modify, distribute, perform, display or sell this Software and/or
its documentation for any purpose.
YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
(INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
Should you have any questions regarding your right to use this Software,
contact Texas Instruments Incorporated at www.TI.com.
**************************************************************************************************/
#include <fcntl.h>
#include <getopt.h>
#include <poll.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
#include "RAS_lib.h"
#define FIFO_BTD2AUDIO_FILE "/tmp/Fifo_bdt_tiaudio"
#define RAS_CMD_MASK 0x07
#define RAS_START_CMD 0x04
#define RAS_DATA_TIC1_CMD 0x01
#define RAS_STOP_CMD 0x02
#define RAS_DATA_RAW_CMD 0x03
#define TRUE 1
#define FALSE 0
int fp;
static pthread_mutex_t audio_mutex = PTHREAD_MUTEX_INITIALIZER;
int frame_type;
int SeqNum, PrevSeqNum;
static float throughput, throughput_min = 10000000, throughput_max = 0,
throughput_ave = 0, throughput_raw_ave = 0;
static int cumulatedBytes = 0;
static int totalcumulatedBytes = 0;
static int totalcumulatedRawBytes = 0;
struct timeval prevTimeThrougput, prevTimeStarting, curTime, prevPacket;
long int elapsedTimeSinceLastPacket = 1;
char ras_pec_mode;
char previousFrameExist = 0;
unsigned char audioFrame[200];
unsigned char audio_data_len;
unsigned char audioFrameIndex = 0;
FILE *fout_wav;
FILE *fout_tic1;
char outFile_wav[1024];
char outFile_tic1[1024];
char fileListIndex = 0;
char NewFilename[1024] = "";
char NewOutputFilename[1024] = "";
char outFile[1024];
unsigned char Data_len;
int file_open = FALSE;
int streamStarted = TRUE;
int nbFrameLost;
int nbFrameReceived;
static void audioRenameOutputFile(void) {
strcpy(NewFilename, "");
strcpy(NewOutputFilename, "");
strcat(NewOutputFilename, "gattToolAudio");
{
{
char temp[8];
fileListIndex++;
strncat(NewOutputFilename, outFile, strlen(outFile));
strcat(NewOutputFilename, "_");
sprintf(temp, "%d", fileListIndex);
strcat(NewOutputFilename, temp);
}
}
// Add the new suffix.
strcpy(outFile_wav, NewOutputFilename);
strcpy(outFile_tic1, NewOutputFilename);
strcat(outFile_wav, ".wav");
strcat(outFile_tic1, ".tic1");
// Open the file
{
fout_wav = fopen(outFile_wav, "w");
if (fout_wav != NULL) {
printf("===> Wav File Created %s <=== \n", outFile_wav);
} else {
perror("fopen3:");
exit(-1);
}
fout_tic1 = fopen(outFile_tic1, "w");
if (fout_tic1 != NULL) {
printf("===> TIC1 File Created %s <=== \n", outFile_tic1);
} else {
perror("fopen4:");
exit(-1);
}
file_open = TRUE;
}
}
static void audioAddWaveHeader(FILE *fout_wav) {
// Initialize directly subchunksize1
unsigned char Header[100] = {0x52, 0x49, 0x46, 0x46, 0xFF, 0xFF,
0xFF, 0xFF, 0x57, 0x41, 0x56, 0x45};
// subchunksize2
Header[12] = 0x66;
Header[13] = 0x6d;
Header[14] = 0x74;
Header[15] = 0x20;
Header[16] = 16;
Header[17] = 0;
Header[18] = 0;
Header[19] = 0;
Header[20] = 1;
Header[21] = 0;
Header[22] = 1;
Header[23] = 0;
Header[24] = 0x80;
Header[25] = 0x3E;
Header[26] = 0;
Header[27] = 0;
Header[28] = 0x00;
Header[29] = 0x7D;
Header[30] = 0;
Header[31] = 0;
Header[32] = 2;
Header[33] = 0;
Header[34] = 16;
Header[35] = 0;
Header[36] = 0x64;
Header[37] = 0x61;
Header[38] = 0x74;
Header[39] = 0x61;
Header[40] = 0xFF;
Header[41] = 0xFF;
Header[42] = 0xFF;
Header[43] = 0xFF;
fwrite(Header, sizeof(char), 44, fout_wav);
printf("===> Add Wav Header <=== \n");
}
long int audioElapsedTime(struct timeval *timeStart, struct timeval *timeEnd) {
long int diffPrev;
long int decrementValue;
int t = 0;
if (timeStart->tv_usec >= timeEnd->tv_usec) {
diffPrev = timeStart->tv_usec - timeEnd->tv_usec;
t = 0;
} else {
diffPrev = (timeStart->tv_usec + 1000000) - timeEnd->tv_usec;
t = 1;
}
decrementValue =
(diffPrev + 1000000 * (timeStart->tv_sec - timeEnd->tv_sec - t)) /
1000; // Res in ms
return decrementValue;
}
void audioResetStream(void) {
gettimeofday(&prevTimeThrougput, NULL);
gettimeofday(&prevTimeStarting, NULL);
totalcumulatedBytes = 0;
totalcumulatedRawBytes = 0;
cumulatedBytes = 0;
throughput = 0;
throughput_min = 10000000;
throughput_max = 0;
throughput_ave = 0;
throughput_raw_ave = 0;
PrevSeqNum = 0;
ras_pec_mode = 1;
streamStarted = FALSE;
nbFrameLost = 0;
nbFrameReceived = 0;
if (RAS_Init(ras_pec_mode)) {
// printf("fail to initialize remoTI audio subsystem");
// exit(-1);
}
previousFrameExist = 0;
audioFrameIndex = 0;
elapsedTimeSinceLastPacket = audioElapsedTime(&curTime, &prevPacket);
if (file_open && elapsedTimeSinceLastPacket > 700) {
// Equivalent to dead link timer
// Close current file and reopen a new one.
// Stop Frame
fflush(fout_wav);
fclose(fout_wav);
fout_wav = NULL;
fflush(fout_tic1);
fclose(fout_tic1);
fout_tic1 = NULL;
// Need to add File size in the header of the wav file
{
int filesize;
unsigned char file[4];
fout_wav = fopen(outFile_wav, "r+b");
if (fout_wav == NULL) {
perror("fopen6:");
exit(-1);
}
fseek(fout_wav, 0L, SEEK_END);
filesize = ftell(fout_wav);
file[0] = (unsigned char)(((filesize - 44) & 0xFF));
file[1] = (unsigned char)(((filesize - 44) & 0xFF00) >> 8);
file[2] = (unsigned char)(((filesize - 44) & 0xFF0000) >> 16);
file[3] = (unsigned char)(((filesize - 44) & 0xFF000000) >> 24);
fseek(fout_wav, 40, SEEK_SET);
fwrite(file, 1, 4, fout_wav);
fclose(fout_wav);
fout_wav = NULL;
}
file_open = FALSE;
printf("===> AUDIO STOP BEFORE START <=== \n");
}
if (!file_open) {
audioRenameOutputFile();
// Add .Wav header to .wave output file
if (fout_wav) audioAddWaveHeader(fout_wav);
}
}
static void audio_ParseData(unsigned char *pdu, unsigned short len) {
long int decrementValue, elapsed_time;
int i;
frame_type = pdu[3] & 0x7;
SeqNum = (pdu[3] >> 3) & 0x1F;
// s = g_string_new(NULL);
Data_len =
(len -
4); // This is audio data length only (audio frame header+ audio data)
// printf("FT = 0x%02x ,SeqNum: %d, len: %d\n", frame_type, SeqNum, len);
cumulatedBytes += Data_len;
totalcumulatedBytes += Data_len;
totalcumulatedRawBytes += Data_len + 3 + 4 + 1;
gettimeofday(&curTime, NULL);
decrementValue = audioElapsedTime(&curTime, &prevTimeThrougput);
elapsed_time = audioElapsedTime(&curTime, &prevTimeStarting);
// check if 1s has elapse since last packet.
if (decrementValue > 1000) {
// Calculate and Display Throughput
throughput =
(float)(8 * (((float)cumulatedBytes) / ((float)decrementValue)));
(throughput_min > throughput) ? throughput_min = throughput
: throughput_min;
(throughput_max < throughput) ? throughput_max = throughput
: throughput_max;
gettimeofday(&prevTimeThrougput, NULL);
}
if (elapsed_time > 500) // Not meaningful before
{
throughput_ave =
(float)(8 * ((float)totalcumulatedBytes) / ((float)elapsed_time));
throughput_raw_ave =
(float)(8 * ((float)totalcumulatedRawBytes) / ((float)elapsed_time));
}
if (decrementValue > 1000) {
cumulatedBytes = 0;
printf(
"ElapsedTime(ms): %ld, throughput(kbps): %2.2f (%2.2f/%2.2f) "
"Ave:(%2.2f) Raw Ave: (%2.2f), AudioPER:%2.2f%%, ( %d lost over %d "
"sent) \n",
elapsed_time, throughput, throughput_min, throughput_max,
throughput_ave, throughput_raw_ave,
(double)(100 * (double)nbFrameLost /
(double)(nbFrameLost + nbFrameReceived)),
nbFrameLost, nbFrameReceived + nbFrameLost);
}
// Throughput estimation
if (frame_type == RAS_START_CMD) {
printf("===> AUDIO START <=== \n");
audioResetStream();
streamStarted = TRUE;
} else if (frame_type == RAS_DATA_TIC1_CMD) {
if (!streamStarted) {
audioResetStream();
streamStarted = TRUE;
}
nbFrameReceived++;
gettimeofday(&prevPacket, NULL);
if (PrevSeqNum + 1 != SeqNum) {
if (SeqNum < (PrevSeqNum + 1)) {
nbFrameLost += 32 + SeqNum - (PrevSeqNum + 1);
} else
nbFrameLost += SeqNum - (PrevSeqNum + 1);
printf("FRAME LOST !!!!(%d != %d) (%d nbFrameLost for %d sent\n",
PrevSeqNum + 1, SeqNum, nbFrameLost,
nbFrameLost + nbFrameReceived);
}
if (SeqNum == 31)
PrevSeqNum = -1;
else
PrevSeqNum = SeqNum;
// Decode Frame if any exist.
if (previousFrameExist) {
short temp[1024];
unsigned short decLength;
// printf("decode Frame %d\n", PrevSeqNum );
RAS_Decode(RAS_DECODE_TI_TYPE1, audioFrame, audio_data_len, temp,
&decLength);
if (fout_wav != NULL) {
/*Write the decoded audio to file*/
fwrite(temp, sizeof(short), decLength / 2, fout_wav);
}
if (fout_tic1 != NULL) {
int8 temp2[512];
temp2[0] = audio_data_len;
memcpy(&temp2[1], audioFrame, audio_data_len);
/*Write the decoded audio to file*/
fwrite(temp2, sizeof(char), audio_data_len + 1, fout_tic1);
}
}
previousFrameExist = 1;
// Store Data in audio frame:
audioFrameIndex = 0;
audio_data_len = Data_len; // Remove audio frame Header
for (i = 0; i < Data_len; i++) audioFrame[audioFrameIndex++] = pdu[i + 4];
} else if (frame_type == RAS_STOP_CMD) {
printf("===> AUDIO STOP <=== \n");
// Stop Frame
fflush(fout_wav);
fclose(fout_wav);
fout_wav = NULL;
fflush(fout_tic1);
fclose(fout_tic1);
previousFrameExist = 0;
fout_tic1 = NULL;
// Need to add File size in the header of the wav file
{
int filesize;
unsigned char file[4];
fout_wav = fopen(outFile_wav, "r+b");
if (fout_wav != NULL) {
printf("===> Wav File open for length update: %s <=== \n",
outFile_wav);
} else {
perror("fopen5:");
exit(-1);
}
fseek(fout_wav, 0L, SEEK_END);
filesize = ftell(fout_wav);
file[0] = (unsigned char)(((filesize - 44) & 0xFF));
file[1] = (unsigned char)(((filesize - 44) & 0xFF00) >> 8);
file[2] = (unsigned char)(((filesize - 44) & 0xFF0000) >> 16);
file[3] = (unsigned char)(((filesize - 44) & 0xFF000000) >> 24);
fseek(fout_wav, 40, SEEK_SET);
fwrite(file, 1, 4, fout_wav);
fclose(fout_wav);
fout_wav = NULL;
}
file_open = FALSE;
}
}
int main(int argc, char **argv) {
int attframecnt = 0;
int bytes_read = 0;
int num_bytes = 0;
int total_bytes = 0;
int read_state = 0;
unsigned char readbuf[256];
unsigned char dummybuf[256];
while (1) {
pthread_mutex_lock(&audio_mutex);
{
// printf("Open reading pipe ...\n");
fp = open(FIFO_BTD2AUDIO_FILE, O_RDONLY);
if (fp == -1) {
printf("can't open the pipe\n");
exit(-1);
}
// Read a single byte to know the length of the data
bytes_read = read(fp, &num_bytes, 1);
printf("%d bytes of Data (bytes to read further=%d): \n", bytes_read,
num_bytes);
if ((bytes_read) && (num_bytes == 4)) {
printf("Reading %d bytes of Audio Frame\n", num_bytes);
bytes_read = read(fp, &readbuf[0], num_bytes);
total_bytes += bytes_read;
printf("Submitting Audio Frame. Size=%d\n", total_bytes);
// Call Audio protocol Handler:
audio_ParseData(&readbuf[0], total_bytes);
total_bytes = 0;
} else if ((bytes_read) && (num_bytes == 23)) {
if (read_state == 0) {
int rasFrame = 0;
bytes_read = read(fp, &readbuf[total_bytes], num_bytes);
total_bytes += bytes_read;
printf(
"Received %d bytes of Data (total_bytes=%d), retrieve data: \n",
bytes_read, total_bytes);
rasFrame = readbuf[3] & 0x7;
if (rasFrame == 0x01) {
// Reading Complete Audio Frame
read_state = 1;
attframecnt = 0;
}
}
if (read_state == 1) {
/*
//Read a single byte to know
the length of the data
bytes_read = read(fp,
&num_bytes, 1);
printf("%d bytes of Data
(bytes to read further=%d): \n", bytes_read, num_bytes);
// printf("Bytes to read =
%d\n",
num_bytes);
if( (bytes_read) && (num_bytes
== 23))
{
*/
// Read the ATT Header data(3 Bytes) to Dummy file
bytes_read = read(fp, &dummybuf[0], 3);
// Read Actual data to readbuf
bytes_read = read(fp, &readbuf[total_bytes], (num_bytes - 3));
total_bytes += bytes_read;
printf("Received %d bytes of Data (total_bytes=%d): \n", bytes_read,
total_bytes);
attframecnt += 1;
/* }
else
{
if(bytes_read)
{
//Read the ATT frame
to Dummy buffer
printf("Error while
reading Audio ATT Frame. Only %d bytes\n", num_bytes);
bytes_read = read(fp,
&dummybuf[0], num_bytes);
printf("Audio noti:
Len: %d, Data: (0) 0x%x, Data: (1) 0x%x, Data: (2) 0x%x, Data: (3)
0x%x, (4) 0x%x, (5) 0x%x, (6) 0x%x, (7) 0x%x, (8) 0x%x, (9) 0x%x,
(10) 0x%x, (11) 0x%x, (12) 0x%x, (19) 0x%x, (20) 0x%x, (21) 0x%x,
(22) 0x%x ", num_bytes, dummybuf[0], dummybuf[1], dummybuf[2],
dummybuf[3], dummybuf[4], dummybuf[5], dummybuf[6], dummybuf[7],
dummybuf[8], dummybuf[9], dummybuf[10], dummybuf[11], dummybuf[12],
dummybuf[num_bytes-4], dummybuf[num_bytes-3],
dummybuf[num_bytes-2], dummybuf[num_bytes-1]);
}
}
*/
}
if (attframecnt > 4) {
printf("Submitting Audio Frame. Size=%d\n", total_bytes);
// Call Audio protocol Handler:
audio_ParseData(&readbuf[0], total_bytes);
read_state = 0;
total_bytes = 0;
}
} else {
if (bytes_read) {
// Read the ATT frame to Dummy buffer
bytes_read = read(fp, &dummybuf[0], num_bytes);
printf("Ignoring ATT Frame\n");
} else {
printf("End of Pipe Reached. Closing Pipe\n");
}
}
// Send Data Back to the Coordinator or End Device
// printf("\n");
bytes_read = 0;
num_bytes = 0;
printf("Close reading pipe...\n");
close(fp);
}
pthread_mutex_unlock(&audio_mutex);
// msleep(500);
}
printf("Exiting App...\n");
}