VirtualBox

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

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

AudioAdapterImpl.cpp: There might be more OSS users, so join them up.

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