VirtualBox

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

最後變更 在這個檔案從96172是 96172,由 vboxsync 提交於 3 年 前

Recording/Main: Changed IRecordingScreenSettings::features attribute to get/set a safe array of RecordingFeature entries instead of an anonymous ULONG. Makes it much easier to use. bugref:10275

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

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