audiorecord.cpp 11.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 *  Copyright (C) 2008 Savoir-Faire Linux inc.
 *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
 *
 *  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 3 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "audiorecord.h"

22
// structure for the wave header
23

24
struct wavhdr {
25 26 27 28 29 30 31 32 33 34 35 36 37
    char riff[4];           // "RIFF"
    SINT32 file_size;       // in bytes
    char wave[4];           // "WAVE"
    char fmt[4];            // "fmt "
    SINT32 chunk_size;      // in bytes (16 for PCM)
    SINT16 format_tag;      // 1=PCM, 2=ADPCM, 3=IEEE float, 6=A-Law, 7=Mu-Law
    SINT16 num_chans;       // 1=mono, 2=stereo
    SINT32 sample_rate;
    SINT32 bytes_per_sec;
    SINT16 bytes_per_samp;  // 2=16-bit mono, 4=16-bit stereo
    SINT16 bits_per_samp;
    char data[4];           // "data"
    SINT32 data_length;     // in bytes
38
};
39 40


41 42
AudioRecord::AudioRecord()
{
43

44
    sndSmplRate_ = 8000;
45 46 47 48 49
    channels_ = 1;
    byteCounter_ = 0;
    recordingEnabled_ = false;
    fp = 0;
    nbSamplesMax_ = 3000;
50

51 52 53 54 55
    createFilename();

    mixBuffer_ = new SFLDataFormat[nbSamplesMax_];
    micBuffer_ = new SFLDataFormat[nbSamplesMax_];
    spkBuffer_ = new SFLDataFormat[nbSamplesMax_];
56 57
}

58 59
AudioRecord::~AudioRecord()
{
60 61 62
    delete [] mixBuffer_;
    delete [] micBuffer_;
    delete [] spkBuffer_;
63 64 65
}


66 67 68
void AudioRecord::setSndSamplingRate (int smplRate)
{
    sndSmplRate_ = smplRate;
69 70
}

71
void AudioRecord::setRecordingOption (FILE_TYPE type, SOUND_FORMAT format, int sndSmplRate, std::string path)
72
{
73 74


75 76 77 78 79 80
    fileType_ = type;
    sndFormat_ = format;
    channels_ = 1;
    sndSmplRate_ = sndSmplRate;

    savePath_ = path + "/";
81

82 83
}

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106


void AudioRecord::initFileName (std::string peerNumber)
{

    std::string fName;

    fName = fileName_;
    fName.append ("-"+peerNumber);

    if (fileType_ == FILE_RAW) {
        if (strstr (fileName_, ".raw") == NULL) {
            printf ("AudioRecord::openFile::concatenate .raw file extension: name : %s \n", fileName_);
            fName.append (".raw");
        }
    } else if (fileType_ == FILE_WAV) {
        if (strstr (fileName_, ".wav") == NULL) {
            printf ("AudioRecord::openFile::concatenate .wav file extension: name : %s \n", fileName_);
            fName.append (".wav");
        }
    }

    savePath_.append (fName);
107 108
}

109 110 111 112 113
void AudioRecord::openFile()
{


    _debug ("AudioRecord::openFile()\n");
114

115
    bool result = false;
116

117
    _debug ("AudioRecord::openFile()\n");
118

119 120 121
    if (isFileExist()) {
        _debug ("AudioRecord::Filename does not exist, creating one \n");
        byteCounter_ = 0;
122

123 124 125 126 127 128 129
        if (fileType_ == FILE_RAW) {
            result = setRawFile();
        } else if (fileType_ == FILE_WAV) {
            result = setWavFile();
        }
    } else {
        _debug ("AudioRecord::Filename already exist opening it \n");
Alexandre Savard's avatar
Alexandre Savard committed
130

131 132 133 134 135 136
        if (fileType_ == FILE_RAW) {
            result = openExistingRawFile();
        } else if (fileType_ == FILE_WAV) {
            result = openExistingWavFile();
        }
    }
137 138 139
}


140 141 142 143 144 145 146 147 148 149 150 151
void AudioRecord::closeFile()
{

    if (fp == 0) return;

    if (fileType_ == FILE_RAW)
        fclose (fp);
    else if (fileType_ == FILE_WAV)
        this->closeWavFile();



152 153 154
}


155 156 157 158 159 160 161 162 163 164
bool AudioRecord::isOpenFile()
{

    if (fp) {
        _debug ("AudioRecord::isOpenFile(): file already openend\n");
        return true;
    } else {
        _debug ("AudioRecord::isOpenFIle(): file not openend \n");
        return false;
    }
165 166
}

167 168 169 170 171 172 173 174 175

bool AudioRecord::isFileExist()
{
    _debug ("AudioRecord::isFileExist(): try to open name : %s \n", fileName_);

    if (fopen (fileName_,"rb") ==0) {
        return true;
    }

176 177 178
    return false;
}

179 180 181 182
bool AudioRecord::isRecording()
{
    _debug ("AudioRecording::isRecording() %i \n", recordingEnabled_);

183

184 185 186 187
    if (recordingEnabled_)
        return true;
    else
        return false;
alexandresavard's avatar
alexandresavard committed
188 189
}

190

191 192 193 194 195
bool AudioRecord::setRecording()
{
    _debug ("AudioRecord::setRecording() \n");

    if (isOpenFile()) {
196
        _debug ("AudioRecord::setRecording()::file already opened \n");
197 198 199 200 201 202 203 204 205 206 207 208

        if (!recordingEnabled_)
            recordingEnabled_ = true;
        else
            recordingEnabled_ = false;
    } else {
        _debug ("AudioRecord::setRecording():Opening the wave file in call during call instantiation \n");
        openFile();

        recordingEnabled_ = true; // once opend file, start recording
    }

Emmanuel Milou's avatar
Emmanuel Milou committed
209 210
    // WARNING: Unused return value
    return true;
211

212 213 214 215 216 217 218 219
}

void AudioRecord::stopRecording()
{
    _debug ("AudioRecording::stopRecording() \n");

    if (recordingEnabled_)
        recordingEnabled_ = false;
220 221
}

alexandresavard's avatar
alexandresavard committed
222

223 224 225
void AudioRecord::createFilename()
{

alexandresavard's avatar
alexandresavard committed
226
    time_t rawtime;
227

alexandresavard's avatar
alexandresavard committed
228 229
    struct tm * timeinfo;

230 231
    rawtime = time (NULL);
    timeinfo = localtime (&rawtime);
alexandresavard's avatar
alexandresavard committed
232 233

    stringstream out;
234

alexandresavard's avatar
alexandresavard committed
235 236
    // DATE
    out << timeinfo->tm_year+1900;
237

alexandresavard's avatar
alexandresavard committed
238
    if (timeinfo->tm_mon < 9) // january is 01, not 1
239 240
        out << 0;

alexandresavard's avatar
alexandresavard committed
241
    out << timeinfo->tm_mon+1;
242

alexandresavard's avatar
alexandresavard committed
243
    if (timeinfo->tm_mday < 10) // 01 02 03, not 1 2 3
244 245
        out << 0;

alexandresavard's avatar
alexandresavard committed
246
    out << timeinfo->tm_mday;
247

alexandresavard's avatar
alexandresavard committed
248
    out << '-';
249

alexandresavard's avatar
alexandresavard committed
250 251
    // hour
    if (timeinfo->tm_hour < 10) // 01 02 03, not 1 2 3
252 253
        out << 0;

alexandresavard's avatar
alexandresavard committed
254
    out << timeinfo->tm_hour;
255

alexandresavard's avatar
alexandresavard committed
256
    out << ':';
257

alexandresavard's avatar
alexandresavard committed
258
    if (timeinfo->tm_min < 10) // 01 02 03, not 1 2 3
259 260
        out << 0;

alexandresavard's avatar
alexandresavard committed
261
    out << timeinfo->tm_min;
262

alexandresavard's avatar
alexandresavard committed
263
    out << ':';
264

alexandresavard's avatar
alexandresavard committed
265
    if (timeinfo->tm_sec < 10) // 01 02 03,  not 1 2 3
266 267
        out << 0;

alexandresavard's avatar
alexandresavard committed
268 269 270
    out << timeinfo->tm_sec;

    // fileName_ = out.str();
271
    strncpy (fileName_, out.str().c_str(), 8192);
alexandresavard's avatar
alexandresavard committed
272

273
    printf ("AudioRecord::createFilename::filename for this call %s \n",fileName_);
alexandresavard's avatar
alexandresavard committed
274 275
}

276 277
bool AudioRecord::setRawFile()
{
278

279
    fp = fopen (savePath_.c_str(), "wb");
280

281 282 283 284 285 286 287 288 289
    if (!fp) {
        _debug ("AudioRecord::setRawFile() : could not create RAW file!\n");
        return false;
    }

    if (sndFormat_ != INT16) {   // TODO need to change INT16 to SINT16
        sndFormat_ = INT16;
        _debug ("AudioRecord::setRawFile() : using 16-bit signed integer data format for file.\n");
    }
290

291 292 293
    _debug ("AudioRecord:setRawFile() : created RAW file.\n");

    return true;
294 295 296
}


297 298 299 300 301 302 303 304 305 306 307
bool AudioRecord::setWavFile()
{

    fp = fopen (savePath_.c_str(), "wb");

    if (!fp) {
        _debug ("AudioRecord::setWavFile() : could not create WAV file.\n");
        return false;
    }

    struct wavhdr hdr = {"RIF", 44, "WAV", "fmt", 16, 1, 1,
308
        sndSmplRate_, 0, 2, 16, "dat", 0
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
    };

    hdr.riff[3] = 'F';

    hdr.wave[3] = 'E';

    hdr.fmt[3]  = ' ';

    hdr.data[3] = 'a';

    hdr.num_chans = channels_;

    if (sndFormat_ == INT16) {   //  TODO need to write INT16 to SINT16
        hdr.bits_per_samp = 16;
    }

    hdr.bytes_per_samp = (SINT16) (channels_ * hdr.bits_per_samp / 8);

    hdr.bytes_per_sec = (SINT32) (hdr.sample_rate * hdr.bytes_per_samp);


    if (fwrite (&hdr, 4, 11, fp) != 11) {
        _debug ("AudioRecord::setWavFile() : could not write WAV header for file. \n");
        return false;
    }

    _debug ("AudioRecord::setWavFile() : created WAV file. \n");
336

337
    return true;
338 339 340
}


341
bool AudioRecord::openExistingRawFile()
342 343 344 345 346 347 348
{
    fp = fopen (fileName_, "ab+");

    if (!fp) {
        _debug ("AudioRecord::openExistingRawFile() : could not create RAW file!\n");
        return false;
    }
349

Emmanuel Milou's avatar
Emmanuel Milou committed
350
    return true;
351
}
352 353


354
bool AudioRecord::openExistingWavFile()
355 356
{
    _debug ("AudioRecord::openExistingWavFile() \n");
357

358
    fp = fopen (fileName_, "rb+");
359

360 361 362 363
    if (!fp) {
        _debug ("AudioRecord::openExistingWavFile() : could not open WAV file rb+!\n");
        return false;
    }
364

365
    printf ("AudioRecord::openExistingWavFile()::Tried to open %s \n",fileName_);
366

367 368
    if (fseek (fp, 40, SEEK_SET) != 0) // jump to data length
        _debug ("AudioRecord::OpenExistingWavFile: 1.Couldn't seek offset 40 in the file \n");
369

370 371
    if (fread (&byteCounter_, 4, 1, fp))
        _debug ("AudioRecord::OpenExistingWavFile : bytecounter Read successfully \n");
372

373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
    if (fseek (fp, 0 , SEEK_END) != 0)
        _debug ("AudioRecors::OpenExistingWavFile : 2.Couldn't seek at the en of the file \n");

    printf ("AudioRecord::OpenExistingWavFile : Byte counter after oppening : %d \n", (int) byteCounter_);

    if (fclose (fp) != 0)
        _debug ("AudioRecord::openExistingWavFile()::ERROR: can't close file r+ \n");



    fp = fopen (fileName_, "ab+");

    if (!fp) {
        _debug ("AudioRecord::openExistingWavFile() : could not createopen WAV file ab+!\n");
        return false;
    }

    if (fseek (fp, 4 , SEEK_END) != 0)
        _debug ("AudioRecors::OpenExistingWavFile : 2.Couldn't seek at the en of the file \n");
392

Emmanuel Milou's avatar
Emmanuel Milou committed
393
    return true;
394

395 396 397
}


398
void AudioRecord::closeWavFile()
399
{
400 401 402 403
    if (fp == 0) {
        _debug ("AudioRecord:: Can't closeWavFile, a file has not yet been opened!\n");
        return;
    }
404 405


406
    SINT32 bytes = byteCounter_ * channels_;
407

408
    fseek (fp, 40, SEEK_SET); // jump to data length
409

410
    if (ferror (fp)) perror ("AudioRecord::closeWavFile()::ERROR: can't reach offset 40\n");
411

412 413 414 415 416 417 418 419 420
    fwrite (&bytes, sizeof (SINT32), 1, fp);

    if (ferror (fp)) perror ("AudioRecord::closeWavFile()::ERROR: can't write bytes for data length \n");

    printf ("AudioRecord::closeWavFile : data bytes: %i \n", (int) bytes);

    bytes = byteCounter_ * channels_ + 44; // + 44 for the wave header

    fseek (fp, 4, SEEK_SET); // jump to file size
421

422
    if (ferror (fp)) perror ("AudioRecord::closeWavFile()::ERROR: can't reach offset 4\n");
423

424
    fwrite (&bytes, 4, 1, fp);
425

426
    if (ferror (fp)) perror ("AudioRecord::closeWavFile()::ERROR: can't reach offset 4\n");
427

428
    printf ("AudioRecord::closeWavFile : bytes : %i \n", (int) bytes);
429

430 431
    if (fclose (fp) != 0)
        _debug ("AudioRecord::closeWavFile()::ERROR: can't close file\n");
432 433 434 435


}

436 437
void AudioRecord::recSpkrData (SFLDataFormat* buffer, int nSamples)
{
438

439
    if (recordingEnabled_) {
440

441
        nbSamplesMic_ = nSamples;
442

443 444
        for (int i = 0; i < nbSamplesMic_; i++)
            micBuffer_[i] = buffer[i];
445
    }
446 447

    return;
448 449
}

450

451 452 453 454 455 456
void AudioRecord::recMicData (SFLDataFormat* buffer, int nSamples)
{

    if (recordingEnabled_) {

        nbSamplesSpk_ = nSamples;
457

458 459
        for (int i = 0; i < nbSamplesSpk_; i++)
            spkBuffer_[i] = buffer[i];
460

461 462
    }

463 464 465 466 467 468 469 470
    return;
}


void AudioRecord::recData (SFLDataFormat* buffer, int nSamples)
{

    if (recordingEnabled_) {
alexandresavard's avatar
alexandresavard committed
471

472 473 474 475 476 477 478 479 480 481 482 483 484 485
        if (fp == 0) {
            _debug ("AudioRecord: Can't record data, a file has not yet been opened!\n");
            return;
        }



        if (sndFormat_ == INT16) {   // TODO change INT16 to SINT16
            if (fwrite (buffer, sizeof (SFLDataFormat), nSamples, fp) != nSamples)
                _debug ("AudioRecord: Could not record data! \n");
            else {
                fflush (fp);
                byteCounter_ += (unsigned long) (nSamples*sizeof (SFLDataFormat));
            }
alexandresavard's avatar
alexandresavard committed
486
        }
487 488
    }

489 490 491 492 493 494 495 496 497 498 499 500 501 502
    return;
}


void AudioRecord::recData (SFLDataFormat* buffer_1, SFLDataFormat* buffer_2, int nSamples_1, int nSamples_2)
{

    if (recordingEnabled_) {

        if (fp == 0) {
            _debug ("AudioRecord: Can't record data, a file has not yet been opened!\n");
            return;
        }

503

504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
        if (sndFormat_ == INT16) {   // TODO change INT16 to SINT16
            for (int k=0; k<nSamples_1; k++) {

                mixBuffer_[k] = (buffer_1[k]+buffer_2[k]);


                if (fwrite (&mixBuffer_[k], 2, 1, fp) != 1)
                    _debug ("AudioRecord: Could not record data!\n");
                else {
                    fflush (fp);
                }
            }
        }

        byteCounter_ += (unsigned long) (nSamples_1*sizeof (SFLDataFormat));

    }

    return;
523
}
524