VirtualBox

source: vbox/trunk/src/VBox/Main/AudioAdapterImpl.cpp@ 15941

Last change on this file since 15941 was 14972, checked in by vboxsync, 16 years ago

#3285: Improve error handling API to include unique error numbers

The mega commit that implements Main-wide usage of new CheckCom*
macros, mostly CheckComArgNotNull, CheckComArgStrNotEmptyOrNull,
CheckComArgOutSafeArrayPointerValid, CheckComArgExpr.
Note that some methods incorrectly returned E_INVALIDARG where they
should have returned E_POINTER and vice versa. If any higher level
function tests these, they will behave differently now...

Special thanks to: vi macros, making it easy to semi-automatically
find and replace several hundred instances of if (!aName) ...

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.9 KB
Line 
1/** @file
2 *
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#include "AudioAdapterImpl.h"
23#include "MachineImpl.h"
24#include "Logging.h"
25
26#include <iprt/cpputils.h>
27
28// constructor / destructor
29/////////////////////////////////////////////////////////////////////////////
30
31DEFINE_EMPTY_CTOR_DTOR (AudioAdapter)
32
33HRESULT AudioAdapter::FinalConstruct()
34{
35 return S_OK;
36}
37
38void AudioAdapter::FinalRelease()
39{
40 uninit ();
41}
42
43// public initializer/uninitializer for internal purposes only
44/////////////////////////////////////////////////////////////////////////////
45
46/**
47 * Initializes the audio adapter object.
48 *
49 * @param aParent Handle of the parent object.
50 */
51HRESULT AudioAdapter::init (Machine *aParent)
52{
53 LogFlowThisFunc (("aParent=%p\n", aParent));
54
55 ComAssertRet (aParent, E_INVALIDARG);
56
57 /* Enclose the state transition NotReady->InInit->Ready */
58 AutoInitSpan autoInitSpan (this);
59 AssertReturn (autoInitSpan.isOk(), E_FAIL);
60
61 unconst (mParent) = aParent;
62 /* mPeer is left null */
63
64 mData.allocate();
65
66 /* Confirm a successful initialization */
67 autoInitSpan.setSucceeded();
68
69 return S_OK;
70}
71
72/**
73 * Initializes the audio adapter object given another audio adapter object
74 * (a kind of copy constructor). This object shares data with
75 * the object passed as an argument.
76 *
77 * @note This object must be destroyed before the original object
78 * it shares data with is destroyed.
79 *
80 * @note Locks @a aThat object for reading.
81 */
82HRESULT AudioAdapter::init (Machine *aParent, AudioAdapter *aThat)
83{
84 LogFlowThisFunc (("aParent=%p, aThat=%p\n", aParent, aThat));
85
86 ComAssertRet (aParent && aThat, E_INVALIDARG);
87
88 /* Enclose the state transition NotReady->InInit->Ready */
89 AutoInitSpan autoInitSpan (this);
90 AssertReturn (autoInitSpan.isOk(), E_FAIL);
91
92 unconst (mParent) = aParent;
93 unconst (mPeer) = aThat;
94
95 AutoCaller thatCaller (aThat);
96 AssertComRCReturnRC (thatCaller.rc());
97
98 AutoReadLock thatLock (aThat);
99 mData.share (aThat->mData);
100
101 /* Confirm a successful initialization */
102 autoInitSpan.setSucceeded();
103
104 return S_OK;
105}
106
107/**
108 * Initializes the guest object given another guest object
109 * (a kind of copy constructor). This object makes a private copy of data
110 * of the original object passed as an argument.
111 *
112 * @note Locks @a aThat object for reading.
113 */
114HRESULT AudioAdapter::initCopy (Machine *aParent, AudioAdapter *aThat)
115{
116 LogFlowThisFunc (("aParent=%p, aThat=%p\n", aParent, aThat));
117
118 ComAssertRet (aParent && aThat, E_INVALIDARG);
119
120 /* Enclose the state transition NotReady->InInit->Ready */
121 AutoInitSpan autoInitSpan (this);
122 AssertReturn (autoInitSpan.isOk(), E_FAIL);
123
124 unconst (mParent) = aParent;
125 /* mPeer is left null */
126
127 AutoCaller thatCaller (aThat);
128 AssertComRCReturnRC (thatCaller.rc());
129
130 AutoReadLock thatLock (aThat);
131 mData.attachCopy (aThat->mData);
132
133 /* Confirm a successful initialization */
134 autoInitSpan.setSucceeded();
135
136 return S_OK;
137}
138
139/**
140 * Uninitializes the instance and sets the ready flag to FALSE.
141 * Called either from FinalRelease() or by the parent when it gets destroyed.
142 */
143void AudioAdapter::uninit()
144{
145 LogFlowThisFunc (("\n"));
146
147 /* Enclose the state transition Ready->InUninit->NotReady */
148 AutoUninitSpan autoUninitSpan (this);
149 if (autoUninitSpan.uninitDone())
150 return;
151
152 mData.free();
153
154 unconst (mPeer).setNull();
155 unconst (mParent).setNull();
156}
157
158// IAudioAdapter properties
159/////////////////////////////////////////////////////////////////////////////
160
161STDMETHODIMP AudioAdapter::COMGETTER(Enabled)(BOOL *aEnabled)
162{
163 CheckComArgOutPointerValid(aEnabled);
164
165 AutoCaller autoCaller (this);
166 CheckComRCReturnRC (autoCaller.rc());
167
168 AutoReadLock alock (this);
169
170 *aEnabled = mData->mEnabled;
171
172 return S_OK;
173}
174
175STDMETHODIMP AudioAdapter::COMSETTER(Enabled)(BOOL aEnabled)
176{
177 AutoCaller autoCaller (this);
178 CheckComRCReturnRC (autoCaller.rc());
179
180 /* the machine needs to be mutable */
181 Machine::AutoMutableStateDependency adep (mParent);
182 CheckComRCReturnRC (adep.rc());
183
184 AutoWriteLock alock (this);
185
186 if (mData->mEnabled != aEnabled)
187 {
188 mData.backup();
189 mData->mEnabled = aEnabled;
190 }
191
192 return S_OK;
193}
194
195STDMETHODIMP AudioAdapter::COMGETTER(AudioDriver)(AudioDriverType_T *aAudioDriver)
196{
197 CheckComArgOutPointerValid(aAudioDriver);
198
199 AutoCaller autoCaller (this);
200 CheckComRCReturnRC (autoCaller.rc());
201
202 AutoReadLock alock (this);
203
204 *aAudioDriver = mData->mAudioDriver;
205
206 return S_OK;
207}
208
209STDMETHODIMP AudioAdapter::COMSETTER(AudioDriver)(AudioDriverType_T aAudioDriver)
210{
211 AutoCaller autoCaller (this);
212 CheckComRCReturnRC (autoCaller.rc());
213
214 /* the machine needs to be mutable */
215 Machine::AutoMutableStateDependency adep (mParent);
216 CheckComRCReturnRC (adep.rc());
217
218 AutoWriteLock alock (this);
219
220 HRESULT rc = S_OK;
221
222 if (mData->mAudioDriver != aAudioDriver)
223 {
224 /*
225 * which audio driver type are we supposed to use?
226 */
227 switch (aAudioDriver)
228 {
229 case AudioDriverType_Null:
230#ifdef RT_OS_WINDOWS
231# ifdef VBOX_WITH_WINMM
232 case AudioDriverType_WinMM:
233# endif
234 case AudioDriverType_DirectSound:
235#endif /* RT_OS_WINDOWS */
236#ifdef RT_OS_SOLARIS
237 case AudioDriverType_SolAudio:
238#endif
239#ifdef RT_OS_LINUX
240 case AudioDriverType_OSS:
241# ifdef VBOX_WITH_ALSA
242 case AudioDriverType_ALSA:
243# endif
244# ifdef VBOX_WITH_PULSE
245 case AudioDriverType_Pulse:
246# endif
247#endif /* RT_OS_LINUX */
248#ifdef RT_OS_DARWIN
249 case AudioDriverType_CoreAudio:
250#endif
251#ifdef RT_OS_OS2
252 case AudioDriverType_MMPM:
253#endif
254 {
255 mData.backup();
256 mData->mAudioDriver = aAudioDriver;
257 break;
258 }
259
260 default:
261 {
262 AssertMsgFailed (("Wrong audio driver type %d\n",
263 aAudioDriver));
264 rc = E_FAIL;
265 }
266 }
267 }
268
269 return rc;
270}
271
272STDMETHODIMP AudioAdapter::COMGETTER(AudioController)(AudioControllerType_T *aAudioController)
273{
274 CheckComArgOutPointerValid(aAudioController);
275
276 AutoCaller autoCaller (this);
277 CheckComRCReturnRC (autoCaller.rc());
278
279 AutoReadLock alock (this);
280
281 *aAudioController = mData->mAudioController;
282
283 return S_OK;
284}
285
286STDMETHODIMP AudioAdapter::COMSETTER(AudioController)(AudioControllerType_T aAudioController)
287{
288 AutoCaller autoCaller (this);
289 CheckComRCReturnRC (autoCaller.rc());
290
291 /* the machine needs to be mutable */
292 Machine::AutoMutableStateDependency adep (mParent);
293 CheckComRCReturnRC (adep.rc());
294
295 AutoWriteLock alock (this);
296
297 HRESULT rc = S_OK;
298
299 if (mData->mAudioController != aAudioController)
300 {
301 /*
302 * which audio hardware type are we supposed to use?
303 */
304 switch (aAudioController)
305 {
306 case AudioControllerType_AC97:
307 case AudioControllerType_SB16:
308 mData.backup();
309 mData->mAudioController = aAudioController;
310 break;
311
312 default:
313 {
314 AssertMsgFailed (("Wrong audio controller type %d\n",
315 aAudioController));
316 rc = E_FAIL;
317 }
318 }
319 }
320
321 return rc;
322}
323
324// IAudioAdapter methods
325/////////////////////////////////////////////////////////////////////////////
326
327// public methods only for internal purposes
328/////////////////////////////////////////////////////////////////////////////
329
330/**
331 * Loads settings from the given machine node.
332 * May be called once right after this object creation.
333 *
334 * @param aMachineNode <Machine> node.
335 *
336 * @note Locks this object for writing.
337 */
338HRESULT AudioAdapter::loadSettings (const settings::Key &aMachineNode)
339{
340 using namespace settings;
341
342 AssertReturn (!aMachineNode.isNull(), E_FAIL);
343
344 AutoCaller autoCaller (this);
345 AssertComRCReturnRC (autoCaller.rc());
346
347 AutoWriteLock alock (this);
348
349 /* Note: we assume that the default values for attributes of optional
350 * nodes are assigned in the Data::Data() constructor and don't do it
351 * here. It implies that this method may only be called after constructing
352 * a new BIOSSettings object while all its data fields are in the default
353 * values. Exceptions are fields whose creation time defaults don't match
354 * values that should be applied when these fields are not explicitly set
355 * in the settings file (for backwards compatibility reasons). This takes
356 * place when a setting of a newly created object must default to A while
357 * the same setting of an object loaded from the old settings file must
358 * default to B. */
359
360 /* AudioAdapter node (required) */
361 Key audioAdapterNode = aMachineNode.key ("AudioAdapter");
362
363 /* is the adapter enabled? (required) */
364 mData->mEnabled = audioAdapterNode.value <bool> ("enabled");
365
366 /* now check the audio adapter (not required, default is AC97) */
367 const char *controller = audioAdapterNode.stringValue ("controller");
368 if (strcmp (controller, "SB16") == 0)
369 mData->mAudioController = AudioControllerType_SB16;
370 else
371 mData->mAudioController = AudioControllerType_AC97;
372
373 /* now check the audio driver (required) */
374 const char *driver = audioAdapterNode.stringValue ("driver");
375 mData->mAudioDriver = AudioDriverType_Null;
376 if (strcmp (driver, "Null") == 0)
377 ; /* Null has been set above */
378#ifdef RT_OS_WINDOWS
379 else if (strcmp (driver, "WinMM") == 0)
380#ifdef VBOX_WITH_WINMM
381 mData->mAudioDriver = AudioDriverType_WinMM;
382#else
383 /* fall back to dsound */
384 mData->mAudioDriver = AudioDriverType_DirectSound;
385#endif
386 else if (strcmp (driver, "DirectSound") == 0)
387 mData->mAudioDriver = AudioDriverType_DirectSound;
388#endif // RT_OS_WINDOWS
389#ifdef RT_OS_SOLARIS
390 else if (strcmp (driver, "SolAudio") == 0)
391 mData->mAudioDriver = AudioDriverType_SolAudio;
392#endif // RT_OS_SOLARIS
393#ifdef RT_OS_LINUX
394 else if (strcmp (driver, "OSS") == 0)
395 mData->mAudioDriver = AudioDriverType_OSS;
396 else if (strcmp (driver, "ALSA") == 0)
397# ifdef VBOX_WITH_ALSA
398 mData->mAudioDriver = AudioDriverType_ALSA;
399# else
400 /* fall back to OSS */
401 mData->mAudioDriver = AudioDriverType_OSS;
402# endif
403 else if (strcmp (driver, "Pulse") == 0)
404# ifdef VBOX_WITH_PULSE
405 mData->mAudioDriver = AudioDriverType_Pulse;
406# else
407 /* fall back to OSS */
408 mData->mAudioDriver = AudioDriverType_OSS;
409# endif
410#endif // RT_OS_LINUX
411#ifdef RT_OS_DARWIN
412 else if (strcmp (driver, "CoreAudio") == 0)
413 mData->mAudioDriver = AudioDriverType_CoreAudio;
414#endif
415#ifdef RT_OS_OS2
416 else if (strcmp (driver, "MMPM") == 0)
417 mData->mAudioDriver = AudioDriverType_MMPM;
418#endif
419 else
420 AssertMsgFailed (("Invalid driver '%s'\n", driver));
421
422 return S_OK;
423}
424
425/**
426 * Saves settings to the given machine node.
427 *
428 * @param aMachineNode <Machine> node.
429 *
430 * @note Locks this object for reading.
431 */
432HRESULT AudioAdapter::saveSettings (settings::Key &aMachineNode)
433{
434 using namespace settings;
435
436 AssertReturn (!aMachineNode.isNull(), E_FAIL);
437
438 AutoCaller autoCaller (this);
439 AssertComRCReturnRC (autoCaller.rc());
440
441 AutoReadLock alock (this);
442
443 Key node = aMachineNode.createKey ("AudioAdapter");
444
445 const char *controllerStr = NULL;
446 switch (mData->mAudioController)
447 {
448 case AudioControllerType_SB16:
449 {
450 controllerStr = "SB16";
451 break;
452 }
453 default:
454 {
455 controllerStr = "AC97";
456 break;
457 }
458 }
459 node.setStringValue ("controller", controllerStr);
460
461 const char *driverStr = NULL;
462 switch (mData->mAudioDriver)
463 {
464 case AudioDriverType_Null:
465 {
466 driverStr = "Null";
467 break;
468 }
469#ifdef RT_OS_WINDOWS
470 case AudioDriverType_WinMM:
471# ifdef VBOX_WITH_WINMM
472 {
473 driverStr = "WinMM";
474 break;
475 }
476# endif
477 case AudioDriverType_DirectSound:
478 {
479 driverStr = "DirectSound";
480 break;
481 }
482#endif /* RT_OS_WINDOWS */
483#ifdef RT_OS_SOLARIS
484 case AudioDriverType_SolAudio:
485 {
486 driverStr = "SolAudio";
487 break;
488 }
489#endif
490#ifdef RT_OS_LINUX
491 case AudioDriverType_ALSA:
492# ifdef VBOX_WITH_ALSA
493 {
494 driverStr = "ALSA";
495 break;
496 }
497# endif
498 case AudioDriverType_Pulse:
499# ifdef VBOX_WITH_PULSE
500 {
501 driverStr = "Pulse";
502 break;
503 }
504# endif
505 case AudioDriverType_OSS:
506 {
507 driverStr = "OSS";
508 break;
509 }
510#endif /* RT_OS_LINUX */
511#ifdef RT_OS_DARWIN
512 case AudioDriverType_CoreAudio:
513 {
514 driverStr = "CoreAudio";
515 break;
516 }
517#endif
518#ifdef RT_OS_OS2
519 case AudioDriverType_MMPM:
520 {
521 driverStr = "MMPM";
522 break;
523 }
524#endif
525 default:
526 ComAssertMsgFailedRet (("Wrong audio driver type! driver = %d",
527 mData->mAudioDriver),
528 E_FAIL);
529 }
530 node.setStringValue ("driver", driverStr);
531
532 node.setValue <bool> ("enabled", !!mData->mEnabled);
533
534 return S_OK;
535}
536
537/**
538 * @note Locks this object for writing.
539 */
540bool AudioAdapter::rollback()
541{
542 /* sanity */
543 AutoCaller autoCaller (this);
544 AssertComRCReturn (autoCaller.rc(), false);
545
546 AutoWriteLock alock (this);
547
548 bool changed = false;
549
550 if (mData.isBackedUp())
551 {
552 /* we need to check all data to see whether anything will be changed
553 * after rollback */
554 changed = mData.hasActualChanges();
555 mData.rollback();
556 }
557
558 return changed;
559}
560
561/**
562 * @note Locks this object for writing, together with the peer object (also
563 * for writing) if there is one.
564 */
565void AudioAdapter::commit()
566{
567 /* sanity */
568 AutoCaller autoCaller (this);
569 AssertComRCReturnVoid (autoCaller.rc());
570
571 /* sanity too */
572 AutoCaller peerCaller (mPeer);
573 AssertComRCReturnVoid (peerCaller.rc());
574
575 /* lock both for writing since we modify both (mPeer is "master" so locked
576 * first) */
577 AutoMultiWriteLock2 alock (mPeer, this);
578
579 if (mData.isBackedUp())
580 {
581 mData.commit();
582 if (mPeer)
583 {
584 /* attach new data to the peer and reshare it */
585 mPeer->mData.attach (mData);
586 }
587 }
588}
589
590/**
591 * @note Locks this object for writing, together with the peer object
592 * represented by @a aThat (locked for reading).
593 */
594void AudioAdapter::copyFrom (AudioAdapter *aThat)
595{
596 AssertReturnVoid (aThat != NULL);
597
598 /* sanity */
599 AutoCaller autoCaller (this);
600 AssertComRCReturnVoid (autoCaller.rc());
601
602 /* sanity too */
603 AutoCaller thatCaller (aThat);
604 AssertComRCReturnVoid (thatCaller.rc());
605
606 /* peer is not modified, lock it for reading (aThat is "master" so locked
607 * first) */
608 AutoMultiLock2 alock (aThat->rlock(), this->wlock());
609
610 /* this will back up current data */
611 mData.assignCopy (aThat->mData);
612}
613/* 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