VirtualBox

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

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

Main: Use the new "Default" audio driver by default for newly created VMs. bugref:10051

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

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