VirtualBox

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

Last change on this file since 25837 was 25819, checked in by vboxsync, 15 years ago

FreeBSD: Add support for PulseAudio. Contributed by Noriyoshi Kawano and Bernhard Froehlich (thank you)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.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/cpp/utils.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 COMMA_LOCKVAL_SRC_POS);
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 COMMA_LOCKVAL_SRC_POS);
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 if (FAILED(autoCaller.rc())) return autoCaller.rc();
181
182 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
183
184 *aEnabled = mData->mEnabled;
185
186 return S_OK;
187}
188
189STDMETHODIMP AudioAdapter::COMSETTER(Enabled)(BOOL aEnabled)
190{
191 AutoCaller autoCaller(this);
192 if (FAILED(autoCaller.rc())) return autoCaller.rc();
193
194 /* the machine needs to be mutable */
195 Machine::AutoMutableStateDependency adep(mParent);
196 if (FAILED(adep.rc())) return adep.rc();
197
198 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
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 if (FAILED(autoCaller.rc())) return autoCaller.rc();
215
216 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
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 if (FAILED(autoCaller.rc())) return autoCaller.rc();
227
228 /* the machine needs to be mutable */
229 Machine::AutoMutableStateDependency adep(mParent);
230 if (FAILED(adep.rc())) return adep.rc();
231
232 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
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_FREEBSD
265# ifdef VBOX_WITH_PULSE
266 case AudioDriverType_Pulse:
267# endif
268#endif
269#ifdef RT_OS_DARWIN
270 case AudioDriverType_CoreAudio:
271#endif
272#ifdef RT_OS_OS2
273 case AudioDriverType_MMPM:
274#endif
275 {
276 mData.backup();
277 mData->mAudioDriver = aAudioDriver;
278 break;
279 }
280
281 default:
282 {
283 AssertMsgFailed (("Wrong audio driver type %d\n",
284 aAudioDriver));
285 rc = E_FAIL;
286 }
287 }
288 }
289
290 return rc;
291}
292
293STDMETHODIMP AudioAdapter::COMGETTER(AudioController)(AudioControllerType_T *aAudioController)
294{
295 CheckComArgOutPointerValid(aAudioController);
296
297 AutoCaller autoCaller(this);
298 if (FAILED(autoCaller.rc())) return autoCaller.rc();
299
300 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
301
302 *aAudioController = mData->mAudioController;
303
304 return S_OK;
305}
306
307STDMETHODIMP AudioAdapter::COMSETTER(AudioController)(AudioControllerType_T aAudioController)
308{
309 AutoCaller autoCaller(this);
310 if (FAILED(autoCaller.rc())) return autoCaller.rc();
311
312 /* the machine needs to be mutable */
313 Machine::AutoMutableStateDependency adep(mParent);
314 if (FAILED(adep.rc())) return adep.rc();
315
316 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
317
318 HRESULT rc = S_OK;
319
320 if (mData->mAudioController != aAudioController)
321 {
322 /*
323 * which audio hardware type are we supposed to use?
324 */
325 switch (aAudioController)
326 {
327 case AudioControllerType_AC97:
328 case AudioControllerType_SB16:
329 mData.backup();
330 mData->mAudioController = aAudioController;
331 break;
332
333 default:
334 {
335 AssertMsgFailed (("Wrong audio controller type %d\n",
336 aAudioController));
337 rc = E_FAIL;
338 }
339 }
340 }
341
342 return rc;
343}
344
345// IAudioAdapter methods
346/////////////////////////////////////////////////////////////////////////////
347
348// public methods only for internal purposes
349/////////////////////////////////////////////////////////////////////////////
350
351AudioAdapter::Data::Data()
352{
353 /* Generic defaults */
354 mEnabled = false;
355 mAudioController = AudioControllerType_AC97;
356 /* Driver defaults to the null audio driver */
357 mAudioDriver = AudioDriverType_Null;
358}
359
360/**
361 * Loads settings from the given machine node.
362 * May be called once right after this object creation.
363 *
364 * @param aMachineNode <Machine> node.
365 *
366 * @note Locks this object for writing.
367 */
368HRESULT AudioAdapter::loadSettings(const settings::AudioAdapter &data)
369{
370 AutoCaller autoCaller(this);
371 AssertComRCReturnRC(autoCaller.rc());
372
373 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
374
375 /* Note: we assume that the default values for attributes of optional
376 * nodes are assigned in the Data::Data() constructor and don't do it
377 * here. It implies that this method may only be called after constructing
378 * a new AudioAdapter object while all its data fields are in the default
379 * values. Exceptions are fields whose creation time defaults don't match
380 * values that should be applied when these fields are not explicitly set
381 * in the settings file (for backwards compatibility reasons). This takes
382 * place when a setting of a newly created object must default to A while
383 * the same setting of an object loaded from the old settings file must
384 * default to B. */
385
386 mData->mEnabled = data.fEnabled;
387 mData->mAudioController = data.controllerType;
388 mData->mAudioDriver = data.driverType;
389
390 return S_OK;
391}
392
393/**
394 * Saves settings to the given machine node.
395 *
396 * @param aMachineNode <Machine> node.
397 *
398 * @note Locks this object for reading.
399 */
400HRESULT AudioAdapter::saveSettings(settings::AudioAdapter &data)
401{
402 AutoCaller autoCaller(this);
403 AssertComRCReturnRC(autoCaller.rc());
404
405 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
406
407 data.fEnabled = !!mData->mEnabled;
408 data.controllerType = mData->mAudioController;
409 data.driverType = mData->mAudioDriver;
410 return S_OK;
411}
412
413/**
414 * @note Locks this object for writing.
415 */
416bool AudioAdapter::rollback()
417{
418 /* sanity */
419 AutoCaller autoCaller(this);
420 AssertComRCReturn (autoCaller.rc(), false);
421
422 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
423
424 bool changed = false;
425
426 if (mData.isBackedUp())
427 {
428 /* we need to check all data to see whether anything will be changed
429 * after rollback */
430 changed = mData.hasActualChanges();
431 mData.rollback();
432 }
433
434 return changed;
435}
436
437/**
438 * @note Locks this object for writing, together with the peer object (also
439 * for writing) if there is one.
440 */
441void AudioAdapter::commit()
442{
443 /* sanity */
444 AutoCaller autoCaller(this);
445 AssertComRCReturnVoid (autoCaller.rc());
446
447 /* sanity too */
448 AutoCaller peerCaller (mPeer);
449 AssertComRCReturnVoid (peerCaller.rc());
450
451 /* lock both for writing since we modify both (mPeer is "master" so locked
452 * first) */
453 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
454
455 if (mData.isBackedUp())
456 {
457 mData.commit();
458 if (mPeer)
459 {
460 /* attach new data to the peer and reshare it */
461 mPeer->mData.attach (mData);
462 }
463 }
464}
465
466/**
467 * @note Locks this object for writing, together with the peer object
468 * represented by @a aThat (locked for reading).
469 */
470void AudioAdapter::copyFrom (AudioAdapter *aThat)
471{
472 AssertReturnVoid (aThat != NULL);
473
474 /* sanity */
475 AutoCaller autoCaller(this);
476 AssertComRCReturnVoid (autoCaller.rc());
477
478 /* sanity too */
479 AutoCaller thatCaller (aThat);
480 AssertComRCReturnVoid (thatCaller.rc());
481
482 /* peer is not modified, lock it for reading (aThat is "master" so locked
483 * first) */
484 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
485 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
486
487 /* this will back up current data */
488 mData.assignCopy (aThat->mData);
489}
490/* 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