VirtualBox

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

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

Main: added default audio driver method to ISystemProperties

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