c++audioip-cameraadpcm

How to play G726 ADPCM buffer?


I want to play the audio that was received from IP Camera. The format of compressed audio data is G726 ADPCM.

I have searched for a few days on internet, but I haven't done it yet.

I have tried many many ways to play back it. Tried to decode to PCM and build header to create Wave file, but all was failed (Maybe i had some mistake while do it).

But today, I found the code for recording and playing wave audio from PC.

Here is code:

// ADPCM.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <MMSystem.h>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    const int NUMPTS = 8000*10;//44100 * 10;
    int sampleRate = 8000;//44100;
    short int waveIn[NUMPTS];

    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)
    {
        char fault[256];
        waveInGetErrorTextA(result, fault, 256);
        MessageBoxA(NULL, fault, "Failed to open waveform input device.", MB_OK | MB_ICONEXCLAMATION);
        return 1;
    }

    WaveInHdr.lpData = (LPSTR)waveIn;
    WaveInHdr.dwBufferLength = 2 * NUMPTS;
    WaveInHdr.dwBytesRecorded = 0;
    WaveInHdr.dwUser = 0;
    WaveInHdr.dwFlags = 0;
    WaveInHdr.dwLoops = 0;
    waveInPrepareHeader(hWaveIn, &WaveInHdr, sizeof(WAVEHDR));

    result = waveInAddBuffer(hWaveIn, &WaveInHdr, sizeof(WAVEHDR));
    if(result)
    {
        MessageBoxA(NULL, "Failed to read block from device", NULL, MB_OK | MB_ICONEXCLAMATION);
        return 1;
    }

    result = waveInStart(hWaveIn);
    if(result)
    {
        MessageBoxA(NULL, "Failed to start recording", NULL, MB_OK | MB_ICONEXCLAMATION);
        return 1;
    }

    cout << "Recording..." << endl;
    Sleep((NUMPTS/sampleRate) * 1000); //Sleep while recording

    cout << "Playing..." << endl;

    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((NUMPTS/sampleRate) * 1000); //Sleep for as long as there was recorded

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

    return 0;
}

I had the PCM data stored in my buffer and I want to modify the above code to play it, so i have edited it as the following code:

const int NUMPTS = 4000;//44100 * 10;
    int sampleRate = 8000;//44100;
    CHAR waveIn[NUMPTS];

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

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


    WaveInHdr.lpData = (LPSTR)waveIn;
    WaveInHdr.dwBufferLength = 2 * NUMPTS;
    WaveInHdr.dwBytesRecorded = 0;
    WaveInHdr.dwUser = 0;
    WaveInHdr.dwFlags = 0;
    WaveInHdr.dwLoops = 0;
    waveInPrepareHeader(hWaveIn, &WaveInHdr, sizeof(WAVEHDR));

    memcpy(WaveInHdr.lpData, myPCMBuffer, NUMPTS);

    waveOutWrite(hWaveOut, &WaveInHdr, sizeof(WaveInHdr));

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

But It threw the message "Run-Time Check Failure #3 - The variable 'hWaveIn' is being used without being initialized" when waveOutUnprepareHeader() is called.

How to init hWaveIn?

This is the first time I work with wave audio therefore I pretty stupid ^^.

Can you show me the correct way to do it?


Solution

  • To initilize hWaveIn open the audio device:

    MMRESULT waveInOpen(
      LPHWAVEIN phwi, 
      UINT uDeviceID, 
      LPCWAVEFORMATEX pwfx, 
      DWORD dwCallback, 
      DWORD dwInstance, 
      DWORD fdwOpen 
    );
    

    Example:

    result = waveInOpen(&hWaveIn, WAVE_MAPPER,&pFormat,
                0L, 0L, WAVE_FORMAT_DIRECT);
     if (result)
     {
      char fault[256];
      waveInGetErrorText(result, fault, 256);
      Application->MessageBox(fault, "Failed to open waveform input device.",
                  MB_OK | MB_ICONEXCLAMATION);
      return;
     }