VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/RecordingSettingsImpl.cpp@ 96137

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

Recording/Main: Propagate errors further up, to let clients ask IRecordingSettings directly what actually went wrong via IVirtualBoxErrorInfo. ​bugref:10275

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.8 KB
Line 
1/* $Id: RecordingSettingsImpl.cpp 96137 2022-08-11 14:35:45Z vboxsync $ */
2/** @file
3 *
4 * VirtualBox COM class implementation - Machine capture settings.
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_RECORDINGSETTINGS
20#include "LoggingNew.h"
21
22#include "RecordingSettingsImpl.h"
23#include "RecordingScreenSettingsImpl.h"
24#include "MachineImpl.h"
25
26#include <iprt/cpp/utils.h>
27#include <VBox/settings.h>
28
29#include "AutoStateDep.h"
30#include "AutoCaller.h"
31#include "Global.h"
32
33////////////////////////////////////////////////////////////////////////////////
34//
35// RecordSettings private data definition
36//
37////////////////////////////////////////////////////////////////////////////////
38
39struct RecordingSettings::Data
40{
41 Data()
42 : pMachine(NULL)
43 { }
44
45 Machine * const pMachine;
46 const ComObjPtr<RecordingSettings> pPeer;
47 RecordingScreenSettingsObjMap mapScreenObj;
48
49 // use the XML settings structure in the members for simplicity
50 Backupable<settings::RecordingCommonSettings> bd;
51};
52
53DEFINE_EMPTY_CTOR_DTOR(RecordingSettings)
54
55HRESULT RecordingSettings::FinalConstruct()
56{
57 return BaseFinalConstruct();
58}
59
60void RecordingSettings::FinalRelease()
61{
62 uninit();
63 BaseFinalRelease();
64}
65
66/**
67 * Initializes the recording settings object.
68 *
69 * @returns COM result indicator
70 */
71HRESULT RecordingSettings::init(Machine *aParent)
72{
73 LogFlowThisFuncEnter();
74 LogFlowThisFunc(("aParent: %p\n", aParent));
75
76 ComAssertRet(aParent, E_INVALIDARG);
77
78 /* Enclose the state transition NotReady->InInit->Ready */
79 AutoInitSpan autoInitSpan(this);
80 AssertReturn(autoInitSpan.isOk(), E_FAIL);
81
82 m = new Data();
83
84 /* share the parent weakly */
85 unconst(m->pMachine) = aParent;
86
87 m->bd.allocate();
88
89 i_applyDefaults();
90
91 autoInitSpan.setSucceeded();
92
93 LogFlowThisFuncLeave();
94 return S_OK;
95}
96
97/**
98 * Initializes the capture settings object given another capture settings object
99 * (a kind of copy constructor). This object shares data with
100 * the object passed as an argument.
101 *
102 * @note This object must be destroyed before the original object
103 * it shares data with is destroyed.
104 *
105 * @note Locks @a aThat object for reading.
106 */
107HRESULT RecordingSettings::init(Machine *aParent, RecordingSettings *aThat)
108{
109 LogFlowThisFuncEnter();
110 LogFlowThisFunc(("aParent: %p, aThat: %p\n", aParent, aThat));
111
112 ComAssertRet(aParent && aThat, E_INVALIDARG);
113
114 /* Enclose the state transition NotReady->InInit->Ready */
115 AutoInitSpan autoInitSpan(this);
116 AssertReturn(autoInitSpan.isOk(), E_FAIL);
117
118 m = new Data();
119
120 unconst(m->pMachine) = aParent;
121 unconst(m->pPeer) = aThat;
122
123 AutoCaller thatCaller(aThat);
124 AssertComRCReturnRC(thatCaller.rc());
125
126 AutoReadLock thatlock(aThat COMMA_LOCKVAL_SRC_POS);
127
128 m->bd.share(aThat->m->bd);
129
130 /* Make sure to add a reference when sharing the screen objects with aThat. */
131 for (RecordingScreenSettingsObjMap::const_iterator itScreenThat = aThat->m->mapScreenObj.begin();
132 itScreenThat != aThat->m->mapScreenObj.end();
133 ++itScreenThat)
134 itScreenThat->second->i_reference();
135
136 m->mapScreenObj = aThat->m->mapScreenObj;
137
138 autoInitSpan.setSucceeded();
139
140 LogFlowThisFuncLeave();
141 return S_OK;
142}
143
144/**
145 * Initializes the guest object given another guest object
146 * (a kind of copy constructor). This object makes a private copy of data
147 * of the original object passed as an argument.
148 *
149 * @note Locks @a aThat object for reading.
150 */
151HRESULT RecordingSettings::initCopy(Machine *aParent, RecordingSettings *aThat)
152{
153 LogFlowThisFuncEnter();
154 LogFlowThisFunc(("aParent: %p, aThat: %p\n", aParent, aThat));
155
156 ComAssertRet(aParent && aThat, E_INVALIDARG);
157
158 /* Enclose the state transition NotReady->InInit->Ready */
159 AutoInitSpan autoInitSpan(this);
160 AssertReturn(autoInitSpan.isOk(), E_FAIL);
161
162 m = new Data();
163
164 unconst(m->pMachine) = aParent;
165 // mPeer is left null
166
167 AutoReadLock thatlock(aThat COMMA_LOCKVAL_SRC_POS);
168 m->bd.attachCopy(aThat->m->bd);
169
170 HRESULT hrc = S_OK;
171
172 for (RecordingScreenSettingsObjMap::const_iterator itScreenThat = aThat->m->mapScreenObj.begin();
173 itScreenThat != aThat->m->mapScreenObj.end();
174 ++itScreenThat)
175 {
176 ComObjPtr<RecordingScreenSettings> pSettings;
177 pSettings.createObject();
178 hrc = pSettings->initCopy(this, itScreenThat->second);
179 if (FAILED(hrc)) return hrc;
180
181 try
182 {
183 m->mapScreenObj[itScreenThat->first] = pSettings;
184 }
185 catch (...)
186 {
187 hrc = E_OUTOFMEMORY;
188 }
189 }
190
191 if (SUCCEEDED(hrc))
192 autoInitSpan.setSucceeded();
193
194 LogFlowThisFuncLeave();
195 return hrc;
196}
197
198/**
199 * Uninitializes the instance and sets the ready flag to FALSE.
200 * Called either from FinalRelease() or by the parent when it gets destroyed.
201 */
202void RecordingSettings::uninit()
203{
204 LogFlowThisFuncEnter();
205
206 /* Enclose the state transition Ready->InUninit->NotReady */
207 AutoUninitSpan autoUninitSpan(this);
208 if (autoUninitSpan.uninitDone())
209 return;
210
211 /* Make sure to destroy screen objects attached to this object.
212 * Note: This also decrements the refcount of a screens object, in case it's shared among other recording settings. */
213 i_destroyAllScreenObj(m->mapScreenObj);
214
215 m->bd.free();
216
217 unconst(m->pPeer) = NULL;
218 unconst(m->pMachine) = NULL;
219
220 delete m;
221 m = NULL;
222
223 LogFlowThisFuncLeave();
224}
225
226// IRecordSettings properties
227/////////////////////////////////////////////////////////////////////////////
228
229HRESULT RecordingSettings::getEnabled(BOOL *enabled)
230{
231 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
232
233 *enabled = m->bd->fEnabled;
234
235 return S_OK;
236}
237
238HRESULT RecordingSettings::setEnabled(BOOL enable)
239{
240 /* the machine needs to be mutable */
241 AutoMutableOrSavedOrRunningStateDependency adep(m->pMachine);
242 if (FAILED(adep.rc())) return adep.rc();
243
244 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
245
246 const bool fEnabled = RT_BOOL(enable);
247
248 HRESULT hrc = S_OK;
249
250 if (m->bd->fEnabled != fEnabled)
251 {
252 m->bd.backup();
253 m->bd->fEnabled = fEnabled;
254
255 alock.release();
256
257 hrc = m->pMachine->i_onRecordingChange(enable);
258 if (FAILED(hrc))
259 {
260 com::ErrorInfo errMachine; /* Get error info from machine call above. */
261
262 /*
263 * Normally we would do the actual change _after_ i_onRecordingChange() succeeded.
264 * We cannot do this because that function uses RecordSettings::GetEnabled to
265 * determine if it should start or stop capturing. Therefore we need to manually
266 * undo change.
267 */
268 alock.acquire();
269 m->bd->fEnabled = m->bd.backedUpData()->fEnabled;
270
271 if (errMachine.isBasicAvailable())
272 hrc = setError(errMachine);
273 }
274 else
275 {
276 AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS); // pMachine is const, needs no locking
277 m->pMachine->i_setModified(Machine::IsModified_Recording);
278
279 /* Make sure to release the mutable dependency lock from above before
280 * actually saving the settings. */
281 adep.release();
282
283 /** Save settings if online - @todo why is this required? -- @bugref{6818} */
284 if (Global::IsOnline(m->pMachine->i_getMachineState()))
285 {
286 com::ErrorInfo errMachine;
287 hrc = m->pMachine->i_saveSettings(NULL, mlock);
288 if (FAILED(hrc))
289 {
290 /* Got error info from machine call above. */
291 if (errMachine.isBasicAvailable())
292 hrc = setError(errMachine);
293 }
294 }
295 }
296 }
297
298 return hrc;
299}
300
301HRESULT RecordingSettings::getScreens(std::vector<ComPtr<IRecordingScreenSettings> > &aRecordScreenSettings)
302{
303 LogFlowThisFuncEnter();
304
305 AssertPtr(m->pMachine);
306 ComPtr<IGraphicsAdapter> pGraphicsAdapter;
307 m->pMachine->COMGETTER(GraphicsAdapter)(pGraphicsAdapter.asOutParam());
308 ULONG cMonitors = 0;
309 if (!pGraphicsAdapter.isNull())
310 pGraphicsAdapter->COMGETTER(MonitorCount)(&cMonitors);
311
312 i_syncToMachineDisplays(cMonitors);
313
314 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
315
316 HRESULT hrc = S_OK;
317
318 try
319 {
320 aRecordScreenSettings.clear();
321 aRecordScreenSettings.resize(m->mapScreenObj.size());
322 }
323 catch (...)
324 {
325 hrc = E_OUTOFMEMORY;
326 }
327
328 if (FAILED(hrc))
329 return hrc;
330
331 RecordingScreenSettingsObjMap::const_iterator itScreenObj = m->mapScreenObj.begin();
332 size_t i = 0;
333 while (itScreenObj != m->mapScreenObj.end())
334 {
335 itScreenObj->second.queryInterfaceTo(aRecordScreenSettings[i].asOutParam());
336 AssertBreakStmt(aRecordScreenSettings[i].isNotNull(), hrc = E_POINTER);
337 ++i;
338 ++itScreenObj;
339 }
340
341 Assert(aRecordScreenSettings.size() == m->mapScreenObj.size());
342
343 return hrc;
344}
345
346HRESULT RecordingSettings::getScreenSettings(ULONG uScreenId, ComPtr<IRecordingScreenSettings> &aRecordScreenSettings)
347{
348 LogFlowThisFuncEnter();
349
350 AssertPtr(m->pMachine);
351 ComPtr<IGraphicsAdapter> pGraphicsAdapter;
352 m->pMachine->COMGETTER(GraphicsAdapter)(pGraphicsAdapter.asOutParam());
353 ULONG cMonitors = 0;
354 if (!pGraphicsAdapter.isNull())
355 pGraphicsAdapter->COMGETTER(MonitorCount)(&cMonitors);
356
357 i_syncToMachineDisplays(cMonitors);
358
359 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
360
361 if (uScreenId + 1 > m->mapScreenObj.size())
362 return setError(E_INVALIDARG, tr("Invalid screen ID specified"));
363
364 RecordingScreenSettingsObjMap::const_iterator itScreen = m->mapScreenObj.find(uScreenId);
365 if (itScreen != m->mapScreenObj.end())
366 {
367 itScreen->second.queryInterfaceTo(aRecordScreenSettings.asOutParam());
368 return S_OK;
369 }
370
371 return VBOX_E_OBJECT_NOT_FOUND;
372}
373
374// IRecordSettings methods
375/////////////////////////////////////////////////////////////////////////////
376
377// public methods only for internal purposes
378/////////////////////////////////////////////////////////////////////////////
379
380/**
381 * Adds a screen settings object to a particular map.
382 *
383 * @returns IPRT status code. VERR_ALREADY_EXISTS if the object in question already exists.
384 * @param screenSettingsMap Map to add screen settings to.
385 * @param idScreen Screen ID to add settings for.
386 * @param data Recording screen settings to use for that screen.
387 */
388int RecordingSettings::i_createScreenObj(RecordingScreenSettingsObjMap &screenSettingsMap,
389 uint32_t idScreen, const settings::RecordingScreenSettings &data)
390{
391 AssertReturn(screenSettingsMap.find(idScreen) == screenSettingsMap.end(), VERR_ALREADY_EXISTS);
392
393 int vrc = VINF_SUCCESS;
394
395 ComObjPtr<RecordingScreenSettings> recordingScreenSettings;
396 HRESULT hrc = recordingScreenSettings.createObject();
397 if (SUCCEEDED(hrc))
398 {
399 hrc = recordingScreenSettings->init(this, idScreen, data);
400 if (SUCCEEDED(hrc))
401 {
402 try
403 {
404 screenSettingsMap[idScreen] = recordingScreenSettings;
405 }
406 catch (std::bad_alloc &)
407 {
408 vrc = VERR_NO_MEMORY;
409 }
410 }
411 }
412
413 LogThisFunc(("%p: Screen %RU32 -> %Rrc\n", recordingScreenSettings.m_p, idScreen, vrc));
414 return vrc;
415}
416
417/**
418 * Removes a screen settings object from a particular map.
419 *
420 * If the internal reference count hits 0, the screen settings object will be destroyed.
421 * This means that this screen settings object is not being used anymore by other recording settings (as shared data).
422 *
423 * @returns IPRT status code.
424 * @retval VERR_NOT_FOUND if specified screen was not found.
425 * @param screenSettingsMap Map to remove screen settings from.
426 * @param idScreen ID of screen to remove.
427 */
428int RecordingSettings::i_destroyScreenObj(RecordingScreenSettingsObjMap &screenSettingsMap, uint32_t idScreen)
429{
430 AssertReturn(screenSettingsMap.find(idScreen) != screenSettingsMap.end(), VERR_NOT_FOUND);
431
432 RecordingScreenSettingsObjMap::iterator itScreen = screenSettingsMap.find(idScreen);
433
434 /* Make sure to consume the pointer before the one of the
435 * iterator gets released. */
436 ComObjPtr<RecordingScreenSettings> pScreenSettings = itScreen->second;
437
438 screenSettingsMap.erase(itScreen);
439
440 LogThisFunc(("%p: Screen %RU32, cRefs=%RI32\n", pScreenSettings.m_p, idScreen, pScreenSettings->i_getReferences()));
441
442 pScreenSettings->i_release();
443
444 /* Only destroy the object if nobody else keeps a reference to it anymore. */
445 if (pScreenSettings->i_getReferences() == 0)
446 {
447 LogThisFunc(("%p: Screen %RU32 -> Null\n", pScreenSettings.m_p, idScreen));
448 pScreenSettings.setNull();
449 }
450
451 return VINF_SUCCESS;
452}
453
454/**
455 * Destroys all screen settings objects of a particular map.
456 *
457 * @returns IPRT status code.
458 * @param screenSettingsMap Map to destroy screen settings objects for.
459 */
460int RecordingSettings::i_destroyAllScreenObj(RecordingScreenSettingsObjMap &screenSettingsMap)
461{
462 LogFlowThisFuncEnter();
463
464 int vrc = VINF_SUCCESS;
465
466 RecordingScreenSettingsObjMap::iterator itScreen = screenSettingsMap.begin();
467 while (itScreen != screenSettingsMap.end())
468 {
469 vrc = i_destroyScreenObj(screenSettingsMap, itScreen->first);
470 if (RT_FAILURE(vrc))
471 break;
472
473 itScreen = screenSettingsMap.begin();
474 }
475
476 Assert(screenSettingsMap.size() == 0);
477 return vrc;
478}
479
480/**
481 * Loads settings from the given settings.
482 * May be called once right after this object creation.
483 *
484 * @param data Capture settings to load from.
485 *
486 * @note Locks this object for writing.
487 */
488HRESULT RecordingSettings::i_loadSettings(const settings::RecordingSettings &data)
489{
490 LogFlowThisFuncEnter();
491
492 AutoCaller autoCaller(this);
493 AssertComRCReturnRC(autoCaller.rc());
494
495 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
496
497 HRESULT hrc = S_OK;
498
499 LogFlowThisFunc(("Data has %zu screens\n", data.mapScreens.size()));
500
501 settings::RecordingScreenSettingsMap::const_iterator itScreenData = data.mapScreens.begin();
502 while (itScreenData != data.mapScreens.end())
503 {
504 RecordingScreenSettingsObjMap::iterator itScreen = m->mapScreenObj.find(itScreenData->first);
505 if (itScreen != m->mapScreenObj.end())
506 {
507 hrc = itScreen->second->i_loadSettings(itScreenData->second);
508 if (FAILED(hrc))
509 break;
510 }
511 else
512 {
513 int vrc = i_createScreenObj(m->mapScreenObj,
514 itScreenData->first /* uScreenId */, itScreenData->second /* Settings */);
515 if (RT_FAILURE(vrc))
516 {
517 hrc = E_OUTOFMEMORY; /* Most likely. */
518 break;
519 }
520 }
521
522 ++itScreenData;
523 }
524
525 if (SUCCEEDED(hrc))
526 {
527 ComAssertComRCRet(hrc, hrc);
528 AssertReturn(m->mapScreenObj.size() == data.mapScreens.size(), E_UNEXPECTED);
529
530 // simply copy
531 m->bd.assignCopy(&data.common);
532 }
533
534 LogFlowThisFunc(("Returning %Rhrc\n", hrc));
535 return hrc;
536}
537
538/**
539 * Resets the internal object state by destroying all screen settings objects.
540 */
541void RecordingSettings::i_reset(void)
542{
543 LogFlowThisFuncEnter();
544
545 i_destroyAllScreenObj(m->mapScreenObj);
546}
547
548/**
549 * Saves settings to the given settings.
550 *
551 * @param data Where to store the capture settings to.
552 *
553 * @note Locks this object for reading.
554 */
555HRESULT RecordingSettings::i_saveSettings(settings::RecordingSettings &data)
556{
557 LogFlowThisFuncEnter();
558
559 AutoCaller autoCaller(this);
560 AssertComRCReturnRC(autoCaller.rc());
561
562 AssertPtr(m->pMachine);
563 ComPtr<IGraphicsAdapter> pGraphicsAdapter;
564 m->pMachine->COMGETTER(GraphicsAdapter)(pGraphicsAdapter.asOutParam());
565 ULONG cMonitors = 0;
566 if (!pGraphicsAdapter.isNull())
567 pGraphicsAdapter->COMGETTER(MonitorCount)(&cMonitors);
568
569 int rc2 = i_syncToMachineDisplays(cMonitors);
570 AssertRC(rc2);
571
572 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
573
574 data.common = *m->bd.data();
575
576 HRESULT hrc = S_OK;
577
578 for (RecordingScreenSettingsObjMap::const_iterator itScreen = m->mapScreenObj.begin();
579 itScreen != m->mapScreenObj.end();
580 ++itScreen)
581 {
582 hrc = itScreen->second->i_saveSettings(data.mapScreens[itScreen->first /* Screen ID */]);
583 if (FAILED(hrc))
584 break;
585 }
586
587 LogFlowThisFuncLeave();
588 return hrc;
589}
590
591void RecordingSettings::i_rollback(void)
592{
593 /* sanity */
594 AutoCaller autoCaller(this);
595 AssertComRCReturnVoid(autoCaller.rc());
596
597 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
598
599 m->bd.rollback();
600
601 for (RecordingScreenSettingsObjMap::const_iterator itScreen = m->mapScreenObj.begin();
602 itScreen != m->mapScreenObj.end();
603 ++itScreen)
604 {
605 itScreen->second->i_rollback();
606 }
607}
608
609void RecordingSettings::i_commit(void)
610{
611 /* sanity */
612 AutoCaller autoCaller(this);
613 AssertComRCReturnVoid(autoCaller.rc());
614
615 /* sanity too */
616 AutoCaller peerCaller(m->pPeer);
617 AssertComRCReturnVoid(peerCaller.rc());
618
619 /* lock both for writing since we modify both (mPeer is "master" so locked
620 * first) */
621 AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
622
623 if (m->bd.isBackedUp())
624 {
625 m->bd.commit();
626 if (m->pPeer)
627 {
628 /* attach new data to the peer and reshare it */
629 m->pPeer->m->bd.attach(m->bd);
630 }
631
632 for (RecordingScreenSettingsObjMap::const_iterator itScreenObj = m->mapScreenObj.begin();
633 itScreenObj != m->mapScreenObj.end();
634 ++itScreenObj)
635 {
636 itScreenObj->second->i_commit();
637 if (m->pPeer)
638 m->pPeer->i_commit();
639 }
640 }
641}
642
643HRESULT RecordingSettings::i_copyFrom(RecordingSettings *aThat)
644{
645 AssertPtrReturn(aThat, E_INVALIDARG);
646
647 /* sanity */
648 AutoCaller autoCaller(this);
649 AssertComRCReturn(autoCaller.rc(), VBOX_E_INVALID_OBJECT_STATE);
650
651 /* sanity too */
652 AutoCaller thatCaller(aThat);
653 AssertComRCReturn(thatCaller.rc(), VBOX_E_INVALID_OBJECT_STATE);
654
655 /* peer is not modified, lock it for reading (aThat is "master" so locked
656 * first) */
657 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
658 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
659
660 /* this will back up current data */
661 m->bd.assignCopy(aThat->m->bd);
662
663 HRESULT hrc = S_OK;
664
665 for (RecordingScreenSettingsObjMap::const_iterator itScreenThat = aThat->m->mapScreenObj.begin();
666 itScreenThat != aThat->m->mapScreenObj.end();
667 ++itScreenThat)
668 {
669 RecordingScreenSettingsObjMap::iterator itScreen = m->mapScreenObj.find(itScreenThat->first);
670 if (itScreen != m->mapScreenObj.end())
671 {
672 itScreen->second->i_copyFrom(itScreenThat->second);
673 }
674 else
675 {
676 int vrc = i_createScreenObj(m->mapScreenObj,
677 itScreenThat->first /* uScreenId */, itScreenThat->second->i_getData() /* Settings */);
678 if (RT_FAILURE(vrc))
679 {
680 hrc = E_OUTOFMEMORY; /* Most likely. */
681 break;
682 }
683 }
684 }
685
686 return hrc;
687}
688
689void RecordingSettings::i_applyDefaults(void)
690{
691 /* sanity */
692 AutoCaller autoCaller(this);
693 AssertComRCReturnVoid(autoCaller.rc());
694
695 AssertPtr(m->pMachine);
696 ComPtr<IGraphicsAdapter> pGraphicsAdapter;
697 m->pMachine->COMGETTER(GraphicsAdapter)(pGraphicsAdapter.asOutParam());
698 ULONG cMonitors = 0;
699 if (!pGraphicsAdapter.isNull())
700 pGraphicsAdapter->COMGETTER(MonitorCount)(&cMonitors);
701
702 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
703
704 /* Initialize default capturing settings here. */
705 m->bd->fEnabled = false;
706
707 /* First, do a reset so that all internal screen settings objects are destroyed. */
708 i_reset();
709 /* Second, sync (again) to configured machine displays to (re-)create screen settings objects. */
710 i_syncToMachineDisplays(cMonitors);
711}
712
713/**
714 * Returns the full path to the default recording file.
715 */
716int RecordingSettings::i_getDefaultFilename(Utf8Str &strFile, uint32_t idScreen, bool fWithFileExtension)
717{
718 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
719
720 strFile = m->pMachine->i_getSettingsFileFull(); // path/to/machinesfolder/vmname/vmname.vbox
721 strFile.stripSuffix();
722 strFile.append(Utf8StrFmt("-screen%RU32", idScreen));
723 if (fWithFileExtension)
724 strFile.append(".webm");
725
726 return VINF_SUCCESS;
727}
728
729/**
730 * Determines whether the recording settings currently can be changed or not.
731 *
732 * @returns \c true if the settings can be changed, \c false if not.
733 */
734bool RecordingSettings::i_canChangeSettings(void)
735{
736 AutoAnyStateDependency adep(m->pMachine);
737 if (FAILED(adep.rc()))
738 return false;
739
740 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
741
742 /* Only allow settings to be changed when recording is disabled when the machine is running. */
743 if ( Global::IsOnline(adep.machineState())
744 && m->bd->fEnabled)
745 {
746 return false;
747 }
748
749 return true;
750}
751
752/**
753 * Gets called when the machine object needs to know that the recording settings
754 * have been changed.
755 */
756void RecordingSettings::i_onSettingsChanged(void)
757{
758 LogFlowThisFuncEnter();
759
760 AutoWriteLock mlock(m->pMachine COMMA_LOCKVAL_SRC_POS);
761 m->pMachine->i_setModified(Machine::IsModified_Recording);
762 mlock.release();
763
764 LogFlowThisFuncLeave();
765}
766
767/**
768 * Synchronizes the screen settings (COM) objects and configuration data
769 * to the number of the machine's configured displays.
770 *
771 * Note: This function ASSUMES that we always have configured VM displays
772 * as a consequtive sequence with no holes in between.
773 */
774int RecordingSettings::i_syncToMachineDisplays(uint32_t cDisplays)
775{
776 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
777
778 LogThisFunc(("%p: cDisplays=%RU32 vs. %zu\n", this, cDisplays, m->mapScreenObj.size()));
779
780 /* If counts match, take a shortcut. */
781 if (cDisplays == m->mapScreenObj.size())
782 return VINF_SUCCESS;
783
784 /* Create all new screen settings objects which are not there yet. */
785 for (ULONG i = 0; i < cDisplays; i++)
786 {
787 if (m->mapScreenObj.find(i) == m->mapScreenObj.end())
788 {
789 settings::RecordingScreenSettings defaultScreenSettings(i /* Screen ID */); /* Apply default settings. */
790
791 int vrc2 = i_createScreenObj(m->mapScreenObj, i /* Screen ID */, defaultScreenSettings);
792 AssertRC(vrc2);
793 }
794 }
795
796 /* Remove all left over screen settings objects which are not needed anymore. */
797 for (ULONG i = cDisplays; i < (ULONG)m->mapScreenObj.size(); i++)
798 {
799 int vrc2 = i_destroyScreenObj(m->mapScreenObj, i /* Screen ID */);
800 AssertRC(vrc2);
801 }
802
803 Assert(m->mapScreenObj.size() == cDisplays);
804
805 LogFlowThisFuncLeave();
806 return VINF_SUCCESS;
807}
808
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