TYPE * __restrict end = to + count;\\r
while (to != end)\\r
{\\r
- *to ++ = (TYPE)((float)(from[0] + from[1]) * 0.70710678118654752440084436210485f/*1/sqrt(2)*/);\\r
+ *to ++ = (TYPE)((float)(from[0] + from[1]) * 0.5f);\\r
from += 2;\\r
}\r
\r
}\r
#endif\r
\r
+ // For full-duplex output resize buffer to be the same as for input\r
+ if (output && fullDuplex)\r
+ framesPerLatency = pStream->in.framesPerHostCallback;\r
+\r
// Avoid 0 frames\r
if (framesPerLatency == 0)\r
framesPerLatency = MakeFramesFromHns(pInfo->DefaultDevicePeriod, pSub->wavex.Format.nSamplesPerSec);\r
\r
if (outputParameters && inputParameters)\r
{\r
- // serious problem #1\r
- if (stream->in.period != stream->out.period)\r
+ // serious problem #1 - No, Not a problem, especially concerning Exclusive mode.\r
+ // Input device in exclusive mode somehow is getting large buffer always, thus we\r
+ // adjust Output latency to reflect it, thus period will differ but playback will be \r
+ // normal.\r
+ /*if (stream->in.period != stream->out.period)\r
{\r
PRINT(("WASAPI: OpenStream: period discrepancy\n"));\r
LogPaError(result = paBadIODeviceCombination);\r
goto error;\r
- }\r
+ }*/\r
\r
// serious problem #2 - No, Not a problem, as framesPerHostCallback take into account\r
// sample size while it is not a problem for PA full-duplex, we must care of\r
\r
// Set Input latency\r
stream->streamRepresentation.streamInfo.inputLatency =\r
- PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor)\r
+ ((double)PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor) / sampleRate)\r
+ ((inputParameters)?stream->in.latency_seconds : 0);\r
\r
// Set Output latency\r
stream->streamRepresentation.streamInfo.outputLatency =\r
- PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor)\r
+ ((double)PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor) / sampleRate)\r
+ ((outputParameters)?stream->out.latency_seconds : 0);\r
\r
// Set SR\r
}\r
else\r
{\r
+#if 0\r
// Processing Loop\r
- while (WaitForSingleObject(stream->hCloseRequest, sleep_ms) == WAIT_TIMEOUT)\r
+ while (WaitForSingleObject(stream->hCloseRequest, 1) == WAIT_TIMEOUT)\r
{\r
UINT32 i_frames = 0, i_processed = 0;\r
BYTE *i_data = NULL, *o_data = NULL, *o_data_host = NULL;\r
break;\r
}\r
}\r
+#else\r
+ // Processing Loop\r
+ //sleep_ms = 1;\r
+ while (WaitForSingleObject(stream->hCloseRequest, sleep_ms) == WAIT_TIMEOUT)\r
+ {\r
+ UINT32 i_frames = 0, i_processed = 0;\r
+ BYTE *i_data = NULL, *o_data = NULL, *o_data_host = NULL;\r
+ DWORD i_flags = 0;\r
+ UINT32 o_frames = 0;\r
+ //BOOL repeat = FALSE;\r
+\r
+ // going below 1 msec resolution, switching between 1 ms and no waiting\r
+ //if (stream->in.shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)\r
+ // sleep_ms = !sleep_ms;\r
+\r
+ // get available frames\r
+ if ((hr = PollGetOutputFramesAvailable(stream, &o_frames)) != S_OK)\r
+ {\r
+ LogHostError(hr);\r
+ break;\r
+ }\r
+\r
+ while (o_frames != 0)\r
+ {\r
+ // get host input buffer\r
+ if ((hr = IAudioCaptureClient_GetBuffer(stream->cclient, &i_data, &i_frames, &i_flags, NULL, NULL)) != S_OK)\r
+ {\r
+ if (hr == AUDCLNT_S_BUFFER_EMPTY)\r
+ break; // no data in capture buffer\r
+\r
+ LogHostError(hr);\r
+ break;\r
+ }\r
+\r
+ //PA_DEBUG(("full-duplex: o_frames[%d] i_frames[%d] repeat[%d]\n", o_frames, i_frames, repeat));\r
+ //repeat = TRUE;\r
+\r
+ // process equal ammount of frames\r
+ if (o_frames >= i_frames)\r
+ {\r
+ // process input ammount of frames\r
+ UINT32 o_processed = i_frames;\r
+\r
+ // get host output buffer\r
+ if ((hr = IAudioRenderClient_GetBuffer(stream->rclient, o_processed, &o_data)) == S_OK)\r
+ {\r
+ // processed amount of i_frames\r
+ i_processed = i_frames;\r
+ o_data_host = o_data;\r
+\r
+ // convert output mono\r
+ if (stream->out.monoMixer)\r
+ {\r
+ #define __DIV_8(v) ((v) >> 3) //!< (v / 8)\r
+ UINT32 mono_frames_size = o_processed * __DIV_8(stream->out.wavex.Format.wBitsPerSample);\r
+ #undef __DIV_8\r
+ // expand buffer (one way only for better performance due to no calls to realloc)\r
+ if (mono_frames_size > stream->out.monoBufferSize)\r
+ {\r
+ stream->out.monoBuffer = realloc(stream->out.monoBuffer, (stream->out.monoBufferSize = mono_frames_size));\r
+ if (stream->out.monoBuffer == NULL)\r
+ {\r
+ LogPaError(paInsufficientMemory);\r
+ goto thread_error;\r
+ }\r
+ }\r
+\r
+ // replace buffer pointer\r
+ o_data = (BYTE *)stream->out.monoBuffer;\r
+ }\r
+\r
+ // convert input mono\r
+ if (stream->in.monoMixer)\r
+ {\r
+ #define __DIV_8(v) ((v) >> 3) //!< (v / 8)\r
+ UINT32 mono_frames_size = i_processed * __DIV_8(stream->in.wavex.Format.wBitsPerSample);\r
+ #undef __DIV_8\r
+ // expand buffer (one way only for better performance due to no calls to realloc)\r
+ if (mono_frames_size > stream->in.monoBufferSize)\r
+ {\r
+ stream->in.monoBuffer = realloc(stream->in.monoBuffer, (stream->in.monoBufferSize = mono_frames_size));\r
+ if (stream->in.monoBuffer == NULL)\r
+ {\r
+ LogPaError(paInsufficientMemory);\r
+ goto thread_error;\r
+ }\r
+ }\r
+\r
+ // mix 2 to 1 input channels\r
+ stream->in.monoMixer(stream->in.monoBuffer, i_data, i_processed);\r
+\r
+ // replace buffer pointer\r
+ i_data = (BYTE *)stream->in.monoBuffer;\r
+ }\r
+\r
+ // process\r
+ processor[S_FULLDUPLEX].processor(i_data, i_processed, o_data, o_processed, processor[S_FULLDUPLEX].userData);\r
+\r
+ // mix 1 to 2 output channels\r
+ if (stream->out.monoBuffer)\r
+ stream->out.monoMixer(o_data_host, stream->out.monoBuffer, o_processed);\r
+\r
+ // release host output buffer\r
+ if ((hr = IAudioRenderClient_ReleaseBuffer(stream->rclient, o_processed, 0)) != S_OK)\r
+ LogHostError(hr);\r
+\r
+ o_frames -= o_processed;\r
+ }\r
+ else\r
+ {\r
+ if (stream->out.shareMode != AUDCLNT_SHAREMODE_SHARED)\r
+ LogHostError(hr); // be silent in shared mode, try again next time\r
+ }\r
+ }\r
+ else\r
+ {\r
+ i_processed = 0;\r
+ goto fd_release_buffer_in;\r
+ }\r
+\r
+fd_release_buffer_in:\r
+\r
+ // release host input buffer\r
+ if ((hr = IAudioCaptureClient_ReleaseBuffer(stream->cclient, i_processed)) != S_OK)\r
+ {\r
+ LogHostError(hr);\r
+ break;\r
+ }\r
+\r
+ // break processing, input hasn't been accumulated yet\r
+ if (i_processed == 0)\r
+ break;\r
+ }\r
+ }\r
+#endif\r
}\r
\r
thread_end:\r