/***************************************************************************
 *   Copyright (C) 2007 by Marco Lorrai                                    *
 *   marco.lorrai@abbeynet.it                                              *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "audio.h"
#include "setting.h"
#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 <iostream>

Audio::Audio() 
{
    end=1;
    device = Setting::GetInstance()->GetAudioDeviceFile();
}

Audio::~Audio()
{
    
}

int Audio::Open()
{
    fd = open(device.c_str(), O_RDWR);
    if (fd < 0) {
        std::string message = "open of " + device + " failed";
        perror(message.c_str());   
        return -1;
    }
    return 0;
}

int Audio::startAcquisition(int channels, int rate, int sampleSize)
{
    int arg;
    int status;
    arg = sampleSize;     
    status = ioctl(fd, SOUND_PCM_WRITE_BITS, &arg);
    if (status == -1)
        perror("SOUND_PCM_WRITE_BITS ioctl failed");
    if (arg != sampleSize)
        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");
    
    /*frequency: 100 Hz*/
    bufferSize = sampleSize*rate*channels/800;    
    buffer = new unsigned char[bufferSize];
    return bufferSize;
}

void* Audio::Entry()
{
    int status;
    while (true) {  
        status = read(fd, buffer, bufferSize); /* record some sound */
        mutex.Lock();
        if (!end) {
            mutex.Unlock();
            break;
        }
        mutex.Unlock();
        if (status != bufferSize)
            perror("read wrong number of bytes");            
        else {
            //printf("read %d bytes\n", bufferSize);
            mutex.Lock();
            queue.push_back(std::string((char*)buffer, bufferSize));            
            mutex.Unlock();
        }
    }
    status = close(fd);
    if(status < 0) {
        std::string message = "error closing " + device;
        perror(message.c_str());
    }
    delete [] buffer;
}

std::vector<std::string> Audio::getAudioFrames()
{
    mutex.Lock();
    std::vector<std::string> ret = queue;    
    queue.clear();
    mutex.Unlock();
    return ret;
}

void Audio::stopAcquisition()
{
    mutex.Lock();
    end = 0;
    mutex.Unlock();
}


