Merge lp:~phablet-team/qtubuntu-camera/fix-trust-prompt-bugs into lp:qtubuntu-camera/stable
- fix-trust-prompt-bugs
- Merge into stable
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 |
Related 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
- 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.
- 152. By Florian Boucault
-
Small status fix
- 153. By Florian Boucault
-
Reset m_audioCaptureA
vailable in cleanup.
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.
Jim Hodapp (jhodapp) : | # |
Preview Diff
1 | === modified file 'debian/changelog' |
2 | --- debian/changelog 2015-07-10 18:12:33 +0000 |
3 | +++ debian/changelog 2015-08-21 20:10:16 +0000 |
4 | @@ -1,4 +1,4 @@ |
5 | -qtubuntu-camera (0.3.3+15.10.20150710-0ubuntu1) wily; urgency=medium |
6 | +qtubuntu-camera (0.3.3+15.04.20150710-0ubuntu1) vivid; urgency=medium |
7 | |
8 | [ CI Train Bot ] |
9 | * New rebuild forced. |
10 | @@ -9,7 +9,7 @@ |
11 | |
12 | -- CI Train Bot <ci-train-bot@canonical.com> Fri, 10 Jul 2015 18:12:33 +0000 |
13 | |
14 | -qtubuntu-camera (0.3.3+15.10.20150706-0ubuntu1) wily; urgency=medium |
15 | +qtubuntu-camera (0.3.3+15.04.20150706-0ubuntu1) vivid; urgency=medium |
16 | |
17 | [ Alberto Aguirre ] |
18 | * Remove dependency on platform-api. Use QScreen instead to obtain |
19 | @@ -20,7 +20,7 @@ |
20 | |
21 | -- CI Train Bot <ci-train-bot@canonical.com> Mon, 06 Jul 2015 18:22:45 +0000 |
22 | |
23 | -qtubuntu-camera (0.3.3+15.10.20150629-0ubuntu1) wily; urgency=medium |
24 | +qtubuntu-camera (0.3.3+15.04.20150629-0ubuntu1) vivid; urgency=medium |
25 | |
26 | [ Florian Boucault ] |
27 | * Write GPS location even if no altitude is given. (LP: #1447689) |
28 | |
29 | === modified file 'debian/control' |
30 | --- debian/control 2015-07-10 18:07:53 +0000 |
31 | +++ debian/control 2015-08-21 20:10:16 +0000 |
32 | @@ -8,7 +8,7 @@ |
33 | libhybris-dev (>= 0.1.0+git20131207+e452e83-0ubuntu34), |
34 | libpulse-dev, |
35 | libqt5opengl5-dev, |
36 | - libqtubuntu-media-signals-dev (>=0.3+15.10.20150618.1-0ubuntu1), |
37 | + libqtubuntu-media-signals-dev (>=0.3+15.04.20141104-0ubuntu1), |
38 | pkg-config, |
39 | qt5-default, |
40 | qtmultimedia5-dev, |
41 | |
42 | === modified file 'src/aalmediarecordercontrol.cpp' |
43 | --- src/aalmediarecordercontrol.cpp 2015-01-26 16:21:39 +0000 |
44 | +++ src/aalmediarecordercontrol.cpp 2015-08-21 20:10:16 +0000 |
45 | @@ -25,7 +25,6 @@ |
46 | #include <QDebug> |
47 | #include <QFile> |
48 | #include <QFileInfo> |
49 | -#include <QThread> |
50 | #include <QTimer> |
51 | |
52 | #include <hybris/camera/camera_compatibility_layer.h> |
53 | @@ -65,7 +64,7 @@ |
54 | m_currentState(QMediaRecorder::StoppedState), |
55 | m_currentStatus(QMediaRecorder::UnloadedStatus), |
56 | m_recordingTimer(0), |
57 | - m_workerThread(0) |
58 | + m_audioCaptureAvailable(false) |
59 | { |
60 | } |
61 | |
62 | @@ -83,6 +82,8 @@ |
63 | << errno << ")"; |
64 | } |
65 | deleteRecorder(); |
66 | + m_audioCaptureThread.quit(); |
67 | + m_audioCaptureThread.wait(); |
68 | } |
69 | |
70 | /*! |
71 | @@ -158,76 +159,44 @@ |
72 | /*! |
73 | * \brief Starts the main microphone reader/writer loop in AudioCapture (run) |
74 | */ |
75 | -void AalMediaRecorderControl::onStartThread() |
76 | +void AalMediaRecorderControl::startAudioCaptureThread() |
77 | { |
78 | - qDebug() << "Starting microphone reader/writer worker thread"; |
79 | - // Start the microphone read/write worker thread |
80 | - m_workerThread->start(); |
81 | - Q_EMIT startWorkerThread(); |
82 | + qDebug() << "Starting microphone reader/writer thread"; |
83 | + // Start the microphone read/write thread |
84 | + m_audioCaptureThread.start(); |
85 | + Q_EMIT audioCaptureThreadStarted(); |
86 | } |
87 | |
88 | /*! |
89 | * \brief AalMediaRecorderControl::init makes sure the mediarecorder is |
90 | * initialized |
91 | */ |
92 | -void AalMediaRecorderControl::initRecorder() |
93 | +bool AalMediaRecorderControl::initRecorder() |
94 | { |
95 | if (m_mediaRecorder == 0) { |
96 | m_mediaRecorder = android_media_new_recorder(); |
97 | - |
98 | - m_audioCapture = new AudioCapture(m_mediaRecorder); |
99 | - m_workerThread = new QThread; |
100 | - |
101 | - if (m_audioCapture == 0) { |
102 | - qWarning() << "Unable to create new audio capture, audio recording won't function"; |
103 | - Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "Unable to create new audio capture, audio recording won't function"); |
104 | - } |
105 | - else |
106 | - { |
107 | - bool ret = false; |
108 | - |
109 | - // Make sure that m_audioCapture is executed within the m_workerThread affinity |
110 | - m_audioCapture->moveToThread(m_workerThread); |
111 | - |
112 | - // Finished signal is for when the workerThread is completed. Important to connect this so that |
113 | - // resources are cleaned up in the proper order and not leaked |
114 | - ret = connect(m_audioCapture, SIGNAL(finished()), m_workerThread, SLOT(quit())); |
115 | - if (!ret) |
116 | - qWarning() << "Failed to connect quit() to the m_audioCapture finished signal"; |
117 | - ret = connect(m_audioCapture, SIGNAL(finished()), m_audioCapture, SLOT(deleteLater())); |
118 | - if (!ret) |
119 | - qWarning() << "Failed to connect deleteLater() to the m_audioCapture finished signal"; |
120 | - // Clean up the worker thread after we finish recording |
121 | - ret = connect(m_workerThread, SIGNAL(finished()), m_workerThread, SLOT(deleteLater())); |
122 | - if (!ret) |
123 | - qWarning() << "Failed to connect deleteLater() to the m_workerThread finished signal"; |
124 | - // startWorkerThread signal comes from an Android layer callback that resides down in |
125 | - // the AudioRecordHybris class |
126 | - ret = connect(this, SIGNAL(startWorkerThread()), m_audioCapture, SLOT(run())); |
127 | - if (!ret) |
128 | - qWarning() << "Failed to connect run() to the local startWorkerThread signal"; |
129 | - |
130 | - // Call onStartThreadCb when the reader side of the named pipe has been setup |
131 | - m_audioCapture->init(&AalMediaRecorderControl::onStartThreadCb, this); |
132 | - } |
133 | - |
134 | if (m_mediaRecorder == 0) { |
135 | qWarning() << "Unable to create new media recorder"; |
136 | Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "Unable to create new media recorder"); |
137 | + return false; |
138 | + } |
139 | + |
140 | + int audioInitError = initAudioCapture(); |
141 | + if (audioInitError == 0) { |
142 | + m_audioCaptureAvailable = true; |
143 | } else { |
144 | - setStatus(QMediaRecorder::LoadedStatus); |
145 | - android_recorder_set_error_cb(m_mediaRecorder, &AalMediaRecorderControl::errorCB, this); |
146 | - android_camera_unlock(m_service->androidControl()); |
147 | + m_audioCaptureAvailable = false; |
148 | + if (audioInitError == AudioCapture::AUDIO_CAPTURE_TIMEOUT_ERROR) { |
149 | + deleteRecorder(); |
150 | + return false; |
151 | + } |
152 | } |
153 | - } |
154 | - |
155 | - if (m_recordingTimer == 0) { |
156 | - m_recordingTimer = new QTimer(this); |
157 | - m_recordingTimer->setInterval(DURATION_UPDATE_INTERVAL); |
158 | - m_recordingTimer->setSingleShot(false); |
159 | - QObject::connect(m_recordingTimer, SIGNAL(timeout()), |
160 | - this, SLOT(updateDuration())); |
161 | - } |
162 | + |
163 | + android_recorder_set_error_cb(m_mediaRecorder, &AalMediaRecorderControl::errorCB, this); |
164 | + android_camera_unlock(m_service->androidControl()); |
165 | + } |
166 | + |
167 | + return true; |
168 | } |
169 | |
170 | /*! |
171 | @@ -236,6 +205,8 @@ |
172 | */ |
173 | void AalMediaRecorderControl::deleteRecorder() |
174 | { |
175 | + deleteAudioCapture(); |
176 | + |
177 | if (m_mediaRecorder == 0) |
178 | return; |
179 | |
180 | @@ -245,6 +216,43 @@ |
181 | setStatus(QMediaRecorder::UnloadedStatus); |
182 | } |
183 | |
184 | +int AalMediaRecorderControl::initAudioCapture() |
185 | +{ |
186 | + // setting up audio recording; m_audioCapture is executed within the m_workerThread affinity |
187 | + m_audioCapture = new AudioCapture(m_mediaRecorder); |
188 | + int audioInitError = m_audioCapture->setupMicrophoneStream(); |
189 | + if (audioInitError != 0) |
190 | + { |
191 | + qWarning() << "Failed to setup PulseAudio microphone recording stream"; |
192 | + delete m_audioCapture; |
193 | + m_audioCapture = 0; |
194 | + } else { |
195 | + m_audioCapture->moveToThread(&m_audioCaptureThread); |
196 | + |
197 | + // startWorkerThread signal comes from an Android layer callback that resides down in |
198 | + // the AudioRecordHybris class |
199 | + connect(this, SIGNAL(audioCaptureThreadStarted()), m_audioCapture, SLOT(run())); |
200 | + |
201 | + // Call recorderReadAudioCallback when the reader side of the named pipe has been setup |
202 | + m_audioCapture->init(&AalMediaRecorderControl::recorderReadAudioCallback, this); |
203 | + } |
204 | + return audioInitError; |
205 | +} |
206 | + |
207 | +void AalMediaRecorderControl::deleteAudioCapture() |
208 | +{ |
209 | + if (m_audioCapture == 0) |
210 | + return; |
211 | + |
212 | + m_audioCapture->stopCapture(); |
213 | + m_audioCaptureThread.quit(); |
214 | + m_audioCaptureThread.wait(); |
215 | + |
216 | + delete m_audioCapture; |
217 | + m_audioCapture = 0; |
218 | + m_audioCaptureAvailable = false; |
219 | +} |
220 | + |
221 | /*! |
222 | * \brief AalMediaRecorderControl::errorCB handles errors from the android layer |
223 | * \param context |
224 | @@ -285,10 +293,7 @@ |
225 | |
226 | switch (state) { |
227 | case QMediaRecorder::RecordingState: { |
228 | - int ret = startRecording(); |
229 | - if (ret == -1) { |
230 | - setStatus(QMediaRecorder::LoadedStatus); |
231 | - } |
232 | + startRecording(); |
233 | break; |
234 | } |
235 | case QMediaRecorder::StoppedState: { |
236 | @@ -349,17 +354,21 @@ |
237 | return RECORDER_INITIALIZATION_ERROR; |
238 | } |
239 | |
240 | + if (m_currentStatus != QMediaRecorder::UnloadedStatus) { |
241 | + qWarning() << "Can't start a recording while another one is in progess"; |
242 | + return RECORDER_NOT_AVAILABLE_ERROR; |
243 | + } |
244 | + |
245 | + setStatus(QMediaRecorder::LoadingStatus); |
246 | + |
247 | m_duration = 0; |
248 | Q_EMIT durationChanged(m_duration); |
249 | |
250 | - initRecorder(); |
251 | - if (m_mediaRecorder == 0) { |
252 | - deleteRecorder(); |
253 | + if (!initRecorder()) { |
254 | + setStatus(QMediaRecorder::UnloadedStatus); |
255 | return RECORDER_NOT_AVAILABLE_ERROR; |
256 | } |
257 | |
258 | - setStatus(QMediaRecorder::StartingStatus); |
259 | - |
260 | QVideoEncoderSettings videoSettings = m_service->videoEncoderControl()->videoSettings(); |
261 | |
262 | int ret; |
263 | @@ -369,12 +378,15 @@ |
264 | Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "android_recorder_setCamera() failed\n"); |
265 | return RECORDER_INITIALIZATION_ERROR; |
266 | } |
267 | - //state initial / idle |
268 | - ret = android_recorder_setAudioSource(m_mediaRecorder, ANDROID_AUDIO_SOURCE_CAMCORDER); |
269 | - if (ret < 0) { |
270 | - deleteRecorder(); |
271 | - Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "android_recorder_setAudioSource() failed"); |
272 | - return RECORDER_INITIALIZATION_ERROR; |
273 | + // state initial / idle |
274 | + if (m_audioCaptureAvailable) { |
275 | + ret = android_recorder_setAudioSource(m_mediaRecorder, ANDROID_AUDIO_SOURCE_CAMCORDER); |
276 | + if (ret < 0) { |
277 | + deleteRecorder(); |
278 | + Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "android_recorder_setAudioSource() failed"); |
279 | + return RECORDER_INITIALIZATION_ERROR; |
280 | + } |
281 | + |
282 | } |
283 | ret = android_recorder_setVideoSource(m_mediaRecorder, ANDROID_VIDEO_SOURCE_CAMERA); |
284 | if (ret < 0) { |
285 | @@ -382,19 +394,21 @@ |
286 | Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "android_recorder_setVideoSource() failed"); |
287 | return RECORDER_INITIALIZATION_ERROR; |
288 | } |
289 | - //state initialized |
290 | + // state initialized |
291 | ret = android_recorder_setOutputFormat(m_mediaRecorder, ANDROID_OUTPUT_FORMAT_MPEG_4); |
292 | if (ret < 0) { |
293 | deleteRecorder(); |
294 | Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "android_recorder_setOutputFormat() failed"); |
295 | return RECORDER_INITIALIZATION_ERROR; |
296 | } |
297 | - //state DataSourceConfigured |
298 | - ret = android_recorder_setAudioEncoder(m_mediaRecorder, ANDROID_AUDIO_ENCODER_AAC); |
299 | - if (ret < 0) { |
300 | - deleteRecorder(); |
301 | - Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "android_recorder_setAudioEncoder() failed"); |
302 | - return RECORDER_INITIALIZATION_ERROR; |
303 | + // state DataSourceConfigured |
304 | + if (m_audioCaptureAvailable) { |
305 | + ret = android_recorder_setAudioEncoder(m_mediaRecorder, ANDROID_AUDIO_ENCODER_AAC); |
306 | + if (ret < 0) { |
307 | + deleteRecorder(); |
308 | + Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "android_recorder_setAudioEncoder() failed"); |
309 | + return RECORDER_INITIALIZATION_ERROR; |
310 | + } |
311 | } |
312 | // FIXME set codec from settings |
313 | ret = android_recorder_setVideoEncoder(m_mediaRecorder, ANDROID_VIDEO_ENCODER_H264); |
314 | @@ -466,7 +480,11 @@ |
315 | Q_EMIT error(RECORDER_INITIALIZATION_ERROR, "android_recorder_prepare() failed"); |
316 | return RECORDER_INITIALIZATION_ERROR; |
317 | } |
318 | - //state prepared |
319 | + |
320 | + setStatus(QMediaRecorder::LoadedStatus); |
321 | + setStatus(QMediaRecorder::StartingStatus); |
322 | + |
323 | + // state prepared |
324 | ret = android_recorder_start(m_mediaRecorder); |
325 | if (ret < 0) { |
326 | close(m_outfd); |
327 | @@ -481,6 +499,13 @@ |
328 | |
329 | setStatus(QMediaRecorder::RecordingStatus); |
330 | |
331 | + if (m_recordingTimer == 0) { |
332 | + m_recordingTimer = new QTimer(this); |
333 | + m_recordingTimer->setInterval(DURATION_UPDATE_INTERVAL); |
334 | + m_recordingTimer->setSingleShot(false); |
335 | + QObject::connect(m_recordingTimer, SIGNAL(timeout()), |
336 | + this, SLOT(updateDuration())); |
337 | + } |
338 | m_recordingTimer->start(); |
339 | |
340 | return 0; |
341 | @@ -496,8 +521,9 @@ |
342 | qWarning() << "Can't stop recording properly, m_mediaRecorder is NULL"; |
343 | return; |
344 | } |
345 | - if (m_audioCapture == 0) { |
346 | - qWarning() << "Can't stop recording properly, m_audioCapture is NULL"; |
347 | + |
348 | + if (m_currentStatus != QMediaRecorder::RecordingStatus) { |
349 | + qWarning() << "Can't stop a recording that has not started"; |
350 | return; |
351 | } |
352 | |
353 | @@ -514,7 +540,9 @@ |
354 | // NOTE: This must come after the android_recorder_stop call, otherwise the |
355 | // RecordThread instance will block the MPEG4Writer pthread_join when trying to |
356 | // cleanly stop recording. |
357 | - m_audioCapture->stopCapture(); |
358 | + if (m_audioCapture != 0) { |
359 | + m_audioCapture->stopCapture(); |
360 | + } |
361 | |
362 | android_recorder_reset(m_mediaRecorder); |
363 | |
364 | @@ -542,9 +570,10 @@ |
365 | android_recorder_setParameters(m_mediaRecorder, param.toLocal8Bit().data()); |
366 | } |
367 | |
368 | -void AalMediaRecorderControl::onStartThreadCb(void *context) |
369 | +void AalMediaRecorderControl::recorderReadAudioCallback(void *context) |
370 | { |
371 | AalMediaRecorderControl *thiz = static_cast<AalMediaRecorderControl*>(context); |
372 | - if (thiz != NULL) |
373 | - thiz->onStartThread(); |
374 | + if (thiz != NULL) { |
375 | + thiz->startAudioCaptureThread(); |
376 | + } |
377 | } |
378 | |
379 | === modified file 'src/aalmediarecordercontrol.h' |
380 | --- src/aalmediarecordercontrol.h 2015-01-23 02:49:03 +0000 |
381 | +++ src/aalmediarecordercontrol.h 2015-08-21 20:10:16 +0000 |
382 | @@ -21,6 +21,7 @@ |
383 | #include <QMediaRecorderControl> |
384 | #include <QSize> |
385 | #include <QUrl> |
386 | +#include <QThread> |
387 | |
388 | #include <stdint.h> |
389 | |
390 | @@ -58,23 +59,25 @@ |
391 | virtual void setMuted(bool muted); |
392 | virtual void setState(QMediaRecorder::State state); |
393 | virtual void setVolume(qreal gain); |
394 | - void onStartThread(); |
395 | + void startAudioCaptureThread(); |
396 | |
397 | signals: |
398 | - void startWorkerThread(); |
399 | + void audioCaptureThreadStarted(); |
400 | |
401 | private Q_SLOTS: |
402 | virtual void updateDuration(); |
403 | void handleError(); |
404 | + void deleteAudioCapture(); |
405 | |
406 | private: |
407 | - void initRecorder(); |
408 | + bool initRecorder(); |
409 | void deleteRecorder(); |
410 | + int initAudioCapture(); |
411 | void setStatus(QMediaRecorder::Status status); |
412 | int startRecording(); |
413 | void stopRecording(); |
414 | void setParameter(const QString ¶meter, int value); |
415 | - static void onStartThreadCb(void *context); |
416 | + static void recorderReadAudioCallback(void *context); |
417 | |
418 | AalCameraService *m_service; |
419 | MediaRecorderWrapper *m_mediaRecorder; |
420 | @@ -85,7 +88,8 @@ |
421 | QMediaRecorder::State m_currentState; |
422 | QMediaRecorder::Status m_currentStatus; |
423 | QTimer *m_recordingTimer; |
424 | - QThread *m_workerThread; |
425 | + QThread m_audioCaptureThread; |
426 | + bool m_audioCaptureAvailable; |
427 | |
428 | static const int RECORDER_GENERAL_ERROR = -1; |
429 | static const int RECORDER_NOT_AVAILABLE_ERROR = -2; |
430 | |
431 | === modified file 'src/audiocapture.cpp' |
432 | --- src/audiocapture.cpp 2014-12-03 17:08:38 +0000 |
433 | +++ src/audiocapture.cpp 2015-08-21 20:10:16 +0000 |
434 | @@ -37,6 +37,8 @@ |
435 | |
436 | AudioCapture::~AudioCapture() |
437 | { |
438 | + android_recorder_set_audio_read_cb(m_mediaRecorder, NULL, NULL); |
439 | + |
440 | if (m_audioPipe >= 0) |
441 | close(m_audioPipe); |
442 | if (m_paStream != NULL) |
443 | @@ -46,10 +48,10 @@ |
444 | /*! |
445 | * \brief Initializes AudioCapture so that it's ready to read microphone data from Pulseaudio |
446 | */ |
447 | -bool AudioCapture::init(StartWorkerThreadCb cb, void *context) |
448 | +bool AudioCapture::init(RecorderReadAudioCallback callback, void *context) |
449 | { |
450 | - // The MediaRecorderLayer will call method (cb) when it's ready to encode a new audio buffer |
451 | - android_recorder_set_audio_read_cb(m_mediaRecorder, cb, context); |
452 | + // The MediaRecorderLayer will call method (callback) when it's ready to encode a new audio buffer |
453 | + android_recorder_set_audio_read_cb(m_mediaRecorder, callback, context); |
454 | |
455 | return true; |
456 | } |
457 | @@ -68,17 +70,12 @@ |
458 | */ |
459 | void AudioCapture::run() |
460 | { |
461 | + m_flagExit = false; |
462 | qDebug() << __PRETTY_FUNCTION__; |
463 | |
464 | int bytesWritten = 0, bytesRead = 0; |
465 | const size_t readSize = sizeof(m_audioBuf); |
466 | |
467 | - if (!setupMicrophoneStream()) |
468 | - { |
469 | - qWarning() << "Failed to setup PulseAudio microphone recording stream"; |
470 | - return; |
471 | - } |
472 | - |
473 | if (!setupPipe()) |
474 | { |
475 | qWarning() << "Failed to open /dev/socket/micshm, cannot write data to pipe"; |
476 | @@ -101,8 +98,6 @@ |
477 | pa_simple_free(m_paStream); |
478 | m_paStream = NULL; |
479 | } |
480 | - |
481 | - Q_EMIT finished(); |
482 | } |
483 | |
484 | /*! |
485 | @@ -122,21 +117,9 @@ |
486 | } |
487 | |
488 | /*! |
489 | - * \brief Signals AalMediaRecorderControl to start the main thread loop. |
490 | - * \detail This is necessary due to thread contexts. Starting of the main thread loop |
491 | - * for AudioCapture must be done in the main thread context and not in the AudioCapture |
492 | - * thread context, otherwise the loop start signal will never be seen. |
493 | - */ |
494 | -void AudioCapture::startThreadLoop() |
495 | -{ |
496 | - Q_EMIT startThread(); |
497 | - qDebug() << "Emitted startThread(), should start reading from mic"; |
498 | -} |
499 | - |
500 | -/*! |
501 | * \brief Sets up the Pulseaudio microphone input channel |
502 | */ |
503 | -bool AudioCapture::setupMicrophoneStream() |
504 | +int AudioCapture::setupMicrophoneStream() |
505 | { |
506 | // FIXME: Get these parameters more dynamically from the control |
507 | static const pa_sample_spec ss = { |
508 | @@ -150,10 +133,14 @@ |
509 | if (m_paStream == NULL) |
510 | { |
511 | qWarning() << "Failed to open a PulseAudio channel to read the microphone: " << pa_strerror(error); |
512 | - return false; |
513 | + if (error == PA_ERR_TIMEOUT) { |
514 | + return AUDIO_CAPTURE_TIMEOUT_ERROR; |
515 | + } else { |
516 | + return AUDIO_CAPTURE_GENERAL_ERROR; |
517 | + } |
518 | } |
519 | |
520 | - return true; |
521 | + return 0; |
522 | } |
523 | |
524 | /*! |
525 | |
526 | === modified file 'src/audiocapture.h' |
527 | --- src/audiocapture.h 2014-07-30 14:50:39 +0000 |
528 | +++ src/audiocapture.h 2015-08-21 20:10:16 +0000 |
529 | @@ -34,28 +34,24 @@ |
530 | { |
531 | Q_OBJECT |
532 | |
533 | - typedef void (*StartWorkerThreadCb)(void *context); |
534 | + typedef void (*RecorderReadAudioCallback)(void *context); |
535 | public: |
536 | + static const int AUDIO_CAPTURE_GENERAL_ERROR = -1; |
537 | + static const int AUDIO_CAPTURE_TIMEOUT_ERROR = -2; |
538 | + |
539 | explicit AudioCapture(MediaRecorderWrapper *mediaRecorder); |
540 | ~AudioCapture(); |
541 | |
542 | - bool init(StartWorkerThreadCb cb, void *context); |
543 | + bool init(RecorderReadAudioCallback callback, void *context); |
544 | /* Terminates the Pulseaudio reader/writer QThread */ |
545 | + int setupMicrophoneStream(); |
546 | void stopCapture(); |
547 | |
548 | -signals: |
549 | - void startThread(); |
550 | - void finished(); |
551 | - |
552 | public Q_SLOTS: |
553 | void run(); |
554 | |
555 | -private Q_SLOTS: |
556 | - void startThreadLoop(); |
557 | - |
558 | private: |
559 | int readMicrophone(); |
560 | - bool setupMicrophoneStream(); |
561 | bool setupPipe(); |
562 | ssize_t loopWrite(int fd, const void *data, size_t len); |
563 | int writeDataToPipe(); |
564 | |
565 | === modified file 'unittests/stubs/audiocapture_stub.cpp' |
566 | --- unittests/stubs/audiocapture_stub.cpp 2014-07-30 14:50:39 +0000 |
567 | +++ unittests/stubs/audiocapture_stub.cpp 2015-08-21 20:10:16 +0000 |
568 | @@ -29,7 +29,7 @@ |
569 | { |
570 | } |
571 | |
572 | -bool AudioCapture::init(StartWorkerThreadCb cb, void *context) |
573 | +bool AudioCapture::init(RecorderReadAudioCallback cb, void *context) |
574 | { |
575 | Q_UNUSED(cb); |
576 | Q_UNUSED(context); |
577 | @@ -40,14 +40,14 @@ |
578 | { |
579 | } |
580 | |
581 | +int AudioCapture::setupMicrophoneStream() |
582 | +{ |
583 | +} |
584 | + |
585 | void AudioCapture::run() |
586 | { |
587 | } |
588 | |
589 | -void AudioCapture::startThreadLoop() |
590 | -{ |
591 | -} |
592 | - |
593 | int AudioCapture::readMicrophone() |
594 | { |
595 | return 0; |
A few comments/questions inline.