VirtualBox

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

Last change on this file since 7936 was 7525, checked in by vboxsync, 17 years ago

Solaris host audio: fixes and integrated into Main. Needs more
rigorous testing, only tested locally here. BFE still acts weird.

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