VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/AudioAdapterImpl.cpp@ 56088

Last change on this file since 56088 was 56088, checked in by vboxsync, 10 years ago

pr6522. First part: added logic which allows to read\save audio properties in form key=value in VM xml setting file

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.3 KB
Line 
1/* $Id: AudioAdapterImpl.cpp 56088 2015-05-27 08:55:54Z vboxsync $ */
2/** @file
3 *
4 * VirtualBox COM class implementation
5 */
6
7/*
8 * Copyright (C) 2006-2015 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#include "AudioAdapterImpl.h"
20#include "MachineImpl.h"
21
22#include <iprt/cpp/utils.h>
23
24#include <VBox/settings.h>
25
26#include "AutoStateDep.h"
27#include "AutoCaller.h"
28#include "Logging.h"
29
30struct AudioAdapterData
31{
32 AudioAdapterData() :
33 mEnabled(false),
34 mAudioDriver(AudioDriverType_Null),
35 mAudioController(AudioControllerType_AC97)
36 {}
37
38 BOOL mEnabled;
39 AudioDriverType_T mAudioDriver;
40 AudioControllerType_T mAudioController;
41 std::map<com::Utf8Str, com::Utf8Str> properties;
42};
43
44struct AudioAdapter::Data
45{
46 Backupable<AudioAdapterData> m;
47};
48
49// constructor / destructor
50/////////////////////////////////////////////////////////////////////////////
51
52AudioAdapter::AudioAdapter()
53 : mParent(NULL),
54 mData(NULL)
55{
56}
57
58AudioAdapter::~AudioAdapter()
59{
60}
61
62HRESULT AudioAdapter::FinalConstruct()
63{
64 return BaseFinalConstruct();
65}
66
67void AudioAdapter::FinalRelease()
68{
69 uninit();
70 BaseFinalRelease();
71}
72
73// public initializer/uninitializer for internal purposes only
74/////////////////////////////////////////////////////////////////////////////
75
76/**
77 * Initializes the audio adapter object.
78 *
79 * @param aParent Handle of the parent object.
80 */
81HRESULT AudioAdapter::init (Machine *aParent)
82{
83 LogFlowThisFunc(("aParent=%p\n", aParent));
84
85 ComAssertRet(aParent, E_INVALIDARG);
86
87 /* Enclose the state transition NotReady->InInit->Ready */
88 AutoInitSpan autoInitSpan(this);
89 AssertReturn(autoInitSpan.isOk(), E_FAIL);
90
91 /* Get the default audio driver out of the system properties */
92 ComPtr<IVirtualBox> VBox;
93 HRESULT rc = aParent->COMGETTER(Parent)(VBox.asOutParam());
94 if (FAILED(rc)) return rc;
95 ComPtr<ISystemProperties> sysProps;
96 rc = VBox->COMGETTER(SystemProperties)(sysProps.asOutParam());
97 if (FAILED(rc)) return rc;
98 AudioDriverType_T defaultAudioDriver;
99 rc = sysProps->COMGETTER(DefaultAudioDriver)(&defaultAudioDriver);
100 if (FAILED(rc)) return rc;
101
102 unconst(mParent) = aParent;
103 /* mPeer is left null */
104
105 mData = new Data();
106 mData->m.allocate();
107 mData->m->mAudioDriver = defaultAudioDriver;
108
109 /* Confirm a successful initialization */
110 autoInitSpan.setSucceeded();
111
112 return S_OK;
113}
114
115/**
116 * Initializes the audio adapter object given another audio adapter object
117 * (a kind of copy constructor). This object shares data with
118 * the object passed as an argument.
119 *
120 * @note This object must be destroyed before the original object
121 * it shares data with is destroyed.
122 *
123 * @note Locks @a aThat object for reading.
124 */
125HRESULT AudioAdapter::init (Machine *aParent, AudioAdapter *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 unconst(mParent) = aParent;
136 unconst(mPeer) = aThat;
137
138 AutoCaller thatCaller (aThat);
139 AssertComRCReturnRC(thatCaller.rc());
140
141 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
142 mData = new Data();
143 mData->m.share (aThat->mData->m);
144
145 /* Confirm a successful initialization */
146 autoInitSpan.setSucceeded();
147
148 return S_OK;
149}
150
151/**
152 * Initializes the guest object given another guest object
153 * (a kind of copy constructor). This object makes a private copy of data
154 * of the original object passed as an argument.
155 *
156 * @note Locks @a aThat object for reading.
157 */
158HRESULT AudioAdapter::initCopy (Machine *aParent, AudioAdapter *aThat)
159{
160 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
161
162 ComAssertRet(aParent && aThat, E_INVALIDARG);
163
164 /* Enclose the state transition NotReady->InInit->Ready */
165 AutoInitSpan autoInitSpan(this);
166 AssertReturn(autoInitSpan.isOk(), E_FAIL);
167
168 unconst(mParent) = aParent;
169 /* mPeer is left null */
170
171 AutoCaller thatCaller (aThat);
172 AssertComRCReturnRC(thatCaller.rc());
173
174 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
175 mData = new Data();
176 mData->m.attachCopy (aThat->mData->m);
177
178 /* Confirm a successful initialization */
179 autoInitSpan.setSucceeded();
180
181 return S_OK;
182}
183
184/**
185 * Uninitializes the instance and sets the ready flag to FALSE.
186 * Called either from FinalRelease() or by the parent when it gets destroyed.
187 */
188void AudioAdapter::uninit()
189{
190 LogFlowThisFunc(("\n"));
191
192 /* Enclose the state transition Ready->InUninit->NotReady */
193 AutoUninitSpan autoUninitSpan(this);
194 if (autoUninitSpan.uninitDone())
195 return;
196
197 mData->m.free();
198 delete mData;
199 mData = NULL;
200
201 unconst(mPeer) = NULL;
202 unconst(mParent) = NULL;
203}
204
205// IAudioAdapter properties
206/////////////////////////////////////////////////////////////////////////////
207
208HRESULT AudioAdapter::getEnabled(BOOL *aEnabled)
209{
210 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
211
212 *aEnabled = mData->m->mEnabled;
213
214 return S_OK;
215}
216
217HRESULT AudioAdapter::setEnabled(BOOL aEnabled)
218{
219 /* the machine needs to be mutable */
220 AutoMutableStateDependency adep(mParent);
221 if (FAILED(adep.rc())) return adep.rc();
222
223 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
224
225 if (mData->m->mEnabled != aEnabled)
226 {
227 mData->m.backup();
228 mData->m->mEnabled = aEnabled;
229
230 alock.release();
231 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
232 mParent->i_setModified(Machine::IsModified_AudioAdapter);
233 }
234
235 return S_OK;
236}
237
238HRESULT AudioAdapter::getEnabledIn(BOOL *aEnabled)
239{
240 NOREF(aEnabled);
241 return E_NOTIMPL;
242}
243
244HRESULT AudioAdapter::setEnabledIn(BOOL aEnabled)
245{
246 NOREF(aEnabled);
247 return E_NOTIMPL;
248}
249
250HRESULT AudioAdapter::getEnabledOut(BOOL *aEnabled)
251{
252 NOREF(aEnabled);
253 return E_NOTIMPL;
254}
255
256HRESULT AudioAdapter::setEnabledOut(BOOL aEnabled)
257{
258 NOREF(aEnabled);
259 return E_NOTIMPL;
260}
261
262HRESULT AudioAdapter::getAudioDriver(AudioDriverType_T *aAudioDriver)
263{
264 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
265
266 *aAudioDriver = mData->m->mAudioDriver;
267
268 return S_OK;
269}
270
271HRESULT AudioAdapter::setAudioDriver(AudioDriverType_T aAudioDriver)
272{
273
274 /* the machine needs to be mutable */
275 AutoMutableOrSavedStateDependency adep(mParent);
276 if (FAILED(adep.rc())) return adep.rc();
277
278 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
279
280 HRESULT rc = S_OK;
281
282 if (mData->m->mAudioDriver != aAudioDriver)
283 {
284 if (settings::MachineConfigFile::isAudioDriverAllowedOnThisHost(aAudioDriver))
285 {
286 mData->m.backup();
287 mData->m->mAudioDriver = aAudioDriver;
288 alock.release();
289 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
290 mParent->i_setModified(Machine::IsModified_AudioAdapter);
291 }
292 else
293 {
294 AssertMsgFailed(("Wrong audio driver type %d\n", aAudioDriver));
295 rc = E_FAIL;
296 }
297 }
298
299 return rc;
300}
301
302HRESULT AudioAdapter::getAudioController(AudioControllerType_T *aAudioController)
303{
304 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
305
306 *aAudioController = mData->m->mAudioController;
307
308 return S_OK;
309}
310
311HRESULT AudioAdapter::setAudioController(AudioControllerType_T aAudioController)
312{
313 /* the machine needs to be mutable */
314 AutoMutableStateDependency adep(mParent);
315 if (FAILED(adep.rc())) return adep.rc();
316
317 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
318
319 HRESULT rc = S_OK;
320
321 if (mData->m->mAudioController != aAudioController)
322 {
323 /*
324 * which audio hardware type are we supposed to use?
325 */
326 switch (aAudioController)
327 {
328 case AudioControllerType_AC97:
329 case AudioControllerType_SB16:
330 case AudioControllerType_HDA:
331 {
332 mData->m.backup();
333 mData->m->mAudioController = aAudioController;
334 alock.release();
335 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
336 mParent->i_setModified(Machine::IsModified_AudioAdapter);
337 break;
338 }
339
340 default:
341 AssertMsgFailed (("Wrong audio controller type %d\n",
342 aAudioController));
343 rc = E_FAIL;
344 }
345 }
346
347 return rc;
348}
349
350HRESULT AudioAdapter::getPropertiesList(std::vector<com::Utf8Str>& aProperties)
351{
352 using namespace settings;
353
354 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
355
356 aProperties.resize(0);
357 StringsMap::const_iterator cit = mData->m->properties.begin();
358 while(cit!=mData->m->properties.end())
359 {
360 Utf8Str key = cit->first;
361 aProperties.push_back(cit->first);
362 ++cit;
363 }
364
365 return S_OK;
366}
367
368HRESULT AudioAdapter::getProperty(const com::Utf8Str &aKey, com::Utf8Str &aValue)
369{
370 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
371
372 settings::StringsMap::const_iterator cit = mData->m->properties.find(aKey);
373 if (cit != mData->m->properties.end())
374 aValue = cit->second;
375
376 return S_OK;
377}
378
379HRESULT AudioAdapter::setProperty(const com::Utf8Str &aKey, const com::Utf8Str &aValue)
380{
381 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
382
383 /* Generic properties processing.
384 * Look up the old value first; if nothing's changed then do nothing.
385 */
386 Utf8Str strOldValue;
387
388 settings::StringsMap::const_iterator cit = mData->m->properties.find(aKey);
389 if (cit != mData->m->properties.end())
390 strOldValue = cit->second;
391
392 if (strOldValue != aValue)
393 {
394 if (aValue.isEmpty())
395 mData->m->properties.erase(aKey);
396 else
397 mData->m->properties[aKey] = aValue;
398 }
399
400 alock.release();
401
402 return S_OK;
403}
404
405// IAudioAdapter methods
406/////////////////////////////////////////////////////////////////////////////
407
408// public methods only for internal purposes
409/////////////////////////////////////////////////////////////////////////////
410
411/**
412 * Loads settings from the given machine node.
413 * May be called once right after this object creation.
414 *
415 * @param aMachineNode <Machine> node.
416 *
417 * @note Locks this object for writing.
418 */
419HRESULT AudioAdapter::i_loadSettings(const settings::AudioAdapter &data)
420{
421 AutoCaller autoCaller(this);
422 AssertComRCReturnRC(autoCaller.rc());
423
424 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
425
426 /* Note: we assume that the default values for attributes of optional
427 * nodes are assigned in the Data::Data() constructor and don't do it
428 * here. It implies that this method may only be called after constructing
429 * a new AudioAdapter object while all its data fields are in the default
430 * values. Exceptions are fields whose creation time defaults don't match
431 * values that should be applied when these fields are not explicitly set
432 * in the settings file (for backwards compatibility reasons). This takes
433 * place when a setting of a newly created object must default to A while
434 * the same setting of an object loaded from the old settings file must
435 * default to B. */
436
437 mData->m->mEnabled = data.fEnabled;
438 mData->m->mAudioController = data.controllerType;
439 mData->m->mAudioDriver = data.driverType;
440
441 std::map<com::Utf8Str, com::Utf8Str>::const_iterator cit = data.properties.begin();
442 while(cit!=data.properties.end())
443 {
444 mData->m->properties[cit->first] = cit->second;
445 ++cit;
446 }
447
448 return S_OK;
449}
450
451/**
452 * Saves settings to the given machine node.
453 *
454 * @param aMachineNode <Machine> node.
455 *
456 * @note Locks this object for reading.
457 */
458HRESULT AudioAdapter::i_saveSettings(settings::AudioAdapter &data)
459{
460 AutoCaller autoCaller(this);
461 AssertComRCReturnRC(autoCaller.rc());
462
463 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
464
465 data.fEnabled = !!mData->m->mEnabled;
466 data.controllerType = mData->m->mAudioController;
467 data.driverType = mData->m->mAudioDriver;
468
469 std::map<com::Utf8Str, com::Utf8Str>::const_iterator cit = mData->m->properties.begin();
470 while(cit!=mData->m->properties.end())
471 {
472 data.properties[cit->first] = cit->second;
473 ++cit;
474 }
475
476 return S_OK;
477}
478
479/**
480 * @note Locks this object for writing.
481 */
482void AudioAdapter::i_rollback()
483{
484 /* sanity */
485 AutoCaller autoCaller(this);
486 AssertComRCReturnVoid(autoCaller.rc());
487
488 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
489
490 mData->m.rollback();
491}
492
493/**
494 * @note Locks this object for writing, together with the peer object (also
495 * for writing) if there is one.
496 */
497void AudioAdapter::i_commit()
498{
499 /* sanity */
500 AutoCaller autoCaller(this);
501 AssertComRCReturnVoid (autoCaller.rc());
502
503 /* sanity too */
504 AutoCaller peerCaller (mPeer);
505 AssertComRCReturnVoid (peerCaller.rc());
506
507 /* lock both for writing since we modify both (mPeer is "master" so locked
508 * first) */
509 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
510
511 if (mData->m.isBackedUp())
512 {
513 mData->m.commit();
514 if (mPeer)
515 {
516 /* attach new data to the peer and reshare it */
517 mPeer->mData->m.attach (mData->m);
518 }
519 }
520}
521
522/**
523 * @note Locks this object for writing, together with the peer object
524 * represented by @a aThat (locked for reading).
525 */
526void AudioAdapter::i_copyFrom(AudioAdapter *aThat)
527{
528 AssertReturnVoid (aThat != NULL);
529
530 /* sanity */
531 AutoCaller autoCaller(this);
532 AssertComRCReturnVoid (autoCaller.rc());
533
534 /* sanity too */
535 AutoCaller thatCaller (aThat);
536 AssertComRCReturnVoid (thatCaller.rc());
537
538 /* peer is not modified, lock it for reading (aThat is "master" so locked
539 * first) */
540 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
541 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
542
543 /* this will back up current data */
544 mData->m.assignCopy(aThat->mData->m);
545}
546/* vi: set tabstop=4 shiftwidth=4 expandtab: */
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