Changeset 34906 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Dec 9, 2010 4:29:49 PM (14 years ago)
- svn:sync-xref-src-repo-rev:
- 68723
- Location:
- trunk/src/VBox/Devices
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/audio.c
r33400 r34906 1551 1551 1552 1552 if (s->drv_opaque) { 1553 /* Filter must be installed before initializing voices. */ 1554 drv = filteraudio_install(drv, s->drv_opaque); 1553 1555 audio_init_nb_voices_out (s, drv); 1554 1556 audio_init_nb_voices_in (s, drv); -
trunk/src/VBox/Devices/Audio/audio_int.h
r12977 r34906 314 314 unsigned cSamples); 315 315 316 /* 317 * Filter interface. 318 */ 319 typedef DECLCALLBACK(int) FNAUDIOINPUTCALLBACK(void* pvCtx, uint32_t cbSamples, const void *pvSamples); 320 typedef FNAUDIOINPUTCALLBACK *PFNAUDIOINPUTCALLBACK; 321 322 int filter_output_intercepted(void); 323 int filter_output_begin(void **ppvOutputCtx, struct audio_pcm_info *pinfo, int samples); 324 void filter_output_end(void *pvOutputCtx); 325 326 int filter_input_intercepted(void); 327 int filter_input_begin(void **ppvInputCtx, PFNAUDIOINPUTCALLBACK pfnCallback, void *pvCallback, HWVoiceIn *phw, int samples); 328 void filter_input_end(void *pvInputCtx); 329 330 struct audio_driver *filteraudio_install(struct audio_driver *pDrv, void *pDrvOpaque); 331 316 332 #endif /* audio_int.h */ -
trunk/src/VBox/Devices/Audio/audiosniffer.c
r32339 r34906 5 5 6 6 /* 7 * Copyright (C) 2006-20 07Oracle Corporation7 * Copyright (C) 2006-2010 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 22 22 23 23 #include <VBox/log.h> 24 #include <iprt/asm.h> 24 25 #include <iprt/assert.h> 25 26 #include <iprt/uuid.h> … … 40 41 /** Whether audio should reach the host driver too. */ 41 42 bool fKeepHostAudio; 43 44 /** Whether audio input operations should be forwarded to the connector. */ 45 bool fInterceptAudioInput; 42 46 43 47 /** Pointer to device instance. */ … … 100 104 101 105 /* 102 * Audio Sniffer PDM device. 103 */ 106 * Filter interface. 107 */ 108 109 /* Internal audio input context, which makes sure that: 110 * - the filter audio input callback is not called after the filter has issued filter_input_end; 111 * - maintains internal information and state of the audio stream. 112 */ 113 typedef struct SnifferInputCtx 114 { 115 /* Whether the context is still in use by the filter or I'll check. */ 116 int32_t volatile cRefs; 117 118 /* The filter callback for incoming audio data. */ 119 PFNAUDIOINPUTCALLBACK pfnFilterCallback; 120 void *pvFilterCallback; 121 122 /* Whether the stream has been ended by the filter. */ 123 bool fEndedByFilter; 124 125 /* Context pointer returned by pfnAudioInputBegin. */ 126 void *pvUserCtx; 127 128 /* Audio format used for recording. */ 129 HWVoiceIn *phw; 130 131 /* Number of bytes per frame (bitsPerSample * channels) of the actual input format. */ 132 uint32_t cBytesPerFrame; 133 134 /* Frequency of the actual audio format. */ 135 int iFreq; 136 137 /* Convertion from the actual input format to st_sample_t. */ 138 t_sample *conv; 139 140 /* If the actual format frequence differs from the requested format, this is not NULL. */ 141 void *rate; 142 143 } SnifferInputCtx; 144 145 /* 146 * Filter audio output. 147 */ 148 149 /* Whether the filter should intercept audio output. */ 150 int filter_output_intercepted(void) 151 { 152 return 0; /* @todo Not implemented yet.*/ 153 } 154 155 /* Filter informs that an audio output is starting. */ 156 int filter_output_begin(void **ppvOutputCtx, struct audio_pcm_info *pinfo, int samples) 157 { 158 return VERR_NOT_SUPPORTED; /* @todo Not implemented yet.*/ 159 } 160 161 /* Filter informs that the audio output has been stopped. */ 162 void filter_output_end(void *pvOutputCtx) 163 { 164 return; /* @todo Not implemented yet.*/ 165 } 166 167 /* 168 * Filter audio input. 169 */ 170 171 /* Whether the filter should intercept audio input. */ 172 int filter_input_intercepted(void) 173 { 174 if (!g_pData || !g_pData->pDrv) 175 { 176 return 0; 177 } 178 179 return g_pData->fInterceptAudioInput; 180 } 181 182 /* Filter informs that an audio input is starting. */ 183 int filter_input_begin (void **ppvInputCtx, PFNAUDIOINPUTCALLBACK pfnCallback, void *pvCallback, HWVoiceIn *phw, int cSamples) 184 { 185 int rc = VINF_SUCCESS; 186 187 SnifferInputCtx *pCtx = NULL; 188 189 if (!g_pData || !g_pData->pDrv) 190 { 191 return VERR_NOT_SUPPORTED; 192 } 193 194 pCtx = (SnifferInputCtx *)RTMemAlloc(sizeof(SnifferInputCtx)); 195 196 if (!pCtx) 197 { 198 return VERR_NO_MEMORY; 199 } 200 201 pCtx->cRefs = 2; /* Context is used by both the filter and the user. */ 202 pCtx->pfnFilterCallback = pfnCallback; 203 pCtx->pvFilterCallback = pvCallback; 204 pCtx->fEndedByFilter = false; 205 pCtx->pvUserCtx = NULL; 206 pCtx->phw = phw; 207 pCtx->cBytesPerFrame = 1; 208 pCtx->iFreq = 0; 209 pCtx->conv = NULL; 210 pCtx->rate = NULL; 211 212 rc = g_pData->pDrv->pfnAudioInputBegin (g_pData->pDrv, 213 &pCtx->pvUserCtx, /* Returned by the pDrv. */ 214 pCtx, 215 cSamples, /* How many samples in one block is preferred. */ 216 phw->info.freq, /* Required frequency. */ 217 phw->info.nchannels, /* Number of audio channels. */ 218 phw->info.bits); /* A sample size in one channel, samples are signed. */ 219 220 if (RT_SUCCESS(rc)) 221 { 222 *ppvInputCtx = pCtx; 223 } 224 else 225 { 226 RTMemFree(pCtx); 227 } 228 229 Log(("input_begin rc = %Rrc\n", rc)); 230 231 return rc; 232 } 233 234 /* Filter informs that the audio input must be stopped. */ 235 void filter_input_end(void *pvCtx) 236 { 237 int32_t c; 238 239 SnifferInputCtx *pCtx = (SnifferInputCtx *)pvCtx; 240 241 void *pvUserCtx = pCtx->pvUserCtx; 242 243 pCtx->fEndedByFilter = true; 244 245 c = ASMAtomicDecU32(&pCtx->cRefs); 246 247 if (c == 0) 248 { 249 /* The caller will not use this context anymore. */ 250 if (pCtx->rate) 251 { 252 st_rate_stop (pCtx->rate); 253 } 254 RTMemFree(pCtx); 255 pCtx = NULL; 256 } 257 258 if (!g_pData || !g_pData->pDrv) 259 { 260 AssertFailed(); 261 return; 262 } 263 264 g_pData->pDrv->pfnAudioInputEnd (g_pData->pDrv, 265 pvUserCtx); 266 267 Log(("input_end\n")); 268 } 269 270 271 /* 272 * Audio PDM device. 273 */ 274 static DECLCALLBACK(int) iface_AudioInputIntercept (PPDMIAUDIOSNIFFERPORT pInterface, bool fIntercept) 275 { 276 AUDIOSNIFFERSTATE *pThis = RT_FROM_MEMBER(pInterface, AUDIOSNIFFERSTATE, IPort); 277 278 Assert(g_pData == pThis); 279 280 pThis->fInterceptAudioInput = fIntercept; 281 282 return VINF_SUCCESS; 283 } 284 285 static DECLCALLBACK(int) iface_AudioInputEventBegin (PPDMIAUDIOSNIFFERPORT pInterface, 286 void *pvContext, 287 int iSampleHz, 288 int cChannels, 289 int cBits, 290 bool fUnsigned) 291 { 292 int bitIdx; 293 294 AUDIOSNIFFERSTATE *pThis = RT_FROM_MEMBER(pInterface, AUDIOSNIFFERSTATE, IPort); 295 296 int rc = VINF_SUCCESS; 297 298 SnifferInputCtx *pCtx = (SnifferInputCtx *)pvContext; 299 300 Log(("FilterAudio: AudioInputEventBegin: %dHz,%dch,%dbits,%d ended %d\n", 301 iSampleHz, cChannels, cBits, fUnsigned, pCtx->fEndedByFilter)); 302 303 Assert(g_pData == pThis); 304 305 /* Prepare a format convertion for the actually used format. */ 306 pCtx->cBytesPerFrame = ((cBits + 7) / 8) * cChannels; 307 308 if (cBits == 16) 309 { 310 bitIdx = 1; 311 } 312 else if (cBits == 32) 313 { 314 bitIdx = 2; 315 } 316 else 317 { 318 bitIdx = 0; 319 } 320 321 pCtx->conv = mixeng_conv[(cChannels == 2)? 1: 0] /* stereo */ 322 [!fUnsigned] /* sign */ 323 [0] /* big endian */ 324 [bitIdx]; /* bits */ 325 326 if (iSampleHz && iSampleHz != pCtx->phw->info.freq) 327 { 328 pCtx->rate = st_rate_start (iSampleHz, pCtx->phw->info.freq); 329 pCtx->iFreq = iSampleHz; 330 } 331 332 return rc; 333 } 334 335 static DECLCALLBACK(int) iface_AudioInputEventData (PPDMIAUDIOSNIFFERPORT pInterface, 336 void *pvContext, 337 const void *pvData, 338 uint32_t cbData) 339 { 340 AUDIOSNIFFERSTATE *pThis = RT_FROM_MEMBER(pInterface, AUDIOSNIFFERSTATE, IPort); 341 342 int rc = VINF_SUCCESS; 343 344 SnifferInputCtx *pCtx = (SnifferInputCtx *)pvContext; 345 346 Log(("FilterAudio: AudioInputEventData: pvData %p. cbData %d, ended %d\n", pvData, cbData, pCtx->fEndedByFilter)); 347 348 Assert(g_pData == pThis); 349 350 if ( !pCtx->fEndedByFilter 351 && pCtx->conv) 352 { 353 /* Convert PCM samples to st_sample_t. 354 * And then apply rate convertion if necessary. 355 */ 356 /* @todo Optimization: allocate ps buffer once per context and reallocate if cbData changes. */ 357 uint32_t cs = cbData / pCtx->cBytesPerFrame; 358 st_sample_t *ps = (st_sample_t *)RTMemAlloc(cs * sizeof(st_sample_t)); 359 if (ps) 360 { 361 void *pvSamplesRateDst = NULL; 362 363 void *pvSamples = NULL; 364 uint32_t cbSamples = 0; 365 366 pCtx->conv(ps, pvData, cs, &nominal_volume); 367 368 if (pCtx->rate) 369 { 370 uint32_t csConverted = (cs * pCtx->phw->info.freq) / pCtx->iFreq; 371 pvSamplesRateDst = RTMemAlloc(csConverted * sizeof(st_sample_t)); 372 373 if (pvSamplesRateDst) 374 { 375 int csSrc = cs; 376 int csDst = csConverted; 377 378 st_rate_flow (pCtx->rate, 379 ps, (st_sample_t *)pvSamplesRateDst, 380 &csSrc, &csDst); 381 382 pvSamples = pvSamplesRateDst; 383 cbSamples = csDst * sizeof(st_sample_t); 384 } 385 else 386 { 387 rc = VERR_NO_MEMORY; 388 } 389 } 390 else 391 { 392 pvSamples = ps; 393 cbSamples = cs * sizeof(st_sample_t); 394 } 395 396 if (cbSamples) 397 { 398 rc = pCtx->pfnFilterCallback(pCtx->pvFilterCallback, cbSamples, pvSamples); 399 } 400 401 RTMemFree(pvSamplesRateDst); 402 RTMemFree(ps); 403 } 404 else 405 { 406 rc = VERR_NO_MEMORY; 407 } 408 } 409 410 return rc; 411 } 412 413 static DECLCALLBACK(void) iface_AudioInputEventEnd (PPDMIAUDIOSNIFFERPORT pInterface, 414 void *pvContext) 415 { 416 int32_t c; 417 418 AUDIOSNIFFERSTATE *pThis = RT_FROM_MEMBER(pInterface, AUDIOSNIFFERSTATE, IPort); 419 420 SnifferInputCtx *pCtx = (SnifferInputCtx *)pvContext; 421 422 Log(("FilterAudio: AudioInputEventEnd: ended %d\n", pCtx->fEndedByFilter)); 423 424 Assert(g_pData == pThis); 425 426 c = ASMAtomicDecU32(&pCtx->cRefs); 427 428 if (c == 0) 429 { 430 /* The caller will not use this context anymore. */ 431 if (pCtx->rate) 432 { 433 st_rate_stop (pCtx->rate); 434 } 435 RTMemFree(pCtx); 436 } 437 } 438 104 439 105 440 static DECLCALLBACK(int) iface_Setup (PPDMIAUDIOSNIFFERPORT pInterface, bool fEnable, bool fKeepHostAudio) … … 159 494 * Validate configuration. 160 495 */ 161 if (!CFGMR3AreValuesValid(pCfgHandle, " \0"))496 if (!CFGMR3AreValuesValid(pCfgHandle, "InterceptAudioInput\0")) 162 497 { 163 498 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES; … … 170 505 pThis->fKeepHostAudio = true; 171 506 pThis->pDrv = NULL; 507 rc = CFGMR3QueryBoolDef(pCfgHandle, "InterceptAudioInput", &pThis->fInterceptAudioInput, false); 508 if (RT_FAILURE(rc)) 509 return PDMDEV_SET_ERROR(pDevIns, rc, 510 N_("Configuration error: Failed to get the \"YieldOnLSRRead\" value")); 172 511 173 512 /* … … 179 518 /* Audio Sniffer port */ 180 519 pThis->IPort.pfnSetup = iface_Setup; 520 pThis->IPort.pfnAudioInputIntercept = iface_AudioInputIntercept; 521 pThis->IPort.pfnAudioInputEventBegin = iface_AudioInputEventBegin; 522 pThis->IPort.pfnAudioInputEventData = iface_AudioInputEventData; 523 pThis->IPort.pfnAudioInputEventEnd = iface_AudioInputEventEnd; 181 524 182 525 /* -
trunk/src/VBox/Devices/Makefile.kmk
r34876 r34906 794 794 Audio/mixeng.c \ 795 795 Audio/noaudio.c \ 796 Audio/filteraudio.c \ 796 797 Input/DrvKeyboardQueue.cpp \ 797 798 Input/DrvMouseQueue.cpp \
Note:
See TracChangeset
for help on using the changeset viewer.