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. */
|
---|
43 | typedef 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 */
|
---|
57 | typedef IORINGBUFFER* PIORINGBUFFER;
|
---|
58 |
|
---|
59 | PPDMDRVINS gpDrvIns; //@todo handle this bad programming;
|
---|
60 |
|
---|
61 | static 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 |
|
---|
82 | static void IORingBufferDestroy(PIORINGBUFFER pBuffer)
|
---|
83 | {
|
---|
84 | if (pBuffer)
|
---|
85 | {
|
---|
86 | if (pBuffer->pBuffer)
|
---|
87 | RTMemFree(pBuffer->pBuffer);
|
---|
88 | RTMemFree(pBuffer);
|
---|
89 | }
|
---|
90 | }
|
---|
91 |
|
---|
92 | DECL_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 |
|
---|
101 | DECL_FORCE_INLINE(uint32_t) IORingBufferFree(PIORINGBUFFER pBuffer)
|
---|
102 | {
|
---|
103 | AssertPtr(pBuffer);
|
---|
104 | return pBuffer->cBufSize - ASMAtomicReadU32(&pBuffer->cBufferUsed);
|
---|
105 | }
|
---|
106 |
|
---|
107 | DECL_FORCE_INLINE(uint32_t) IORingBufferUsed(PIORINGBUFFER pBuffer)
|
---|
108 | {
|
---|
109 | AssertPtr(pBuffer);
|
---|
110 | return ASMAtomicReadU32(&pBuffer->cBufferUsed);
|
---|
111 | }
|
---|
112 |
|
---|
113 | DECL_FORCE_INLINE(uint32_t) IORingBufferSize(PIORINGBUFFER pBuffer)
|
---|
114 | {
|
---|
115 | AssertPtr(pBuffer);
|
---|
116 | return pBuffer->cBufSize;
|
---|
117 | }
|
---|
118 |
|
---|
119 | static 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 |
|
---|
146 | DECL_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 |
|
---|
155 | static 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 |
|
---|
182 | DECL_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
|
---|
210 | volume_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
|
---|
221 | static 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 | */
|
---|
237 | typedef 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;
|
---|
248 | typedef struct PDMHOSTVOICEOUT PDMHOSTVOICEOUT;
|
---|
249 | typedef PDMHOSTVOICEOUT *PPDMHOSTVOICEOUT;
|
---|
250 |
|
---|
251 | typedef 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 | };
|
---|
276 | typedef VRDEVoice *PVRDEVoice;
|
---|
277 |
|
---|
278 | typedef struct VRDEVoiceOut
|
---|
279 | {
|
---|
280 | PDMHOSTVOICEOUT pHostVoiceOut;
|
---|
281 | uint64_t old_ticks;
|
---|
282 | uint64_t cSamplesSentPerSec;
|
---|
283 | };
|
---|
284 | typedef VRDEVoiceOut * PVRDEVoiceOut;
|
---|
285 |
|
---|
286 | AudioVRDE::AudioVRDE(Console *console)
|
---|
287 | : mpDrv(NULL),
|
---|
288 | mParent(console)
|
---|
289 | {
|
---|
290 | }
|
---|
291 |
|
---|
292 | AudioVRDE::~AudioVRDE()
|
---|
293 | {
|
---|
294 | if (mpDrv)
|
---|
295 | {
|
---|
296 | mpDrv->pAudioVRDE = NULL;
|
---|
297 | mpDrv = NULL;
|
---|
298 | }
|
---|
299 | }
|
---|
300 |
|
---|
301 | PPDMIAUDIOCONNECTOR AudioVRDE::getDrvAudioPort()
|
---|
302 | {
|
---|
303 | Assert(mpDrv);
|
---|
304 | return mpDrv->pUpPort;
|
---|
305 | }
|
---|
306 |
|
---|
307 | void AudioVRDE::handleVRDESvrCmdAudioInputIntercept(bool fIntercept)
|
---|
308 | {
|
---|
309 | LogFlow(("AudioVRDE: handleVRDPCmdInputIntercept\n"));
|
---|
310 | }
|
---|
311 |
|
---|
312 | static DECLCALLBACK(void *) drvAudioVRDEInit(PPDMIHOSTAUDIO pInterface)
|
---|
313 | {
|
---|
314 | LogFlow(("drvAudioVRDEInit \n"));
|
---|
315 | return 1;
|
---|
316 | }
|
---|
317 |
|
---|
318 | static 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 | */
|
---|
357 | static 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 |
|
---|
379 | int 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 |
|
---|
402 | int 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 | */
|
---|
419 | static 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 |
|
---|
434 | int 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 |
|
---|
445 | static inline void *advance (void *p, int incr)
|
---|
446 | {
|
---|
447 | uint8_t *d = (uint8_t*)p;
|
---|
448 | return (d + incr);
|
---|
449 | }
|
---|
450 |
|
---|
451 | uint64_t audio_get_ticks_per_sec (void)
|
---|
452 | {
|
---|
453 | return PDMDrvHlpTMGetVirtualFreq (gpDrvIns);
|
---|
454 | }
|
---|
455 |
|
---|
456 | uint64_t audio_get_clock (void)
|
---|
457 | {
|
---|
458 | return PDMDrvHlpTMGetVirtualTime (gpDrvIns);
|
---|
459 | }
|
---|
460 |
|
---|
461 | void 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 |
|
---|
480 | void 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 | */
|
---|
509 | static 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 |
|
---|
569 | STDMETHODIMP 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 | */
|
---|
615 | void 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 | */
|
---|
659 | void 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 |
|
---|
681 | static 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 |
|
---|
693 | static 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 |
|
---|
703 | static 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 |
|
---|
779 | static 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 |
|
---|
832 | static 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 |
|
---|
839 | static 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 |
|
---|
845 | static DECLCALLBACK(int) drvAudioVRDEDisableEnableOut(PPDMIHOSTAUDIO pInterface, PPDMHOSTVOICEOUT hw, int cmd)
|
---|
846 | {
|
---|
847 | LogFlow(("DrvAudioVRDE: drvAudioVRDEDisableEnableOut \n"));
|
---|
848 | return VINF_SUCCESS;
|
---|
849 | }
|
---|
850 |
|
---|
851 | static 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 |
|
---|
908 | static 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 | */
|
---|
921 | static 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 |
|
---|
931 | static DECLCALLBACK(void) drvAudioVRDEDestruct(PPDMDRVINS pDrvIns)
|
---|
932 | {
|
---|
933 | }
|
---|
934 |
|
---|
935 | /**
|
---|
936 | * Construct a DirectSound Audio driver instance.
|
---|
937 | *
|
---|
938 | * @copydoc FNPDMDRVCONSTRUCT
|
---|
939 | */
|
---|
940 | DECLCALLBACK(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 | */
|
---|
1010 | const 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 |
|
---|