Merge lp:~phablet-team/qtubuntu-camera/fix-trust-prompt-bugs into lp:qtubuntu-camera/stable

Proposed by Jim Hodapp
Status: Merged
Approved by: Jim Hodapp
Approved revision: 153
Merged at revision: 149
Proposed branch: lp:~phablet-team/qtubuntu-camera/fix-trust-prompt-bugs
Merge into: lp:qtubuntu-camera/stable
Diff against target: 595 lines (+152/-136)
7 files modified
debian/changelog (+3/-3)
debian/control (+1/-1)
src/aalmediarecordercontrol.cpp (+115/-86)
src/aalmediarecordercontrol.h (+9/-5)
src/audiocapture.cpp (+13/-26)
src/audiocapture.h (+6/-10)
unittests/stubs/audiocapture_stub.cpp (+5/-5)
To merge this branch: bzr merge lp:~phablet-team/qtubuntu-camera/fix-trust-prompt-bugs
Reviewer Review Type Date Requested Status
Jim Hodapp (community) code Approve
Review via email: mp+268776@code.launchpad.net

Commit message

Refactor media recorder code to:
- ensure proper cleanups
- prevent double start/stop of recordings
- allow for soundless recordings
- do not start recording before microphone access is allowed/forbidden by user

Description of the change

Refactor media recorder code to:
- ensure proper cleanups
- prevent double start/stop of recordings
- allow for soundless recordings
- do not start recording before microphone access is allowed/forbidden by user

Fixes:
Bug #1487126: Camera/mic trust: initial video corrupt
Bug #1487131: Camera/mic trust: mic denial in camera-app freezes camera
Bug #1487159: revoking mic permission in system-settings, camera appears to record but video is unplayable

To post a comment you must log in.
149. By Florian Boucault

Refactor media recorder code to:
- ensure proper cleanups
- prevent double start/stop of recordings
- allow for soundless recordings
- do not start recording before microphone access is allowed/forbidden by user

150. By Florian Boucault

Slightly clearer if/else

151. By Jim Hodapp

Fix package version and libqtubuntu-media-signals-dev dependency version.

Revision history for this message
Jim Hodapp (jhodapp) wrote :

A few comments/questions inline.

review: Needs Fixing (code)
152. By Florian Boucault

Small status fix

153. By Florian Boucault

Reset m_audioCaptureAvailable in cleanup.

Revision history for this message
Florian Boucault (fboucault) :
154. By Florian Boucault

In the case of a timeout error signalled by pulseaudio when trying to use the microphone, be smart and prevent any further recording.

Revision history for this message
Jim Hodapp (jhodapp) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/changelog'
--- debian/changelog 2015-07-10 18:12:33 +0000
+++ debian/changelog 2015-08-21 20:10:16 +0000
@@ -1,4 +1,4 @@
1qtubuntu-camera (0.3.3+15.10.20150710-0ubuntu1) wily; urgency=medium1qtubuntu-camera (0.3.3+15.04.20150710-0ubuntu1) vivid; urgency=medium
22
3 [ CI Train Bot ]3 [ CI Train Bot ]
4 * New rebuild forced.4 * New rebuild forced.
@@ -9,7 +9,7 @@
99
10 -- CI Train Bot <ci-train-bot@canonical.com> Fri, 10 Jul 2015 18:12:33 +000010 -- CI Train Bot <ci-train-bot@canonical.com> Fri, 10 Jul 2015 18:12:33 +0000
1111
12qtubuntu-camera (0.3.3+15.10.20150706-0ubuntu1) wily; urgency=medium12qtubuntu-camera (0.3.3+15.04.20150706-0ubuntu1) vivid; urgency=medium
1313
14 [ Alberto Aguirre ]14 [ Alberto Aguirre ]
15 * Remove dependency on platform-api. Use QScreen instead to obtain15 * Remove dependency on platform-api. Use QScreen instead to obtain
@@ -20,7 +20,7 @@
2020
21 -- CI Train Bot <ci-train-bot@canonical.com> Mon, 06 Jul 2015 18:22:45 +000021 -- CI Train Bot <ci-train-bot@canonical.com> Mon, 06 Jul 2015 18:22:45 +0000
2222
23qtubuntu-camera (0.3.3+15.10.20150629-0ubuntu1) wily; urgency=medium23qtubuntu-camera (0.3.3+15.04.20150629-0ubuntu1) vivid; urgency=medium
2424
25 [ Florian Boucault ]25 [ Florian Boucault ]
26 * Write GPS location even if no altitude is given. (LP: #1447689)26 * Write GPS location even if no altitude is given. (LP: #1447689)
2727
=== modified file 'debian/control'
--- debian/control 2015-07-10 18:07:53 +0000
+++ debian/control 2015-08-21 20:10:16 +0000
@@ -8,7 +8,7 @@
8 libhybris-dev (>= 0.1.0+git20131207+e452e83-0ubuntu34),8 libhybris-dev (>= 0.1.0+git20131207+e452e83-0ubuntu34),
9 libpulse-dev,9 libpulse-dev,
10 libqt5opengl5-dev,10 libqt5opengl5-dev,
11 libqtubuntu-media-signals-dev (>=0.3+15.10.20150618.1-0ubuntu1),11 libqtubuntu-media-signals-dev (>=0.3+15.04.20141104-0ubuntu1),
12 pkg-config,12 pkg-config,
13 qt5-default,13 qt5-default,
14 qtmultimedia5-dev,14 qtmultimedia5-dev,
1515
=== modified file 'src/aalmediarecordercontrol.cpp'
--- src/aalmediarecordercontrol.cpp 2015-01-26 16:21:39 +0000
+++ src/aalmediarecordercontrol.cpp 2015-08-21 20:10:16 +0000
@@ -25,7 +25,6 @@
25#include <QDebug>25#include <QDebug>
26#include <QFile>26#include <QFile>
27#include <QFileInfo>27#include <QFileInfo>
28#include <QThread>
29#include <QTimer>28#include <QTimer>
3029
31#include <hybris/camera/camera_compatibility_layer.h>30#include <hybris/camera/camera_compatibility_layer.h>
@@ -65,7 +64,7 @@
65 m_currentState(QMediaRecorder::StoppedState),64 m_currentState(QMediaRecorder::StoppedState),
66 m_currentStatus(QMediaRecorder::UnloadedStatus),65 m_currentStatus(QMediaRecorder::UnloadedStatus),
67 m_recordingTimer(0),66 m_recordingTimer(0),
68 m_workerThread(0)67 m_audioCaptureAvailable(false)
69{68{
70}69}
7170
@@ -83,6 +82,8 @@
83 << errno << ")";82 << errno << ")";
84 }83 }
85 deleteRecorder();84 deleteRecorder();
85 m_audioCaptureThread.quit();
86 m_audioCaptureThread.wait();
86}87}
8788
88/*!89/*!
@@ -158,76 +159,44 @@
158/*!159/*!
159 * \brief Starts the main microphone reader/writer loop in AudioCapture (run)160 * \brief Starts the main microphone reader/writer loop in AudioCapture (run)
160 */161 */
161void AalMediaRecorderControl::onStartThread()162void AalMediaRecorderControl::startAudioCaptureThread()
162{163{
163 qDebug() << "Starting microphone reader/writer worker thread";164 qDebug() << "Starting microphone reader/writer thread";
164 // Start the microphone read/write worker thread165 // Start the microphone read/write thread
165 m_workerThread->start();166 m_audioCaptureThread.start();
166 Q_EMIT startWorkerThread();167 Q_EMIT audioCaptureThreadStarted();
167}168}
168169
169/*!170/*!
170 * \brief AalMediaRecorderControl::init makes sure the mediarecorder is171 * \brief AalMediaRecorderControl::init makes sure the mediarecorder is
171 * initialized172 * initialized
172 */173 */
173void AalMediaRecorderControl::initRecorder()174bool AalMediaRecorderControl::initRecorder()
174{175{
175 if (m_mediaRecorder == 0) {176 if (m_mediaRecorder == 0) {
176 m_mediaRecorder = android_media_new_recorder();177 m_mediaRecorder = android_media_new_recorder();
177
178 m_audioCapture = new AudioCapture(m_mediaRecorder);
179 m_workerThread = new QThread;
180
181 if (m_audioCapture == 0) {
182 qWarning() << "Unable to create new audio capture, audio recording won't function";
183 Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "Unable to create new audio capture, audio recording won't function");
184 }
185 else
186 {
187 bool ret = false;
188
189 // Make sure that m_audioCapture is executed within the m_workerThread affinity
190 m_audioCapture->moveToThread(m_workerThread);
191
192 // Finished signal is for when the workerThread is completed. Important to connect this so that
193 // resources are cleaned up in the proper order and not leaked
194 ret = connect(m_audioCapture, SIGNAL(finished()), m_workerThread, SLOT(quit()));
195 if (!ret)
196 qWarning() << "Failed to connect quit() to the m_audioCapture finished signal";
197 ret = connect(m_audioCapture, SIGNAL(finished()), m_audioCapture, SLOT(deleteLater()));
198 if (!ret)
199 qWarning() << "Failed to connect deleteLater() to the m_audioCapture finished signal";
200 // Clean up the worker thread after we finish recording
201 ret = connect(m_workerThread, SIGNAL(finished()), m_workerThread, SLOT(deleteLater()));
202 if (!ret)
203 qWarning() << "Failed to connect deleteLater() to the m_workerThread finished signal";
204 // startWorkerThread signal comes from an Android layer callback that resides down in
205 // the AudioRecordHybris class
206 ret = connect(this, SIGNAL(startWorkerThread()), m_audioCapture, SLOT(run()));
207 if (!ret)
208 qWarning() << "Failed to connect run() to the local startWorkerThread signal";
209
210 // Call onStartThreadCb when the reader side of the named pipe has been setup
211 m_audioCapture->init(&AalMediaRecorderControl::onStartThreadCb, this);
212 }
213
214 if (m_mediaRecorder == 0) {178 if (m_mediaRecorder == 0) {
215 qWarning() << "Unable to create new media recorder";179 qWarning() << "Unable to create new media recorder";
216 Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "Unable to create new media recorder");180 Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "Unable to create new media recorder");
181 return false;
182 }
183
184 int audioInitError = initAudioCapture();
185 if (audioInitError == 0) {
186 m_audioCaptureAvailable = true;
217 } else {187 } else {
218 setStatus(QMediaRecorder::LoadedStatus);188 m_audioCaptureAvailable = false;
219 android_recorder_set_error_cb(m_mediaRecorder, &AalMediaRecorderControl::errorCB, this);189 if (audioInitError == AudioCapture::AUDIO_CAPTURE_TIMEOUT_ERROR) {
220 android_camera_unlock(m_service->androidControl());190 deleteRecorder();
191 return false;
192 }
221 }193 }
222 }194
223195 android_recorder_set_error_cb(m_mediaRecorder, &AalMediaRecorderControl::errorCB, this);
224 if (m_recordingTimer == 0) {196 android_camera_unlock(m_service->androidControl());
225 m_recordingTimer = new QTimer(this);197 }
226 m_recordingTimer->setInterval(DURATION_UPDATE_INTERVAL);198
227 m_recordingTimer->setSingleShot(false);199 return true;
228 QObject::connect(m_recordingTimer, SIGNAL(timeout()),
229 this, SLOT(updateDuration()));
230 }
231}200}
232201
233/*!202/*!
@@ -236,6 +205,8 @@
236 */205 */
237void AalMediaRecorderControl::deleteRecorder()206void AalMediaRecorderControl::deleteRecorder()
238{207{
208 deleteAudioCapture();
209
239 if (m_mediaRecorder == 0)210 if (m_mediaRecorder == 0)
240 return;211 return;
241212
@@ -245,6 +216,43 @@
245 setStatus(QMediaRecorder::UnloadedStatus);216 setStatus(QMediaRecorder::UnloadedStatus);
246}217}
247218
219int AalMediaRecorderControl::initAudioCapture()
220{
221 // setting up audio recording; m_audioCapture is executed within the m_workerThread affinity
222 m_audioCapture = new AudioCapture(m_mediaRecorder);
223 int audioInitError = m_audioCapture->setupMicrophoneStream();
224 if (audioInitError != 0)
225 {
226 qWarning() << "Failed to setup PulseAudio microphone recording stream";
227 delete m_audioCapture;
228 m_audioCapture = 0;
229 } else {
230 m_audioCapture->moveToThread(&m_audioCaptureThread);
231
232 // startWorkerThread signal comes from an Android layer callback that resides down in
233 // the AudioRecordHybris class
234 connect(this, SIGNAL(audioCaptureThreadStarted()), m_audioCapture, SLOT(run()));
235
236 // Call recorderReadAudioCallback when the reader side of the named pipe has been setup
237 m_audioCapture->init(&AalMediaRecorderControl::recorderReadAudioCallback, this);
238 }
239 return audioInitError;
240}
241
242void AalMediaRecorderControl::deleteAudioCapture()
243{
244 if (m_audioCapture == 0)
245 return;
246
247 m_audioCapture->stopCapture();
248 m_audioCaptureThread.quit();
249 m_audioCaptureThread.wait();
250
251 delete m_audioCapture;
252 m_audioCapture = 0;
253 m_audioCaptureAvailable = false;
254}
255
248/*!256/*!
249 * \brief AalMediaRecorderControl::errorCB handles errors from the android layer257 * \brief AalMediaRecorderControl::errorCB handles errors from the android layer
250 * \param context258 * \param context
@@ -285,10 +293,7 @@
285293
286 switch (state) {294 switch (state) {
287 case QMediaRecorder::RecordingState: {295 case QMediaRecorder::RecordingState: {
288 int ret = startRecording();296 startRecording();
289 if (ret == -1) {
290 setStatus(QMediaRecorder::LoadedStatus);
291 }
292 break;297 break;
293 }298 }
294 case QMediaRecorder::StoppedState: {299 case QMediaRecorder::StoppedState: {
@@ -349,17 +354,21 @@
349 return RECORDER_INITIALIZATION_ERROR;354 return RECORDER_INITIALIZATION_ERROR;
350 }355 }
351356
357 if (m_currentStatus != QMediaRecorder::UnloadedStatus) {
358 qWarning() << "Can't start a recording while another one is in progess";
359 return RECORDER_NOT_AVAILABLE_ERROR;
360 }
361
362 setStatus(QMediaRecorder::LoadingStatus);
363
352 m_duration = 0;364 m_duration = 0;
353 Q_EMIT durationChanged(m_duration);365 Q_EMIT durationChanged(m_duration);
354366
355 initRecorder();367 if (!initRecorder()) {
356 if (m_mediaRecorder == 0) {368 setStatus(QMediaRecorder::UnloadedStatus);
357 deleteRecorder();
358 return RECORDER_NOT_AVAILABLE_ERROR;369 return RECORDER_NOT_AVAILABLE_ERROR;
359 }370 }
360371
361 setStatus(QMediaRecorder::StartingStatus);
362
363 QVideoEncoderSettings videoSettings = m_service->videoEncoderControl()->videoSettings();372 QVideoEncoderSettings videoSettings = m_service->videoEncoderControl()->videoSettings();
364373
365 int ret;374 int ret;
@@ -369,12 +378,15 @@
369 Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "android_recorder_setCamera() failed\n");378 Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "android_recorder_setCamera() failed\n");
370 return RECORDER_INITIALIZATION_ERROR;379 return RECORDER_INITIALIZATION_ERROR;
371 }380 }
372 //state initial / idle381 // state initial / idle
373 ret = android_recorder_setAudioSource(m_mediaRecorder, ANDROID_AUDIO_SOURCE_CAMCORDER);382 if (m_audioCaptureAvailable) {
374 if (ret < 0) {383 ret = android_recorder_setAudioSource(m_mediaRecorder, ANDROID_AUDIO_SOURCE_CAMCORDER);
375 deleteRecorder();384 if (ret < 0) {
376 Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "android_recorder_setAudioSource() failed");385 deleteRecorder();
377 return RECORDER_INITIALIZATION_ERROR;386 Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "android_recorder_setAudioSource() failed");
387 return RECORDER_INITIALIZATION_ERROR;
388 }
389
378 }390 }
379 ret = android_recorder_setVideoSource(m_mediaRecorder, ANDROID_VIDEO_SOURCE_CAMERA);391 ret = android_recorder_setVideoSource(m_mediaRecorder, ANDROID_VIDEO_SOURCE_CAMERA);
380 if (ret < 0) {392 if (ret < 0) {
@@ -382,19 +394,21 @@
382 Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "android_recorder_setVideoSource() failed");394 Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "android_recorder_setVideoSource() failed");
383 return RECORDER_INITIALIZATION_ERROR;395 return RECORDER_INITIALIZATION_ERROR;
384 }396 }
385 //state initialized397 // state initialized
386 ret = android_recorder_setOutputFormat(m_mediaRecorder, ANDROID_OUTPUT_FORMAT_MPEG_4);398 ret = android_recorder_setOutputFormat(m_mediaRecorder, ANDROID_OUTPUT_FORMAT_MPEG_4);
387 if (ret < 0) {399 if (ret < 0) {
388 deleteRecorder();400 deleteRecorder();
389 Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "android_recorder_setOutputFormat() failed");401 Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "android_recorder_setOutputFormat() failed");
390 return RECORDER_INITIALIZATION_ERROR;402 return RECORDER_INITIALIZATION_ERROR;
391 }403 }
392 //state DataSourceConfigured404 // state DataSourceConfigured
393 ret = android_recorder_setAudioEncoder(m_mediaRecorder, ANDROID_AUDIO_ENCODER_AAC);405 if (m_audioCaptureAvailable) {
394 if (ret < 0) {406 ret = android_recorder_setAudioEncoder(m_mediaRecorder, ANDROID_AUDIO_ENCODER_AAC);
395 deleteRecorder();407 if (ret < 0) {
396 Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "android_recorder_setAudioEncoder() failed");408 deleteRecorder();
397 return RECORDER_INITIALIZATION_ERROR;409 Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "android_recorder_setAudioEncoder() failed");
410 return RECORDER_INITIALIZATION_ERROR;
411 }
398 }412 }
399 // FIXME set codec from settings413 // FIXME set codec from settings
400 ret = android_recorder_setVideoEncoder(m_mediaRecorder, ANDROID_VIDEO_ENCODER_H264);414 ret = android_recorder_setVideoEncoder(m_mediaRecorder, ANDROID_VIDEO_ENCODER_H264);
@@ -466,7 +480,11 @@
466 Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "android_recorder_prepare() failed");480 Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "android_recorder_prepare() failed");
467 return RECORDER_INITIALIZATION_ERROR;481 return RECORDER_INITIALIZATION_ERROR;
468 }482 }
469 //state prepared483
484 setStatus(QMediaRecorder::LoadedStatus);
485 setStatus(QMediaRecorder::StartingStatus);
486
487 // state prepared
470 ret = android_recorder_start(m_mediaRecorder);488 ret = android_recorder_start(m_mediaRecorder);
471 if (ret < 0) {489 if (ret < 0) {
472 close(m_outfd);490 close(m_outfd);
@@ -481,6 +499,13 @@
481499
482 setStatus(QMediaRecorder::RecordingStatus);500 setStatus(QMediaRecorder::RecordingStatus);
483501
502 if (m_recordingTimer == 0) {
503 m_recordingTimer = new QTimer(this);
504 m_recordingTimer->setInterval(DURATION_UPDATE_INTERVAL);
505 m_recordingTimer->setSingleShot(false);
506 QObject::connect(m_recordingTimer, SIGNAL(timeout()),
507 this, SLOT(updateDuration()));
508 }
484 m_recordingTimer->start();509 m_recordingTimer->start();
485510
486 return 0;511 return 0;
@@ -496,8 +521,9 @@
496 qWarning() << "Can't stop recording properly, m_mediaRecorder is NULL";521 qWarning() << "Can't stop recording properly, m_mediaRecorder is NULL";
497 return;522 return;
498 }523 }
499 if (m_audioCapture == 0) {524
500 qWarning() << "Can't stop recording properly, m_audioCapture is NULL";525 if (m_currentStatus != QMediaRecorder::RecordingStatus) {
526 qWarning() << "Can't stop a recording that has not started";
501 return;527 return;
502 }528 }
503529
@@ -514,7 +540,9 @@
514 // NOTE: This must come after the android_recorder_stop call, otherwise the540 // NOTE: This must come after the android_recorder_stop call, otherwise the
515 // RecordThread instance will block the MPEG4Writer pthread_join when trying to541 // RecordThread instance will block the MPEG4Writer pthread_join when trying to
516 // cleanly stop recording.542 // cleanly stop recording.
517 m_audioCapture->stopCapture();543 if (m_audioCapture != 0) {
544 m_audioCapture->stopCapture();
545 }
518546
519 android_recorder_reset(m_mediaRecorder);547 android_recorder_reset(m_mediaRecorder);
520548
@@ -542,9 +570,10 @@
542 android_recorder_setParameters(m_mediaRecorder, param.toLocal8Bit().data());570 android_recorder_setParameters(m_mediaRecorder, param.toLocal8Bit().data());
543}571}
544572
545void AalMediaRecorderControl::onStartThreadCb(void *context)573void AalMediaRecorderControl::recorderReadAudioCallback(void *context)
546{574{
547 AalMediaRecorderControl *thiz = static_cast<AalMediaRecorderControl*>(context);575 AalMediaRecorderControl *thiz = static_cast<AalMediaRecorderControl*>(context);
548 if (thiz != NULL)576 if (thiz != NULL) {
549 thiz->onStartThread();577 thiz->startAudioCaptureThread();
578 }
550}579}
551580
=== modified file 'src/aalmediarecordercontrol.h'
--- src/aalmediarecordercontrol.h 2015-01-23 02:49:03 +0000
+++ src/aalmediarecordercontrol.h 2015-08-21 20:10:16 +0000
@@ -21,6 +21,7 @@
21#include <QMediaRecorderControl>21#include <QMediaRecorderControl>
22#include <QSize>22#include <QSize>
23#include <QUrl>23#include <QUrl>
24#include <QThread>
2425
25#include <stdint.h>26#include <stdint.h>
2627
@@ -58,23 +59,25 @@
58 virtual void setMuted(bool muted);59 virtual void setMuted(bool muted);
59 virtual void setState(QMediaRecorder::State state);60 virtual void setState(QMediaRecorder::State state);
60 virtual void setVolume(qreal gain);61 virtual void setVolume(qreal gain);
61 void onStartThread();62 void startAudioCaptureThread();
6263
63signals:64signals:
64 void startWorkerThread();65 void audioCaptureThreadStarted();
6566
66private Q_SLOTS:67private Q_SLOTS:
67 virtual void updateDuration();68 virtual void updateDuration();
68 void handleError();69 void handleError();
70 void deleteAudioCapture();
6971
70private:72private:
71 void initRecorder();73 bool initRecorder();
72 void deleteRecorder();74 void deleteRecorder();
75 int initAudioCapture();
73 void setStatus(QMediaRecorder::Status status);76 void setStatus(QMediaRecorder::Status status);
74 int startRecording();77 int startRecording();
75 void stopRecording();78 void stopRecording();
76 void setParameter(const QString &parameter, int value);79 void setParameter(const QString &parameter, int value);
77 static void onStartThreadCb(void *context);80 static void recorderReadAudioCallback(void *context);
7881
79 AalCameraService *m_service;82 AalCameraService *m_service;
80 MediaRecorderWrapper *m_mediaRecorder;83 MediaRecorderWrapper *m_mediaRecorder;
@@ -85,7 +88,8 @@
85 QMediaRecorder::State m_currentState;88 QMediaRecorder::State m_currentState;
86 QMediaRecorder::Status m_currentStatus;89 QMediaRecorder::Status m_currentStatus;
87 QTimer *m_recordingTimer;90 QTimer *m_recordingTimer;
88 QThread *m_workerThread;91 QThread m_audioCaptureThread;
92 bool m_audioCaptureAvailable;
8993
90 static const int RECORDER_GENERAL_ERROR = -1;94 static const int RECORDER_GENERAL_ERROR = -1;
91 static const int RECORDER_NOT_AVAILABLE_ERROR = -2;95 static const int RECORDER_NOT_AVAILABLE_ERROR = -2;
9296
=== modified file 'src/audiocapture.cpp'
--- src/audiocapture.cpp 2014-12-03 17:08:38 +0000
+++ src/audiocapture.cpp 2015-08-21 20:10:16 +0000
@@ -37,6 +37,8 @@
3737
38AudioCapture::~AudioCapture()38AudioCapture::~AudioCapture()
39{39{
40 android_recorder_set_audio_read_cb(m_mediaRecorder, NULL, NULL);
41
40 if (m_audioPipe >= 0)42 if (m_audioPipe >= 0)
41 close(m_audioPipe);43 close(m_audioPipe);
42 if (m_paStream != NULL)44 if (m_paStream != NULL)
@@ -46,10 +48,10 @@
46/*!48/*!
47 * \brief Initializes AudioCapture so that it's ready to read microphone data from Pulseaudio49 * \brief Initializes AudioCapture so that it's ready to read microphone data from Pulseaudio
48 */50 */
49bool AudioCapture::init(StartWorkerThreadCb cb, void *context)51bool AudioCapture::init(RecorderReadAudioCallback callback, void *context)
50{52{
51 // The MediaRecorderLayer will call method (cb) when it's ready to encode a new audio buffer53 // The MediaRecorderLayer will call method (callback) when it's ready to encode a new audio buffer
52 android_recorder_set_audio_read_cb(m_mediaRecorder, cb, context);54 android_recorder_set_audio_read_cb(m_mediaRecorder, callback, context);
5355
54 return true;56 return true;
55}57}
@@ -68,17 +70,12 @@
68 */70 */
69void AudioCapture::run()71void AudioCapture::run()
70{72{
73 m_flagExit = false;
71 qDebug() << __PRETTY_FUNCTION__;74 qDebug() << __PRETTY_FUNCTION__;
7275
73 int bytesWritten = 0, bytesRead = 0;76 int bytesWritten = 0, bytesRead = 0;
74 const size_t readSize = sizeof(m_audioBuf);77 const size_t readSize = sizeof(m_audioBuf);
7578
76 if (!setupMicrophoneStream())
77 {
78 qWarning() << "Failed to setup PulseAudio microphone recording stream";
79 return;
80 }
81
82 if (!setupPipe())79 if (!setupPipe())
83 {80 {
84 qWarning() << "Failed to open /dev/socket/micshm, cannot write data to pipe";81 qWarning() << "Failed to open /dev/socket/micshm, cannot write data to pipe";
@@ -101,8 +98,6 @@
101 pa_simple_free(m_paStream);98 pa_simple_free(m_paStream);
102 m_paStream = NULL;99 m_paStream = NULL;
103 }100 }
104
105 Q_EMIT finished();
106}101}
107102
108/*!103/*!
@@ -122,21 +117,9 @@
122}117}
123118
124/*!119/*!
125 * \brief Signals AalMediaRecorderControl to start the main thread loop.
126 * \detail This is necessary due to thread contexts. Starting of the main thread loop
127 * for AudioCapture must be done in the main thread context and not in the AudioCapture
128 * thread context, otherwise the loop start signal will never be seen.
129 */
130void AudioCapture::startThreadLoop()
131{
132 Q_EMIT startThread();
133 qDebug() << "Emitted startThread(), should start reading from mic";
134}
135
136/*!
137 * \brief Sets up the Pulseaudio microphone input channel120 * \brief Sets up the Pulseaudio microphone input channel
138 */121 */
139bool AudioCapture::setupMicrophoneStream()122int AudioCapture::setupMicrophoneStream()
140{123{
141 // FIXME: Get these parameters more dynamically from the control124 // FIXME: Get these parameters more dynamically from the control
142 static const pa_sample_spec ss = {125 static const pa_sample_spec ss = {
@@ -150,10 +133,14 @@
150 if (m_paStream == NULL)133 if (m_paStream == NULL)
151 {134 {
152 qWarning() << "Failed to open a PulseAudio channel to read the microphone: " << pa_strerror(error);135 qWarning() << "Failed to open a PulseAudio channel to read the microphone: " << pa_strerror(error);
153 return false;136 if (error == PA_ERR_TIMEOUT) {
137 return AUDIO_CAPTURE_TIMEOUT_ERROR;
138 } else {
139 return AUDIO_CAPTURE_GENERAL_ERROR;
140 }
154 }141 }
155142
156 return true;143 return 0;
157}144}
158145
159/*!146/*!
160147
=== modified file 'src/audiocapture.h'
--- src/audiocapture.h 2014-07-30 14:50:39 +0000
+++ src/audiocapture.h 2015-08-21 20:10:16 +0000
@@ -34,28 +34,24 @@
34{34{
35 Q_OBJECT35 Q_OBJECT
3636
37 typedef void (*StartWorkerThreadCb)(void *context);37 typedef void (*RecorderReadAudioCallback)(void *context);
38public:38public:
39 static const int AUDIO_CAPTURE_GENERAL_ERROR = -1;
40 static const int AUDIO_CAPTURE_TIMEOUT_ERROR = -2;
41
39 explicit AudioCapture(MediaRecorderWrapper *mediaRecorder);42 explicit AudioCapture(MediaRecorderWrapper *mediaRecorder);
40 ~AudioCapture();43 ~AudioCapture();
4144
42 bool init(StartWorkerThreadCb cb, void *context);45 bool init(RecorderReadAudioCallback callback, void *context);
43 /* Terminates the Pulseaudio reader/writer QThread */46 /* Terminates the Pulseaudio reader/writer QThread */
47 int setupMicrophoneStream();
44 void stopCapture();48 void stopCapture();
4549
46signals:
47 void startThread();
48 void finished();
49
50public Q_SLOTS:50public Q_SLOTS:
51 void run();51 void run();
5252
53private Q_SLOTS:
54 void startThreadLoop();
55
56private:53private:
57 int readMicrophone();54 int readMicrophone();
58 bool setupMicrophoneStream();
59 bool setupPipe();55 bool setupPipe();
60 ssize_t loopWrite(int fd, const void *data, size_t len);56 ssize_t loopWrite(int fd, const void *data, size_t len);
61 int writeDataToPipe();57 int writeDataToPipe();
6258
=== modified file 'unittests/stubs/audiocapture_stub.cpp'
--- unittests/stubs/audiocapture_stub.cpp 2014-07-30 14:50:39 +0000
+++ unittests/stubs/audiocapture_stub.cpp 2015-08-21 20:10:16 +0000
@@ -29,7 +29,7 @@
29{29{
30}30}
3131
32bool AudioCapture::init(StartWorkerThreadCb cb, void *context)32bool AudioCapture::init(RecorderReadAudioCallback cb, void *context)
33{33{
34 Q_UNUSED(cb);34 Q_UNUSED(cb);
35 Q_UNUSED(context);35 Q_UNUSED(context);
@@ -40,14 +40,14 @@
40{40{
41}41}
4242
43int AudioCapture::setupMicrophoneStream()
44{
45}
46
43void AudioCapture::run()47void AudioCapture::run()
44{48{
45}49}
4650
47void AudioCapture::startThreadLoop()
48{
49}
50
51int AudioCapture::readMicrophone()51int AudioCapture::readMicrophone()
52{52{
53 return 0;53 return 0;

Subscribers

People subscribed via source and target branches

to all changes: