VirtualBox

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

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

Solaris/Audio: Boomer(OSS) support (disabled, requires snv_115+).

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