Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Microphone input
#1
I think my mic is broken or something so can someone test this please...

Microphone.h 

Code: (Select All)
#ifndef QBLIVE_AUDIO_H
#define QBLIVE_AUDIO_H

#include <windows.h>
#include <mmsystem.h>
#include <shellapi.h>
#include <vector>

#pragma comment(lib, "winmm.lib")
#pragma comment(lib, "shell32.lib")

#define SAMPLE_RATE 44100
#define CHUNK_SIZE 4096

static HWAVEIN hWaveIn = NULL;
static HWAVEOUT hWaveOut = NULL;
static WAVEHDR waveHdrIn;
static short captureBuffer[CHUNK_SIZE];
static std::vector<short> recordedData;
static bool isRecording = false;

// Driver Callback: Background thread catches audio chunks as they arrive
void CALLBACK waveInProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) {
    if (uMsg == WIM_DATA && isRecording) {
        WAVEHDR* pHdr = (WAVEHDR*)dwParam1;
        short* raw = (short*)pHdr->lpData;
        // Efficiently append raw 16-bit samples to the storage vector
        recordedData.insert(recordedData.end(), raw, raw + (pHdr->dwBytesRecorded / 2));
        // Re-queue the buffer to keep recording without gaps
        waveInAddBuffer(hwi, pHdr, sizeof(WAVEHDR));
    }
}

extern "C" {
    __declspec(dllexport) int InitAudio() {
        // CD Quality: Mono, 44100Hz, 16-bit PCM
        WAVEFORMATEX wfx = { WAVE_FORMAT_PCM, 1, SAMPLE_RATE, SAMPLE_RATE * 2, 2, 16, 0 };
       
        // Open Microphone
        MMRESULT res = waveInOpen(&hWaveIn, WAVE_MAPPER, &wfx, (DWORD_PTR)waveInProc, 0, CALLBACK_FUNCTION);
        if (res != MMSYSERR_NOERROR) return (int)res;

        waveHdrIn.lpData = (LPSTR)captureBuffer;
        waveHdrIn.dwBufferLength = CHUNK_SIZE * 2;
        waveHdrIn.dwFlags = 0;
        waveInPrepareHeader(hWaveIn, &waveHdrIn, sizeof(WAVEHDR));
       
        // Open Speakers
        if (waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL) != MMSYSERR_NOERROR) return -99;
       
        return 0;
    }

    __declspec(dllexport) void StartRecord() {
        recordedData.clear();
        isRecording = true;
        waveInAddBuffer(hWaveIn, &waveHdrIn, sizeof(WAVEHDR));
        waveInStart(hWaveIn);
    }

    __declspec(dllexport) void StopRecord() {
        isRecording = false;
        waveInStop(hWaveIn);
        waveInReset(hWaveIn);
    }

    __declspec(dllexport) int GetRecordedSize() {
        return (int)recordedData.size();
    }

    __declspec(dllexport) void PlayRecording() {
        if (recordedData.empty()) return;
        static WAVEHDR playHdr; // Static ensures memory persists during playback
        playHdr.lpData = (LPSTR)recordedData.data();
        playHdr.dwBufferLength = (DWORD)recordedData.size() * 2;
        playHdr.dwFlags = 0;
        waveOutPrepareHeader(hWaveOut, &playHdr, sizeof(WAVEHDR));
        waveOutWrite(hWaveOut, &playHdr, sizeof(WAVEHDR));
    }

    __declspec(dllexport) void OpenMicSettings() {
        ShellExecuteA(NULL, "open", "ms-settings:privacy-microphone", NULL, NULL, SW_SHOWNORMAL);
    }

    __declspec(dllexport) void ShutdownAudio() {
        if (hWaveIn) { waveInReset(hWaveIn); waveInClose(hWaveIn); }
        if (hWaveOut) { waveOutReset(hWaveOut); waveOutClose(hWaveOut); }
    }

        // Converts 16-bit samples to 32-bit floats for QB64 _SNDRAW
    // buffer = the QB64 float array, offset = starting sample, count = samples to get
    __declspec(dllexport) void Audio_Get_SndRaw(float* buffer, int offset, int count) {
        if (recordedData.empty() || offset < 0) return;
       
        for (int i = 0; i < count; i++) {
            int index = offset + i;
            if (index < (int)recordedData.size()) {
                // Convert signed 16-bit (-32768 to 32767) to float (-1.0 to 1.0)
                buffer[i] = (float)recordedData[index] / 32768.0f;
            } else {
                buffer[i] = 0.0f; // Fill remaining buffer with silence if out of range
            }
        }
    }

}
#endif

ANd the QB64 stuff 

Code: (Select All)
' Finalized QBLive Audio Studio 2025
DECLARE LIBRARY "Microphone"
  FUNCTION InitAudio& ()
  SUB StartRecord ()
  SUB StopRecord ()
  FUNCTION GetRecordedSize& ()
  SUB PlayRecording ()
  SUB OpenMicSettings ()
  SUB ShutdownAudio ()
  SUB Audio_Get_SndRaw (buffer AS SINGLE, BYVAL offset AS LONG, BYVAL count AS LONG)

END DECLARE

SCREEN _NEWIMAGE(800, 600, 32)
_TITLE "QBLive Audio Recorder 2025"

' 1. Check Permissions
res& = InitAudio
IF res& <> 0 THEN
  PRINT "--- AUDIO INITIALIZATION ERROR ---"
  PRINT "Result Code:"; res&
  PRINT "Hardware not found or Privacy Permissions denied."
  PRINT
  INPUT "Open Windows Microphone Settings? (Y/N) ", c$
  IF UCASE$(c$) = "Y" THEN OpenMicSettings
  END
END IF

isRecording = 0
PRINT "Ready. Press SPACE to Record."

DO
  k$ = INKEY$
  IF k$ = " " THEN
    IF isRecording = 0 THEN
      StartRecord
      isRecording = 1
    ELSE
      StopRecord
      isRecording = 0
      CLS
      PRINT "Playing back"; GetRecordedSize; "samples..."
      'PlayRecording ''// This maybe the error

      samples& = GetRecordedSize

      IF samples& > 0 THEN
        PRINT "Playing back via _SNDRAW..."

        ' We process in chunks of 4096 (matching your C++ CHUNK_SIZE)
        chunkSize& = 4096
        REDIM tempBuffer(chunkSize& - 1) AS SINGLE

        FOR currentOffset& = 0 TO samples& STEP chunkSize&
          ' 1. Fill our QB64 float buffer from the C++ recordedData vector
          Audio_Get_SndRaw tempBuffer(0), currentOffset&, chunkSize&

          ' 2. Call our standalone sub to handle the actual playback
          PlayFloatBuffer tempBuffer(), chunkSize&
        NEXT currentOffset&

        PRINT "Playback finished."
      END IF

      PRINT "Press SPACE to record again."
    END IF
    _DELAY .3 ' Toggle debounce
  END IF

  IF isRecording THEN
    LOCATE 1, 1: PRINT "RECORDING... ["; GetRecordedSize; "samples]"
  END IF
  _LIMIT 60
LOOP UNTIL _EXIT

ShutdownAudio
SYSTEM


SUB PlayFloatBuffer (floatArray() AS SINGLE, count AS LONG)
  ' Designed for 44100Hz Mono Audio
  IF count <= 0 THEN EXIT SUB

  FOR i& = 0 TO count - 1
    ' 1. Send the sample to _SNDRAW (mono automatically goes to both speakers)
    _SNDRAW floatArray(i&)

    ' 2. Check the sound pipe length.
    ' If we queue too much data (> 0.2 seconds), we wait.
    ' If we don't wait, QB64 will eat up all your RAM trying to store the samples.
    IF i& MOD 100 = 0 THEN ' Check every 100 samples to save CPU
      DO WHILE _SNDRAWLEN > 0.2
        _LIMIT 100 ' Give the CPU a rest while the sound card works
      LOOP
    END IF
  NEXT i&
END SUB

@Petr 90% there i reckon...needs a better brain!

Unseeen
Reply
#2
Hi, your program works here as expected. Is microphone recording enabled in system settings?  

But, try this (save it as microphone2.h), BAS source remains the same.

Code: (Select All)
#ifndef QBLIVE_AUDIO_H
#define QBLIVE_AUDIO_H

// IMPORTANT: This is C++ (uses std::vector). QB64PE compiles with a C++ toolchain.

#include <windows.h>
#include <mmsystem.h>
#include <shellapi.h>
#include <vector>

#ifndef SAMPLE_RATE
#define SAMPLE_RATE 44100
#endif

#ifndef CHUNK_SAMPLES
#define CHUNK_SAMPLES 4096    // samples per buffer (mono, 16-bit)
#endif

#ifndef NUM_INPUT_BUFFERS
#define NUM_INPUT_BUFFERS 4    // >=2 recommended; 4..8 typical
#endif

// -----------------------------------------------------------------------------
// Internal state
// -----------------------------------------------------------------------------
static HWAVEIN  g_hWaveIn  = NULL;
static HWAVEOUT g_hWaveOut = NULL;

static WAVEFORMATEX g_wfx = { 0 };

static WAVEHDR g_inHdr[NUM_INPUT_BUFFERS];
static short  g_inBuf[NUM_INPUT_BUFFERS][CHUNK_SAMPLES];

static std::vector<short> g_recorded;  // shared between threads -> must lock
static std::vector<short> g_playback;  // stable snapshot for async waveOut

static CRITICAL_SECTION g_cs;
static LONG g_csInit = 0;

static volatile LONG g_isInitialized  = 0;
static volatile LONG g_isRecording    = 0;
static volatile LONG g_isShuttingDown = 0;

static HANDLE g_worker = NULL;
static DWORD  g_workerTid = 0;
static HANDLE g_workerReady = NULL;

static const UINT WM_QBLIVE_REQUEUE = (WM_APP + 0x334);

static WAVEHDR g_playHdr;
static LONG g_playHdrPrepared = 0;

static MMRESULT g_lastMM = MMSYSERR_NOERROR;

// -----------------------------------------------------------------------------
// Tiny helpers
// -----------------------------------------------------------------------------
static void qbl_lock()  { if (InterlockedCompareExchange(&g_csInit, 0, 0)) EnterCriticalSection(&g_cs); }
static void qbl_unlock() { if (InterlockedCompareExchange(&g_csInit, 0, 0)) LeaveCriticalSection(&g_cs); }

static void qbl_set_last(MMRESULT mm) { g_lastMM = mm; }

// -----------------------------------------------------------------------------
// waveIn callback
// -----------------------------------------------------------------------------
/*
  IMPORTANT FIX #1:
  The original code called waveInAddBuffer() inside the waveInProc callback.
  That is a known deadlock/reentrancy risk on some drivers.

  Correct pattern:
    - Do *minimal* work in the callback.
    - Hand off the WAVEHDR pointer to a worker thread.
    - The worker thread copies audio + calls waveInAddBuffer().
*/
static void CALLBACK qbl_waveInProc(HWAVEIN, UINT uMsg, DWORD_PTR, DWORD_PTR dwParam1, DWORD_PTR)
{
    if (uMsg != WIM_DATA) return;
    if (g_workerTid) PostThreadMessage(g_workerTid, WM_QBLIVE_REQUEUE, (WPARAM)dwParam1, 0);
}

// -----------------------------------------------------------------------------
// Worker thread proc
// -----------------------------------------------------------------------------
/*
  IMPORTANT FIX #2:
  std::vector is not thread-safe. The original code appended to recordedData in
  the driver callback thread while QB code could read it concurrently.
  That can cause reallocations + invalid pointers + crashes / silence.

  Here we serialize access with a CRITICAL_SECTION and do the copy outside the callback.
*/
static DWORD WINAPI qbl_workerProc(void*)
{
    // Ensure message queue exists
    MSG msg;
    PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);

    if (g_workerReady) SetEvent(g_workerReady);

    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (msg.message != WM_QBLIVE_REQUEUE) continue;
        if (InterlockedCompareExchange(&g_isShuttingDown, 0, 0)) continue;

        WAVEHDR* pHdr = (WAVEHDR*)msg.wParam;
        if (!pHdr) continue;

        if (InterlockedCompareExchange(&g_isRecording, 0, 0))
        {
            const int sampleCount = (int)(pHdr->dwBytesRecorded / sizeof(short));
            if (sampleCount > 0)
            {
                qbl_lock();
                g_recorded.insert(g_recorded.end(),
                                  (short*)pHdr->lpData,
                                  (short*)pHdr->lpData + sampleCount);
                qbl_unlock();
            }

            // Re-queue buffer here (NOT in callback)
            waveInAddBuffer(g_hWaveIn, pHdr, sizeof(WAVEHDR));
        }
    }
    return 0;
}

// =============================================================================
// Public API for QB64 (must be C linkage, no name mangling)
// =============================================================================
extern "C" {

// Optional debug helpers (not required by your BAS file)
int GetLastMMResult()
{
    return (int)g_lastMM;
}

void GetLastMMErrorTextA(char* outText, int outTextBytes)
{
    if (!outText || outTextBytes <= 0) return;
    outText[0] = 0;

    char tmp[256] = { 0 };
    if (waveInGetErrorTextA(g_lastMM, tmp, (UINT)sizeof(tmp)) == MMSYSERR_NOERROR ||
        waveOutGetErrorTextA(g_lastMM, tmp, (UINT)sizeof(tmp)) == MMSYSERR_NOERROR)
    {
        lstrcpynA(outText, tmp, outTextBytes);
    }
    else
    {
        lstrcpynA(outText, "Unknown MMRESULT", outTextBytes);
    }
}

int InitAudio()
{
    if (InterlockedCompareExchange(&g_isInitialized, 0, 0))
        return 0;

    g_lastMM = MMSYSERR_NOERROR;

    if (!InterlockedCompareExchange(&g_csInit, 1, 0))
        InitializeCriticalSection(&g_cs);

    // Start worker thread
    g_workerReady = CreateEvent(NULL, TRUE, FALSE, NULL);
    g_worker = CreateThread(NULL, 0, qbl_workerProc, NULL, 0, &g_workerTid);
    if (!g_worker)
    {
        qbl_set_last(MMSYSERR_ERROR);
        return (int)MMSYSERR_ERROR;
    }
    WaitForSingleObject(g_workerReady, INFINITE);
    CloseHandle(g_workerReady);
    g_workerReady = NULL;

    // CD-ish format: Mono, 44100Hz, 16-bit PCM
    g_wfx.wFormatTag      = WAVE_FORMAT_PCM;
    g_wfx.nChannels      = 1;
    g_wfx.nSamplesPerSec  = SAMPLE_RATE;
    g_wfx.wBitsPerSample  = 16;
    g_wfx.nBlockAlign    = (g_wfx.nChannels * g_wfx.wBitsPerSample) / 8;
    g_wfx.nAvgBytesPerSec = g_wfx.nSamplesPerSec * g_wfx.nBlockAlign;
    g_wfx.cbSize          = 0;

    // Open Microphone
    MMRESULT res = waveInOpen(&g_hWaveIn, WAVE_MAPPER, &g_wfx, (DWORD_PTR)qbl_waveInProc, 0, CALLBACK_FUNCTION);
    if (res != MMSYSERR_NOERROR) { qbl_set_last(res); return (int)res; }

    // Prepare multiple input buffers (IMPORTANT FIX #3: not just one)
    ZeroMemory(g_inHdr, sizeof(g_inHdr));
    for (int i = 0; i < NUM_INPUT_BUFFERS; i++)
    {
        g_inHdr[i].lpData = (LPSTR)g_inBuf[i];
        g_inHdr[i].dwBufferLength = (DWORD)sizeof(g_inBuf[i]);
        g_inHdr[i].dwFlags = 0;

        res = waveInPrepareHeader(g_hWaveIn, &g_inHdr[i], sizeof(WAVEHDR));
        if (res != MMSYSERR_NOERROR) { qbl_set_last(res); return (int)res; }
    }

    // Open Speakers
    res = waveOutOpen(&g_hWaveOut, WAVE_MAPPER, &g_wfx, 0, 0, CALLBACK_NULL);
    if (res != MMSYSERR_NOERROR) { qbl_set_last(res); return (int)res; }

    ZeroMemory(&g_playHdr, sizeof(g_playHdr));
    InterlockedExchange(&g_playHdrPrepared, 0);

    InterlockedExchange(&g_isShuttingDown, 0);
    InterlockedExchange(&g_isInitialized, 1);
    return 0;
}

void StartRecord()
{
    if (!InterlockedCompareExchange(&g_isInitialized, 0, 0)) return;

    qbl_lock();
    g_recorded.clear();
    qbl_unlock();

    // Queue buffers BEFORE starting
    for (int i = 0; i < NUM_INPUT_BUFFERS; i++)
        waveInAddBuffer(g_hWaveIn, &g_inHdr[i], sizeof(WAVEHDR));

    InterlockedExchange(&g_isRecording, 1);
    waveInStart(g_hWaveIn);
}

void StopRecord()
{
    if (!InterlockedCompareExchange(&g_isInitialized, 0, 0)) return;

    InterlockedExchange(&g_isRecording, 0);
    waveInStop(g_hWaveIn);
    waveInReset(g_hWaveIn);
}

int GetRecordedSize()
{
    int n = 0;
    qbl_lock();
    n = (int)g_recorded.size();
    qbl_unlock();
    return n;
}

void PlayRecording()
{
    if (!InterlockedCompareExchange(&g_isInitialized, 0, 0)) return;

    /*
      IMPORTANT FIX #4:
      waveOutWrite is asynchronous. The original code passed recordedData.data()
      directly; but recordedData can reallocate / clear later -> invalid pointer.

      We snapshot to g_playback so the memory remains stable during playback.
    */
    qbl_lock();
    g_playback = g_recorded;
    qbl_unlock();

    if (g_playback.empty()) return;

    // Stop current playback if any
    waveOutReset(g_hWaveOut);

    if (InterlockedCompareExchange(&g_playHdrPrepared, 0, 0))
    {
        waveOutUnprepareHeader(g_hWaveOut, &g_playHdr, sizeof(WAVEHDR));
        InterlockedExchange(&g_playHdrPrepared, 0);
    }

    ZeroMemory(&g_playHdr, sizeof(g_playHdr));
    g_playHdr.lpData = (LPSTR)g_playback.data();
    g_playHdr.dwBufferLength = (DWORD)(g_playback.size() * sizeof(short));
    g_playHdr.dwFlags = 0;

    MMRESULT res = waveOutPrepareHeader(g_hWaveOut, &g_playHdr, sizeof(WAVEHDR));
    if (res != MMSYSERR_NOERROR) { qbl_set_last(res); return; }
    InterlockedExchange(&g_playHdrPrepared, 1);

    res = waveOutWrite(g_hWaveOut, &g_playHdr, sizeof(WAVEHDR));
    if (res != MMSYSERR_NOERROR) { qbl_set_last(res); return; }
}

void OpenMicSettings()
{
    // If Windows privacy blocks the mic, capture APIs will appear to "work" but deliver silence.
    ShellExecuteA(NULL, "open", "ms-settings:privacy-microphone", NULL, NULL, SW_SHOWNORMAL);
}

void ShutdownAudio()
{
    if (!InterlockedCompareExchange(&g_isInitialized, 0, 0)) return;

    InterlockedExchange(&g_isShuttingDown, 1);
    InterlockedExchange(&g_isRecording, 0);

    if (g_hWaveIn)
    {
        waveInStop(g_hWaveIn);
        waveInReset(g_hWaveIn);

        for (int i = 0; i < NUM_INPUT_BUFFERS; i++)
            waveInUnprepareHeader(g_hWaveIn, &g_inHdr[i], sizeof(WAVEHDR));

        waveInClose(g_hWaveIn);
        g_hWaveIn = NULL;
    }

    if (g_hWaveOut)
    {
        waveOutReset(g_hWaveOut);

        if (InterlockedCompareExchange(&g_playHdrPrepared, 0, 0))
        {
            waveOutUnprepareHeader(g_hWaveOut, &g_playHdr, sizeof(WAVEHDR));
            InterlockedExchange(&g_playHdrPrepared, 0);
        }

        waveOutClose(g_hWaveOut);
        g_hWaveOut = NULL;
    }

    // Stop worker thread
    if (g_workerTid) PostThreadMessage(g_workerTid, WM_QUIT, 0, 0);
    if (g_worker)
    {
        WaitForSingleObject(g_worker, INFINITE);
        CloseHandle(g_worker);
        g_worker = NULL;
    }
    g_workerTid = 0;

    qbl_lock();
    g_recorded.clear();
    g_playback.clear();
    qbl_unlock();

    InterlockedExchange(&g_isInitialized, 0);

    if (InterlockedCompareExchange(&g_csInit, 0, 0))
    {
        DeleteCriticalSection(&g_cs);
        InterlockedExchange(&g_csInit, 0);
    }
}

// QB64 helper: fills a float buffer (mono) for _SNDRAW
void Audio_Get_SndRaw(float* buffer, int offset, int count)
{
    if (!buffer || count <= 0) return;
    if (offset < 0) offset = 0;

    qbl_lock();
    const int n = (int)g_recorded.size();

    for (int i = 0; i < count; i++)
    {
        const int idx = offset + i;
        if (idx < n)
            buffer[i] = (float)g_recorded[idx] / 32768.0f; // [-1, 1)
        else
            buffer[i] = 0.0f;
    }
    qbl_unlock();
}

} // extern "C"

#endif // QBLIVE_AUDIO_H


Reply
#3
I'm getting an error message in Microphone.h. Otherwise, I can't help, as I've never dealt with such topics before. Sad

[Image: 18te-Zeile-Fehler.jpg]
Reply
#4
@Kernelpanic: H file is C or C++ program. Save it as microphone.h to folder with program. Do not insert it to QB64 IDE. Then copy BAS source code to IDE, save it to the same folder as H file, compile Bas to exe and run it.


Reply
#5
Okay, that was it! Thanks! It works with both versions of the C file; however, the name in the BAS file needs to be adjusted in `Microphone2.h` for your file (... BAS source remains the same). Of course , the QB IDE can't do anything with the C file. The error message only appears because no microphone is connected.

[Image: Audio-funktioniert2025-12-25-170058.jpg]


I tried something similar in a smaller format, where the external h file had to be declared in the BAS file. I'm surprised it works without that here.

Code: (Select All)

Option _Explicit

'In QB64 mit "Declare Library" wie angegeben
Declare Library "D:\Lab\QuickBasic64\Extern-nicht-Basic\Basic-ruft-C\bfibonacci"
  Function fibo& (ByVal N As Integer)
End Declare

Dim As Integer N, rueckgabe
Dim As Single zeitstart, zeitende

Timer On

Cls
Locate 3, 3
Input "Berechnet die Fibonacci-Zahl von: ", N

zeitstart = Timer

Locate 5, 3
rueckgabe = fibo&(N%)
If rueckgabe = -1 Then
  Print "Eingabe zu gross!"
  Sleep: System
Else
  Print Using "Die Fibonacci-Zahl von ## = ###,########"; N; fibo&(N%)
End If

zeitende = Timer

Locate 7, 3
Print Using "Sekunden: ##.#### "; zeitende - zeitstart

End

Code: (Select All)

#include <stdio.h>
#include <stdlib.h>

long fibo(int n)
{
long x, y;
int i;

//Um bei 3 eine Anzeige von: 1 2 3 zu erreichen
x = y = i = 1;
if (n == 0 || n == 1)
{
return(n);
}
if (n > 40)
{
return(-1);
//sonst Überlauf
}
else while (i < n)
{
x = x + y; y = x - y; i++;
}
return(x);
}
Reply
#6
So me mic is defo broke!

@Petr Thanks for the mods...now im thinking with the enet server/client idea and microphone and webcams it's viable to think about a VOIP and Video Calling interface! 

Thanks for fixing it too!

Unseen
Reply
#7
Okay, it's working. I've connected a microphone.

What do I do with it now?  Rolleyes

[Image: Audio-Mikro-angeschlossen2025-12-25.jpg]
Reply
#8
@Unseen Machine

If you succeed, it’ll be a revolutionary breakthrough for QB64PE. The first video client over a network in this language—that would be the absolute peak. The language has the potential for it. Text clients already exist, so this is a brilliant idea. I’m not going to compete with you on this; I really want to see you pull it off. I think it’s going to work.

I have plenty of ideas, but first things first—this will be a great foundation. Of course, if you’re looking for a collaborator, I’m in. But I won't develop anything in this direction without your go-ahead. I’d suggest making it rock-solid on LAN first. See how it handles a 'stress test,' like someone pulling the cable and plugging it back in... I'm not sure how you're handling packet loss yet, as I haven't checked the code, but networks can be real monsters...


Reply
#9
@Kernelpanic

Well, for example, you could start complaining: 'What kind of program did you give me?! That guy I hear singing is way too loud! Who is that? Who’s talking to me?!' Or maybe: 'Good grief, you nearly gave me a heart attack!  Big Grin


Reply
#10
Im never in competition...I know that the WinAPI and C++ are my learning points and TBH they make me feel dumb as F sometimes! Like, with the extra omphh of C++ comes way more aggro and pathways....Im enjoying the process though!

If the webcam lib can capture an image then the eNet lib is 100% a viable way to use it...my demo of it is just that, a demo! But it should show how MMO games and VOIP and Video Chat are pheasible...also as eNet has 3 layers of delivery of data and this seems to remove the "Useless" aspect from UDP!

YOU are above me on knowledge in this arena so heres the baton! Take POINT!

Unseen
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Let's take this input for a spin doppler 0 618 05-07-2022, 02:57 PM
Last Post: doppler

Forum Jump:


Users browsing this thread: 1 Guest(s)