/* 
 * autorec_v103.c
 *
 * 2009-01-07: Default noise limit changed from 1 to 0.5.
 * Possible to specify noise level at the command line at runtime. If not specified, the default of 0.5 is used.
 * Started with "<programname> 0.4" to get a noise level of 0.4
 *
 * 2008-03-07: Changed program to only read from /dev/dsp (so that it will not
 * block for other programs writing to /dev/dsp for play back).
 *
 * Runs until Control-C is pressed.
 * Compile like this: gcc -o autorec_v102 autorec_v102.c && chmod 744 autorec_v102
 * Storing ALSA-settings: /usr/sbin/alsactl -f alsa_settings.copy store
 * Decrypt files like this (needs private key and password):
 *   gpg -o <output_filename> -d <input_filename>
 *   ex: gpg -o out.ogg -d 20080225_181220.ogg.gpg
 *
 * The program flow is like this:
 * Get input (one second of data) and evaluate if data or noise.
 * If data=true & recording=false: Generate filename
 *                                 Start recording to file
 *                                 Set variable "recording" to true.
 *                                 Set "number_of_silent_runs" to zero.
 * If data=true & recording=true:  Add data to open file.
 *                                 Set "number_of_silent_runs" to zero.
 *                                 Append data to file.
 * If data=false & recording=true. Increment "number_of_silent_runs".
 *    If "number_of_silent_runs" > 10:
 *                                 Close file.
 *                                 Remove last 10 seconds in file (is silence).
 *                                 Convert file to ogg format.
 *                                 Encrypt file to gpg
 *                                 Set "recording" to false.
 *    Else   Append data to file.
 */

#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <stdio.h>
#include <linux/soundcard.h>
#include <time.h>

#define LENGTH 1    /* how many seconds of speech to store */
#define RATE 8000   /* the sampling rate */
#define SIZE 8      /* sample size: 8 or 16 bits */
#define CHANNELS 1  /* 1 = mono 2 = stereo */
#define NOISE_LIMIT 0.5  /* The limit for average amplitude for deciding to record or not */
#define DEBUG 0     /* If DEBUG=1 then print extra information to screen. */
unsigned char buf[LENGTH*RATE*SIZE*CHANNELS/8]; /* buffer holding digitized audio */


int write_buf_to_file(FILE *fptr){  // Function to write 1 second of audio data to file.
  if(fwrite(buf,sizeof(buf),1,fptr) != 1){
    printf("\nError. Can not write to file.\n");
    return 1;
  } else {
    if (DEBUG) printf("Have now written data to file.\n");
    return 0;
  }
}

int read_buf_from_file(FILE *fptr){  // Function to read 1 second of audio from file.
  if(fread(buf,sizeof(buf),1,fptr) != 1){
    printf("\nError. Can not read from file.\n");
    return 1;
  } else {
    if (DEBUG) printf("Have now read data from file.\n");
    return 0;
  }
}

int main(int argc,char *argv[])
{
  int fd;	/* sound device file descriptor */
  int arg;	/* argument for ioctl calls */
  int status;   /* return status of system calls */
  int number_of_silent_runs = 0; int data=0; int recording=0;
  int index=0; int avg_norm=0; int count=0;
  float noise_limit_var = 0;
  FILE *fptr;
  FILE *fptr_final;
  char timestring[20]; char filename[20]; char filename_final[20];
  time_t tval;
  struct tm *now;
  char timebuf[128];

  if (argc>2) {
    printf("Program should only be started with max 1 argument. Exiting program.\n");
    exit(0);
  } else if (argc==2) {
    noise_limit_var = atof(argv[1]);
    printf("Using LIMIT value of %f\n",noise_limit_var);
  } else {
    noise_limit_var = NOISE_LIMIT;
    printf("No noise_limit specified as arugment. Using default value %f.\n",noise_limit_var);
  }


  fd = open("/dev/dsp", O_RDONLY);  /* open sound device for read only*/
  if (fd < 0) {
    perror("open of /dev/dsp failed");
    exit(1);
  }

  /* set sampling parameters */
  arg = SIZE;	   /* sample size */
  status = ioctl(fd, SOUND_PCM_WRITE_BITS, &arg);
  if (status == -1)
    perror("SOUND_PCM_WRITE_BITS ioctl failed");
  if (arg != SIZE)
    perror("unable to set sample size");

  arg = CHANNELS;  /* mono or stereo */
  status = ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &arg);
  if (status == -1)
    perror("SOUND_PCM_WRITE_CHANNELS ioctl failed");
  if (arg != CHANNELS)
    perror("unable to set number of channels");

  arg = RATE;	   /* sampling rate */
  status = ioctl(fd, SOUND_PCM_WRITE_RATE, &arg);
  if (status == -1)
    perror("SOUND_PCM_WRITE_WRITE ioctl failed");
  while(1) { //loop until Control-C
    if (DEBUG) printf("Now starting to record some sound....");
    index=0; avg_norm=0; count=0;
    status = read(fd, buf, sizeof(buf)); /* record some sound */
    if (status != sizeof(buf))
      perror("Read wrong number of bytes");
    if (DEBUG) printf("Evaluating...");
    while(index<sizeof(buf)) {
      avg_norm = avg_norm + abs(buf[index]-128);
      count++; index++;
    }
    double avg_result= (double) avg_norm/count;
    if (DEBUG) printf("Signal level result %f. ",avg_result);
    if (avg_result > noise_limit_var) data=1; else {data=0;number_of_silent_runs++;}
    if (DEBUG) printf("Data=%d, rec=%d, silent_runs=%d.\n",data,recording,number_of_silent_runs);
    if (data && !recording) { 
      if (DEBUG) printf("Will now start to record to file.\n");
      if (DEBUG) printf("First generating filename.\n");
      /* Get current date and time */
      tval = time(NULL);
      now = localtime(&tval);
      sprintf (timestring,"%02d%02d%02d_%02d%02d%02d",
      now->tm_year+1900, now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);
      sprintf (filename, "%s", timestring);
      printf("Starts recording to file %s..... \n",filename);
      if((fptr = fopen(filename,"w+"))==NULL){
        printf("\nError opening file: %s.\n",filename);
        exit(1);
      }
      write_buf_to_file(fptr);
      recording = 1;               // Set variable "recording" to true.
      number_of_silent_runs = 0;   // Set "number_of_silent_runs" to zero.
    } else if (data && recording) {  //  Add data to open file.
      write_buf_to_file(fptr);
      recording = 1;               // Set variable "recording" to true.
      number_of_silent_runs = 0;   // Set "number_of_silent_runs" to zero
    } else if (!data && recording) {
      if (number_of_silent_runs > 10){
	//Copies all from the file (fptr) to another file (fptr_final) excluding the last 10 seconds (which are silence).
	rewind(fptr);
	sprintf (filename_final, "%s.final", filename);
        if((fptr_final = fopen(filename_final,"w"))==NULL){
          printf("\nError: File %s can not be opened!\n",filename_final);
          exit(1);
        }
	fseek(fptr,0,SEEK_END);
	int filesize_fptr=ftell(fptr);   // File size in bytes.
	int file_size_seconds=filesize_fptr/8000;   // File size in seconds.
	rewind(fptr);
	while (file_size_seconds-- > 10) {  // The last 10 seconds should not be included.
	  read_buf_from_file(fptr);
	  write_buf_to_file(fptr_final);
  	  if (DEBUG) printf("Block copied. File_size_seconds is now: %d\n",file_size_seconds);
	}
	int filesize_fptr_final=ftell(fptr_final);
	if (filesize_fptr != filesize_fptr_final + 80000)
	  printf("Error: Final file has other size (%d) than expected (%d)!\n",filesize_fptr_final,filesize_fptr-80000);
	else
	  if (DEBUG) printf("File size seems correct. Recorded %d seconds.\n",filesize_fptr_final/8000);
        fclose(fptr);	             // Close file
	fclose(fptr_final);
	char system_command[100];
	sprintf(system_command,"oggenc -o %s.ogg -B 8 -C 1 -R 8000 -q -1 --quiet %s 2> /dev/null",filename,filename_final);
	if (DEBUG) printf("Is about to run the command: %s\n",system_command);
	system(system_command);
	printf("Recorded %d seconds to file %s.ogg\n\n",filesize_fptr_final/8000, filename); 
	if (DEBUG) printf("Now  pgp encrypting file...");
	sprintf(system_command,"gpg -e -r test %s.ogg",filename);
	if (DEBUG) printf("Is about to run the command: %s\n",system_command);
	system(system_command);
	remove(filename);
	remove(filename_final);
	sprintf(filename_final,"%s.ogg",filename);  //Note: Overwriting filename_final.
	remove(filename_final);
	recording=0;               // Set "recording" to false.
        file_size_seconds=0;
      } else {
	write_buf_to_file(fptr);
      }
    }  // Ending if else for data and recording variable status.
  }  // Ending while-loop
}

