VirtualBox

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

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

Main: Added audio codec type property, including recommended type.

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