VirtualBox

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

Last change on this file since 6734 was 6597, checked in by vboxsync, 17 years ago

SB16 taken from qemu

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.6 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_NullAudioDriver:
228#ifdef RT_OS_WINDOWS
229# ifdef VBOX_WITH_WINMM
230 case AudioDriverType_WINMMAudioDriver:
231# endif
232 case AudioDriverType_DSOUNDAudioDriver:
233#endif /* RT_OS_WINDOWS */
234#ifdef RT_OS_LINUX
235 case AudioDriverType_OSSAudioDriver:
236# ifdef VBOX_WITH_ALSA
237 case AudioDriverType_ALSAAudioDriver:
238# endif
239# ifdef VBOX_WITH_PULSE
240 case AudioDriverType_PulseAudioDriver:
241# endif
242#endif /* RT_OS_LINUX */
243#ifdef RT_OS_DARWIN
244 case AudioDriverType_CoreAudioDriver:
245#endif
246#ifdef RT_OS_OS2
247 case AudioDriverType_MMPMAudioDriver:
248#endif
249 {
250 mData.backup();
251 mData->mAudioDriver = aAudioDriver;
252 break;
253 }
254
255 default:
256 {
257 AssertMsgFailed (("Wrong audio driver type %d\n",
258 aAudioDriver));
259 rc = E_FAIL;
260 }
261 }
262 }
263
264 return rc;
265}
266
267STDMETHODIMP AudioAdapter::COMGETTER(AudioController)(AudioControllerType_T *aAudioController)
268{
269 if (!aAudioController)
270 return E_POINTER;
271
272 AutoCaller autoCaller (this);
273 CheckComRCReturnRC (autoCaller.rc());
274
275 AutoReaderLock alock (this);
276
277 *aAudioController = mData->mAudioController;
278
279 return S_OK;
280}
281
282STDMETHODIMP AudioAdapter::COMSETTER(AudioController)(AudioControllerType_T aAudioController)
283{
284 AutoCaller autoCaller (this);
285 CheckComRCReturnRC (autoCaller.rc());
286
287 /* the machine needs to be mutable */
288 Machine::AutoMutableStateDependency adep (mParent);
289 CheckComRCReturnRC (adep.rc());
290
291 AutoLock alock (this);
292
293 HRESULT rc = S_OK;
294
295 if (mData->mAudioController != aAudioController)
296 {
297 /*
298 * which audio hardware type are we supposed to use?
299 */
300 switch (aAudioController)
301 {
302 case AudioControllerType_AC97:
303 case AudioControllerType_SB16:
304 mData.backup();
305 mData->mAudioController = aAudioController;
306 break;
307
308 default:
309 {
310 AssertMsgFailed (("Wrong audio controller type %d\n",
311 aAudioController));
312 rc = E_FAIL;
313 }
314 }
315 }
316
317 return rc;
318}
319
320// IAudioAdapter methods
321/////////////////////////////////////////////////////////////////////////////
322
323// public methods only for internal purposes
324/////////////////////////////////////////////////////////////////////////////
325
326/**
327 * Loads settings from the given machine node.
328 * May be called once right after this object creation.
329 *
330 * @param aMachineNode <Machine> node.
331 *
332 * @note Locks this object for writing.
333 */
334HRESULT AudioAdapter::loadSettings (const settings::Key &aMachineNode)
335{
336 using namespace settings;
337
338 AssertReturn (!aMachineNode.isNull(), E_FAIL);
339
340 AutoCaller autoCaller (this);
341 AssertComRCReturnRC (autoCaller.rc());
342
343 AutoLock alock (this);
344
345 /* Note: we assume that the default values for attributes of optional
346 * nodes are assigned in the Data::Data() constructor and don't do it
347 * here. It implies that this method may only be called after constructing
348 * a new BIOSSettings object while all its data fields are in the default
349 * values. Exceptions are fields whose creation time defaults don't match
350 * values that should be applied when these fields are not explicitly set
351 * in the settings file (for backwards compatibility reasons). This takes
352 * place when a setting of a newly created object must default to A while
353 * the same setting of an object loaded from the old settings file must
354 * default to B. */
355
356 /* AudioAdapter node (required) */
357 Key audioAdapterNode = aMachineNode.key ("AudioAdapter");
358
359 /* is the adapter enabled? (required) */
360 mData->mEnabled = audioAdapterNode.value <bool> ("enabled");
361
362 /* now check the audio adapter (not required, default is AC97) */
363 const char *controller = audioAdapterNode.stringValue ("controller");
364 if (strcmp (controller, "SB16") == 0)
365 mData->mAudioController = AudioControllerType_SB16;
366 else
367 mData->mAudioController = AudioControllerType_AC97;
368
369 /* now check the audio driver (required) */
370 const char *driver = audioAdapterNode.stringValue ("driver");
371 mData->mAudioDriver = AudioDriverType_NullAudioDriver;
372 if (strcmp (driver, "null") == 0)
373 ; /* Null has been set above */
374#ifdef RT_OS_WINDOWS
375 else if (strcmp (driver, "winmm") == 0)
376#ifdef VBOX_WITH_WINMM
377 mData->mAudioDriver = AudioDriverType_WINMMAudioDriver;
378#else
379 /* fall back to dsound */
380 mData->mAudioDriver = AudioDriverType_DSOUNDAudioDriver;
381#endif
382 else if (strcmp (driver, "dsound") == 0)
383 mData->mAudioDriver = AudioDriverType_DSOUNDAudioDriver;
384#endif // RT_OS_WINDOWS
385#ifdef RT_OS_LINUX
386 else if (strcmp (driver, "oss") == 0)
387 mData->mAudioDriver = AudioDriverType_OSSAudioDriver;
388 else if (strcmp (driver, "alsa") == 0)
389# ifdef VBOX_WITH_ALSA
390 mData->mAudioDriver = AudioDriverType_ALSAAudioDriver;
391# else
392 /* fall back to OSS */
393 mData->mAudioDriver = AudioDriverType_OSSAudioDriver;
394# endif
395 else if (strcmp (driver, "pulse") == 0)
396# ifdef VBOX_WITH_PULSE
397 mData->mAudioDriver = AudioDriverType_PulseAudioDriver;
398# else
399 /* fall back to OSS */
400 mData->mAudioDriver = AudioDriverType_OSSAudioDriver;
401# endif
402#endif // RT_OS_LINUX
403#ifdef RT_OS_DARWIN
404 else if (strcmp (driver, "coreaudio") == 0)
405 mData->mAudioDriver = AudioDriverType_CoreAudioDriver;
406#endif
407#ifdef RT_OS_OS2
408 else if (strcmp (driver, "mmpm") == 0)
409 mData->mAudioDriver = AudioDriverType_MMPMAudioDriver;
410#endif
411 else
412 AssertMsgFailed (("Invalid driver '%s'\n", driver));
413
414 return S_OK;
415}
416
417/**
418 * Saves settings to the given machine node.
419 *
420 * @param aMachineNode <Machine> node.
421 *
422 * @note Locks this object for reading.
423 */
424HRESULT AudioAdapter::saveSettings (settings::Key &aMachineNode)
425{
426 using namespace settings;
427
428 AssertReturn (!aMachineNode.isNull(), E_FAIL);
429
430 AutoCaller autoCaller (this);
431 AssertComRCReturnRC (autoCaller.rc());
432
433 AutoReaderLock alock (this);
434
435 Key node = aMachineNode.createKey ("AudioAdapter");
436
437 const char *controllerStr = NULL;
438 switch (mData->mAudioController)
439 {
440 case AudioControllerType_SB16:
441 {
442 controllerStr = "SB16";
443 break;
444 }
445 default:
446 {
447 controllerStr = "AC97";
448 break;
449 }
450 }
451 node.setStringValue ("controller", controllerStr);
452
453 const char *driverStr = NULL;
454 switch (mData->mAudioDriver)
455 {
456 case AudioDriverType_NullAudioDriver:
457 {
458 driverStr = "null";
459 break;
460 }
461#ifdef RT_OS_WINDOWS
462 case AudioDriverType_WINMMAudioDriver:
463# ifdef VBOX_WITH_WINMM
464 {
465 driverStr = "winmm";
466 break;
467 }
468# endif
469 case AudioDriverType_DSOUNDAudioDriver:
470 {
471 driverStr = "dsound";
472 break;
473 }
474#endif /* RT_OS_WINDOWS */
475#ifdef RT_OS_LINUX
476 case AudioDriverType_ALSAAudioDriver:
477# ifdef VBOX_WITH_ALSA
478 {
479 driverStr = "alsa";
480 break;
481 }
482# endif
483 case AudioDriverType_PulseAudioDriver:
484# ifdef VBOX_WITH_PULSE
485 {
486 driverStr = "pulse";
487 break;
488 }
489# endif
490 case AudioDriverType_OSSAudioDriver:
491 {
492 driverStr = "oss";
493 break;
494 }
495#endif /* RT_OS_LINUX */
496#ifdef RT_OS_DARWIN
497 case AudioDriverType_CoreAudioDriver:
498 {
499 driverStr = "coreaudio";
500 break;
501 }
502#endif
503#ifdef RT_OS_OS2
504 case AudioDriverType_MMPMAudioDriver:
505 {
506 driverStr = "mmpm";
507 break;
508 }
509#endif
510 default:
511 ComAssertMsgFailedRet (("Wrong audio driver type! driver = %d\n",
512 mData->mAudioDriver),
513 E_FAIL);
514 }
515 node.setStringValue ("driver", driverStr);
516
517 node.setValue <bool> ("enabled", !!mData->mEnabled);
518
519 return S_OK;
520}
521
522/**
523 * @note Locks this object for writing.
524 */
525bool AudioAdapter::rollback()
526{
527 /* sanity */
528 AutoCaller autoCaller (this);
529 AssertComRCReturn (autoCaller.rc(), false);
530
531 AutoLock alock (this);
532
533 bool changed = false;
534
535 if (mData.isBackedUp())
536 {
537 /* we need to check all data to see whether anything will be changed
538 * after rollback */
539 changed = mData.hasActualChanges();
540 mData.rollback();
541 }
542
543 return changed;
544}
545
546/**
547 * @note Locks this object for writing, together with the peer object (also
548 * for writing) if there is one.
549 */
550void AudioAdapter::commit()
551{
552 /* sanity */
553 AutoCaller autoCaller (this);
554 AssertComRCReturnVoid (autoCaller.rc());
555
556 /* sanity too */
557 AutoCaller thatCaller (mPeer);
558 AssertComRCReturnVoid (thatCaller.rc());
559
560 /* lock both for writing since we modify both */
561 AutoMultiLock <2> alock (this->wlock(), AutoLock::maybeWlock (mPeer));
562
563 if (mData.isBackedUp())
564 {
565 mData.commit();
566 if (mPeer)
567 {
568 /* attach new data to the peer and reshare it */
569 mPeer->mData.attach (mData);
570 }
571 }
572}
573
574/**
575 * @note Locks this object for writing, together with the peer object
576 * represented by @a aThat (locked for reading).
577 */
578void AudioAdapter::copyFrom (AudioAdapter *aThat)
579{
580 AssertReturnVoid (aThat != NULL);
581
582 /* sanity */
583 AutoCaller autoCaller (this);
584 AssertComRCReturnVoid (autoCaller.rc());
585
586 /* sanity too */
587 AutoCaller thatCaller (mPeer);
588 AssertComRCReturnVoid (thatCaller.rc());
589
590 /* peer is not modified, lock it for reading */
591 AutoMultiLock <2> alock (this->wlock(), aThat->rlock());
592
593 /* this will back up current data */
594 mData.assignCopy (aThat->mData);
595}
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