Add tools/gfrm-voice-test.c

Exercise GFRM210 voice support.

Change-Id: I00f9ab90dffa9ab5f23737356b3534903f6d0115
diff --git a/Makefile.tools b/Makefile.tools
index af709b8..661d20b 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -227,6 +227,9 @@
 tools_mpris_proxy_SOURCES = tools/mpris-proxy.c
 tools_mpris_proxy_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@
 
+bin_PROGRAMS += tools/gfrm-voice-demo
+tools_gfrm_voice_demo_SOURCES = tools/gfrm-voice-demo.c
+
 dist_man_MANS += tools/hciattach.1 tools/hciconfig.1 \
 			tools/hcitool.1 tools/hcidump.1 \
 			tools/rfcomm.1 tools/rctest.1 tools/l2ping.1 \
diff --git a/tools/gfrm-voice-demo.c b/tools/gfrm-voice-demo.c
new file mode 100644
index 0000000..d40a954
--- /dev/null
+++ b/tools/gfrm-voice-demo.c
@@ -0,0 +1,132 @@
+#define _BSD_SOURCE
+#include <endian.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.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;
+  const char *outfile = "/tmp/audio.wav";
+  int outfd;
+  uint8_t buf[8192];
+  WAV_hdr_t hdr;
+  ssize_t len, totlen=0;
+  int num_no_data = -1;
+  int c;
+
+  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 = open("/tmp/rcu_audio_pcm", O_RDONLY)) < 0) {
+    perror("open /tmp/rcu_audio_pcm");
+    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);
+  }
+
+  while (1) {
+    len = read(fd, buf, sizeof(buf));
+    if (len > 0) {
+      totlen += len;
+      if (write(outfd, buf, len) != len) {
+        fprintf(stderr, "short write!\n");
+        exit(1);
+      }
+      num_no_data = 0;
+    } else if (len < 0) {
+      perror("read");
+      exit(1);
+    } else if (len == 0) {
+      if (num_no_data >= 5) {
+        break;
+      }
+      sleep(1);
+      if (num_no_data >= 0) {
+        num_no_data++;
+      }
+    }
+  }
+
+  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);
+}