VirtualBox

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

Last change on this file since 96407 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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

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