VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/RecordingScreenSettingsImpl.cpp@ 95639

Last change on this file since 95639 was 95639, checked in by vboxsync, 3 years ago

Recording: Settings handling fixes / overhaul. This adds the ability to handle per-screen settings, which can be different from the first screen (screen 0). Also fixed a couple of bugs regarding snapshot handling and persistence (committing, rolling back, ++) in that area. FE/VBoxManage now can also list the per-screen settings. Added some further @todos. bugref:9286

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.8 KB
Line 
1/* $Id: RecordingScreenSettingsImpl.cpp 95639 2022-07-14 08:30:45Z vboxsync $ */
2/** @file
3 *
4 * VirtualBox COM class implementation - Recording settings of one virtual screen.
5 */
6
7/*
8 * Copyright (C) 2018-2022 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.215389.xyz. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#define LOG_GROUP LOG_GROUP_MAIN_RECORDINGSCREENSETTINGS
20#include "LoggingNew.h"
21
22#include "RecordingScreenSettingsImpl.h"
23#include "RecordingSettingsImpl.h"
24#include "MachineImpl.h"
25
26#include <iprt/path.h>
27#include <iprt/cpp/utils.h>
28#include <VBox/settings.h>
29
30#include "AutoStateDep.h"
31#include "AutoCaller.h"
32#include "Global.h"
33
34////////////////////////////////////////////////////////////////////////////////
35//
36// RecordScreenSettings private data definition
37//
38////////////////////////////////////////////////////////////////////////////////
39
40struct RecordingScreenSettings::Data
41{
42 Data()
43 : pParent(NULL)
44 { }
45
46 RecordingSettings * const pParent;
47 const ComObjPtr<RecordingScreenSettings> pPeer;
48 uint32_t uScreenId;
49
50 // use the XML settings structure in the members for simplicity
51 Backupable<settings::RecordingScreenSettings> bd;
52};
53
54// constructor / destructor
55////////////////////////////////////////////////////////////////////////////////
56
57DEFINE_EMPTY_CTOR_DTOR(RecordingScreenSettings)
58
59HRESULT RecordingScreenSettings::FinalConstruct()
60{
61 return BaseFinalConstruct();
62}
63
64void RecordingScreenSettings::FinalRelease()
65{
66 uninit();
67 BaseFinalRelease();
68}
69
70// public initializer/uninitializer for internal purposes only
71////////////////////////////////////////////////////////////////////////////////
72
73/**
74 * Initializes the recording screen settings object.
75 *
76 * @returns COM result indicator
77 */
78HRESULT RecordingScreenSettings::init(RecordingSettings *aParent, uint32_t uScreenId,
79 const settings::RecordingScreenSettings& aThat)
80{
81 LogFlowThisFunc(("aParent: %p\n", aParent));
82
83 ComAssertRet(aParent, E_INVALIDARG);
84
85 /* Enclose the state transition NotReady->InInit->Ready */
86 AutoInitSpan autoInitSpan(this);
87 AssertReturn(autoInitSpan.isOk(), E_FAIL);
88
89 m = new Data();
90
91 /* Share the parent & machine weakly. */
92 unconst(m->pParent) = aParent;
93 /* mPeer is left null. */
94
95 /* Simply copy the settings data. */
96 m->uScreenId = uScreenId;
97 m->bd.allocate();
98 m->bd->operator=(aThat);
99
100 HRESULT hrc = S_OK;
101
102 int vrc = i_initInternal();
103 if (RT_SUCCESS(vrc))
104 {
105 autoInitSpan.setSucceeded();
106 }
107 else
108 {
109 autoInitSpan.setFailed();
110 hrc = E_UNEXPECTED;
111 }
112
113 LogFlowThisFuncLeave();
114 return hrc;
115}
116
117/**
118 * Initializes the recording settings object given another recording settings object
119 * (a kind of copy constructor). This object shares data with
120 * the object passed as an argument.
121 *
122 * @note This object must be destroyed before the original object
123 * it shares data with is destroyed.
124 */
125HRESULT RecordingScreenSettings::init(RecordingSettings *aParent, RecordingScreenSettings *aThat)
126{
127 LogFlowThisFunc(("aParent: %p, aThat: %p\n", aParent, aThat));
128
129 ComAssertRet(aParent && aThat, E_INVALIDARG);
130
131 /* Enclose the state transition NotReady->InInit->Ready */
132 AutoInitSpan autoInitSpan(this);
133 AssertReturn(autoInitSpan.isOk(), E_FAIL);
134
135 m = new Data();
136
137 unconst(m->pParent) = aParent;
138 unconst(m->pPeer) = aThat;
139
140 AutoCaller thatCaller(aThat);
141 AssertComRCReturnRC(thatCaller.rc());
142
143 AutoReadLock thatlock(aThat COMMA_LOCKVAL_SRC_POS);
144
145 m->uScreenId = aThat->m->uScreenId;
146 m->bd.share(aThat->m->bd);
147
148 HRESULT rc = S_OK;
149
150 int vrc = i_initInternal();
151 if (RT_SUCCESS(vrc))
152 {
153 autoInitSpan.setSucceeded();
154 }
155 else
156 {
157 autoInitSpan.setFailed();
158 rc = E_UNEXPECTED;
159 }
160
161 LogFlowThisFuncLeave();
162 return rc;
163}
164
165/**
166 * Initializes the guest object given another guest object
167 * (a kind of copy constructor). This object makes a private copy of data
168 * of the original object passed as an argument.
169 */
170HRESULT RecordingScreenSettings::initCopy(RecordingSettings *aParent, RecordingScreenSettings *aThat)
171{
172 LogFlowThisFunc(("aParent: %p, aThat: %p\n", aParent, aThat));
173
174 ComAssertRet(aParent && aThat, E_INVALIDARG);
175
176 /* Enclose the state transition NotReady->InInit->Ready */
177 AutoInitSpan autoInitSpan(this);
178 AssertReturn(autoInitSpan.isOk(), E_FAIL);
179
180 m = new Data();
181
182 unconst(m->pParent) = aParent;
183 /* mPeer is left null. */
184
185 AutoCaller thatCaller(aThat);
186 AssertComRCReturnRC(thatCaller.rc());
187
188 AutoReadLock thatlock(aThat COMMA_LOCKVAL_SRC_POS);
189
190 m->uScreenId = aThat->m->uScreenId;
191 m->bd.attachCopy(aThat->m->bd);
192
193 HRESULT hrc = S_OK;
194
195 int vrc = i_initInternal();
196 if (RT_SUCCESS(vrc))
197 {
198 autoInitSpan.setSucceeded();
199 }
200 else
201 {
202 autoInitSpan.setFailed();
203 hrc = E_UNEXPECTED;
204 }
205
206 LogFlowThisFuncLeave();
207 return hrc;
208}
209
210/**
211 * Uninitializes the instance and sets the ready flag to FALSE.
212 * Called either from FinalRelease() or by the parent when it gets destroyed.
213 */
214void RecordingScreenSettings::uninit()
215{
216 LogFlowThisFuncEnter();
217
218 /* Enclose the state transition Ready->InUninit->NotReady */
219 AutoUninitSpan autoUninitSpan(this);
220 if (autoUninitSpan.uninitDone())
221 return;
222
223 m->bd.free();
224
225 unconst(m->pPeer) = NULL;
226 unconst(m->pParent) = NULL;
227
228 delete m;
229 m = NULL;
230
231 LogFlowThisFuncLeave();
232}
233
234HRESULT RecordingScreenSettings::isFeatureEnabled(RecordingFeature_T aFeature, BOOL *aEnabled)
235{
236 AutoCaller autoCaller(this);
237 if (FAILED(autoCaller.rc())) return autoCaller.rc();
238
239 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
240
241 settings::RecordingFeatureMap::const_iterator itFeature = m->bd->featureMap.find(aFeature);
242
243 *aEnabled = ( itFeature != m->bd->featureMap.end()
244 && itFeature->second == true);
245
246 return S_OK;
247}
248
249HRESULT RecordingScreenSettings::getId(ULONG *id)
250{
251 AutoCaller autoCaller(this);
252 if (FAILED(autoCaller.rc())) return autoCaller.rc();
253
254 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
255
256 *id = m->uScreenId;
257
258 return S_OK;
259}
260
261HRESULT RecordingScreenSettings::getEnabled(BOOL *enabled)
262{
263 AutoCaller autoCaller(this);
264 if (FAILED(autoCaller.rc())) return autoCaller.rc();
265
266 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
267
268 *enabled = m->bd->fEnabled ? TRUE : FALSE;
269
270 return S_OK;
271}
272
273HRESULT RecordingScreenSettings::setEnabled(BOOL enabled)
274{
275 AutoCaller autoCaller(this);
276 if (FAILED(autoCaller.rc())) return autoCaller.rc();
277
278 LogFlowThisFunc(("Screen %RU32\n", m->uScreenId));
279
280 if (!m->pParent->i_canChangeSettings())
281 return setError(E_INVALIDARG, tr("Cannot change enabled state of screen while recording is enabled"));
282
283 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
284
285 if (m->bd->fEnabled != RT_BOOL(enabled))
286 {
287 m->bd.backup();
288 m->bd->fEnabled = RT_BOOL(enabled);
289 alock.release();
290
291 m->pParent->i_onSettingsChanged();
292 }
293
294 LogFlowThisFunc(("Screen %RU32\n", m->uScreenId));
295 return S_OK;
296}
297
298HRESULT RecordingScreenSettings::getFeatures(ULONG *aFeatures)
299{
300 AutoCaller autoCaller(this);
301 if (FAILED(autoCaller.rc())) return autoCaller.rc();
302
303 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
304
305 *aFeatures = 0;
306
307 settings::RecordingFeatureMap::const_iterator itFeature = m->bd->featureMap.begin();
308 while (itFeature != m->bd->featureMap.end())
309 {
310 if (itFeature->second) /* Is feature enable? */
311 *aFeatures |= (ULONG)itFeature->first;
312
313 ++itFeature;
314 }
315
316 return S_OK;
317}
318
319HRESULT RecordingScreenSettings::setFeatures(ULONG aFeatures)
320{
321 AutoCaller autoCaller(this);
322 if (FAILED(autoCaller.rc())) return autoCaller.rc();
323
324 if (!m->pParent->i_canChangeSettings())
325 return setError(E_INVALIDARG, tr("Cannot change features while recording is enabled"));
326
327 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
328
329 m->bd.backup();
330
331 settings::RecordingFeatureMap featureMapOld = m->bd->featureMap;
332 m->bd->featureMap.clear();
333
334 if (aFeatures & RecordingFeature_Audio)
335 m->bd->featureMap[RecordingFeature_Audio] = true;
336 if (aFeatures & RecordingFeature_Video)
337 m->bd->featureMap[RecordingFeature_Video] = true;
338
339 if (m->bd->featureMap != featureMapOld)
340 {
341 alock.release();
342
343 m->pParent->i_onSettingsChanged();
344 }
345
346 return S_OK;
347}
348
349HRESULT RecordingScreenSettings::getDestination(RecordingDestination_T *aDestination)
350{
351 AutoCaller autoCaller(this);
352 if (FAILED(autoCaller.rc())) return autoCaller.rc();
353
354 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
355
356 *aDestination = m->bd->enmDest;
357
358 return S_OK;
359}
360
361HRESULT RecordingScreenSettings::setDestination(RecordingDestination_T aDestination)
362{
363 AutoCaller autoCaller(this);
364 if (FAILED(autoCaller.rc())) return autoCaller.rc();
365
366 if (!m->pParent->i_canChangeSettings())
367 return setError(E_INVALIDARG, tr("Cannot change destination type while recording is enabled"));
368
369 if (aDestination != RecordingDestination_File)
370 return setError(E_INVALIDARG, tr("Destination type invalid / not supported"));
371
372 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
373
374 if (m->bd->enmDest != aDestination)
375 {
376 m->bd.backup();
377 m->bd->enmDest = aDestination;
378
379 m->pParent->i_onSettingsChanged();
380 }
381
382 return S_OK;
383}
384
385HRESULT RecordingScreenSettings::getFilename(com::Utf8Str &aFilename)
386{
387 AutoCaller autoCaller(this);
388 if (FAILED(autoCaller.rc())) return autoCaller.rc();
389
390 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
391
392 /* Get default file name if an empty string or a single "." is set. */
393 if ( m->bd->File.strName.isEmpty()
394 || m->bd->File.strName.equals("."))
395 {
396 int vrc = m->pParent->i_getDefaultFilename(aFilename, m->uScreenId, true /* fWithFileExtension */);
397 if (RT_FAILURE(vrc))
398 return setErrorBoth(E_INVALIDARG, vrc, tr("Error retrieving default file name"));
399
400 /* Important: Don't assign the default file name to File.strName, as this woulnd't be considered
401 * as default settings anymore! */
402 }
403 else /* Return custom file name. */
404 aFilename = m->bd->File.strName;
405
406 return S_OK;
407}
408
409HRESULT RecordingScreenSettings::setFilename(const com::Utf8Str &aFilename)
410{
411 AutoCaller autoCaller(this);
412 if (FAILED(autoCaller.rc())) return autoCaller.rc();
413
414 if (!m->pParent->i_canChangeSettings())
415 return setError(E_INVALIDARG, tr("Cannot change file name while recording is enabled"));
416
417 if (aFilename.isNotEmpty())
418 {
419 if (!RTPathStartsWithRoot(aFilename.c_str()))
420 return setError(E_INVALIDARG, tr("Recording file name '%s' is not absolute"), aFilename.c_str());
421 }
422
423 /** @todo Add more sanity? */
424
425 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
426
427 /* Note: When setting an empty file name, this will return the screen's default file name when using ::getFileName(). */
428 if (m->bd->File.strName != aFilename)
429 {
430 m->bd.backup();
431 m->bd->File.strName = aFilename;
432
433 alock.release();
434
435 m->pParent->i_onSettingsChanged();
436 }
437
438 return S_OK;
439}
440
441HRESULT RecordingScreenSettings::getMaxTime(ULONG *aMaxTimeS)
442{
443 AutoCaller autoCaller(this);
444 if (FAILED(autoCaller.rc())) return autoCaller.rc();
445
446 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
447
448 *aMaxTimeS = m->bd->ulMaxTimeS;
449
450 return S_OK;
451}
452
453HRESULT RecordingScreenSettings::setMaxTime(ULONG aMaxTimeS)
454{
455 AutoCaller autoCaller(this);
456 if (FAILED(autoCaller.rc())) return autoCaller.rc();
457
458 if (!m->pParent->i_canChangeSettings())
459 return setError(E_INVALIDARG, tr("Cannot change maximum time while recording is enabled"));
460
461 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
462
463 if (m->bd->ulMaxTimeS != aMaxTimeS)
464 {
465 m->bd.backup();
466 m->bd->ulMaxTimeS = aMaxTimeS;
467
468 alock.release();
469
470 m->pParent->i_onSettingsChanged();
471 }
472
473 return S_OK;
474}
475
476HRESULT RecordingScreenSettings::getMaxFileSize(ULONG *aMaxFileSizeMB)
477{
478 AutoCaller autoCaller(this);
479 if (FAILED(autoCaller.rc())) return autoCaller.rc();
480
481 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
482
483 *aMaxFileSizeMB = m->bd->File.ulMaxSizeMB;
484
485 return S_OK;
486}
487
488HRESULT RecordingScreenSettings::setMaxFileSize(ULONG aMaxFileSize)
489{
490 AutoCaller autoCaller(this);
491 if (FAILED(autoCaller.rc())) return autoCaller.rc();
492
493 if (!m->pParent->i_canChangeSettings())
494 return setError(E_INVALIDARG, tr("Cannot change maximum file size while recording is enabled"));
495
496 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
497
498 if (m->bd->File.ulMaxSizeMB != aMaxFileSize)
499 {
500 m->bd.backup();
501 m->bd->File.ulMaxSizeMB = aMaxFileSize;
502
503 alock.release();
504
505 m->pParent->i_onSettingsChanged();
506 }
507
508 return S_OK;
509}
510
511HRESULT RecordingScreenSettings::getOptions(com::Utf8Str &aOptions)
512{
513 AutoCaller autoCaller(this);
514 if (FAILED(autoCaller.rc())) return autoCaller.rc();
515
516 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
517
518 aOptions = m->bd->strOptions;
519
520 return S_OK;
521}
522
523HRESULT RecordingScreenSettings::setOptions(const com::Utf8Str &aOptions)
524{
525 AutoCaller autoCaller(this);
526 if (FAILED(autoCaller.rc())) return autoCaller.rc();
527
528 if (!m->pParent->i_canChangeSettings())
529 return setError(E_INVALIDARG, tr("Cannot change options while recording is enabled"));
530
531 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
532
533 int vrc = RecordingScreenSettings::i_parseOptionsString(aOptions, *m->bd.data());
534 if (RT_FAILURE(vrc))
535 return setError(E_INVALIDARG, tr("Invalid option specified"));
536
537 m->bd.backup();
538 m->bd->strOptions = aOptions;
539
540 alock.release();
541
542 m->pParent->i_onSettingsChanged();
543
544 return S_OK;
545}
546
547HRESULT RecordingScreenSettings::getAudioCodec(RecordingAudioCodec_T *aCodec)
548{
549 AutoCaller autoCaller(this);
550 if (FAILED(autoCaller.rc())) return autoCaller.rc();
551
552 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
553
554 *aCodec = m->bd->Audio.enmAudioCodec;
555
556 return S_OK;
557}
558
559HRESULT RecordingScreenSettings::setAudioCodec(RecordingAudioCodec_T aCodec)
560{
561 AutoCaller autoCaller(this);
562 if (FAILED(autoCaller.rc())) return autoCaller.rc();
563
564 if (!m->pParent->i_canChangeSettings())
565 return setError(E_INVALIDARG, tr("Cannot change audio codec while recording is enabled"));
566
567 if (aCodec != RecordingAudioCodec_Opus)
568 return setError(E_INVALIDARG, tr("Audio codec not supported"));
569
570 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
571
572 if (m->bd->Audio.enmAudioCodec != aCodec)
573 {
574 m->bd.backup();
575 m->bd->Audio.enmAudioCodec = aCodec;
576
577 alock.release();
578
579 m->pParent->i_onSettingsChanged();
580 }
581
582 return S_OK;
583}
584
585HRESULT RecordingScreenSettings::getAudioHz(ULONG *aHz)
586{
587 AutoCaller autoCaller(this);
588 if (FAILED(autoCaller.rc())) return autoCaller.rc();
589
590 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
591
592 *aHz = m->bd->Audio.uHz;
593
594 return S_OK;
595}
596
597HRESULT RecordingScreenSettings::setAudioHz(ULONG aHz)
598{
599 AutoCaller autoCaller(this);
600 if (FAILED(autoCaller.rc())) return autoCaller.rc();
601
602 if (!m->pParent->i_canChangeSettings())
603 return setError(E_INVALIDARG, tr("Cannot change audio Hertz rate while recording is enabled"));
604
605 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
606
607 if (m->bd->Audio.uHz != (uint16_t)aHz)
608 {
609 m->bd.backup();
610 m->bd->Audio.uHz = (uint16_t)aHz;
611
612 alock.release();
613
614 m->pParent->i_onSettingsChanged();
615 }
616
617 return S_OK;
618}
619
620HRESULT RecordingScreenSettings::getAudioBits(ULONG *aBits)
621{
622 AutoCaller autoCaller(this);
623 if (FAILED(autoCaller.rc())) return autoCaller.rc();
624
625 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
626
627 *aBits = m->bd->Audio.cBits;
628
629 return S_OK;
630}
631
632HRESULT RecordingScreenSettings::setAudioBits(ULONG aBits)
633{
634 AutoCaller autoCaller(this);
635 if (FAILED(autoCaller.rc())) return autoCaller.rc();
636
637 if (!m->pParent->i_canChangeSettings())
638 return setError(E_INVALIDARG, tr("Cannot change audio bits while recording is enabled"));
639
640 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
641
642 if (m->bd->Audio.cBits != (uint8_t)aBits)
643 {
644 m->bd.backup();
645 m->bd->Audio.cBits = (uint8_t)aBits;
646
647 alock.release();
648
649 m->pParent->i_onSettingsChanged();
650 }
651
652 return S_OK;
653}
654
655HRESULT RecordingScreenSettings::getAudioChannels(ULONG *aChannels)
656{
657 AutoCaller autoCaller(this);
658 if (FAILED(autoCaller.rc())) return autoCaller.rc();
659
660 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
661
662 *aChannels = m->bd->Audio.cChannels;
663
664 return S_OK;
665}
666
667HRESULT RecordingScreenSettings::setAudioChannels(ULONG aChannels)
668{
669 AutoCaller autoCaller(this);
670 if (FAILED(autoCaller.rc())) return autoCaller.rc();
671
672 if (!m->pParent->i_canChangeSettings())
673 return setError(E_INVALIDARG, tr("Cannot change audio channels while recording is enabled"));
674
675 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
676
677 if (m->bd->Audio.cChannels != (uint8_t)aChannels)
678 {
679 m->bd.backup();
680 m->bd->Audio.cChannels = (uint8_t)aChannels;
681
682 alock.release();
683
684 m->pParent->i_onSettingsChanged();
685 }
686
687 return S_OK;
688}
689
690HRESULT RecordingScreenSettings::getVideoCodec(RecordingVideoCodec_T *aCodec)
691{
692 AutoCaller autoCaller(this);
693 if (FAILED(autoCaller.rc())) return autoCaller.rc();
694
695 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
696
697 *aCodec = m->bd->Video.enmCodec;
698
699 return S_OK;
700}
701
702HRESULT RecordingScreenSettings::setVideoCodec(RecordingVideoCodec_T aCodec)
703{
704 AutoCaller autoCaller(this);
705 if (FAILED(autoCaller.rc())) return autoCaller.rc();
706
707 if (!m->pParent->i_canChangeSettings())
708 return setError(E_INVALIDARG, tr("Cannot change video codec while recording is enabled"));
709
710 if (aCodec != RecordingVideoCodec_VP8)
711 return setError(E_INVALIDARG, tr("Video codec not supported"));
712
713 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
714
715 if (m->bd->Video.enmCodec != aCodec)
716 {
717 m->bd.backup();
718 m->bd->Video.enmCodec = aCodec;
719
720 alock.release();
721
722 m->pParent->i_onSettingsChanged();
723 }
724
725 return S_OK;
726}
727
728HRESULT RecordingScreenSettings::getVideoWidth(ULONG *aVideoWidth)
729{
730 AutoCaller autoCaller(this);
731 if (FAILED(autoCaller.rc())) return autoCaller.rc();
732
733 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
734
735 *aVideoWidth = m->bd->Video.ulWidth;
736
737 return S_OK;
738}
739
740HRESULT RecordingScreenSettings::setVideoWidth(ULONG aVideoWidth)
741{
742 AutoCaller autoCaller(this);
743 if (FAILED(autoCaller.rc())) return autoCaller.rc();
744
745 if (!m->pParent->i_canChangeSettings())
746 return setError(E_INVALIDARG, tr("Cannot change video width while recording is enabled"));
747
748 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
749
750 if (m->bd->Video.ulWidth != aVideoWidth)
751 {
752 m->bd.backup();
753 m->bd->Video.ulWidth = aVideoWidth;
754
755 alock.release();
756
757 m->pParent->i_onSettingsChanged();
758 }
759
760 return S_OK;
761}
762
763HRESULT RecordingScreenSettings::getVideoHeight(ULONG *aVideoHeight)
764{
765 AutoCaller autoCaller(this);
766 if (FAILED(autoCaller.rc())) return autoCaller.rc();
767
768 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
769
770 *aVideoHeight = m->bd->Video.ulHeight;
771
772 return S_OK;
773}
774
775HRESULT RecordingScreenSettings::setVideoHeight(ULONG aVideoHeight)
776{
777 AutoCaller autoCaller(this);
778 if (FAILED(autoCaller.rc())) return autoCaller.rc();
779
780 if (!m->pParent->i_canChangeSettings())
781 return setError(E_INVALIDARG, tr("Cannot change video height while recording is enabled"));
782
783 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
784
785 if (m->bd->Video.ulHeight != aVideoHeight)
786 {
787 m->bd.backup();
788 m->bd->Video.ulHeight = aVideoHeight;
789
790 alock.release();
791
792 m->pParent->i_onSettingsChanged();
793 }
794
795 return S_OK;
796}
797
798HRESULT RecordingScreenSettings::getVideoRate(ULONG *aVideoRate)
799{
800 AutoCaller autoCaller(this);
801 if (FAILED(autoCaller.rc())) return autoCaller.rc();
802
803 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
804
805 *aVideoRate = m->bd->Video.ulRate;
806
807 return S_OK;
808}
809
810HRESULT RecordingScreenSettings::setVideoRate(ULONG aVideoRate)
811{
812 AutoCaller autoCaller(this);
813 if (FAILED(autoCaller.rc())) return autoCaller.rc();
814
815 if (!m->pParent->i_canChangeSettings())
816 return setError(E_INVALIDARG, tr("Cannot change video rate while recording is enabled"));
817
818 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
819
820 if (m->bd->Video.ulRate != aVideoRate)
821 {
822 m->bd.backup();
823 m->bd->Video.ulRate = aVideoRate;
824
825 alock.release();
826
827 m->pParent->i_onSettingsChanged();
828 }
829
830 return S_OK;
831}
832
833HRESULT RecordingScreenSettings::getVideoRateControlMode(RecordingVideoRateControlMode_T *aMode)
834{
835 AutoCaller autoCaller(this);
836 if (FAILED(autoCaller.rc())) return autoCaller.rc();
837
838 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
839
840 *aMode = RecordingVideoRateControlMode_CBR; /** @todo Implement VBR. */
841
842 return S_OK;
843}
844
845HRESULT RecordingScreenSettings::setVideoRateControlMode(RecordingVideoRateControlMode_T aMode)
846{
847 AutoCaller autoCaller(this);
848 if (FAILED(autoCaller.rc())) return autoCaller.rc();
849
850 if (!m->pParent->i_canChangeSettings())
851 return setError(E_INVALIDARG, tr("Cannot change video rate control mode while recording is enabled"));
852
853 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
854
855 /** @todo Implement this. */
856 RT_NOREF(aMode);
857
858 return E_NOTIMPL;
859}
860
861HRESULT RecordingScreenSettings::getVideoFPS(ULONG *aVideoFPS)
862{
863 AutoCaller autoCaller(this);
864 if (FAILED(autoCaller.rc())) return autoCaller.rc();
865
866 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
867
868 *aVideoFPS = m->bd->Video.ulFPS;
869
870 return S_OK;
871}
872
873HRESULT RecordingScreenSettings::setVideoFPS(ULONG aVideoFPS)
874{
875 AutoCaller autoCaller(this);
876 if (FAILED(autoCaller.rc())) return autoCaller.rc();
877
878 if (!m->pParent->i_canChangeSettings())
879 return setError(E_INVALIDARG, tr("Cannot change video FPS while recording is enabled"));
880
881 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
882
883 if (m->bd->Video.ulFPS != aVideoFPS)
884 {
885 m->bd.backup();
886 m->bd->Video.ulFPS = aVideoFPS;
887
888 alock.release();
889
890 m->pParent->i_onSettingsChanged();
891 }
892
893 return S_OK;
894}
895
896HRESULT RecordingScreenSettings::getVideoScalingMethod(RecordingVideoScalingMethod_T *aMode)
897{
898 AutoCaller autoCaller(this);
899 if (FAILED(autoCaller.rc())) return autoCaller.rc();
900
901 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
902
903 *aMode = RecordingVideoScalingMethod_None; /** @todo Implement this. */
904
905 return S_OK;
906}
907
908HRESULT RecordingScreenSettings::setVideoScalingMethod(RecordingVideoScalingMethod_T aMode)
909{
910 AutoCaller autoCaller(this);
911 if (FAILED(autoCaller.rc())) return autoCaller.rc();
912
913 if (!m->pParent->i_canChangeSettings())
914 return setError(E_INVALIDARG, tr("Cannot change video rate scaling method while recording is enabled"));
915
916 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
917
918 /** @todo Implement this. */
919 RT_NOREF(aMode);
920
921 return E_NOTIMPL;
922}
923
924/**
925 * Initializes data, internal version.
926 *
927 * @returns VBox status code.
928 */
929int RecordingScreenSettings::i_initInternal(void)
930{
931 AssertPtrReturn(m, VERR_INVALID_POINTER);
932
933 int vrc = i_parseOptionsString(m->bd->strOptions, *m->bd.data());
934 if (RT_FAILURE(vrc))
935 return vrc;
936
937 switch (m->bd->enmDest)
938 {
939 case RecordingDestination_File:
940 {
941 /* Note: Leave the file name empty here, which means using the default setting.
942 * Important when comparing with the default settings! */
943 break;
944 }
945
946 default:
947 break;
948 }
949
950 return vrc;
951}
952
953
954// public methods only for internal purposes
955////////////////////////////////////////////////////////////////////////////////
956
957/**
958 * Loads settings from the given machine node.
959 * May be called once right after this object creation.
960 *
961 * @returns HRESULT
962 * @param data Configuration settings to load.
963 */
964HRESULT RecordingScreenSettings::i_loadSettings(const settings::RecordingScreenSettings &data)
965{
966 AutoCaller autoCaller(this);
967 AssertComRCReturnRC(autoCaller.rc());
968
969 AutoReadLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
970 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
971
972 // simply copy
973 m->bd.assignCopy(&data);
974 return S_OK;
975}
976
977/**
978 * Saves settings to the given machine node.
979 *
980 * @returns HRESULT
981 * @param data Configuration settings to save to.
982 */
983HRESULT RecordingScreenSettings::i_saveSettings(settings::RecordingScreenSettings &data)
984{
985 /* sanity */
986 AutoCaller autoCaller(this);
987 AssertComRCReturnRC(autoCaller.rc());
988
989 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
990
991 data = *m->bd.data();
992
993 return S_OK;
994}
995
996void RecordingScreenSettings::i_rollback(void)
997{
998 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
999 m->bd.rollback();
1000}
1001
1002void RecordingScreenSettings::i_commit(void)
1003{
1004 /* sanity */
1005 AutoCaller autoCaller(this);
1006 AssertComRCReturnVoid(autoCaller.rc());
1007
1008 /* sanity too */
1009 AutoCaller peerCaller(m->pPeer);
1010 AssertComRCReturnVoid(peerCaller.rc());
1011
1012 /* lock both for writing since we modify both (mPeer is "master" so locked
1013 * first) */
1014 AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
1015
1016 if (m->bd.isBackedUp())
1017 {
1018 m->bd.commit();
1019 if (m->pPeer)
1020 {
1021 /* attach new data to the peer and reshare it */
1022 AutoWriteLock peerlock(m->pPeer COMMA_LOCKVAL_SRC_POS);
1023 m->pPeer->m->bd.attach(m->bd);
1024 }
1025 }
1026}
1027
1028void RecordingScreenSettings::i_copyFrom(RecordingScreenSettings *aThat)
1029{
1030 AssertReturnVoid(aThat != NULL);
1031
1032 /* sanity */
1033 AutoCaller autoCaller(this);
1034 AssertComRCReturnVoid(autoCaller.rc());
1035
1036 /* sanity too */
1037 AutoCaller thatCaller(aThat);
1038 AssertComRCReturnVoid(thatCaller.rc());
1039
1040 /* peer is not modified, lock it for reading (aThat is "master" so locked
1041 * first) */
1042 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
1043 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
1044
1045 /* this will back up current data */
1046 m->bd.assignCopy(aThat->m->bd);
1047}
1048
1049/**
1050 * Applies default screen recording settings.
1051 *
1052 * @note Locks this object for writing.
1053 */
1054void RecordingScreenSettings::i_applyDefaults(void)
1055{
1056 /* sanity */
1057 AutoCaller autoCaller(this);
1058 AssertComRCReturnVoid(autoCaller.rc());
1059
1060 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1061
1062 m->bd->applyDefaults();
1063}
1064
1065settings::RecordingScreenSettings &RecordingScreenSettings::i_getData(void)
1066{
1067 /* sanity */
1068 AutoCaller autoCaller(this);
1069 AssertComRC(autoCaller.rc());
1070
1071 AssertPtr(m);
1072 return *m->bd.data();
1073}
1074
1075/**
1076 * Parses a recording screen options string and stores the parsed result in the specified screen settings.
1077 *
1078 * @returns IPRT status code.
1079 * @param strOptions Options string to parse.
1080 * @param screenSettings Where to store the parsed result into.
1081 */
1082/* static */
1083int RecordingScreenSettings::i_parseOptionsString(const com::Utf8Str &strOptions,
1084 settings::RecordingScreenSettings &screenSettings)
1085{
1086 /*
1087 * Parse options string.
1088 */
1089 size_t pos = 0;
1090 com::Utf8Str key, value;
1091 while ((pos = strOptions.parseKeyValue(key, value, pos)) != com::Utf8Str::npos)
1092 {
1093 if (key.compare("vc_quality", Utf8Str::CaseInsensitive) == 0)
1094 {
1095#ifdef VBOX_WITH_LIBVPX
1096 if (value.compare("realtime", Utf8Str::CaseInsensitive) == 0)
1097 mVideoRecCfg.Video.Codec.VPX.uEncoderDeadline = VPX_DL_REALTIME;
1098 else if (value.compare("good", Utf8Str::CaseInsensitive) == 0)
1099 mVideoRecCfg.Video.Codec.VPX.uEncoderDeadline = 1000000 / mVideoRecCfg.Video.uFPS;
1100 else if (value.compare("best", Utf8Str::CaseInsensitive) == 0)
1101 mVideoRecCfg.Video.Codec.VPX.uEncoderDeadline = VPX_DL_BEST_QUALITY;
1102 else
1103 {
1104 mVideoRecCfg.Video.Codec.VPX.uEncoderDeadline = value.toUInt32();
1105 }
1106#endif
1107 }
1108 else if (key.compare("vc_enabled", Utf8Str::CaseInsensitive) == 0)
1109 {
1110 if (value.compare("false", Utf8Str::CaseInsensitive) == 0)
1111 {
1112 screenSettings.featureMap[RecordingFeature_Video] = false;
1113 }
1114 }
1115 else if (key.compare("ac_enabled", Utf8Str::CaseInsensitive) == 0)
1116 {
1117#ifdef VBOX_WITH_AUDIO_RECORDING
1118 if (value.compare("true", Utf8Str::CaseInsensitive) == 0)
1119 {
1120 screenSettings.featureMap[RecordingFeature_Audio] = true;
1121 }
1122#endif
1123 }
1124 else if (key.compare("ac_profile", Utf8Str::CaseInsensitive) == 0)
1125 {
1126#ifdef VBOX_WITH_AUDIO_RECORDING
1127 if (value.compare("low", Utf8Str::CaseInsensitive) == 0)
1128 {
1129 screenSettings.Audio.uHz = 8000;
1130 screenSettings.Audio.cBits = 16;
1131 screenSettings.Audio.cChannels = 1;
1132 }
1133 else if (value.startsWith("med" /* "med[ium]" */, Utf8Str::CaseInsensitive) == 0)
1134 {
1135 /* Stay with the default set above. */
1136 }
1137 else if (value.compare("high", Utf8Str::CaseInsensitive) == 0)
1138 {
1139 screenSettings.Audio.uHz = 48000;
1140 screenSettings.Audio.cBits = 16;
1141 screenSettings.Audio.cChannels = 2;
1142 }
1143#endif
1144 }
1145 /* else just ignore. */
1146
1147 } /* while */
1148
1149 return VINF_SUCCESS;
1150}
1151
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette