~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/src/audio/audiorecord.cpp

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 *  Copyright (C) 2004-2012 Savoir-Faire Linux Inc.
 
2
 *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
3
3
 *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
4
4
 *
5
5
 *  This program is free software; you can redistribute it and/or modify
33
33
#endif
34
34
 
35
35
#include "audiorecord.h"
 
36
#include <sndfile.hh>
36
37
#include <unistd.h>
37
38
#include <sstream> // for stringstream
38
39
#include <algorithm>
40
41
#include "logger.h"
41
42
#include "fileutils.h"
42
43
 
43
 
// structure for the wave header
44
 
 
45
 
struct wavhdr {
46
 
    char riff[4];           // "RIFF"
47
 
    SINT32 file_size;       // in bytes
48
 
    char wave[4];           // "WAVE"
49
 
    char fmt[4];            // "fmt "
50
 
    SINT32 chunk_size;      // in bytes (16 for PCM)
51
 
    SINT16 format_tag;      // 1=PCM, 2=ADPCM, 3=IEEE float, 6=A-Law, 7=Mu-Law
52
 
    SINT16 num_chans;       // 1=mono, 2=stereo
53
 
    SINT32 sample_rate;
54
 
    SINT32 bytes_per_sec;
55
 
    SINT16 bytes_per_samp;  // 2=16-bit mono, 4=16-bit stereo
56
 
    SINT16 bits_per_samp;
57
 
    char data[4];           // "data"
58
 
    SINT32 data_length;     // in bytes
59
 
};
60
 
 
61
44
namespace {
62
45
std::string
63
46
createFilename()
106
89
}
107
90
 
108
91
 
109
 
AudioRecord::AudioRecord() : fileHandle_(NULL)
110
 
    , fileType_(FILE_INVALID)
 
92
AudioRecord::AudioRecord() : fileHandle_(0)
111
93
    , channels_(1)
112
 
    , byteCounter_(0)
113
94
    , sndSmplRate_(8000)
114
 
    , nbSamplesMic_(0)
115
 
    , nbSamplesSpk_(0)
116
95
    , recordingEnabled_(false)
117
 
    , mixBuffer_()
118
 
    , micBuffer_()
119
 
    , spkBuffer_()
120
96
    , filename_(createFilename())
121
97
    , savePath_()
122
98
{
123
99
    WARN("Generate filename for this call %s ", filename_.c_str());
124
100
}
125
101
 
 
102
AudioRecord::~AudioRecord()
 
103
{
 
104
    delete fileHandle_;
 
105
}
 
106
 
126
107
void AudioRecord::setSndSamplingRate(int smplRate)
127
108
{
128
109
    sndSmplRate_ = smplRate;
129
110
}
130
111
 
131
 
void AudioRecord::setRecordingOption(FILE_TYPE type, int sndSmplRate, const std::string &path)
 
112
void AudioRecord::setRecordingOptions(int sndSmplRate, const std::string &path)
132
113
{
133
114
    std::string filePath;
134
115
 
139
120
        filePath = path;
140
121
    }
141
122
 
142
 
    fileType_ = type;
143
123
    channels_ = 1;
144
124
    sndSmplRate_ = sndSmplRate;
145
125
    savePath_ = (*filePath.rbegin() == DIR_SEPARATOR_CH) ? filePath : filePath + DIR_SEPARATOR_STR;
149
129
bool
150
130
nonFilenameCharacter(char c)
151
131
{
152
 
    return not (std::isalnum(c) or c == '_' or c == '.');
 
132
    return not(std::isalnum(c) or c == '_' or c == '.');
153
133
}
154
134
 
155
135
// Replace any character that is inappropriate for a filename with '_'
166
146
    std::string fName(filename_);
167
147
    fName.append("-" + sanitize(peerNumber) + "-" PACKAGE);
168
148
 
169
 
    if (fileType_ == FILE_RAW) {
170
 
        if (filename_.find(".raw") == std::string::npos) {
171
 
            DEBUG("Concatenate .raw file extension: name : %s", filename_.c_str());
172
 
            fName.append(".raw");
173
 
        }
174
 
    } else if (fileType_ == FILE_WAV) {
175
 
        if (filename_.find(".wav") == std::string::npos) {
176
 
            DEBUG("Concatenate .wav file extension: name : %s", filename_.c_str());
177
 
            fName.append(".wav");
178
 
        }
 
149
    if (filename_.find(".wav") == std::string::npos) {
 
150
        DEBUG("Concatenate .wav file extension: name : %s", filename_.c_str());
 
151
        fName.append(".wav");
179
152
    }
180
153
 
181
154
    savePath_.append(fName);
189
162
bool AudioRecord::openFile()
190
163
{
191
164
    bool result = false;
192
 
 
193
 
    if (not fileExists()) {
194
 
        DEBUG("Filename does not exist, creating one");
195
 
        byteCounter_ = 0;
196
 
 
197
 
        if (fileType_ == FILE_RAW)
198
 
            result = setRawFile();
199
 
        else if (fileType_ == FILE_WAV)
200
 
            result = setWavFile();
201
 
    } else {
202
 
        DEBUG("Filename already exists, opening it");
203
 
        if (fileType_ == FILE_RAW)
204
 
            result = openExistingRawFile();
205
 
        else if (fileType_ == FILE_WAV)
206
 
            result = openExistingWavFile();
 
165
    delete fileHandle_;
 
166
    const bool doAppend = fileExists();
 
167
    const int access = doAppend ? SFM_RDWR : SFM_WRITE;
 
168
 
 
169
    fileHandle_ = new SndfileHandle(savePath_.c_str(), access, SF_FORMAT_WAV | SF_FORMAT_PCM_16, channels_, sndSmplRate_);
 
170
 
 
171
    // check overloaded boolean operator
 
172
    if (!*fileHandle_) {
 
173
        WARN("Could not open WAV file!");
 
174
        delete fileHandle_;
 
175
        fileHandle_ = 0;
 
176
        return false;
207
177
    }
208
178
 
 
179
    if (doAppend and fileHandle_->seek(0, SEEK_END) < 0)
 
180
        WARN("Couldn't seek to the end of the file ");
 
181
 
209
182
    return result;
210
183
}
211
184
 
212
185
void AudioRecord::closeFile()
213
186
{
214
 
    if (fileHandle_ == 0) return;
215
 
 
216
 
    if (fileType_ == FILE_RAW)
217
 
        fclose(fileHandle_);
218
 
    else if (fileType_ == FILE_WAV)
219
 
        closeWavFile();
 
187
    delete fileHandle_;
 
188
    fileHandle_ = 0;
220
189
}
221
190
 
222
191
bool AudioRecord::isOpenFile() const
234
203
    return recordingEnabled_;
235
204
}
236
205
 
237
 
void AudioRecord::setRecording()
 
206
bool AudioRecord::toggleRecording()
238
207
{
239
208
    if (isOpenFile()) {
240
209
        recordingEnabled_ = !recordingEnabled_;
241
210
    } else {
242
211
        openFile();
243
 
        recordingEnabled_ = true; // once opend file, start recording
 
212
        recordingEnabled_ = true;
244
213
    }
 
214
 
 
215
    return recordingEnabled_;
245
216
}
246
217
 
247
218
void AudioRecord::stopRecording()
250
221
    recordingEnabled_ = false;
251
222
}
252
223
 
253
 
bool AudioRecord::setRawFile()
254
 
{
255
 
    fileHandle_ = fopen(savePath_.c_str(), "wb");
256
 
 
257
 
    if (!fileHandle_) {
258
 
        WARN("Could not create RAW file!");
259
 
        return false;
260
 
    }
261
 
 
262
 
    DEBUG("created RAW file.");
263
 
 
264
 
    return true;
265
 
}
266
 
 
267
 
namespace {
268
 
    std::string header_to_string(const wavhdr &hdr)
269
 
    {
270
 
        std::stringstream ss;
271
 
        ss << hdr.riff << "\0 "
272
 
           << hdr.file_size << " "
273
 
           << hdr.wave << "\0 "
274
 
           << hdr.fmt << "\0 "
275
 
           << hdr.chunk_size << " "
276
 
           << hdr.format_tag << " "
277
 
           << hdr.num_chans << " "
278
 
           << hdr.sample_rate << " "
279
 
           << hdr.bytes_per_sec << " "
280
 
           << hdr.bytes_per_samp << " "
281
 
           << hdr.bits_per_samp << " "
282
 
           << hdr.data << "\0 "
283
 
           << hdr.data_length;
284
 
        return ss.str();
285
 
    }
286
 
}
287
 
 
288
 
bool AudioRecord::setWavFile()
289
 
{
290
 
    DEBUG("Create new wave file %s, sampling rate: %d", savePath_.c_str(), sndSmplRate_);
291
 
 
292
 
    fileHandle_ = fopen(savePath_.c_str(), "wb");
293
 
 
294
 
    if (!fileHandle_) {
295
 
        WARN("Could not create WAV file.");
296
 
        return false;
297
 
    }
298
 
 
299
 
    /* The text fields are NOT supposed to be null terminated, so we have to
300
 
     * write them as arrays since strings enclosed in quotes include a
301
 
     * null character */
302
 
    wavhdr hdr = {{'R', 'I', 'F', 'F'},
303
 
                  44,
304
 
                  {'W', 'A', 'V', 'E'},
305
 
                  {'f','m', 't', ' '},
306
 
                  16,
307
 
                  1,
308
 
                  channels_,
309
 
                  sndSmplRate_,
310
 
                  -1, /* initialized below */
311
 
                  -1, /* initialized below */
312
 
                  16,
313
 
                  {'d', 'a', 't', 'a'},
314
 
                  0};
315
 
 
316
 
    hdr.bytes_per_samp = channels_ * hdr.bits_per_samp / 8;
317
 
    hdr.bytes_per_sec = hdr.sample_rate * hdr.bytes_per_samp;
318
 
 
319
 
    if (fwrite(&hdr, 4, 11, fileHandle_) != 11) {
320
 
        WARN("Could not write WAV header for file. ");
321
 
        return false;
322
 
    }
323
 
 
324
 
    DEBUG("Wrote wave header \"%s\"", header_to_string(hdr).c_str());
325
 
    return true;
326
 
}
327
 
 
328
 
bool AudioRecord::openExistingRawFile()
329
 
{
330
 
    fileHandle_ = fopen(filename_.c_str(), "ab+");
331
 
 
332
 
    if (!fileHandle_) {
333
 
        WARN("could not create RAW file!");
334
 
        return false;
335
 
    }
336
 
 
337
 
    return true;
338
 
}
339
 
 
340
 
bool AudioRecord::openExistingWavFile()
341
 
{
342
 
    DEBUG("Opening %s", filename_.c_str());
343
 
 
344
 
    fileHandle_ = fopen(filename_.c_str(), "rb+");
345
 
 
346
 
    if (!fileHandle_) {
347
 
        WARN("Could not open WAV file!");
348
 
        return false;
349
 
    }
350
 
 
351
 
    if (fseek(fileHandle_, 40, SEEK_SET) != 0)  // jump to data length
352
 
        WARN("Couldn't seek offset 40 in the file ");
353
 
 
354
 
    if (fread(&byteCounter_, 4, 1, fileHandle_))
355
 
        WARN("bytecounter Read successfully ");
356
 
 
357
 
    if (fseek(fileHandle_, 0 , SEEK_END) != 0)
358
 
        WARN("Couldn't seek at the en of the file ");
359
 
 
360
 
 
361
 
    if (fclose(fileHandle_) != 0)
362
 
        WARN("Can't close file r+ ");
363
 
 
364
 
    fileHandle_ = fopen(filename_.c_str(), "ab+");
365
 
 
366
 
    if (!fileHandle_) {
367
 
        WARN("Could not createopen WAV file ab+!");
368
 
        return false;
369
 
    }
370
 
 
371
 
    if (fseek(fileHandle_, 4 , SEEK_END) != 0)
372
 
        WARN("Couldn't seek at the en of the file ");
373
 
 
374
 
    return true;
375
 
 
376
 
}
377
 
 
378
 
void AudioRecord::closeWavFile()
379
 
{
 
224
void AudioRecord::recData(AudioBuffer& buffer)
 
225
{
 
226
    if (not recordingEnabled_)
 
227
        return;
 
228
 
380
229
    if (fileHandle_ == 0) {
381
 
        DEBUG("Can't closeWavFile, a file has not yet been opened!");
 
230
        DEBUG("Can't record data, a file has not yet been opened!");
382
231
        return;
383
232
    }
384
233
 
385
 
    DEBUG("Close wave file");
386
 
 
387
 
    SINT32 bytes = byteCounter_ * channels_;
388
 
 
389
 
    // jump to data length
390
 
    if (fseek(fileHandle_, 40, SEEK_SET) != 0)
391
 
        WARN("Could not seek in file");
392
 
 
393
 
    if (ferror(fileHandle_))
394
 
        WARN("Can't reach offset 40 while closing");
395
 
 
396
 
    fwrite(&bytes, sizeof(SINT32), 1, fileHandle_);
397
 
 
398
 
    if (ferror(fileHandle_))
399
 
        WARN("Can't write bytes for data length ");
400
 
 
401
 
    bytes = byteCounter_ * channels_ + 44; // + 44 for the wave header
402
 
 
403
 
    // jump to file size
404
 
    if (fseek(fileHandle_, 4, SEEK_SET) != 0)
405
 
        WARN("Could not seek in file");
406
 
 
407
 
    if (ferror(fileHandle_))
408
 
        WARN("Can't reach offset 4");
409
 
 
410
 
    fwrite(&bytes, 4, 1, fileHandle_);
411
 
 
412
 
    if (ferror(fileHandle_))
413
 
        WARN("Can't reach offset 4");
414
 
 
415
 
    if (fclose(fileHandle_) != 0)
416
 
        WARN("Can't close file");
417
 
}
418
 
 
419
 
void AudioRecord::recData(SFLDataFormat* buffer, size_t nSamples)
420
 
{
421
 
    if (recordingEnabled_) {
422
 
        if (fileHandle_ == 0) {
423
 
            DEBUG("Can't record data, a file has not yet been opened!");
424
 
            return;
425
 
        }
426
 
 
427
 
        if (fwrite(buffer, sizeof(SFLDataFormat), nSamples, fileHandle_) != nSamples)
428
 
            WARN("Could not record data! ");
429
 
        else {
430
 
            fflush(fileHandle_);
431
 
            byteCounter_ += nSamples * sizeof(SFLDataFormat);
432
 
        }
 
234
    const int nSamples = buffer.frames();
 
235
 
 
236
    // FIXME: mono only
 
237
    if (fileHandle_->write(buffer.getChannel(0)->data(), nSamples) != nSamples) {
 
238
        WARN("Could not record data!");
 
239
    } else {
 
240
        fileHandle_->writeSync();
433
241
    }
434
242
}