Search code examples
c++audiodirectshowpcm

How to detect silence with IMediaSample in PCM audio


I need to detect silence in PCM audio stream with IMediaSample. Signal is provided by TV and is connected with PC by optic cable to Prodigy 7.1 HiFi soundcard. So far I have this:

bool detectSound(IMediaSample *pSamples)
{
    BYTE *pData;
    pSamples->GetPointer(&pData);
    long size = pSamples->GetActualDataLength();

    long nulls = 0;
    for(long i = 0; i < size; ++i) {
        if(pData[i] == 0)
            ++nulls;
    }

    /* 0.9 to eliminate interference */
    long max_nulls = (long) (0.9 * size);
    if(nulls > max_nulls) {                 /* STOP */
        /* no audio */
        return false;
    }
    else {
        /* audio available */
        return true;
    }
}

The problem is that if I put breakpoint at line marked "STOP", nulls has nearly always the same value and is smaller than max_nulls no matter if I mute TV or not. I noticed that pData[i] values are always 0 or 255. (strange, or not?)

Probably I don't understand what exactly this "data" is and how to interpret it. All I'm sure of is that if there is no audio than all sampled values from waveform should be almost 0.

Could you verify my way of thinking? Thanks in advance.

eclipse

edit:

The problem is somewhere around drivers and AC3 Filter settings, because in "SPDIF Test" I got that 44.1 kHz, 48 kHz and 32 kHz are not supported by DirectSound. Roman's idea is just right and will work when I fix this.


Solution

  • The better way is to find out what PCM data is, and the answer to the posted question is going to be trivial.

    The quicker way is:

    • treat those audio data bytes as SHORT values (you did not mention, but I suppose your audio is 16 bit)
    • it would be better to split into channels and process separately
    • calculate standard deviation
    • silence is when/if the calculated value is under certain small thresold