Changeset 60925 in vbox for trunk/src/VBox/Devices/Audio/AudioMixer.cpp
- Timestamp:
- May 10, 2016 1:27:44 PM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/AudioMixer.cpp
r60353 r60925 4 4 * emulations to achieve proper multiplexing from/to attached 5 5 * devices LUNs. 6 * 7 * This mixer acts as a layer between the audio connector interface and 8 * the actual device emulation, providing mechanisms for audio sources (input) and 9 * audio sinks (output). 10 * 11 * As audio driver instances are handled as LUNs on the device level, this 12 * audio mixer then can take care of e.g. mixing various inputs/outputs to/from 13 * a specific source/sink. 14 * 15 * How and which audio streams are connected to sinks/sources depends on how 16 * the audio mixer has been set up. 17 * 18 * A sink can connect multiple output streams together, whereas a source 19 * does this with input streams. Each sink / source consists of one or more 20 * so-called mixer streams, which then in turn have pointers to the actual 21 * PDM audio input/output streams. 6 22 */ 7 23 … … 32 48 #include <iprt/string.h> 33 49 34 static int audioMixerUpdateSinkVolume(PAUDMIXSINK pSink, const PPDMAUDIOVOLUME pVolMaster); 35 36 37 int AudioMixerAddSink(PAUDIOMIXER pMixer, const char *pszName, AUDMIXSINKDIR enmDir, PAUDMIXSINK *ppSink) 50 static void audioMixerSinkDestroyInternal(PAUDMIXSINK pSink); 51 static int audioMixerSinkUpdateVolume(PAUDMIXSINK pSink, const PPDMAUDIOVOLUME pVolMaster); 52 static void audioMixerSinkRemoveStreamInternal(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream); 53 54 static void audioMixerStreamDestroyInternal(PAUDMIXSTREAM pStream); 55 static void audioMixerStreamFree(PAUDMIXSTREAM pStream); 56 57 int AudioMixerCreateSink(PAUDIOMIXER pMixer, const char *pszName, AUDMIXSINKDIR enmDir, PAUDMIXSINK *ppSink) 38 58 { 39 59 AssertPtrReturn(pMixer, VERR_INVALID_POINTER); 40 60 AssertPtrReturn(pszName, VERR_INVALID_POINTER); 41 /* *ppSink is optional. */61 /* ppSink is optional. */ 42 62 43 63 int rc = VINF_SUCCESS; … … 80 100 } 81 101 82 int AudioMixerAddStreamIn(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOGSTSTRMIN pStream,83 uint32_t uFlags, PAUDMIXSTREAM *ppStream)84 {85 AssertPtrReturn(pSink, VERR_INVALID_POINTER);86 AssertPtrReturn(pStream, VERR_INVALID_POINTER);87 /** @todo Add flag validation. */88 /* ppStream is optional. */89 90 int rc;91 92 if (pSink->cStreams == UINT8_MAX) /* 255 streams per sink max. */93 return VERR_TOO_MUCH_DATA;94 95 PAUDMIXSTREAM pMixStream96 = (PAUDMIXSTREAM)RTMemAllocZ(sizeof(AUDMIXSTREAM));97 if (pMixStream)98 {99 pMixStream->pConn = pConnector;100 pMixStream->pIn = pStream;101 /** @todo Process flags. */102 103 RTListAppend(&pSink->lstStreams, &pMixStream->Node);104 pSink->cStreams++;105 106 LogFlowFunc(("%s: pStream=%p, cStreams=%RU8\n",107 pSink->pszName, pMixStream, pSink->cStreams));108 109 /* Increase the stream's reference count to let others know110 * we're reyling on it to be around now. */111 pStream->State.cRefs++;112 113 if (ppStream)114 *ppStream = pMixStream;115 116 rc = VINF_SUCCESS;117 }118 else119 rc = VERR_NO_MEMORY;120 121 return rc;122 }123 124 int AudioMixerAddStreamOut(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOGSTSTRMOUT pStream,125 uint32_t uFlags, PAUDMIXSTREAM *ppStream)126 {127 AssertPtrReturn(pSink, VERR_INVALID_POINTER);128 AssertPtrReturn(pStream, VERR_INVALID_POINTER);129 /** @todo Add flag validation. */130 /* ppStream is optional. */131 132 int rc;133 134 if (pSink->cStreams == UINT8_MAX) /* 255 streams per sink max. */135 return VERR_TOO_MUCH_DATA;136 137 PAUDMIXSTREAM pMixStream138 = (PAUDMIXSTREAM)RTMemAllocZ(sizeof(AUDMIXSTREAM));139 if (pMixStream)140 {141 pMixStream->pConn = pConnector;142 pMixStream->pOut = pStream;143 /** @todo Process flags. */144 145 RTListAppend(&pSink->lstStreams, &pMixStream->Node);146 pSink->cStreams++;147 148 LogFlowFunc(("%s: pStream=%p, cStreams=%RU8\n",149 pSink->pszName, pMixStream, pSink->cStreams));150 151 /* Increase the stream's reference count to let others know152 * we're reyling on it to be around now. */153 pStream->State.cRefs++;154 155 if (ppStream)156 *ppStream = pMixStream;157 158 rc = VINF_SUCCESS;159 }160 else161 rc = VERR_NO_MEMORY;162 163 return rc;164 }165 166 int AudioMixerControlStream(PAUDIOMIXER pMixer, PAUDMIXSTREAM pHandle)167 {168 return VERR_NOT_IMPLEMENTED;169 }170 171 102 int AudioMixerCreate(const char *pszName, uint32_t uFlags, PAUDIOMIXER *ppMixer) 172 103 { … … 207 138 } 208 139 140 void AudioMixerDebug(PAUDIOMIXER pMixer, PCDBGFINFOHLP pHlp, const char *pszArgs) 141 { 142 PAUDMIXSINK pSink; 143 unsigned iSink = 0; 144 145 pHlp->pfnPrintf(pHlp, "[Master] %s: lVol=%u, rVol=%u, fMuted=%RTbool\n", pMixer->pszName, 146 pMixer->VolMaster.uLeft, pMixer->VolMaster.uRight, pMixer->VolMaster.fMuted); 147 148 RTListForEach(&pMixer->lstSinks, pSink, AUDMIXSINK, Node) 149 { 150 pHlp->pfnPrintf(pHlp, "[Sink %u] %s: lVol=%u, rVol=%u, fMuted=%RTbool\n", iSink, pSink->pszName, 151 pSink->Volume.uLeft, pSink->Volume.uRight, pSink->Volume.fMuted); 152 ++iSink; 153 } 154 } 155 209 156 void AudioMixerDestroy(PAUDIOMIXER pMixer) 210 157 { … … 216 163 PAUDMIXSINK pSink, pSinkNext; 217 164 RTListForEachSafe(&pMixer->lstSinks, pSink, pSinkNext, AUDMIXSINK, Node) 218 AudioMixerRemoveSink(pMixer, pSink); 219 220 Assert(pMixer->cSinks == 0); 165 audioMixerSinkDestroyInternal(pSink); 221 166 222 167 if (pMixer->pszName) … … 227 172 228 173 RTMemFree(pMixer); 229 } 230 231 static void audioMixerDestroySink(PAUDMIXSINK pSink) 174 pMixer = NULL; 175 } 176 177 int AudioMixerGetDeviceFormat(PAUDIOMIXER pMixer, PPDMAUDIOSTREAMCFG pCfg) 178 { 179 AssertPtrReturn(pMixer, VERR_INVALID_POINTER); 180 AssertPtrReturn(pCfg, VERR_INVALID_POINTER); 181 182 /** @todo Perform a deep copy, if needed. */ 183 *pCfg = pMixer->devFmt; 184 185 return VINF_SUCCESS; 186 } 187 188 void AudioMixerInvalidate(PAUDIOMIXER pMixer) 189 { 190 AssertPtrReturnVoid(pMixer); 191 192 LogFlowFunc(("%s: Invalidating ...\n", pMixer->pszName)); 193 194 /* Propagate new master volume to all connected sinks. */ 195 PAUDMIXSINK pSink; 196 RTListForEach(&pMixer->lstSinks, pSink, AUDMIXSINK, Node) 197 { 198 int rc2 = audioMixerSinkUpdateVolume(pSink, &pMixer->VolMaster); 199 AssertRC(rc2); 200 } 201 } 202 203 void AudioMixerRemoveSink(PAUDIOMIXER pMixer, PAUDMIXSINK pSink) 204 { 205 AssertPtrReturnVoid(pMixer); 206 if (!pSink) 207 return; 208 209 /** @todo Check if pSink is part of pMixer. */ 210 211 AudioMixerSinkRemoveAllStreams(pSink); 212 213 Assert(pSink->cStreams == 0); 214 215 RTListNodeRemove(&pSink->Node); 216 217 Assert(pMixer->cSinks); 218 pMixer->cSinks--; 219 220 LogFlowFunc(("%s: pSink=%s, cSinks=%RU8\n", 221 pMixer->pszName, pSink->pszName, pMixer->cSinks)); 222 } 223 224 int AudioMixerSetDeviceFormat(PAUDIOMIXER pMixer, PPDMAUDIOSTREAMCFG pCfg) 225 { 226 AssertPtrReturn(pMixer, VERR_INVALID_POINTER); 227 AssertPtrReturn(pCfg, VERR_INVALID_POINTER); 228 229 /** @todo Perform a deep copy, if needed. */ 230 pMixer->devFmt = *pCfg; 231 232 return VINF_SUCCESS; 233 } 234 235 /** 236 * Sets the mixer's master volume. 237 * 238 * @returns IPRT status code. 239 * @param pMixer Mixer to set master volume for. 240 * @param pVol Volume to set. 241 */ 242 int AudioMixerSetMasterVolume(PAUDIOMIXER pMixer, PPDMAUDIOVOLUME pVol) 243 { 244 AssertPtrReturn(pMixer, VERR_INVALID_POINTER); 245 AssertPtrReturn(pVol, VERR_INVALID_POINTER); 246 247 pMixer->VolMaster = *pVol; 248 249 LogFlowFunc(("%s: lVol=%RU32, rVol=%RU32 => fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n", 250 pMixer->pszName, pVol->uLeft, pVol->uRight, 251 pMixer->VolMaster.fMuted, pMixer->VolMaster.uLeft, pMixer->VolMaster.uRight)); 252 253 AudioMixerInvalidate(pMixer); 254 return VINF_SUCCESS; 255 } 256 257 /***************************************************************************** 258 * Mixer Sink implementation. 259 *****************************************************************************/ 260 261 int AudioMixerSinkAddStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream) 262 { 263 AssertPtrReturn(pSink, VERR_INVALID_POINTER); 264 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 265 266 if (pSink->cStreams == UINT8_MAX) /* 255 streams per sink max. */ 267 return VERR_NO_MORE_HANDLES; 268 269 /** @todo Check if stream already is assigned to (another) sink. */ 270 271 RTListAppend(&pSink->lstStreams, &pStream->Node); 272 pSink->cStreams++; 273 274 LogFlowFunc(("%s: cStreams=%RU8\n", pSink->pszName, pSink->cStreams)); 275 276 return VINF_SUCCESS; 277 } 278 279 static PDMAUDIOSTREAMCMD audioMixerSinkToStreamCmd(AUDMIXSINKCMD enmCmd) 280 { 281 switch (enmCmd) 282 { 283 case AUDMIXSINKCMD_ENABLE: return PDMAUDIOSTREAMCMD_ENABLE; 284 case AUDMIXSINKCMD_DISABLE: return PDMAUDIOSTREAMCMD_DISABLE; 285 case AUDMIXSINKCMD_PAUSE: return PDMAUDIOSTREAMCMD_PAUSE; 286 case AUDMIXSINKCMD_RESUME: return PDMAUDIOSTREAMCMD_RESUME; 287 default: break; 288 } 289 290 AssertMsgFailed(("Unsupported sink command %ld\n", enmCmd)); 291 return PDMAUDIOSTREAMCMD_UNKNOWN; 292 } 293 294 int AudioMixerSinkCtl(PAUDMIXSINK pSink, AUDMIXSINKCMD enmCmd) 295 { 296 AssertPtrReturn(pSink, VERR_INVALID_POINTER); 297 298 PDMAUDIOSTREAMCMD enmCmdStream = audioMixerSinkToStreamCmd(enmCmd); 299 if (enmCmdStream == PDMAUDIOSTREAMCMD_UNKNOWN) 300 return VERR_NOT_SUPPORTED; 301 302 int rc = VINF_SUCCESS; 303 304 PAUDMIXSTREAM pStream; 305 RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node) 306 { 307 int rc2 = AudioMixerStreamCtl(pStream, enmCmdStream, AUDMIXSTRMCTL_FLAG_NONE); 308 if (RT_SUCCESS(rc)) 309 rc = rc2; 310 /* Keep going. Flag? */ 311 } 312 313 LogFlowFunc(("Sink=%s, Cmd=%ld, rc=%Rrc\n", pSink->pszName, enmCmd, rc)); 314 return rc; 315 } 316 317 void AudioMixerSinkDestroy(PAUDMIXSINK pSink) 318 { 319 audioMixerSinkDestroyInternal(pSink); 320 } 321 322 static void audioMixerSinkDestroyInternal(PAUDMIXSINK pSink) 232 323 { 233 324 AssertPtrReturnVoid(pSink); … … 235 326 return; 236 327 328 LogFunc(("%s\n", pSink->pszName)); 329 330 PAUDMIXSTREAM pStream, pStreamNext; 331 RTListForEachSafe(&pSink->lstStreams, pStream, pStreamNext, AUDMIXSTREAM, Node) 332 { 333 audioMixerSinkRemoveStreamInternal(pSink, pStream); 334 audioMixerStreamDestroyInternal(pStream); 335 } 336 337 Assert(pSink->cStreams == 0); 338 237 339 if (pSink->pszName) 238 340 RTStrFree(pSink->pszName); … … 241 343 } 242 344 243 static void audioMixerDestroyStream(PAUDMIXSTREAM pStream) 244 { 245 AssertPtrReturnVoid(pStream); 246 if (!pStream) 247 return; 248 249 RTMemFree(pStream); 250 } 251 252 int AudioMixerGetDeviceFormat(PAUDIOMIXER pMixer, PPDMAUDIOSTREAMCFG pCfg) 253 { 254 AssertPtrReturn(pMixer, VERR_INVALID_POINTER); 255 AssertPtrReturn(pCfg, VERR_INVALID_POINTER); 256 257 /** @todo Perform a deep copy, if needed. */ 258 *pCfg = pMixer->devFmt; 259 260 return VINF_SUCCESS; 261 } 262 263 uint32_t AudioMixerGetStreamCount(PAUDIOMIXER pMixer) 264 { 265 AssertPtrReturn(pMixer, 0); 266 267 uint32_t cStreams = 0; 268 269 PAUDMIXSINK pSink; 270 RTListForEach(&pMixer->lstSinks, pSink, AUDMIXSINK, Node) 271 cStreams += pSink->cStreams; 272 273 return cStreams; 274 } 275 276 void AudioMixerInvalidate(PAUDIOMIXER pMixer) 277 { 278 AssertPtrReturnVoid(pMixer); 279 280 LogFlowFunc(("%s: Invalidating ...\n", pMixer->pszName)); 281 282 /* Propagate new master volume to all connected sinks. */ 283 PAUDMIXSINK pSink; 284 RTListForEach(&pMixer->lstSinks, pSink, AUDMIXSINK, Node) 285 { 286 int rc2 = audioMixerUpdateSinkVolume(pSink, &pMixer->VolMaster); 287 AssertRC(rc2); 288 } 289 } 290 291 int AudioMixerProcessSinkIn(PAUDMIXSINK pSink, AUDMIXOP enmOp, void *pvBuf, uint32_t cbBuf, uint32_t *pcbProcessed) 345 PAUDMIXSTREAM AudioMixerSinkGetStream(PAUDMIXSINK pSink, uint8_t uIndex) 346 { 347 AssertPtrReturn(pSink, NULL); 348 AssertMsgReturn(uIndex < pSink->cStreams, 349 ("Index %RU8 exceeds stream count (%RU8)", uIndex, pSink->cStreams), NULL); 350 351 /* Slow lookup, d'oh. */ 352 PAUDMIXSTREAM pStream = RTListGetFirst(&pSink->lstStreams, AUDMIXSTREAM, Node); 353 while (uIndex) 354 { 355 pStream = RTListGetNext(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node); 356 uIndex--; 357 } 358 359 AssertPtr(pStream); 360 return pStream; 361 } 362 363 uint8_t AudioMixerSinkGetStreamCount(PAUDMIXSINK pSink) 364 { 365 if (!pSink) 366 return 0; 367 368 return pSink->cStreams; 369 } 370 371 int AudioMixerSinkRead(PAUDMIXSINK pSink, AUDMIXOP enmOp, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead) 292 372 { 293 373 AssertPtrReturn(pSink, VERR_INVALID_POINTER); 294 374 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 295 AssertReturn(cbBuf, VERR_INVALID_PARAMETER);296 /* pcb Processed is optional. */375 AssertReturn(cbBuf, VERR_INVALID_PARAMETER); 376 /* pcbRead is optional. */ 297 377 298 378 /** @todo Handle mixing operation enmOp! */ … … 303 383 304 384 int rc = VERR_NOT_FOUND; 305 uint32_t cbProcessed = 0; 306 307 LogFlowFunc(("%s: pvBuf=%p, cbBuf=%zu\n", pSink->pszName, pvBuf, cbBuf)); 385 uint32_t cbRead = 0; 308 386 309 387 PAUDMIXSTREAM pStream; 310 388 RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node) 311 389 { 312 if (!pStream->pConn->pfnIsActiveIn(pStream->pConn, pStream-> pIn))390 if (!pStream->pConn->pfnIsActiveIn(pStream->pConn, pStream->InOut.pIn)) 313 391 continue; 314 392 … … 318 396 while (cbToRead) 319 397 { 320 uint32_t cbRead ;398 uint32_t cbReadStrm; 321 399 AssertPtr(pStream->pConn); 322 rc = pStream->pConn->pfnRead(pStream->pConn, pStream-> pIn,323 (uint8_t *)pvMixBuf + cbTotalRead, cbToRead, &cbRead );400 rc = pStream->pConn->pfnRead(pStream->pConn, pStream->InOut.pIn, 401 (uint8_t *)pvMixBuf + cbTotalRead, cbToRead, &cbReadStrm); 324 402 if ( RT_FAILURE(rc) 325 || !cbRead )403 || !cbReadStrm) 326 404 break; 327 405 328 406 /** @todo Right now we only handle one stream (the last one added in fact). */ 329 407 330 AssertBreakStmt(cbRead <= cbToRead, rc = VERR_BUFFER_OVERFLOW);331 cbToRead -= cbRead;332 cbTotalRead += cbRead ;408 AssertBreakStmt(cbReadStrm <= cbToRead, rc = VERR_BUFFER_OVERFLOW); 409 cbToRead -= cbReadStrm; 410 cbTotalRead += cbReadStrm; 333 411 } 334 412 … … 336 414 continue; 337 415 338 cb Processed = RT_MAX(cbProcessed, cbTotalRead);416 cbRead = RT_MAX(cbRead, cbTotalRead); 339 417 } 340 418 341 419 if (RT_SUCCESS(rc)) 342 420 { 343 memcpy(pvBuf, pvMixBuf, cb Processed); /* @todo Use an intermediate mixing buffer per sink! */344 345 if (pcb Processed)346 *pcb Processed = cbProcessed;421 memcpy(pvBuf, pvMixBuf, cbRead); /* @todo Use an intermediate mixing buffer per sink! */ 422 423 if (pcbRead) 424 *pcbRead = cbRead; 347 425 } 348 426 349 427 RTMemFree(pvMixBuf); 350 428 351 Log FlowFunc(("cbProcessed=%RU32, rc=%Rrc\n", cbProcessed, rc));429 Log3Func(("%s: cbRead=%RU32, rc=%Rrc\n", pSink->pszName, cbRead, rc)); 352 430 return rc; 353 431 } 354 432 355 int AudioMixerProcessSinkOut(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbProcessed) 356 { 357 return VERR_NOT_IMPLEMENTED; 358 } 359 360 void AudioMixerRemoveSink(PAUDIOMIXER pMixer, PAUDMIXSINK pSink) 361 { 362 AssertPtrReturnVoid(pMixer); 363 if (!pSink) 364 return; 365 366 PAUDMIXSTREAM pStream, pStreamNext; 367 RTListForEachSafe(&pSink->lstStreams, pStream, pStreamNext, AUDMIXSTREAM, Node) 368 AudioMixerRemoveStream(pSink, pStream); 369 370 Assert(pSink->cStreams == 0); 371 372 RTListNodeRemove(&pSink->Node); 373 Assert(pMixer->cSinks); 374 pMixer->cSinks--; 375 376 LogFlowFunc(("%s: pSink=%s, cSinks=%RU8\n", 377 pMixer->pszName, pSink->pszName, pMixer->cSinks)); 378 379 audioMixerDestroySink(pSink); 380 } 381 382 void AudioMixerRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream) 433 static void audioMixerSinkRemoveStreamInternal(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream) 383 434 { 384 435 AssertPtrReturnVoid(pSink); … … 386 437 return; 387 438 439 /** @todo Check if pStream is part of pSink. */ 440 388 441 Assert(pSink->cStreams); 389 RTListNodeRemove(&pStream->Node);390 pSink->cStreams--;391 442 392 443 #ifdef DEBUG 393 444 const char *pszStream = pSink->enmDir == AUDMIXSINKDIR_INPUT 394 ? pStream-> pIn->MixBuf.pszName : pStream->pOut->MixBuf.pszName;395 396 LogFlowFunc(("%s: pStream=%s, cStreams=%RU8\n",445 ? pStream->InOut.pIn->MixBuf.pszName : pStream->InOut.pOut->MixBuf.pszName; 446 447 LogFlowFunc(("%s: (Stream = %s), cStreams=%RU8\n", 397 448 pSink->pszName, pszStream ? pszStream : "<Unnamed>", pSink->cStreams)); 398 449 #endif 399 450 400 /* Decrease the reference count again. */ 401 switch (pSink->enmDir) 402 { 403 case AUDMIXSINKDIR_INPUT: 404 { 405 Assert(pStream->pIn->State.cRefs); 406 pStream->pIn->State.cRefs--; 407 break; 408 } 409 410 case AUDMIXSINKDIR_OUTPUT: 411 { 412 Assert(pStream->pOut->State.cRefs); 413 pStream->pOut->State.cRefs--; 414 break; 415 } 416 417 default: 418 AssertMsgFailed(("Not implemented\n")); 419 break; 420 } 421 422 audioMixerDestroyStream(pStream); 423 } 424 425 int AudioMixerSetDeviceFormat(PAUDIOMIXER pMixer, PPDMAUDIOSTREAMCFG pCfg) 426 { 427 AssertPtrReturn(pMixer, VERR_INVALID_POINTER); 428 AssertPtrReturn(pCfg, VERR_INVALID_POINTER); 429 430 /** @todo Perform a deep copy, if needed. */ 431 pMixer->devFmt = *pCfg; 451 /* Remove stream from sink. */ 452 RTListNodeRemove(&pStream->Node); 453 454 Assert(pSink->cStreams); 455 pSink->cStreams--; 456 } 457 458 void AudioMixerSinkRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream) 459 { 460 audioMixerSinkRemoveStreamInternal(pSink, pStream); 461 } 462 463 /** 464 * Removes all attached streams from a given sink. 465 * 466 * @param pSink Sink to remove attached streams from. 467 */ 468 void AudioMixerSinkRemoveAllStreams(PAUDMIXSINK pSink) 469 { 470 if (!pSink) 471 return; 472 473 LogFunc(("%s\n", pSink->pszName)); 474 475 PAUDMIXSTREAM pStream, pStreamNext; 476 RTListForEachSafe(&pSink->lstStreams, pStream, pStreamNext, AUDMIXSTREAM, Node) 477 audioMixerSinkRemoveStreamInternal(pSink, pStream); 478 479 Assert(pSink->cStreams == 0); 480 } 481 482 int AudioMixerSinkSetFormat(PAUDMIXSINK pSink, PPDMPCMPROPS pPCMProps) 483 { 484 AssertPtrReturn(pSink, VERR_INVALID_POINTER); 485 AssertPtrReturn(pPCMProps, VERR_INVALID_POINTER); 486 487 memcpy(&pSink->PCMProps, pPCMProps, sizeof(PDMPCMPROPS)); 488 489 PAUDMIXSTREAM pStream; 490 RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node) 491 { 492 /** @todo Invalidate mix buffers! */ 493 } 432 494 433 495 return VINF_SUCCESS; 434 496 } 435 497 436 static int audioMixerUpdateSinkVolume(PAUDMIXSINK pSink, const PPDMAUDIOVOLUME pVolMaster) 498 /** 499 * Set the volume of an individual sink. 500 * 501 * @returns IPRT status code. 502 * @param pSink Sink to set volume for. 503 * @param pVol Volume to set. 504 */ 505 int AudioMixerSinkSetVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol) 506 { 507 AssertPtrReturn(pSink, VERR_INVALID_POINTER); 508 AssertPtrReturn(pVol, VERR_INVALID_POINTER); 509 AssertPtr(pSink->pParent); 510 511 LogFlowFunc(("%s: fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n", pSink->pszName, pVol->fMuted, pVol->uLeft, pVol->uRight)); 512 513 pSink->Volume = *pVol; 514 515 return audioMixerSinkUpdateVolume(pSink, &pSink->pParent->VolMaster); 516 } 517 518 int AudioMixerSinkUpdate(PAUDMIXSINK pSink) 519 { 520 AssertPtrReturn(pSink, VERR_INVALID_POINTER); 521 522 PAUDMIXSTREAM pStream; 523 RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node) 524 { 525 uint32_t cbIn, cbOut; 526 uint32_t cSamplesLive; 527 int rc2 = pStream->pConn->pfnQueryStatus(pStream->pConn, 528 &cbIn, &cbOut, &cSamplesLive); 529 #ifdef DEBUG 530 if ( cbIn 531 || cbOut 532 || cSamplesLive) 533 { 534 Log3Func(("cbIn=%RU32, cbOut=%RU32, cSamplesLive=%RU32, rc2=%Rrc\n", cbIn, cbOut, cSamplesLive, rc2)); 535 } 536 #endif 537 if (pSink->enmDir == AUDMIXSINKDIR_OUTPUT) 538 { 539 rc2 = pStream->pConn->pfnPlayOut(pStream->pConn, NULL /* pcSamplesPlayed */); 540 if (RT_FAILURE(rc2)) 541 Log3Func(("rc2=%Rrc\n", rc2)); 542 } 543 else if (pSink->enmDir == AUDMIXSINKDIR_INPUT) 544 { 545 //int rc2 = pStream->pConn->pfnCaptureIn(pStream->pConn, NULL /* pcSamplesCaptured */); 546 //Log3Func(("rc2=%Rrc\n", rc2)); 547 } 548 else 549 AssertMsgFailed(("Direction not implemented\n")); 550 } 551 552 return VINF_SUCCESS; 553 } 554 555 static int audioMixerSinkUpdateVolume(PAUDMIXSINK pSink, const PPDMAUDIOVOLUME pVolMaster) 437 556 { 438 557 AssertPtrReturn(pSink, VERR_INVALID_POINTER); … … 461 580 { 462 581 if (fOut) 463 AudioMixBufSetVolume(&pStream-> pOut->MixBuf, &volSink);582 AudioMixBufSetVolume(&pStream->InOut.pOut->MixBuf, &volSink); 464 583 else 465 AudioMixBufSetVolume(&pStream-> pIn->MixBuf, &volSink);584 AudioMixBufSetVolume(&pStream->InOut.pIn->MixBuf, &volSink); 466 585 } 467 586 … … 469 588 } 470 589 471 /** Set the master volume of the mixer. */ 472 int AudioMixerSetMasterVolume(PAUDIOMIXER pMixer, PPDMAUDIOVOLUME pVol) 473 { 474 AssertPtrReturn(pMixer, VERR_INVALID_POINTER); 475 AssertPtrReturn(pVol, VERR_INVALID_POINTER); 476 477 pMixer->VolMaster = *pVol; 478 479 LogFlowFunc(("%s: lVol=%RU32, rVol=%RU32 => fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n", 480 pMixer->pszName, pVol->uLeft, pVol->uRight, 481 pMixer->VolMaster.fMuted, pMixer->VolMaster.uLeft, pMixer->VolMaster.uRight)); 482 483 AudioMixerInvalidate(pMixer); 590 int AudioMixerSinkWrite(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten) 591 { 592 AssertPtrReturn(pSink, VERR_INVALID_POINTER); 593 /* pcbWritten is optional. */ 594 595 if (!pvBuf || !cbBuf) 596 { 597 if (pcbWritten) 598 *pcbWritten = 0; 599 return VINF_SUCCESS; 600 } 601 602 uint32_t cbProcessed = 0; 603 604 PAUDMIXSTREAM pStream; 605 RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node) 606 { 607 int rc2 = pStream->pConn->pfnWrite(pStream->pConn, pStream->InOut.pOut, pvBuf, cbBuf, &cbProcessed); 608 if ( RT_FAILURE(rc2) 609 || cbProcessed < cbBuf) 610 { 611 LogFlowFunc(("rc=%Rrc, cbBuf=%RU32, cbProcessed=%RU32\n", rc2, cbBuf, cbProcessed)); 612 } 613 } 614 615 if (pcbWritten) 616 *pcbWritten = cbBuf; /* Always report back a complete write for now. */ 617 484 618 return VINF_SUCCESS; 485 619 } 486 620 487 /** Set the volume of an individual sink. */ 488 int AudioMixerSetSinkVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol) 489 { 490 AssertPtrReturn(pSink, VERR_INVALID_POINTER); 491 AssertPtrReturn(pVol, VERR_INVALID_POINTER); 492 AssertPtr(pSink->pParent); 493 494 LogFlowFunc(("%s: fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n", pSink->pszName, pVol->fMuted, pVol->uLeft, pVol->uRight)); 495 496 pSink->Volume = *pVol; 497 498 return audioMixerUpdateSinkVolume(pSink, &pSink->pParent->VolMaster); 499 } 500 501 void AudioMixerDebug(PAUDIOMIXER pMixer, PCDBGFINFOHLP pHlp, const char *pszArgs) 502 { 503 PAUDMIXSINK pSink; 504 unsigned iSink = 0; 505 506 pHlp->pfnPrintf(pHlp, "[Master] %s: lVol=%u, rVol=%u, fMuted=%RTbool\n", pMixer->pszName, 507 pMixer->VolMaster.uLeft, pMixer->VolMaster.uRight, pMixer->VolMaster.fMuted); 508 509 RTListForEach(&pMixer->lstSinks, pSink, AUDMIXSINK, Node) 510 { 511 pHlp->pfnPrintf(pHlp, "[Sink %u] %s: lVol=%u, rVol=%u, fMuted=%RTbool\n", iSink, pSink->pszName, 512 pSink->Volume.uLeft, pSink->Volume.uRight, pSink->Volume.fMuted); 513 ++iSink; 514 } 515 } 621 /***************************************************************************** 622 * Mixer Stream implementation. 623 *****************************************************************************/ 624 625 int AudioMixerStreamCtl(PAUDMIXSTREAM pStream, PDMAUDIOSTREAMCMD enmCmd, uint32_t fCtl) 626 { 627 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 628 /** @todo Validate fCtl. */ 629 630 int rc; 631 switch (pStream->enmDir) 632 { 633 case PDMAUDIODIR_IN: 634 { 635 if ( enmCmd == PDMAUDIOSTREAMCMD_ENABLE 636 || enmCmd == PDMAUDIOSTREAMCMD_DISABLE) 637 { 638 rc = pStream->pConn->pfnEnableIn(pStream->pConn, pStream->InOut.pIn, 639 enmCmd == PDMAUDIOSTREAMCMD_ENABLE); 640 } 641 else 642 AssertFailed(); 643 break; 644 } 645 646 case PDMAUDIODIR_OUT: 647 { 648 if ( enmCmd == PDMAUDIOSTREAMCMD_ENABLE 649 || enmCmd == PDMAUDIOSTREAMCMD_DISABLE) 650 { 651 rc = pStream->pConn->pfnEnableOut(pStream->pConn, pStream->InOut.pOut, 652 enmCmd == PDMAUDIOSTREAMCMD_ENABLE); 653 } 654 else 655 AssertFailed(); 656 break; 657 } 658 659 default: 660 AssertMsgFailed(("Not implemented\n")); 661 break; 662 } 663 664 return rc; 665 } 666 667 int AudioMixerStreamCreate(PPDMIAUDIOCONNECTOR pConn, PPDMAUDIOSTREAMCFG pCfg, uint32_t fFlags, PAUDMIXSTREAM *ppStream) 668 { 669 AssertPtrReturn(pConn, VERR_INVALID_POINTER); 670 AssertPtrReturn(pCfg, VERR_INVALID_POINTER); 671 /** @todo Validate fFlags. */ 672 /* ppStream is optional. */ 673 674 PAUDMIXSTREAM pMixStream = (PAUDMIXSTREAM)RTMemAllocZ(sizeof(AUDMIXSTREAM)); 675 if (!pMixStream) 676 return VERR_NO_MEMORY; 677 678 pMixStream->pszName = RTStrDup(pCfg->szName); 679 if (!pMixStream->pszName) 680 { 681 RTMemFree(pMixStream); 682 return VERR_NO_MEMORY; 683 } 684 685 int rc; 686 if (pCfg->enmDir == PDMAUDIODIR_IN) 687 { 688 PPDMAUDIOGSTSTRMIN pGstStrm; 689 rc = pConn->pfnCreateIn(pConn, pCfg, &pGstStrm); 690 if (RT_SUCCESS(rc)) 691 { 692 pMixStream->InOut.pIn = pGstStrm; 693 694 /* Increase the stream's reference count to let others know 695 * we're reyling on it to be around now. */ 696 pConn->pfnAddRefIn(pConn, pGstStrm); 697 } 698 } 699 else if (pCfg->enmDir == PDMAUDIODIR_OUT) 700 { 701 PPDMAUDIOGSTSTRMOUT pGstStrm; 702 rc = pConn->pfnCreateOut(pConn, pCfg, &pGstStrm); 703 if (RT_SUCCESS(rc)) 704 { 705 pMixStream->InOut.pOut = pGstStrm; 706 707 /* Increase the stream's reference count to let others know 708 * we're reyling on it to be around now. */ 709 pConn->pfnAddRefOut(pConn, pGstStrm); 710 } 711 } 712 else 713 rc = VERR_NOT_SUPPORTED; 714 715 if (RT_SUCCESS(rc)) 716 { 717 pMixStream->fFlags = fFlags; 718 pMixStream->enmDir = pCfg->enmDir; 719 pMixStream->pConn = pConn; 720 721 if (ppStream) 722 *ppStream = pMixStream; 723 } 724 else if (pMixStream) 725 { 726 RTStrFree(pMixStream->pszName); 727 pMixStream->pszName = NULL; 728 729 RTMemFree(pMixStream); 730 pMixStream = NULL; 731 } 732 733 return rc; 734 } 735 736 static void audioMixerStreamDestroyInternal(PAUDMIXSTREAM pStream) 737 { 738 if (!pStream) 739 return; 740 741 LogFunc(("%s\n", pStream->pszName)); 742 743 if (pStream->pConn) /* Stream has a connector interface present? */ 744 { 745 if ( pStream->enmDir == PDMAUDIODIR_IN 746 && pStream->pConn->pfnDestroyIn) 747 { 748 if (pStream->InOut.pIn) 749 { 750 pStream->pConn->pfnReleaseIn(pStream->pConn, pStream->InOut.pIn); 751 pStream->pConn->pfnDestroyIn(pStream->pConn, pStream->InOut.pIn); 752 } 753 } 754 else if ( pStream->enmDir == PDMAUDIODIR_OUT 755 && pStream->pConn->pfnDestroyOut) 756 { 757 if (pStream->InOut.pOut) 758 { 759 pStream->pConn->pfnReleaseOut(pStream->pConn, pStream->InOut.pOut); 760 pStream->pConn->pfnDestroyOut(pStream->pConn, pStream->InOut.pOut); 761 } 762 } 763 else 764 AssertFailed(); 765 } 766 767 audioMixerStreamFree(pStream); 768 } 769 770 void AudioMixerStreamDestroy(PAUDMIXSTREAM pStream) 771 { 772 audioMixerStreamDestroyInternal(pStream); 773 } 774 775 static void audioMixerStreamFree(PAUDMIXSTREAM pStream) 776 { 777 if (pStream) 778 { 779 LogFunc(("%s\n", pStream->pszName)); 780 781 if (pStream->pszName) 782 { 783 RTStrFree(pStream->pszName); 784 pStream->pszName = NULL; 785 } 786 787 RTMemFree(pStream); 788 pStream = NULL; 789 } 790 } 791 792 bool AudioMixerStreamIsActive(PAUDMIXSTREAM pStream) 793 { 794 if (!pStream) 795 return false; 796 797 bool fIsValid; 798 switch (pStream->enmDir) 799 { 800 case PDMAUDIODIR_IN: 801 { 802 fIsValid = pStream->pConn->pfnIsActiveIn(pStream->pConn, pStream->InOut.pIn); 803 break; 804 } 805 806 case PDMAUDIODIR_OUT: 807 { 808 fIsValid = pStream->pConn->pfnIsActiveOut(pStream->pConn, pStream->InOut.pOut); 809 break; 810 } 811 812 default: 813 fIsValid = false; 814 AssertMsgFailed(("Not implemented\n")); 815 break; 816 } 817 818 return fIsValid; 819 } 820 821 bool AudioMixerStreamIsValid(PAUDMIXSTREAM pStream) 822 { 823 if (!pStream) 824 return false; 825 826 bool fIsValid; 827 switch (pStream->enmDir) 828 { 829 case PDMAUDIODIR_IN: 830 { 831 fIsValid = pStream->pConn->pfnIsValidIn(pStream->pConn, pStream->InOut.pIn); 832 break; 833 } 834 835 case PDMAUDIODIR_OUT: 836 { 837 fIsValid = pStream->pConn->pfnIsValidOut(pStream->pConn, pStream->InOut.pOut); 838 break; 839 } 840 841 default: 842 fIsValid = false; 843 AssertMsgFailed(("Not implemented\n")); 844 break; 845 } 846 847 return fIsValid; 848 } 849
Note:
See TracChangeset
for help on using the changeset viewer.