Question

I have a problem when try to achieve smooth audio playback using waveOutWrite(). My data includes many adpcmdata bocks which gotten from camera, after decoded each adpcm block I play it by using waveOutWrite(). The first block is played succesfully (atleast i can heard) but i have problem when I play for next block that exist a gap between these blocks. I tried to call sleep() after using waveOutWrite() but it's not ok. Anybody can tell me how i get smooth in this case? Any problem in the way that i playback the audio?

for (i = 0, i < MaxBlockData, i++)  


        BYTE * pcmBuff = new BYTE[length*8];
        memset(pcmBuff, 0, length*8);
        G726 g726;

        int pcmDataSize = 0;
        g726.SetRate(g726.Rate32kBits);
        g726.SetLaw(g726.PCM16);
        pcmDataSize = g726.Decode(pcmBuff, adpcmData[i], 0, length*8); /decode adcmData PCM 16

        if(pcmDataSize > 0)
        {
            int sampleRate = 8000;
            CHAR* waveIn = new CHAR[pcmDataSize];

            HWAVEIN hWaveIn;
            WAVEHDR WaveInHdr;
            MMRESULT result;
            HWAVEOUT hWaveOut;

            WAVEFORMATEX pFormat;
            pFormat.wFormatTag = WAVE_FORMAT_PCM;
            pFormat.nChannels = 1;
            pFormat.nSamplesPerSec = sampleRate;
            pFormat.nAvgBytesPerSec = 2 * sampleRate;
            pFormat.nBlockAlign = 2;
            pFormat.wBitsPerSample = 16;
            pFormat.cbSize = 0;

            result = waveInOpen(&hWaveIn, WAVE_MAPPER, &pFormat, 0, 0, WAVE_FORMAT_DIRECT);

            if(result != MMSYSERR_NOERROR)
            {
                char fault[256];
                waveInGetErrorTextA(result, fault, 256);
                MessageBoxA(NULL, fault, "Failed to open waveform input device.", MB_OK | MB_ICONEXCLAMATION);
                return;
            }

            WaveInHdr.lpData = (LPSTR)waveIn;
            WaveInHdr.dwBufferLength = pcmDataSize;
            WaveInHdr.dwBytesRecorded = 0;
            WaveInHdr.dwUser = 0;
            WaveInHdr.dwFlags = 0;
            WaveInHdr.dwLoops = 0;

            waveInPrepareHeader(hWaveIn, &WaveInHdr, sizeof(WAVEHDR));
            memcpy(WaveInHdr.lpData, pcmBuff, pcmDataSize);

            if(waveOutOpen(&hWaveOut, WAVE_MAPPER, &pFormat, 0, 0, WAVE_FORMAT_DIRECT))
            {
                MessageBoxA(NULL, "Failed to replay", NULL, MB_OK | MB_ICONEXCLAMATION );
            }

            waveOutWrite(hWaveOut, &WaveInHdr, sizeof(WaveInHdr)); 
            Sleep((pcmDataSize/sampleRate ) * 1000); //Sleep for as long as there was recorded

            waveOutUnprepareHeader(hWaveOut, &WaveInHdr, sizeof(WAVEHDR));
            waveInUnprepareHeader(hWaveIn, &WaveInHdr, sizeof(WAVEHDR));
            waveInClose(hWaveIn);
            waveOutClose(hWaveOut);


            WaveInHdr.lpData = NULL;
            delete []waveIn;
        }
    }

Thanks for reading my question.

Was it helpful?

Solution

I won't work like this.
when you play first sample you can't sleep for the time of your next samples, instead you should use double or multi buffering and a callback mechanism.
the overall protocol is as follow:
1) get first block from camera or whatever
2) get second block from camera or whatever
3) write first block and then second block without any wait.
then create a loop that wait for signals from callbackand upon receiving signals write next captured block.

OTHER TIPS

To play audio smoothly using waveOut* family you open device, allocate buffers and keep sending buffers to the device keeping a backlog of data to play. Where you Sleep in your code, you should be working on preparing and writing new data to the device, and in the same time checking for buffers played back (WHDR_DONE flag set to indicate that driver is no longer using the buffer and the application receives it back).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top