VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/DrvAudioVRDE.cpp@ 52320

Last change on this file since 52320 was 51096, checked in by vboxsync, 11 years ago

Main: use RT_FROM_MEMBER instead of RT_OFFSETOF; some Assert* cleanup

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.0 KB
Line 
1/* $Id: DrvAudioVRDE.cpp 51096 2014-04-17 09:29:40Z vboxsync $ */
2/** @file
3 *
4 * VBox Audio VRDE backend
5 */
6
7/*
8 * Copyright (C) 2006-2010 Oracle Corporation
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#include "DrvAudioVRDE.h"
19#include "ConsoleImpl.h"
20#include "ConsoleVRDPServer.h"
21
22#include "Logging.h"
23
24#include <VBox/vmm/pdmaudioifs.h>
25#include <VBox/vmm/pdmdrv.h>
26#include <VBox/RemoteDesktop/VRDE.h>
27#include <VBox/vmm/cfgm.h>
28#include <VBox/err.h>
29#include <iprt/mem.h>
30#include <iprt/cdefs.h>
31
32
33/*******************************************************************************
34 *
35 * IO Ring Buffer section
36 *
37 ******************************************************************************/
38
39/* Implementation of a lock free ring buffer which could be used in a multi
40 * threaded environment. Note that only the acquire, release and getter
41 * functions are threading aware. So don't use reset if the ring buffer is
42 * still in use. */
43typedef struct IORINGBUFFER
44{
45 /* The current read position in the buffer */
46 uint32_t uReadPos;
47 /* The current write position in the buffer */
48 uint32_t uWritePos;
49 /* How much space of the buffer is currently in use */
50 volatile uint32_t cBufferUsed;
51 /* How big is the buffer */
52 uint32_t cBufSize;
53 /* The buffer itself */
54 char *pBuffer;
55} IORINGBUFFER;
56/* Pointer to an ring buffer structure */
57typedef IORINGBUFFER* PIORINGBUFFER;
58
59PPDMDRVINS gpDrvIns; //@todo handle this bad programming;
60
61static void IORingBufferCreate(PIORINGBUFFER *ppBuffer, uint32_t cSize)
62{
63 PIORINGBUFFER pTmpBuffer;
64
65 AssertPtr(ppBuffer);
66
67 *ppBuffer = NULL;
68 pTmpBuffer = RTMemAllocZ(sizeof(IORINGBUFFER));
69 if (pTmpBuffer)
70 {
71 pTmpBuffer->pBuffer = RTMemAlloc(cSize);
72 if(pTmpBuffer->pBuffer)
73 {
74 pTmpBuffer->cBufSize = cSize;
75 *ppBuffer = pTmpBuffer;
76 }
77 else
78 RTMemFree(pTmpBuffer);
79 }
80}
81
82static void IORingBufferDestroy(PIORINGBUFFER pBuffer)
83{
84 if (pBuffer)
85 {
86 if (pBuffer->pBuffer)
87 RTMemFree(pBuffer->pBuffer);
88 RTMemFree(pBuffer);
89 }
90}
91
92DECL_FORCE_INLINE(void) IORingBufferReset(PIORINGBUFFER pBuffer)
93{
94 AssertPtr(pBuffer);
95
96 pBuffer->uReadPos = 0;
97 pBuffer->uWritePos = 0;
98 pBuffer->cBufferUsed = 0;
99}
100
101DECL_FORCE_INLINE(uint32_t) IORingBufferFree(PIORINGBUFFER pBuffer)
102{
103 AssertPtr(pBuffer);
104 return pBuffer->cBufSize - ASMAtomicReadU32(&pBuffer->cBufferUsed);
105}
106
107DECL_FORCE_INLINE(uint32_t) IORingBufferUsed(PIORINGBUFFER pBuffer)
108{
109 AssertPtr(pBuffer);
110 return ASMAtomicReadU32(&pBuffer->cBufferUsed);
111}
112
113DECL_FORCE_INLINE(uint32_t) IORingBufferSize(PIORINGBUFFER pBuffer)
114{
115 AssertPtr(pBuffer);
116 return pBuffer->cBufSize;
117}
118
119static void IORingBufferAquireReadBlock(PIORINGBUFFER pBuffer, uint32_t cReqSize, char **ppStart, uint32_t *pcSize)
120{
121 uint32_t uUsed = 0;
122 uint32_t uSize = 0;
123
124 AssertPtr(pBuffer);
125
126 *ppStart = 0;
127 *pcSize = 0;
128
129 /* How much is in use? */
130 uUsed = ASMAtomicReadU32(&pBuffer->cBufferUsed);
131 if (uUsed > 0)
132 {
133 /* Get the size out of the requested size, the read block till the end
134 * of the buffer & the currently used size. */
135 uSize = RT_MIN(cReqSize, RT_MIN(pBuffer->cBufSize - pBuffer->uReadPos, uUsed));
136 if (uSize > 0)
137 {
138 /* Return the pointer address which point to the current read
139 * position. */
140 *ppStart = pBuffer->pBuffer + pBuffer->uReadPos;
141 *pcSize = uSize;
142 }
143 }
144}
145
146DECL_FORCE_INLINE(void) IORingBufferReleaseReadBlock(PIORINGBUFFER pBuffer, uint32_t cSize)
147{
148 AssertPtr(pBuffer);
149
150 /* Split at the end of the buffer. */
151 pBuffer->uReadPos = (pBuffer->uReadPos + cSize) % pBuffer->cBufSize;
152 ASMAtomicSubU32(&pBuffer->cBufferUsed, cSize);
153}
154
155static void IORingBufferAquireWriteBlock(PIORINGBUFFER pBuffer, uint32_t cReqSize, char **ppStart, uint32_t *pcSize)
156{
157 uint32_t uFree;
158 uint32_t uSize;
159
160 AssertPtr(pBuffer);
161
162 *ppStart = 0;
163 *pcSize = 0;
164
165 /* How much is free? */
166 uFree = pBuffer->cBufSize - ASMAtomicReadU32(&pBuffer->cBufferUsed);
167 if (uFree > 0)
168 {
169 /* Get the size out of the requested size, the write block till the end
170 * of the buffer & the currently free size. */
171 uSize = RT_MIN(cReqSize, RT_MIN(pBuffer->cBufSize - pBuffer->uWritePos, uFree));
172 if (uSize > 0)
173 {
174 /* Return the pointer address which point to the current write
175 * position. */
176 *ppStart = pBuffer->pBuffer + pBuffer->uWritePos;
177 *pcSize = uSize;
178 }
179 }
180}
181
182DECL_FORCE_INLINE(void) IORingBufferReleaseWriteBlock(PIORINGBUFFER pBuffer, uint32_t cSize)
183{
184 AssertPtr(pBuffer);
185
186 /* Split at the end of the buffer. */
187 pBuffer->uWritePos = (pBuffer->uWritePos + cSize) % pBuffer->cBufSize;
188
189 ASMAtomicAddU32(&pBuffer->cBufferUsed, cSize);
190}
191
192/****************** Ring Buffer Function Ends *****************/
193
194//@todo need to see if they need to move to pdmifs.h
195#define AUDIO_HOST_ENDIANNESS 0
196#define VOICE_ENABLE 1
197#define VOICE_DISABLE 2
198
199
200/* Initialization status indicator used for the recreation of the AudioUnits. */
201#define CA_STATUS_UNINIT UINT32_C(0) /* The device is uninitialized */
202#define CA_STATUS_IN_INIT UINT32_C(1) /* The device is currently initializing */
203#define CA_STATUS_INIT UINT32_C(2) /* The device is initialized */
204#define CA_STATUS_IN_UNINIT UINT32_C(3) /* The device is currently uninitializing */
205
206//@todo move t_sample as a PDM interface
207//typedef struct { int mute; uint32_t r; uint32_t l; } volume_t;
208
209#define INT_MAX 0x7fffffff
210volume_t nominal_volume = {
211 0,
212 INT_MAX,
213 INT_MAX
214};
215
216/* The desired buffer length in milliseconds. Will be the target total stream
217 * latency on newer version of pulse. Apparent latency can be less (or more.)
218 * In case its need to be used. Currently its not used.
219 */
220#if 0
221static struct
222{
223 int buffer_msecs_out;
224 int buffer_msecs_in;
225} confAudioVRDE
226=
227{
228 INIT_FIELD (.buffer_msecs_out = ) 100,
229 INIT_FIELD (.buffer_msecs_in = ) 100,
230};
231#endif
232/**
233 * Audio VRDE driver instance data.
234 *
235 * @extends PDMIAUDIOSNIFFERCONNECTOR
236 */
237typedef struct DRVAUDIOVRDE
238{
239 /** Pointer to audio VRDE object */
240 AudioVRDE *pAudioVRDE;
241 PPDMDRVINS pDrvIns;
242 /** Pointer to the driver instance structure. */
243 PDMIHOSTAUDIO IHostAudioR3;
244 ConsoleVRDPServer *pConsoleVRDPServer;
245 /** Pointer to the DrvAudio port interface that is above it. */
246 PPDMIAUDIOCONNECTOR pUpPort;
247} DRVAUDIOVRDE, *PDRVAUDIOVRDE;
248typedef struct PDMHOSTVOICEOUT PDMHOSTVOICEOUT;
249typedef PDMHOSTVOICEOUT *PPDMHOSTVOICEOUT;
250
251typedef struct VRDEVoice
252{
253 /* Audio and audio details for recording */
254 PDMHOSTVOICEIN pHostVoiceIn;
255 void * pvUserCtx;
256 /* Number of bytes per frame (bitsPerSample * channels) of the actual input format. */
257 uint32_t cBytesPerFrame;
258 /* Frequency of the actual audio format. */
259 uint32_t uFrequency;
260 /* If the actual format frequence differs from the requested format, this is not NULL. */
261 void *rate;
262 /* Temporary buffer for st_sample_t representation of the input audio data. */
263 void *pvSamplesBuffer;
264 /* buffer for bytes of samples (not rate converted) */
265 uint32_t cbSamplesBufferAllocated;
266 /* Temporary buffer for frequency conversion. */
267 void *pvRateBuffer;
268 /* buffer for bytes rate converted samples */
269 uint32_t cbRateBufferAllocated;
270 /* A ring buffer for transferring data to the playback thread */
271 PIORINGBUFFER pRecordedVoiceBuf;
272 t_sample * convAudioDevFmtToStSampl;
273 uint32_t fIsInit;
274 uint32_t status;
275};
276typedef VRDEVoice *PVRDEVoice;
277
278typedef struct VRDEVoiceOut
279{
280 PDMHOSTVOICEOUT pHostVoiceOut;
281 uint64_t old_ticks;
282 uint64_t cSamplesSentPerSec;
283};
284typedef VRDEVoiceOut * PVRDEVoiceOut;
285
286AudioVRDE::AudioVRDE(Console *console)
287 : mpDrv(NULL),
288 mParent(console)
289{
290}
291
292AudioVRDE::~AudioVRDE()
293{
294 if (mpDrv)
295 {
296 mpDrv->pAudioVRDE = NULL;
297 mpDrv = NULL;
298 }
299}
300
301PPDMIAUDIOCONNECTOR AudioVRDE::getDrvAudioPort()
302{
303 Assert(mpDrv);
304 return mpDrv->pUpPort;
305}
306
307void AudioVRDE::handleVRDESvrCmdAudioInputIntercept(bool fIntercept)
308{
309 LogFlow(("AudioVRDE: handleVRDPCmdInputIntercept\n"));
310}
311
312static DECLCALLBACK(void *) drvAudioVRDEInit(PPDMIHOSTAUDIO pInterface)
313{
314 LogFlow(("drvAudioVRDEInit \n"));
315 return 1;
316}
317
318static void drvAudioVRDEPcmInitInfo(PDMPCMPROPERTIES * pProps, audsettings_t *as)
319{
320 int bits = 8, sign = 0, shift = 0;
321 LogFlow(("AudioVRDE: PcmInitInfo \n"));
322
323 switch (as->fmt) {
324 case AUD_FMT_S8:
325 sign = 1;
326 case AUD_FMT_U8:
327 break;
328
329 case AUD_FMT_S16:
330 sign = 1;
331 case AUD_FMT_U16:
332 bits = 16;
333 shift = 1;
334 break;
335
336 case AUD_FMT_S32:
337 sign = 1;
338 case AUD_FMT_U32:
339 bits = 32;
340 shift = 2;
341 break;
342 }
343
344 pProps->uFrequency = as->freq;
345 pProps->cBits = bits;
346 pProps->fSigned = sign;
347 pProps->cChannels = as->nchannels;
348 pProps->cShift = (as->nchannels == 2) + shift;
349 pProps->fAlign = (1 << pProps->cShift) - 1;
350 pProps->cbPerSec = pProps->uFrequency << pProps->cShift;
351 pProps->fSwapEndian = (as->endianness != AUDIO_HOST_ENDIANNESS);
352}
353
354/*
355 * Hard voice (playback)
356 */
357static int audio_pcm_hw_find_min_out (PPDMHOSTVOICEOUT hw, int *nb_livep)
358{
359 PPDMGSTVOICEOUT sw;
360 PPDMGSTVOICEOUT pIter;
361 int m = INT_MAX;
362 int nb_live = 0;
363 LogFlow(("Hard Voice Playback \n"));
364
365 RTListForEach(&hw->HeadGstVoiceOut, pIter, PDMGSTVOICEOUT, ListGstVoiceOut)
366 {
367 sw = pIter;
368 if (sw->State.fActive || !sw->State.fEmpty)
369 {
370 m = audio_MIN (m, sw->cSamplesMixed);
371 nb_live += 1;
372 }
373 }
374
375 *nb_livep = nb_live;
376 return m;
377}
378
379int audio_pcm_hw_get_live_out2 (PPDMHOSTVOICEOUT hw, int *nb_live)
380{
381 int smin;
382
383 smin = audio_pcm_hw_find_min_out (hw, nb_live);
384
385 if (!*nb_live) {
386 return 0;
387 }
388 else
389 {
390 int live = smin;
391
392 if (live < 0 || live > hw->cSamples)
393 {
394 LogFlow(("Error: live=%d hw->samples=%d\n", live, hw->cSamples));
395 return 0;
396 }
397 return live;
398 }
399}
400
401
402int audio_pcm_hw_get_live_out (PPDMHOSTVOICEOUT hw)
403{
404 int nb_live;
405 int live;
406
407 live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
408 if (live < 0 || live > hw->cSamples)
409 {
410 LogFlow(("Error: live=%d hw->samples=%d\n", live, hw->cSamples));
411 return 0;
412 }
413 return live;
414}
415
416/*
417 * Hard voice (capture)
418 */
419static int audio_pcm_hw_find_min_in (PPDMHOSTVOICEIN hw)
420{
421 PPDMGSTVOICEIN pIter;
422 int m = hw->cSamplesCaptured;
423
424 RTListForEach(&hw->HeadGstVoiceIn, pIter, PDMGSTVOICEIN, ListGstVoiceIn)
425 {
426 if (pIter->State.fActive)
427 {
428 m = audio_MIN (m, pIter->cHostSamplesAcquired);
429 }
430 }
431 return m;
432}
433
434int audio_pcm_hw_get_live_in (PPDMHOSTVOICEIN hw)
435{
436 int live = hw->cSamplesCaptured - audio_pcm_hw_find_min_in (hw);
437 if (live < 0 || live > hw->cSamples)
438 {
439 LogFlow(("Error: live=%d hw->samples=%d\n", live, hw->cSamples));
440 return 0;
441 }
442 return live;
443}
444
445static inline void *advance (void *p, int incr)
446{
447 uint8_t *d = (uint8_t*)p;
448 return (d + incr);
449}
450
451uint64_t audio_get_ticks_per_sec (void)
452{
453 return PDMDrvHlpTMGetVirtualFreq (gpDrvIns);
454}
455
456uint64_t audio_get_clock (void)
457{
458 return PDMDrvHlpTMGetVirtualTime (gpDrvIns);
459}
460
461void VRDEReallocSampleBuf(PVRDEVoice pVRDEVoice, uint32_t cSamples)
462{
463 uint32_t cbBuffer = cSamples * sizeof(PDMHOSTSTEREOSAMPLE);
464 if (cbBuffer > pVRDEVoice->cbSamplesBufferAllocated)
465 {
466 if (pVRDEVoice->pvSamplesBuffer)
467 {
468 RTMemFree(pVRDEVoice->pvSamplesBuffer);
469 pVRDEVoice->pvSamplesBuffer = NULL;
470 }
471 pVRDEVoice->pvSamplesBuffer = RTMemAlloc(cbBuffer);
472 if (pVRDEVoice->pvSamplesBuffer)
473 pVRDEVoice->cbSamplesBufferAllocated = cbBuffer;
474 else
475 pVRDEVoice->cbSamplesBufferAllocated = 0;
476 }
477
478}
479
480void VRDEReallocRateAdjSampleBuf(PVRDEVoice pVRDEVoice, uint32_t cSamples)
481{
482 uint32_t cbBuffer = cSamples * sizeof(PDMHOSTSTEREOSAMPLE);
483 if (cbBuffer > pVRDEVoice->cbRateBufferAllocated)
484 {
485 RTMemFree(pVRDEVoice->pvRateBuffer);
486 pVRDEVoice->pvRateBuffer = RTMemAlloc(cbBuffer);
487 if (pVRDEVoice->pvRateBuffer)
488 pVRDEVoice->cbRateBufferAllocated = cbBuffer;
489 else
490 pVRDEVoice->cbRateBufferAllocated = 0;
491 }
492}
493
494/*******************************************************************************
495 *
496 * AudioVRDE input section
497 *
498 ******************************************************************************/
499
500/*
501 * Callback to feed audio input buffer. Samples format is be the same as
502 * in the voice. The caller prepares st_sample_t.
503 *
504 * @param cbSamples Size of pvSamples array in bytes.
505 * @param pvSamples Points to an array of samples.
506 *
507 * @return IPRT status code.
508 */
509static int fltRecordingCallback(PVRDEVoice pVRDEVoice, uint32_t cbSamples, const void *pvSamples)
510{
511 int rc = VINF_SUCCESS;
512 uint32_t csAvail = 0;
513 uint32_t csToWrite = 0;
514 uint32_t cbToWrite = 0;
515 uint32_t csWritten = 0;
516 char *pcDst = NULL;
517
518 LogFlow(("audio-filter: fltRecordingCallback\n"));
519
520 Assert((cbSamples % sizeof(PDMHOSTSTEREOSAMPLE)) == 0);
521
522 if (!pVRDEVoice->fIsInit)
523 return VINF_SUCCESS;
524
525 /* If nothing is pending return immediately. */
526 if (cbSamples == 0)
527 return VINF_SUCCESS;
528
529 /* How much space is free in the ring buffer? */
530 PPDMHOSTSTEREOSAMPLE psSrc;
531 csAvail = IORingBufferFree(pVRDEVoice->pRecordedVoiceBuf) / sizeof(PDMHOSTSTEREOSAMPLE); /* bytes -> samples */
532
533 /* How much space is used in the audio buffer. Use the smaller size of the too. */
534 csAvail = RT_MIN(csAvail, cbSamples / sizeof(PDMHOSTSTEREOSAMPLE));
535
536 /* Iterate as long as data is available */
537 while(csWritten < csAvail)
538 {
539 /* How much is left? */
540 csToWrite = csAvail - csWritten;
541 cbToWrite = csToWrite * sizeof(PDMHOSTSTEREOSAMPLE);
542
543 /* Try to acquire the necessary space from the ring buffer. */
544 IORingBufferAquireWriteBlock(pVRDEVoice->pRecordedVoiceBuf, cbToWrite, &pcDst, &cbToWrite);
545
546 /* How much do we get? */
547 csToWrite = cbToWrite / sizeof(PDMHOSTSTEREOSAMPLE);
548
549 /* Break if nothing is free anymore. */
550 if (RT_UNLIKELY(csToWrite == 0))
551 break;
552
553 /* Copy the data from the audio buffer to the ring buffer in PVRDEVoice. */
554 memcpy(pcDst, (uint8_t *)pvSamples + (csWritten * sizeof(PDMHOSTSTEREOSAMPLE)), cbToWrite);
555
556 /* Release the ring buffer, so the main thread could start reading this data. */
557 IORingBufferReleaseWriteBlock(pVRDEVoice->pRecordedVoiceBuf, cbToWrite);
558
559 csWritten += csToWrite;
560 }
561
562 LogFlow(("AudioVRDE: [Input] Finished writing buffer with %RU32 samples (%RU32 bytes)\n",
563 csWritten, csWritten * sizeof(PDMHOSTSTEREOSAMPLE)));
564
565 return rc;
566}
567
568
569STDMETHODIMP AudioVRDE::handleVRDESvrCmdAudioInputEventBegin(void *pvContext, int iSampleHz, int cChannels,
570 int cBits, bool fUnsigned)
571{
572 int bitIdx;
573 PVRDEVoice pVRDEVoice = (PVRDEVoice)pvContext;
574 LogFlow(("AudioVRDE: handleVRDPCmdInputEventBegin\n"));
575 /* Prepare a format convertion for the actually used format. */
576 pVRDEVoice->cBytesPerFrame = ((cBits + 7) / 8) * cChannels;
577 if (cBits == 16)
578 {
579 bitIdx = 1;
580 }
581 else if (cBits == 32)
582 {
583 bitIdx = 2;
584 }
585 else
586 {
587 bitIdx = 0;
588 }
589 //PPDMIAUDIOCONNECTOR pPort = server->mConsole->getAudioVRDE()->getDrvAudioPort();
590 /* Call DrvAudio interface to get the t_sample type conversion function */
591 pVRDEVoice->convAudioDevFmtToStSampl = mpDrv->pUpPort->pfnConvDevFmtToStSample(mpDrv->pUpPort,
592 (cChannels == 2) ? 1 : 0,
593 !fUnsigned, 0, bitIdx
594 );
595 if (pVRDEVoice->convAudioDevFmtToStSampl)
596 {
597 LogFlow(("AudioVRDE: Failed to get the conversion function \n"));
598 }
599 LogFlow(("AudioVRDE: Required freq as requested by VRDP Server = %d\n", iSampleHz));
600 //if (iSampleHz && iSampleHz != pVRDEVoice->pHostVoiceIn.Props.uFrequency)
601 {
602 /* @todo if the above condition is false then pVRDEVoice->uFrequency will remain 0 */
603 pVRDEVoice->rate = mpDrv->pUpPort->pfnPrepareAudioConversion(mpDrv->pUpPort, iSampleHz,
604 pVRDEVoice->pHostVoiceIn.Props.uFrequency);
605 pVRDEVoice->uFrequency = iSampleHz;
606 LogFlow(("AudioVRDE: pVRDEVoice assigned requested freq =%d\n", pVRDEVoice->uFrequency));
607 }
608 return VINF_SUCCESS;
609}
610
611/*
612 * pvContext: pointer to VRDP voice returned by the VRDP server. The is same pointer that we initialized in
613 * drvAudioVRDEDisableEnableIn VOICE_ENABLE case.
614 */
615void AudioVRDE::handleVRDESvrCmdAudioInputEventData(void *pvContext, const void *pvData, uint32_t cbData)
616{
617 PVRDEVoice pVRDEVoice = (PVRDEVoice)pvContext;
618 PPDMHOSTSTEREOSAMPLE pHostStereoSampleBuf; /* target sample buffer */
619 PPDMHOSTSTEREOSAMPLE pConvertedSampleBuf; /* samples adjusted for rate */
620 uint32_t cSamples = cbData / pVRDEVoice->cBytesPerFrame; /* Count of samples */
621 void * pTmpSampleBuf = NULL;
622 uint32_t cConvertedSamples; /* samples adjusted for rate */
623 uint32_t cbSamples; /* count of bytes occupied by samples */
624 uint32_t rc;
625 LogFlow(("AudioVRDE: handleVRDPCmdInputEventData cbData = %d, bytesperfram=%d\n",
626 cbData, pVRDEVoice->cBytesPerFrame));
627
628 VRDEReallocSampleBuf(pVRDEVoice, cSamples);
629 pHostStereoSampleBuf = (PPDMHOSTSTEREOSAMPLE)pVRDEVoice->pvSamplesBuffer;
630 pVRDEVoice->convAudioDevFmtToStSampl(pHostStereoSampleBuf, pvData, cSamples, &nominal_volume);
631
632 /* count of rate adjusted samples */
633 pVRDEVoice->uFrequency = 22100; /* @todo handle this. How pVRDEVoice will get proper value */
634 cConvertedSamples = (cSamples * pVRDEVoice->pHostVoiceIn.Props.uFrequency) / pVRDEVoice->uFrequency;
635 VRDEReallocRateAdjSampleBuf(pVRDEVoice, cConvertedSamples);
636
637 pConvertedSampleBuf = (PPDMHOSTSTEREOSAMPLE)pVRDEVoice->pvRateBuffer;
638
639 if (pConvertedSampleBuf)
640 {
641 uint32_t cSampleSrc = cSamples;
642 uint32_t cSampleDst = cConvertedSamples;
643 mpDrv->pUpPort->pfnDoRateConversion(mpDrv->pUpPort, pVRDEVoice->rate, pHostStereoSampleBuf,
644 pConvertedSampleBuf, &cSampleSrc, &cConvertedSamples);
645 pTmpSampleBuf = pConvertedSampleBuf;
646 cbSamples = cConvertedSamples * sizeof(PDMHOSTSTEREOSAMPLE);
647 }
648
649 if (cbSamples)
650 {
651 rc = fltRecordingCallback(pVRDEVoice, cbSamples, pTmpSampleBuf);
652 }
653}
654
655/*
656 * pvContext: pointer to VRDP voice returned by the VRDP server. The is same pointer that we initialized in
657 * drvAudioVRDEDisableEnableIn VOICE_ENABLE case.
658 */
659void AudioVRDE::handleVRDESvrCmdAudioInputEventEnd(void *pvContext)
660{
661 PVRDEVoice pVRDEVoice = (PVRDEVoice)pvContext;
662 LogFlow(("AudioVRDE: handleVRDPCmdInputEventEnd\n"));
663 /* The caller will not use this context anymore. */
664 if (pVRDEVoice->rate)
665 {
666 mpDrv->pUpPort->pfnEndAudioConversion(mpDrv->pUpPort, pVRDEVoice->rate);
667 }
668
669 if (pVRDEVoice->pvSamplesBuffer)
670 {
671 RTMemFree(pVRDEVoice->pvSamplesBuffer);
672 pVRDEVoice->pvSamplesBuffer = NULL;
673 }
674 if(pVRDEVoice->pvRateBuffer)
675 {
676 RTMemFree(pVRDEVoice->pvRateBuffer);
677 pVRDEVoice->pvRateBuffer = NULL;
678 }
679}
680
681static DECLCALLBACK(int) drvAudioVRDEInitOut(PPDMIHOSTAUDIO pInterface, PPDMHOSTVOICEOUT pHostVoiceOut, audsettings_t *as)
682{
683 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudioR3);
684
685 PVRDEVoiceOut pVRDEVoiceOut = (PVRDEVoiceOut)pHostVoiceOut;
686 LogFlow(("DrvAudioVRDEInitOut: audio input begin cShift=%d\n", pHostVoiceOut->Props.cShift));
687 pHostVoiceOut->cSamples = 6174;
688 drvAudioVRDEPcmInitInfo(&pVRDEVoiceOut->pHostVoiceOut.Props, as);
689 return VINF_SUCCESS;
690
691}
692
693static DECLCALLBACK(int) drvAudioVRDEInitIn (PPDMIHOSTAUDIO pInterface, PPDMHOSTVOICEIN pHostVoiceIn, audsettings_t *as)
694{
695 LogFlow(("DrvAudioVRDE: drvAudioVRDEInitIn \n"));
696 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudioR3);
697 PVRDEVoice pVRDEVoice = (PVRDEVoice)pHostVoiceIn;
698 pHostVoiceIn->cSamples = 6174;
699 drvAudioVRDEPcmInitInfo(&pVRDEVoice->pHostVoiceIn.Props, as);
700 return VINF_SUCCESS;
701}
702
703static DECLCALLBACK(int) drvAudioVRDEPlayIn(PPDMIHOSTAUDIO pInterface, PPDMHOSTVOICEIN pHostVoiceIn)
704{
705 uint32_t cbAvlblRingBuffer = 0;
706 uint32_t cSamplesRingBuffer = 0;
707 uint32_t cSamplesToRead = 0;
708 uint32_t cSamplesRead = 0;
709 uint32_t cbToRead;
710 char *pcSrc;
711 PDMHOSTSTEREOSAMPLE * psDst;
712 //@todo take care of the size of the buffer allocated to pHostVoiceIn
713 PVRDEVoice pVRDEVoice = (PVRDEVoice)pHostVoiceIn;
714 LogFlow(("DrvAudioVRDE: drvAudioVRDEPlayIn \n"));
715
716 /* use this from DrvHostCoreAudio.c */
717 if (ASMAtomicReadU32(&pVRDEVoice->status) != CA_STATUS_INIT)
718 {
719 LogFlow(("AudioVRDE: VRDE voice not initialized \n"));
720 return 0;
721 }
722
723 /* how much space is used in the ring buffer in pRecordedVocieBuf with pAudioVRDE . Bytes-> samples*/
724 cSamplesRingBuffer = IORingBufferUsed(pVRDEVoice->pRecordedVoiceBuf) / sizeof(PDMHOSTSTEREOSAMPLE);
725
726 /* How much space is available in the mix buffer. Use the smaller size of the too. */
727 cSamplesRingBuffer = RT_MIN(cSamplesRingBuffer, (uint32_t)(pVRDEVoice->pHostVoiceIn.cSamples -
728 audio_pcm_hw_get_live_in (&pVRDEVoice->pHostVoiceIn)));
729 LogFlow(("AudioVRDE: [Input] Start reading buffer with %d samples (%d bytes)\n", cSamplesRingBuffer,
730 cSamplesRingBuffer * sizeof(PDMHOSTSTEREOSAMPLE)));
731
732 /* Iterate as long as data is available */
733 while (cSamplesRead < cSamplesRingBuffer)
734 {
735 /* How much is left? Split request at the end of our samples buffer. */
736 cSamplesToRead = RT_MIN(cSamplesRingBuffer - cSamplesRead,
737 (uint32_t)(pVRDEVoice->pHostVoiceIn.cSamples - pVRDEVoice->pHostVoiceIn.offWrite));
738 cbToRead = cSamplesToRead * sizeof(PDMHOSTSTEREOSAMPLE);
739 LogFlow(("AudioVRDE: [Input] Try reading %RU32 samples (%RU32 bytes)\n", cSamplesToRead, cbToRead));
740
741 /* Try to acquire the necessary block from the ring buffer. Remeber in fltRecrodCallback we
742 * we are filling this buffer with the audio data available from VRDP. Here we are reading it
743 */
744 /*todo do I need to introduce a thread to fill the buffer in fltRecordcallback. So that
745 * filling is in separate thread and the reading of that buffer is in separate thread
746 */
747 IORingBufferAquireReadBlock(pVRDEVoice->pRecordedVoiceBuf, cbToRead, &pcSrc, &cbToRead);
748
749 /* How much to we get? */
750 cSamplesToRead = cbToRead / sizeof(PDMHOSTSTEREOSAMPLE);
751 LogFlow(("AuderVRDE: [Input] There are %d samples (%d bytes) available\n", cSamplesToRead, cbToRead));
752
753 /* Break if nothing is used anymore. */
754 if (cSamplesToRead == 0)
755 {
756 LogFlow(("AudioVRDE: Nothing to read \n"));
757 break;
758 }
759
760 /* Copy the data from our ring buffer to the mix buffer. */
761 psDst = pVRDEVoice->pHostVoiceIn.pConversionBuf + pVRDEVoice->pHostVoiceIn.offWrite;
762 memcpy(psDst, pcSrc, cbToRead);
763
764 /* Release the read buffer, so it could be used for new data. */
765 IORingBufferReleaseReadBlock(pVRDEVoice->pRecordedVoiceBuf, cbToRead);
766
767 pVRDEVoice->pHostVoiceIn.offWrite = (pVRDEVoice->pHostVoiceIn.offWrite + cSamplesToRead)
768 % pVRDEVoice->pHostVoiceIn.cSamples;
769
770 /* How much have we reads so far. */
771 cSamplesRead += cSamplesToRead;
772 }
773 LogFlow(("AudioVRDE: [Input] Finished reading buffer with %d samples (%d bytes)\n",
774 cSamplesRead, cSamplesRead * sizeof(PDMHOSTSTEREOSAMPLE)));
775
776 return cSamplesRead;
777}
778
779static DECLCALLBACK(int) drvAudioVRDEPlayOut(PPDMIHOSTAUDIO pInterface, PPDMHOSTVOICEOUT pHostVoiceOut)
780{
781 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudioR3);
782 PVRDEVoiceOut pVRDEVoiceOut = (PVRDEVoiceOut)pHostVoiceOut;
783 int live;
784 uint8_t *pu8Dst;
785 int cSamplesPlayed;
786 int cSamplesToSend = 0;
787 /*
788 * Just call the VRDP server with the data.
789 */
790 live = audio_pcm_hw_get_live_out (pHostVoiceOut);
791 uint64_t now = audio_get_clock();
792 uint64_t ticks = now - pVRDEVoiceOut->old_ticks;
793 uint64_t ticks_per_second = audio_get_ticks_per_sec();
794 cSamplesPlayed = (int)((2 * ticks * pHostVoiceOut->Props.uFrequency + ticks_per_second) / ticks_per_second / 2);
795 if (cSamplesPlayed < 0)
796 cSamplesPlayed = live;
797 pHostVoiceOut->Props.cBits = 128;
798 VRDEAUDIOFORMAT format = VRDE_AUDIO_FMT_MAKE(pHostVoiceOut->Props.uFrequency,
799 pHostVoiceOut->Props.cChannels,
800 pHostVoiceOut->Props.cBits, /* bits per sample */
801 !pHostVoiceOut->Props.fSigned);
802 LogFlow(("DrvAudioVRDE: send audio sample freq=%d, chan=%d, cBits = %d, fsigned = %d, cSamples=%d format=%d \n",
803 pHostVoiceOut->Props.uFrequency, pHostVoiceOut->Props.cChannels,
804 pHostVoiceOut->Props.cBits, pHostVoiceOut->Props.fSigned,
805 pHostVoiceOut->cSamples, format)
806 );
807 pVRDEVoiceOut->old_ticks = now;
808 cSamplesToSend = RT_MIN(live, cSamplesPlayed);
809 if (pHostVoiceOut->offRead + cSamplesToSend > pHostVoiceOut->cSamples)
810 {
811 /* send the samples till the end of pHostStereoSampleBuf */
812 pDrv->pConsoleVRDPServer->SendAudioSamples(&pHostVoiceOut->pHostSterioSampleBuf[pHostVoiceOut->offRead],
813 (pHostVoiceOut->cSamples - pHostVoiceOut->offRead), format);
814 /*pHostStereoSampleBuff already has the samples which exceeded its space. They have overwriten the old
815 * played sampled starting from offset 0. So based on the number of samples that we had to play,
816 * read the number of samples from offset 0 .
817 */
818 pDrv->pConsoleVRDPServer->SendAudioSamples(&pHostVoiceOut->pHostSterioSampleBuf[0],
819 (cSamplesToSend - (pHostVoiceOut->cSamples -
820 pHostVoiceOut->offRead)),
821 format);
822 }
823 else
824 {
825 pDrv->pConsoleVRDPServer->SendAudioSamples(&pHostVoiceOut->pHostSterioSampleBuf[pHostVoiceOut->offRead],
826 cSamplesToSend, format);
827 }
828 pHostVoiceOut->offRead = (pHostVoiceOut->offRead + cSamplesToSend) % pHostVoiceOut->cSamples;
829 return cSamplesToSend;
830}
831
832static DECLCALLBACK(void) drvAudioVRDEFiniIn(PPDMIHOSTAUDIO pInterface, PPDMHOSTVOICEIN hw)
833{
834 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudioR3);
835 LogFlow(("DrvAudioVRDE: drvAudioVRDEFiniIn \n"));
836 pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
837}
838
839static DECLCALLBACK(void) drvAudioVRDEFiniOut(PPDMIHOSTAUDIO pInterface, PPDMHOSTVOICEOUT pHostVoiceOut)
840{
841 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudioR3);
842 LogFlow(("DrvAudioVRDE: audio input end\n"));
843}
844
845static DECLCALLBACK(int) drvAudioVRDEDisableEnableOut(PPDMIHOSTAUDIO pInterface, PPDMHOSTVOICEOUT hw, int cmd)
846{
847 LogFlow(("DrvAudioVRDE: drvAudioVRDEDisableEnableOut \n"));
848 return VINF_SUCCESS;
849}
850
851static DECLCALLBACK(int) drvAudioVRDEDisableEnableIn(PPDMIHOSTAUDIO pInterface, PPDMHOSTVOICEIN pHostVoiceIn, int cmd)
852{
853 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudioR3);
854
855 /* Initialize VRDEVoice and return to VRDP server which returns this struct back to us
856 * in the form void * pvContext
857 */
858 PVRDEVoice pVRDEVoice = (PVRDEVoice)pHostVoiceIn;
859 LogFlow(("DrvAudioVRDE: drvAudioVRDEDisableEnableIn \n"));
860 /* initialize only if not already done */
861 if (cmd == VOICE_ENABLE)
862 {
863 //@todo if (!pVRDEVoice->fIsInit)
864 // IORingBufferReset(pVRDEVoice->pRecordedVoiceBuf);
865 LogFlow(("DrvAudioVRDE: Intializing the VRDE params and buffer \n"));
866 pVRDEVoice->fIsInit = 1;
867 pVRDEVoice->pHostVoiceIn = *pHostVoiceIn;
868 pVRDEVoice->cBytesPerFrame =1 ;
869 pVRDEVoice->uFrequency = 0;
870 pVRDEVoice->rate = NULL;
871 pVRDEVoice->cbSamplesBufferAllocated = 0;
872 pVRDEVoice->pvRateBuffer = NULL;
873 pVRDEVoice->cbRateBufferAllocated = 0;
874
875 pVRDEVoice->pHostVoiceIn.cSamples = 2048;
876 /* Initialize the hardware info section with the audio settings */
877
878 ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_IN_INIT);
879
880 /* Create the internal ring buffer. */
881 IORingBufferCreate(&pVRDEVoice->pRecordedVoiceBuf,
882 pVRDEVoice->pHostVoiceIn.cSamples * sizeof(PDMHOSTSTEREOSAMPLE));
883
884 if (!RT_VALID_PTR(pVRDEVoice->pRecordedVoiceBuf))
885 {
886 LogRel(("AudioVRDE: [Input] Failed to create internal ring buffer\n"));
887 return VERR_NO_MEMORY;
888 }
889
890 ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_INIT);
891 return pDrv->pConsoleVRDPServer->SendAudioInputBegin(NULL, pVRDEVoice, pHostVoiceIn->cSamples,
892 pHostVoiceIn->Props.uFrequency,
893 pHostVoiceIn->Props.cChannels, pHostVoiceIn->Props.cBits);
894 }
895 else if (cmd == VOICE_DISABLE)
896 {
897 LogFlow(("DrvAudioVRDE: Cmd to disable VRDE \n"));
898 pVRDEVoice->fIsInit = 0;
899 ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_IN_UNINIT);
900 IORingBufferDestroy(pVRDEVoice->pRecordedVoiceBuf);
901 pVRDEVoice->pRecordedVoiceBuf = NULL;
902 ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_UNINIT);
903 pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
904 }
905 return VINF_SUCCESS;
906}
907
908static DECLCALLBACK(void) drvAudioVRDEGetConf(PPDMIBASE pInterface, PPDMAUDIOCONF pAudioConf)
909{
910 LogFlow(("drvAudioVRDE: drvAudioVRDEGetConf \n"));
911 /* @todo check if szHostVoiceOut = sizeof VRDEVoice works. VRDEVoice doesn't contain HOSTVOICEOUT. */
912 pAudioConf->szHostVoiceOut = sizeof(VRDEVoice);
913 pAudioConf->szHostVoiceIn = sizeof(VRDEVoice);
914 pAudioConf->MaxHostVoicesOut = 1;
915 pAudioConf->MaxHostVoicesIn = 1;
916}
917
918/**
919 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
920 */
921static DECLCALLBACK(void *) drvAudioVRDEQueryInterface(PPDMIBASE pInterface, const char *pszIID)
922{
923 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
924 PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
925 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
926 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudioR3);
927 return NULL;
928}
929
930
931static DECLCALLBACK(void) drvAudioVRDEDestruct(PPDMDRVINS pDrvIns)
932{
933}
934
935/**
936 * Construct a DirectSound Audio driver instance.
937 *
938 * @copydoc FNPDMDRVCONSTRUCT
939 */
940DECLCALLBACK(int) AudioVRDE::drvAudioVRDEConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
941{
942 PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
943 LogRel(("drvAudioVRDEConstruct\n"));
944
945 /* we save the address of AudioVRDE in Object node in CFGM tree and address of VRDP server in
946 * ObjectVRDPServer node. So presence of both is necessary.
947 */
948 //if (!CFGMR3AreValuesValid(pCfg, "Object\0") || !CFGMR3AreValuesValid(pCfg, "ObjectVRDPServer\0"))
949 // return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
950 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
951 ("Configuration error: Not possible to attach anything to this driver!\n"),
952 VERR_PDM_DRVINS_NO_ATTACH);
953
954 /*
955 * Init the static parts.
956 */
957 pThis->pDrvIns = pDrvIns;
958 gpDrvIns = pDrvIns;
959 /* IBase */
960 pDrvIns->IBase.pfnQueryInterface = drvAudioVRDEQueryInterface;
961 pThis->IHostAudioR3.pfnInitIn = drvAudioVRDEInitIn;
962 pThis->IHostAudioR3.pfnInitOut = drvAudioVRDEInitOut;
963 pThis->IHostAudioR3.pfnDisableEnableOut = drvAudioVRDEDisableEnableOut;
964 pThis->IHostAudioR3.pfnDisableEnableIn = drvAudioVRDEDisableEnableIn;
965 pThis->IHostAudioR3.pfnFiniIn = drvAudioVRDEFiniIn;
966 pThis->IHostAudioR3.pfnFiniOut = drvAudioVRDEFiniOut;
967 pThis->IHostAudioR3.pfnPlayIn = drvAudioVRDEPlayIn;
968 pThis->IHostAudioR3.pfnPlayOut = drvAudioVRDEPlayOut;
969 pThis->IHostAudioR3.pfnGetConf = drvAudioVRDEGetConf;
970 pThis->IHostAudioR3.pfnInit = drvAudioVRDEInit;
971
972 /* Get VRDPServer pointer */
973 void *pv;
974 int rc = CFGMR3QueryPtr(pCfg, "ObjectVRDPServer", &pv);
975 if (RT_FAILURE(rc))
976 {
977 AssertMsgFailed(("DrvAudioVRDE Confguration error: No/bad \"Object\" value! rc=%Rrc\n", rc));
978 return rc;
979 }
980 /* CFGM tree saves the pointer to ConsoleVRDPServer in the Object node of AudioVRDE */
981 pThis->pConsoleVRDPServer = (ConsoleVRDPServer *)pv;
982 pv = NULL;
983
984 rc = CFGMR3QueryPtr(pCfg, "Object", &pv);
985 if (RT_FAILURE(rc))
986 {
987 AssertMsgFailed(("DrvAudioVRDE Confguration error: No/bad \"Object\" value! rc=%Rrc\n", rc));
988 return rc;
989 }
990 pThis->pAudioVRDE = (AudioVRDE *)pv;
991 pThis->pAudioVRDE->mpDrv = pThis;
992 /*
993 * Get the interface for the above driver (DrvAudio) to make mixer/conversion calls .
994 * Described in CFGM tree.
995 */
996 pThis->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIOCONNECTOR);
997 if (!pThis->pUpPort)
998 {
999 AssertMsgFailed(("Configuration error: No Audio Sniffer port interface above!\n"));
1000 return VERR_PDM_MISSING_INTERFACE_ABOVE;
1001 }
1002
1003 return VINF_SUCCESS;
1004}
1005
1006
1007/**
1008 * Char driver registration record.
1009 */
1010const PDMDRVREG g_DrvAudioVRDE =
1011{
1012 PDM_DRVREG_VERSION,
1013 /* szName */
1014 "AudioVRDE",
1015 /* szRCMod */
1016 "",
1017 /* szR0Mod */
1018 "",
1019 /* pszDescription */
1020 "Audio VRDE",
1021 /* fFlags */
1022 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1023 /* fClass. */
1024 PDM_DRVREG_CLASS_AUDIO,
1025 /* cMaxInstances */
1026 ~0U,
1027 /* cbInstance */
1028 sizeof(DRVAUDIOVRDE),
1029 /* pfnConstruct */
1030 AudioVRDE::drvAudioVRDEConstruct,
1031 /* pfnDestruct */
1032 drvAudioVRDEDestruct,
1033 /* pfnRelocate */
1034 NULL,
1035 /* pfnIOCtl */
1036 NULL,
1037 /* pfnPowerOn */
1038 NULL,
1039 /* pfnReset */
1040 NULL,
1041 /* pfnSuspend */
1042 NULL,
1043 /* pfnResume */
1044 NULL,
1045 /* pfnAttach */
1046 NULL,
1047 /* pfnDetach */
1048 NULL,
1049 /* pfnPowerOff */
1050 NULL,
1051 /* pfnSoftReset */
1052 NULL,
1053 /* u32EndVersion */
1054 PDM_DRVREG_VERSION
1055};
1056
1057
1058
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