VirtualBox

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

Last change on this file since 86506 was 82968, checked in by vboxsync, 4 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.5 KB
Line 
1/* $Id: AudioAdapterImpl.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#define LOG_GROUP LOG_GROUP_MAIN_AUDIOADAPTER
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 "LoggingNew.h"
29
30
31// constructor / destructor
32/////////////////////////////////////////////////////////////////////////////
33
34AudioAdapter::AudioAdapter()
35 : mParent(NULL)
36{
37}
38
39AudioAdapter::~AudioAdapter()
40{
41}
42
43HRESULT AudioAdapter::FinalConstruct()
44{
45 return BaseFinalConstruct();
46}
47
48void AudioAdapter::FinalRelease()
49{
50 uninit();
51 BaseFinalRelease();
52}
53
54// public initializer/uninitializer for internal purposes only
55/////////////////////////////////////////////////////////////////////////////
56
57/**
58 * Initializes the audio adapter object.
59 *
60 * @param aParent Handle of the parent object.
61 */
62HRESULT AudioAdapter::init(Machine *aParent)
63{
64 LogFlowThisFunc(("aParent=%p\n", aParent));
65
66 ComAssertRet(aParent, E_INVALIDARG);
67
68 /* Enclose the state transition NotReady->InInit->Ready */
69 AutoInitSpan autoInitSpan(this);
70 AssertReturn(autoInitSpan.isOk(), E_FAIL);
71
72 /* Get the default audio driver out of the system properties */
73 ComPtr<IVirtualBox> VBox;
74 HRESULT rc = aParent->COMGETTER(Parent)(VBox.asOutParam());
75 if (FAILED(rc)) return rc;
76 ComPtr<ISystemProperties> sysProps;
77 rc = VBox->COMGETTER(SystemProperties)(sysProps.asOutParam());
78 if (FAILED(rc)) return rc;
79 AudioDriverType_T defaultAudioDriver;
80 rc = sysProps->COMGETTER(DefaultAudioDriver)(&defaultAudioDriver);
81 if (FAILED(rc)) return rc;
82
83 unconst(mParent) = aParent;
84 /* mPeer is left null */
85
86 mData.allocate();
87 mData->driverType = defaultAudioDriver;
88 mData->fEnabledIn = false;
89 mData->fEnabledOut = false;
90
91 /* Confirm a successful initialization */
92 autoInitSpan.setSucceeded();
93
94 return S_OK;
95}
96
97/**
98 * Initializes the audio adapter object given another audio adapter 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 AudioAdapter::init(Machine *aParent, AudioAdapter *aThat)
108{
109 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
110
111 ComAssertRet(aParent && aThat, E_INVALIDARG);
112
113 /* Enclose the state transition NotReady->InInit->Ready */
114 AutoInitSpan autoInitSpan(this);
115 AssertReturn(autoInitSpan.isOk(), E_FAIL);
116
117 unconst(mParent) = aParent;
118 unconst(mPeer) = aThat;
119
120 AutoCaller thatCaller(aThat);
121 AssertComRCReturnRC(thatCaller.rc());
122
123 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
124 mData.share(aThat->mData);
125
126 /* Confirm a successful initialization */
127 autoInitSpan.setSucceeded();
128
129 return S_OK;
130}
131
132/**
133 * Initializes the audio adapter object given another audio adapter object
134 * (a kind of copy constructor). This object makes a private copy of data
135 * of the original object passed as an argument.
136 *
137 * @note Locks @a aThat object for reading.
138 */
139HRESULT AudioAdapter::initCopy(Machine *aParent, AudioAdapter *aThat)
140{
141 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
142
143 ComAssertRet(aParent && aThat, E_INVALIDARG);
144
145 /* Enclose the state transition NotReady->InInit->Ready */
146 AutoInitSpan autoInitSpan(this);
147 AssertReturn(autoInitSpan.isOk(), E_FAIL);
148
149 unconst(mParent) = aParent;
150 /* mPeer is left null */
151
152 AutoCaller thatCaller(aThat);
153 AssertComRCReturnRC(thatCaller.rc());
154
155 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
156 mData.attachCopy(aThat->mData);
157
158 /* Confirm a successful initialization */
159 autoInitSpan.setSucceeded();
160
161 return S_OK;
162}
163
164/**
165 * Uninitializes the instance and sets the ready flag to FALSE.
166 * Called either from FinalRelease() or by the parent when it gets destroyed.
167 */
168void AudioAdapter::uninit()
169{
170 LogFlowThisFunc(("\n"));
171
172 /* Enclose the state transition Ready->InUninit->NotReady */
173 AutoUninitSpan autoUninitSpan(this);
174 if (autoUninitSpan.uninitDone())
175 return;
176
177 mData.free();
178
179 unconst(mPeer) = NULL;
180 unconst(mParent) = NULL;
181}
182
183// IAudioAdapter properties
184/////////////////////////////////////////////////////////////////////////////
185
186HRESULT AudioAdapter::getEnabled(BOOL *aEnabled)
187{
188 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
189
190 *aEnabled = mData->fEnabled;
191
192 return S_OK;
193}
194
195HRESULT AudioAdapter::setEnabled(BOOL aEnabled)
196{
197 /* the machine needs to be mutable */
198 AutoMutableStateDependency adep(mParent);
199 if (FAILED(adep.rc())) return adep.rc();
200
201 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
202
203 if (mData->fEnabled != RT_BOOL(aEnabled))
204 {
205 mData.backup();
206 mData->fEnabled = RT_BOOL(aEnabled);
207
208 alock.release();
209 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
210 mParent->i_setModified(Machine::IsModified_AudioAdapter);
211 }
212
213 return S_OK;
214}
215
216HRESULT AudioAdapter::getEnabledIn(BOOL *aEnabled)
217{
218 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
219
220 *aEnabled = mData->fEnabledIn;
221
222 return S_OK;
223}
224
225HRESULT AudioAdapter::setEnabledIn(BOOL aEnabled)
226{
227 /* the machine needs to be mutable */
228 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
229 if (FAILED(adep.rc())) return adep.rc();
230
231 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
232 if (RT_BOOL(aEnabled) != mData->fEnabledIn)
233 {
234 mData.backup();
235 mData->fEnabledIn = RT_BOOL(aEnabled);
236
237 // leave the lock before informing callbacks
238 alock.release();
239
240 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
241 mParent->i_setModified(Machine::IsModified_AudioAdapter);
242 mlock.release();
243
244 mParent->i_onAudioAdapterChange(this);
245 }
246
247 return S_OK;
248}
249
250HRESULT AudioAdapter::getEnabledOut(BOOL *aEnabled)
251{
252 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
253
254 *aEnabled = mData->fEnabledOut;
255
256 return S_OK;
257}
258
259HRESULT AudioAdapter::setEnabledOut(BOOL aEnabled)
260{
261 /* the machine needs to be mutable */
262 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
263 if (FAILED(adep.rc())) return adep.rc();
264
265 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
266 if (RT_BOOL(aEnabled) != mData->fEnabledOut)
267 {
268 mData.backup();
269 mData->fEnabledOut = RT_BOOL(aEnabled);
270
271 // leave the lock before informing callbacks
272 alock.release();
273
274 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
275 mParent->i_setModified(Machine::IsModified_AudioAdapter);
276 mlock.release();
277
278 mParent->i_onAudioAdapterChange(this);
279 }
280
281 return S_OK;
282}
283
284HRESULT AudioAdapter::getAudioDriver(AudioDriverType_T *aAudioDriver)
285{
286 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
287
288 *aAudioDriver = mData->driverType;
289
290 return S_OK;
291}
292
293HRESULT AudioAdapter::setAudioDriver(AudioDriverType_T aAudioDriver)
294{
295
296 /* the machine needs to be mutable */
297 AutoMutableOrSavedStateDependency adep(mParent);
298 if (FAILED(adep.rc())) return adep.rc();
299
300 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
301
302 HRESULT rc = S_OK;
303
304 if (mData->driverType != aAudioDriver)
305 {
306 if (settings::MachineConfigFile::isAudioDriverAllowedOnThisHost(aAudioDriver))
307 {
308 mData.backup();
309 mData->driverType = aAudioDriver;
310 alock.release();
311 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
312 mParent->i_setModified(Machine::IsModified_AudioAdapter);
313 }
314 else
315 {
316 AssertMsgFailed(("Wrong audio driver type %d\n", aAudioDriver));
317 rc = E_FAIL;
318 }
319 }
320
321 return rc;
322}
323
324HRESULT AudioAdapter::getAudioController(AudioControllerType_T *aAudioController)
325{
326 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
327
328 *aAudioController = mData->controllerType;
329
330 return S_OK;
331}
332
333HRESULT AudioAdapter::setAudioController(AudioControllerType_T aAudioController)
334{
335 /* the machine needs to be mutable */
336 AutoMutableStateDependency adep(mParent);
337 if (FAILED(adep.rc())) return adep.rc();
338
339 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
340
341 HRESULT rc = S_OK;
342
343 if (mData->controllerType != aAudioController)
344 {
345 AudioCodecType_T defaultCodec;
346
347 /*
348 * which audio hardware type are we supposed to use?
349 */
350 switch (aAudioController)
351 {
352 /* codec type needs to match the controller. */
353 case AudioControllerType_AC97:
354 defaultCodec = AudioCodecType_STAC9700;
355 break;
356 case AudioControllerType_SB16:
357 defaultCodec = AudioCodecType_SB16;
358 break;
359 case AudioControllerType_HDA:
360 defaultCodec = AudioCodecType_STAC9221;
361 break;
362
363 default:
364 AssertMsgFailed(("Wrong audio controller type %d\n", aAudioController));
365 defaultCodec = AudioCodecType_Null; /* Shut up MSC */
366 rc = E_FAIL;
367 }
368 if (rc == S_OK)
369 {
370 mData.backup();
371 mData->controllerType = aAudioController;
372 mData->codecType = defaultCodec;
373 alock.release();
374 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
375 mParent->i_setModified(Machine::IsModified_AudioAdapter);
376 }
377 }
378
379 return rc;
380}
381
382HRESULT AudioAdapter::getAudioCodec(AudioCodecType_T *aAudioCodec)
383{
384 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
385
386 *aAudioCodec = mData->codecType;
387
388 return S_OK;
389}
390
391HRESULT AudioAdapter::setAudioCodec(AudioCodecType_T aAudioCodec)
392{
393 /* the machine needs to be mutable */
394 AutoMutableStateDependency adep(mParent);
395 if (FAILED(adep.rc())) return adep.rc();
396
397 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
398
399 HRESULT rc = S_OK;
400
401 /*
402 * ensure that the codec type matches the audio controller
403 */
404 switch (mData->controllerType)
405 {
406 case AudioControllerType_AC97:
407 {
408 if ( (aAudioCodec != AudioCodecType_STAC9700)
409 && (aAudioCodec != AudioCodecType_AD1980))
410 rc = E_INVALIDARG;
411 break;
412 }
413
414 case AudioControllerType_SB16:
415 {
416 if (aAudioCodec != AudioCodecType_SB16)
417 rc = E_INVALIDARG;
418 break;
419 }
420
421 case AudioControllerType_HDA:
422 {
423 if (aAudioCodec != AudioCodecType_STAC9221)
424 rc = E_INVALIDARG;
425 break;
426 }
427
428 default:
429 AssertMsgFailed(("Wrong audio controller type %d\n",
430 mData->controllerType));
431 rc = E_FAIL;
432 }
433
434 if (!SUCCEEDED(rc))
435 return setError(rc,
436 tr("Invalid audio codec type %d"),
437 aAudioCodec);
438
439 if (mData->codecType != aAudioCodec)
440 {
441 mData.backup();
442 mData->codecType = aAudioCodec;
443 alock.release();
444 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, needs no locking
445 mParent->i_setModified(Machine::IsModified_AudioAdapter);
446 }
447
448 return rc;
449}
450
451HRESULT AudioAdapter::getPropertiesList(std::vector<com::Utf8Str>& aProperties)
452{
453 using namespace settings;
454
455 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
456
457 aProperties.resize(0);
458 StringsMap::const_iterator cit = mData->properties.begin();
459 while(cit != mData->properties.end())
460 {
461 Utf8Str key = cit->first;
462 aProperties.push_back(cit->first);
463 ++cit;
464 }
465
466 return S_OK;
467}
468
469HRESULT AudioAdapter::getProperty(const com::Utf8Str &aKey, com::Utf8Str &aValue)
470{
471 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
472
473 settings::StringsMap::const_iterator cit = mData->properties.find(aKey);
474 if (cit != mData->properties.end())
475 aValue = cit->second;
476
477 return S_OK;
478}
479
480HRESULT AudioAdapter::setProperty(const com::Utf8Str &aKey, const com::Utf8Str &aValue)
481{
482 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
483
484 /* Generic properties processing.
485 * Look up the old value first; if nothing's changed then do nothing.
486 */
487 Utf8Str strOldValue;
488
489 settings::StringsMap::const_iterator cit = mData->properties.find(aKey);
490 if (cit != mData->properties.end())
491 strOldValue = cit->second;
492
493 if (strOldValue != aValue)
494 {
495 if (aValue.isEmpty())
496 mData->properties.erase(aKey);
497 else
498 mData->properties[aKey] = aValue;
499 }
500
501 alock.release();
502
503 return S_OK;
504}
505
506// IAudioAdapter methods
507/////////////////////////////////////////////////////////////////////////////
508
509// public methods only for internal purposes
510/////////////////////////////////////////////////////////////////////////////
511
512/**
513 * Loads settings from the given machine node.
514 * May be called once right after this object creation.
515 *
516 * @param data Configuration settings.
517 *
518 * @note Locks this object for writing.
519 */
520HRESULT AudioAdapter::i_loadSettings(const settings::AudioAdapter &data)
521{
522 AutoCaller autoCaller(this);
523 AssertComRCReturnRC(autoCaller.rc());
524
525 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
526
527 /* Note: we assume that the default values for attributes of optional
528 * nodes are assigned in the Data::Data() constructor and don't do it
529 * here. It implies that this method may only be called after constructing
530 * a new AudioAdapter object while all its data fields are in the default
531 * values. Exceptions are fields whose creation time defaults don't match
532 * values that should be applied when these fields are not explicitly set
533 * in the settings file (for backwards compatibility reasons). This takes
534 * place when a setting of a newly created object must default to A while
535 * the same setting of an object loaded from the old settings file must
536 * default to B. */
537 mData.assignCopy(&data);
538
539 return S_OK;
540}
541
542/**
543 * Saves settings to the given machine node.
544 *
545 * @param data Configuration settings.
546 *
547 * @note Locks this object for reading.
548 */
549HRESULT AudioAdapter::i_saveSettings(settings::AudioAdapter &data)
550{
551 AutoCaller autoCaller(this);
552 AssertComRCReturnRC(autoCaller.rc());
553
554 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
555
556 data = *mData.data();
557
558 return S_OK;
559}
560
561/**
562 * @note Locks this object for writing.
563 */
564void AudioAdapter::i_rollback()
565{
566 /* sanity */
567 AutoCaller autoCaller(this);
568 AssertComRCReturnVoid(autoCaller.rc());
569
570 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
571
572 mData.rollback();
573}
574
575/**
576 * @note Locks this object for writing, together with the peer object (also
577 * for writing) if there is one.
578 */
579void AudioAdapter::i_commit()
580{
581 /* sanity */
582 AutoCaller autoCaller(this);
583 AssertComRCReturnVoid(autoCaller.rc());
584
585 /* sanity too */
586 AutoCaller peerCaller(mPeer);
587 AssertComRCReturnVoid(peerCaller.rc());
588
589 /* lock both for writing since we modify both (mPeer is "master" so locked
590 * first) */
591 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
592
593 if (mData.isBackedUp())
594 {
595 mData.commit();
596 if (mPeer)
597 {
598 /* attach new data to the peer and reshare it */
599 mPeer->mData.attach(mData);
600 }
601 }
602}
603
604/**
605 * @note Locks this object for writing, together with the peer object
606 * represented by @a aThat (locked for reading).
607 */
608void AudioAdapter::i_copyFrom(AudioAdapter *aThat)
609{
610 AssertReturnVoid(aThat != NULL);
611
612 /* sanity */
613 AutoCaller autoCaller(this);
614 AssertComRCReturnVoid(autoCaller.rc());
615
616 /* sanity too */
617 AutoCaller thatCaller(aThat);
618 AssertComRCReturnVoid(thatCaller.rc());
619
620 /* peer is not modified, lock it for reading (aThat is "master" so locked
621 * first) */
622 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
623 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
624
625 /* this will back up current data */
626 mData.assignCopy(aThat->mData);
627}
628/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use