VirtualBox

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

Last change on this file since 60952 was 56662, checked in by vboxsync, 9 years ago

Main: When changing audio controller, change codec as well.

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