VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/audiosniffer.c@ 6521

Last change on this file since 6521 was 5999, checked in by vboxsync, 17 years ago

The Giant CDDL Dual-License Header Change.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.0 KB
Line 
1/** @file
2 *
3 * VBox audio device:
4 * Audio sniffer device
5 */
6
7/*
8 * Copyright (C) 2006-2007 innotek GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#define LOG_GROUP LOG_GROUP_DEV_AUDIO
20#define AUDIO_CAP "sniffer"
21#include <VBox/pdm.h>
22#include <VBox/err.h>
23
24#include <VBox/log.h>
25#include <iprt/assert.h>
26#include <iprt/uuid.h>
27#include <iprt/string.h>
28#include <iprt/alloc.h>
29
30#include "Builtins.h"
31#include "../../vl_vbox.h"
32
33#include "audio.h"
34#include "audio_int.h"
35
36typedef struct _AUDIOSNIFFERSTATE
37{
38 /** If the device is enabled. */
39 bool fEnabled;
40
41 /** Whether audio should reach the host driver too. */
42 bool fKeepHostAudio;
43
44 /** Pointer to device instance. */
45 PPDMDEVINS pDevIns;
46
47 /** Audio Sniffer port base interface. */
48 PDMIBASE Base;
49 /** Audio Sniffer port interface. */
50 PDMIAUDIOSNIFFERPORT Port;
51
52 /** Pointer to base interface of the driver. */
53 PPDMIBASE pDrvBase;
54 /** Audio Sniffer connector interface */
55 PPDMIAUDIOSNIFFERCONNECTOR pDrv;
56
57} AUDIOSNIFFERSTATE;
58
59static AUDIOSNIFFERSTATE *g_pData = NULL;
60
61/*
62 * Public sniffer callbacks to be called from audio driver.
63 */
64
65/* *** Subject to change ***
66 * Process audio output. The function is called when an audio output
67 * driver is about to play audio samples.
68 *
69 * It is expected that there is only one audio data flow,
70 * i.e. one voice.
71 *
72 * @param hw Audio samples information.
73 * @param pvSamples Pointer to audio samples.
74 * @param cSamples Number of audio samples in the buffer.
75 * @returns 'true' if audio also to be played back by the output driver.
76 * 'false' if audio should not be played.
77 */
78DECLCALLBACK(bool) sniffer_run_out (HWVoiceOut *hw, void *pvSamples, unsigned cSamples)
79{
80 int samplesPerSec;
81 int nChannels;
82 int bitsPerSample;
83 bool fUnsigned;
84
85 if (!g_pData || !g_pData->pDrv || !g_pData->fEnabled)
86 {
87 return true;
88 }
89
90 samplesPerSec = hw->info.freq;
91 nChannels = hw->info.nchannels;
92 bitsPerSample = hw->info.bits;
93 fUnsigned = (hw->info.sign == 0);
94
95 g_pData->pDrv->pfnAudioSamplesOut (g_pData->pDrv, pvSamples, cSamples,
96 samplesPerSec, nChannels, bitsPerSample, fUnsigned);
97
98 return g_pData->fKeepHostAudio;
99}
100
101
102/*
103 * Audio Sniffer PDM device.
104 */
105
106/* Converts a Audio Sniffer port interface pointer to a Audio Sniffer state pointer. */
107#define IAUDIOSNIFFERPORT_2_AUDIOSNIFFERSTATE(pInterface) ((AUDIOSNIFFERSTATE *)((uintptr_t)pInterface - RT_OFFSETOF(AUDIOSNIFFERSTATE, Port)))
108
109static DECLCALLBACK(int) iface_Setup (PPDMIAUDIOSNIFFERPORT pInterface, bool fEnable, bool fKeepHostAudio)
110{
111 AUDIOSNIFFERSTATE *pData = IAUDIOSNIFFERPORT_2_AUDIOSNIFFERSTATE(pInterface);
112
113 Assert(g_pData == pData);
114
115 pData->fEnabled = fEnable;
116 pData->fKeepHostAudio = fKeepHostAudio;
117
118 return VINF_SUCCESS;
119}
120
121/**
122 * Queries an interface to the device.
123 *
124 * @returns Pointer to interface.
125 * @returns NULL if the interface was not supported by the driver.
126 * @param pInterface Pointer to this interface structure.
127 * @param enmInterface The requested interface identification.
128 */
129static DECLCALLBACK(void *) iface_QueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
130{
131 AUDIOSNIFFERSTATE *pData = (AUDIOSNIFFERSTATE *)((uintptr_t)pInterface - RT_OFFSETOF(AUDIOSNIFFERSTATE, Base));
132
133 switch (enmInterface)
134 {
135 case PDMINTERFACE_BASE:
136 return &pData->Base;
137 case PDMINTERFACE_AUDIO_SNIFFER_PORT:
138 return &pData->Port;
139 default:
140 return NULL;
141 }
142}
143
144/**
145 * Construct a device instance for a VM.
146 *
147 * @returns VBox status.
148 * @param pDevIns The device instance data.
149 * If the registration structure is needed, pDevIns->pDevReg points to it.
150 * @param iInstance Instance number. Use this to figure out which registers and such to use.
151 * The device number is also found in pDevIns->iInstance, but since it's
152 * likely to be freqently used PDM passes it as parameter.
153 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
154 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
155 * iInstance it's expected to be used a bit in this function.
156 */
157static DECLCALLBACK(int) audioSnifferR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
158{
159 int rc = VINF_SUCCESS;
160
161 AUDIOSNIFFERSTATE *pData = PDMINS2DATA(pDevIns, AUDIOSNIFFERSTATE *);
162
163 Assert(iInstance == 0);
164
165 /*
166 * Validate configuration.
167 */
168 if (!CFGMR3AreValuesValid(pCfgHandle, "\0"))
169 {
170 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
171 }
172
173 /*
174 * Initialize data.
175 */
176 pData->fEnabled = false;
177 pData->fKeepHostAudio = true;
178 pData->pDrv = NULL;
179
180 /*
181 * Interfaces
182 */
183 /* Base */
184 pData->Base.pfnQueryInterface = iface_QueryInterface;
185
186 /* Audio Sniffer port */
187 pData->Port.pfnSetup = iface_Setup;
188
189 /*
190 * Get the corresponding connector interface
191 */
192 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pData->Base, &pData->pDrvBase, "Audio Sniffer Port");
193
194 if (VBOX_SUCCESS(rc))
195 {
196 pData->pDrv = (PPDMIAUDIOSNIFFERCONNECTOR)pData->pDrvBase->pfnQueryInterface(pData->pDrvBase, PDMINTERFACE_AUDIO_SNIFFER_CONNECTOR);
197
198 if (!pData->pDrv)
199 {
200 AssertMsgFailed(("LUN #0 doesn't have a Audio Sniffer connector interface rc=%Vrc\n", rc));
201 rc = VERR_PDM_MISSING_INTERFACE;
202 }
203 }
204 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
205 {
206 Log(("%s/%d: warning: no driver attached to LUN #0.\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
207 rc = VINF_SUCCESS;
208 }
209 else
210 {
211 AssertMsgFailed(("Failed to attach LUN #0. rc=%Vrc\n", rc));
212 }
213
214 if (VBOX_SUCCESS (rc))
215 {
216 /* Save PDM device instance data for future reference. */
217 pData->pDevIns = pDevIns;
218
219 /* Save the pointer to created instance in the global variable, so other
220 * functions could reach it.
221 */
222 g_pData = pData;
223 }
224
225 return rc;
226}
227
228/**
229 * Destruct a device instance.
230 *
231 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
232 * resources can be freed correctly.
233 *
234 * @returns VBox status.
235 * @param pDevIns The device instance data.
236 */
237static DECLCALLBACK(int) audioSnifferR3Destruct(PPDMDEVINS pDevIns)
238{
239 /* Zero the global pointer. */
240 g_pData = NULL;
241
242 return VINF_SUCCESS;
243}
244
245/**
246 * The Audio Sniffer device registration structure.
247 */
248const PDMDEVREG g_DeviceAudioSniffer =
249{
250 /* u32Version */
251 PDM_DEVREG_VERSION,
252 /* szDeviceName */
253 "AudioSniffer",
254 /* szGCMod */
255 "",
256 /* szR0Mod */
257 "",
258 /* pszDescription */
259 "Audio Sniffer device. Redirects audio data to sniffer driver.",
260 /* fFlags */
261 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT,
262 /* fClass */
263 PDM_DEVREG_CLASS_AUDIO,
264 /* cMaxInstances */
265 1,
266 /* cbInstance */
267 sizeof(AUDIOSNIFFERSTATE),
268 /* pfnConstruct */
269 audioSnifferR3Construct,
270 /* pfnDestruct */
271 audioSnifferR3Destruct,
272 /* pfnRelocate */
273 NULL,
274 /* pfnIOCtl */
275 NULL,
276 /* pfnPowerOn */
277 NULL,
278 /* pfnReset */
279 NULL,
280 /* pfnSuspend */
281 NULL,
282 /* pfnResume */
283 NULL,
284 /* pfnAttach */
285 NULL,
286 /* pfnDetach */
287 NULL,
288 /* pfnQueryInterface */
289 NULL,
290 /* pfnInitComplete */
291 NULL
292};
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