~ps-jenkins/qtubuntu-camera/ubuntu-vivid-proposed

« back to all changes in this revision

Viewing changes to src/aalmediarecordercontrol.cpp

  • Committer: CI bot
  • Author(s): Jim Hodapp, Jim Hodapp
  • Date: 2014-08-07 21:29:23 UTC
  • mfrom: (91.1.21 audio-recording)
  • Revision ID: ps-jenkins@lists.canonical.com-20140807212923-2vy4jdebum42ozpd
Created a new AudioCapture class that is responsible for opening the microphone channel from Pulseaudio and feeds the data to the Android side of camera recording via a named pipe Fixes: 1342127
Approved by: Manuel de la Peña

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright (C) 2013 Canonical, Ltd.
 
2
 * Copyright (C) 2013-2014 Canonical, Ltd.
3
3
 *
4
4
 * This program is free software; you can redistribute it and/or modify
5
5
 * it under the terms of the GNU Lesser General Public License as published by
19
19
#include "aalmetadatawritercontrol.h"
20
20
#include "aalvideoencodersettingscontrol.h"
21
21
#include "aalviewfindersettingscontrol.h"
 
22
#include "audiocapture.h"
22
23
#include "storagemanager.h"
23
24
 
24
25
#include <QDebug>
25
26
#include <QFile>
 
27
#include <QThread>
26
28
#include <QTimer>
27
29
 
28
30
#include <hybris/camera/camera_compatibility_layer.h>
37
39
const int AalMediaRecorderControl::RECORDER_NOT_AVAILABLE_ERROR;
38
40
const int AalMediaRecorderControl::RECORDER_INITIALIZATION_ERROR;
39
41
 
40
 
const int AalMediaRecorderControl::DURATION_UPDATE_INTERVALL;
 
42
const int AalMediaRecorderControl::DURATION_UPDATE_INTERVAL;
41
43
 
42
44
const QLatin1String AalMediaRecorderControl::PARAM_AUDIO_BITRATE = QLatin1String("audio-param-encoding-bitrate");
43
45
const QLatin1String AalMediaRecorderControl::PARAM_AUDIO_CHANNELS = QLatin1String("audio-param-number-of-channels");
55
57
   : QMediaRecorderControl(parent),
56
58
    m_service(service),
57
59
    m_mediaRecorder(0),
 
60
    m_audioCapture(0),
58
61
    m_duration(0),
59
62
    m_currentState(QMediaRecorder::StoppedState),
60
63
    m_currentStatus(QMediaRecorder::UnloadedStatus),
61
 
    m_recordingTimer(0)
 
64
    m_recordingTimer(0),
 
65
    m_workerThread(new QThread)
62
66
{
63
67
}
64
68
 
68
72
AalMediaRecorderControl::~AalMediaRecorderControl()
69
73
{
70
74
    delete m_recordingTimer;
 
75
    m_workerThread->deleteLater();
 
76
    m_audioCapture->deleteLater();
71
77
    deleteRecorder();
72
78
}
73
79
 
143
149
}
144
150
 
145
151
/*!
 
152
 * \brief Starts the main microphone reader/writer loop in AudioCapture (run)
 
153
 */
 
154
void AalMediaRecorderControl::onStartThread()
 
155
{
 
156
    qDebug() << "Starting microphone reader/writer worker thread";
 
157
    // Start the microphone read/write worker thread
 
158
    m_workerThread->start();
 
159
    Q_EMIT startWorkerThread();
 
160
}
 
161
 
 
162
/*!
146
163
 * \brief AalMediaRecorderControl::init makes sure the mediarecorder is
147
164
 * initialized
148
165
 */
151
168
    if (m_mediaRecorder == 0) {
152
169
        m_mediaRecorder = android_media_new_recorder();
153
170
 
 
171
        m_audioCapture = new AudioCapture(m_mediaRecorder);
 
172
 
 
173
        if (m_audioCapture == 0) {
 
174
            qWarning() << "Unable to create new audio capture, audio recording won't function";
 
175
            Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "Unable to create new audio capture, audio recording won't function");
 
176
        }
 
177
        else
 
178
        {
 
179
            bool ret = false;
 
180
 
 
181
            // Make sure that m_audioCapture is executed within the m_workerThread affinity
 
182
            m_audioCapture->moveToThread(m_workerThread);
 
183
 
 
184
            // Finished signal is for when the workerThread is completed. Important to connect this so that
 
185
            // resources are cleaned up in the proper order and not leaked
 
186
            ret = connect(m_workerThread, SIGNAL(finished()), m_audioCapture, SLOT(deleteLater()));
 
187
            if (!ret)
 
188
                qWarning() << "Failed to connect deleteLater() to the m_workerThread finished signal";
 
189
            // startWorkerThread signal comes from an Android layer callback that resides down in
 
190
            // the AudioRecordHybris class
 
191
            ret = connect(this, SIGNAL(startWorkerThread()), m_audioCapture, SLOT(run()));
 
192
            if (!ret)
 
193
                qWarning() << "Failed to connect run() to the local startWorkerThread signal";
 
194
 
 
195
            // Call onStartThreadCb when the reader side of the named pipe has been setup
 
196
            m_audioCapture->init(&AalMediaRecorderControl::onStartThreadCb, this);
 
197
        }
 
198
 
154
199
        if (m_mediaRecorder == 0) {
155
200
            qWarning() << "Unable to create new media recorder";
156
201
            Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "Unable to create new media recorder");
163
208
 
164
209
    if (m_recordingTimer == 0) {
165
210
        m_recordingTimer = new QTimer(this);
166
 
        m_recordingTimer->setInterval(DURATION_UPDATE_INTERVALL);
 
211
        m_recordingTimer->setInterval(DURATION_UPDATE_INTERVAL);
167
212
        m_recordingTimer->setSingleShot(false);
168
213
        QObject::connect(m_recordingTimer, SIGNAL(timeout()),
169
214
                         this, SLOT(updateDuration()));
196
241
                              "handleError", Qt::QueuedConnection);
197
242
}
198
243
 
 
244
MediaRecorderWrapper* AalMediaRecorderControl::mediaRecorder() const
 
245
{
 
246
    return m_mediaRecorder;
 
247
}
 
248
 
 
249
AudioCapture *AalMediaRecorderControl::audioCapture() const
 
250
{
 
251
    return m_audioCapture;
 
252
}
 
253
 
199
254
/*!
200
255
 * \reimp
201
256
 */
243
298
 
244
299
void AalMediaRecorderControl::updateDuration()
245
300
{
246
 
    m_duration += DURATION_UPDATE_INTERVALL;
 
301
    m_duration += DURATION_UPDATE_INTERVAL;
247
302
    Q_EMIT durationChanged(m_duration);
248
303
}
249
304
 
273
328
 * FIXME add support for recording audio only
274
329
 */
275
330
int AalMediaRecorderControl::startRecording()
276
 
{    
 
331
{
277
332
    if (m_service->androidControl() == 0) {
278
333
        Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "No camera connection");
279
334
        return RECORDER_INITIALIZATION_ERROR;
406
461
 */
407
462
void AalMediaRecorderControl::stopRecording()
408
463
{
 
464
    qDebug() << __PRETTY_FUNCTION__;
409
465
    if (m_mediaRecorder == 0) {
 
466
        qWarning() << "Can't stop recording properly, m_mediaRecorder is NULL";
 
467
        return;
 
468
    }
 
469
    if (m_audioCapture == 0) {
 
470
        qWarning() << "Can't stop recording properly, m_audioCapture is NULL";
410
471
        return;
411
472
    }
412
473
 
419
480
        return;
420
481
    }
421
482
 
 
483
    // Stop microphone reader/writer loop
 
484
    // NOTE: This must come after the android_recorder_stop call, otherwise the
 
485
    // RecordThread instance will block the MPEG4Writer pthread_join when trying to
 
486
    // cleanly stop recording.
 
487
    m_audioCapture->stopCapture();
 
488
 
422
489
    android_recorder_reset(m_mediaRecorder);
423
490
 
424
491
    m_currentState = QMediaRecorder::StoppedState;
438
505
    QString param =  parameter + QChar('=') + QString::number(value);
439
506
    android_recorder_setParameters(m_mediaRecorder, param.toLocal8Bit().data());
440
507
}
 
508
 
 
509
void AalMediaRecorderControl::onStartThreadCb(void *context)
 
510
{
 
511
    AalMediaRecorderControl *thiz = static_cast<AalMediaRecorderControl*>(context);
 
512
    if (thiz != NULL)
 
513
        thiz->onStartThread();
 
514
}