ILMAUserCallback3 Interface

Implement this user callback interface in order to receive audio buffers. Register the callback by setting the ILMACallback::CallbackObj2 property. This interface has one method, which is called by the LEAD Audio Callback Filter whenever the filter receives an audio buffer.

DirectShow® determines the duration of the audio buffer. However, if you use the LEADTOOLS Multimedia toolkit, you can change the size of the audio buffers using the get_AudioBufferSize property (API) or the AudioBufferSize property (COM).

This interface should be used for C++, .NET or other programming languages that can cast a LONGLONG (__int64) to a pointer. See below for .NET examples (C# and VB.NET) of a class implementing this interface.

Use the ILMAUserCallback2 interface to use a pointer to the data, cast as a 32-bit long value. Use the ILMAUserCallback interface to use variants.

Interface Methods:

HRESULT CallbackProc (LONGLONG pData, long lDataSize, long lBitsPerSample, long lChannels, long lSamplesPerSec, long lAvgBytesPerSec);

This function is called each time an audio sample is received by the filter.

Parameters

pData

Pointer to the sample data cast as a 64-bit LONGLONG (__int64). The sample data is an array of unsigned bytes (8-bit) or signed short (16-bit) values. This value should be cast to a pointer to either unsigned byte or signed short, depending on the value of lBitsPerSample.

lDataSize

The number of elements in pData. If lBitsPerSample is 8, then this also represents the size (in bytes) of the buffer pointed to by pData. If lBitsPerSample is 16, then the size of the pData buffer is lDataSize * 2.

lBitsPerSample

Number of bits per sample of mono data, which determines the format of the data pointed to by pData. Valid values are 8 and 16.

lChannels

Number of channels (i.e. 1=mono, 2=stereo...)

lSamplesPerSec

Sample rate, in samples per second.

lAvgBytesPerSec

Average bandwidth, in bytes per second. It should be equal to lSamplesPerSec * lChannels * (lBitsPerSample / 8).

Returns

AUDCALBK_ERR_OK

Success. The sample data array passes downstream.

AUDCALBK_ERR_DROP

Drop this sample. The sample data array does not pass downstream.

AUDCALBK_ERR_DELIVERLASTSAMPLE

Repeat the last successfully delivered sample.

Other error codes

Any other error codes are returned by the filter as is. The data does not pass downstream.

Comments

Format of audio data:

The general format of the audio data (lChannels) is as follows:

Sample 0

Channel 0

Channel 1

-

Channel lChannels - 1

In this case,

pData(0) is Sample 0, Channel 0
pData
(1) is Sample 0, Channel 1

pData
(lChannels - 1) is Sample 0, Channel lChannels -1
pData
(lChannels) is Sample 1, Channel 0
pData
(lChannels + 1) is Sample 1, Channel 1

The format for mono data is simple, because there is only one channel. In this case, every value in the array is one sample:

pData(0) is Sample 0
pData
(1) is Sample 1

The format for stereo data is still simple: there are two values per sample (one for the left channel and the other for the right channel):

pData(0) is Sample 0, Left channel
pData
(1) is Sample 0, Right channel
pData
(2) is Sample 1, Left channel
pData
(3) is Sample 1, Right channel

The format of the value depends on whether lBitsPerChannel is 8 or 16.

Format of 8-bit audio data:

The values in the array are unsigned and range between 0 and 255. The real audio value is obtained by subtracting 128 from the array value, and should range between -128 and 127. When changing the value, remember to add 128 before putting the data back.

Format of 16-bit data:

The values in the array are signed and range between -32768 and 32767. They contain the real audio values. It is not necessary to perform conversions like those for the 8-bit data.

Examples

Example1: Fast C# code (using unsafe code)

This C# code silences the sound track by setting all sound values to 0. Note that this sample uses pointers, which means your application must be compiled using unsafe code. For slower, safe code, look at the second example, which is written in VB.NET.

private void Form1_Load(object sender, EventArgs e)
{
   string file = @"c:\myfile.avi";

   // Insert Audio Callback Filter
   LTMMLib.ltmmProcessor proc = GetAudioProcessor("LEAD Audio Callback Filter");
   playControl.SelectedAudioProcessors.Add(proc, 0);

   // Hook callback.
   LMACallbackLib.LMACallback audioCallback = (LMACallbackLib.LMACallback)playControl.GetSubObject((int)LTMMLib.ltmmPlay_Object.ltmmPlay_Object_SelAudioProcessor);
   audioCallback.CallbackObj2 = new AudioCallback(audioCallback);

   // Play it.
   playControl.sourcefile = file;
}

public class AudioCallback : LMACallbackLib.ILMAUserCallback3
{
   unsafe public void CallbackProc(long pData, int lDataSize, int lBitsPerSample, int lChannels, int lSamplesPerSec, int lAvgBytesPerSec)
   {
      IntPtr ptrData = new IntPtr(pData);
      int i;
      if (lBitsPerPixel == 16)
      {
         short* ptrData16 = (short*)ptrData.ToPointer();

         for(i = 0; i < lDataSize; i++)
            ptrData16[i] = 0;
      }
      else
      {
         byte* ptrData8 = (byte*)ptrData.ToPointer();

         for(i = 0; i < lDataSize; i++)
            ptrData8[i] = 0;
      }

      ' If you need to return a HRESULT other than AUDCALBK_ERR_OK, then you need to throw an exception   
      ' throw new ReturnValueException(LMACallbackLib.AudCalBkErrConstants.AUDCALBK_ERR_XXX);
   }
}
 

Example2: VB.NET code (slower, but using safe code)

This VB.NET code silences the sound track by setting all of the sound values to 0. Note that this sample is safe, does not use pointers, but is slower than the unsafe code above.

Public Class VBAudioCallback : Implements LMACallbackLib.ILMAUserCallback3
   Public Sub New()
   End Sub

   Sub CallbackProc(ByVal pData As Long, ByVal lDataSize As Integer, ByVal lBitsPerSample As Integer, ByVal lChannels As Integer, ByVal lSamplesPerSec As Integer, ByVal lAvgBytesPerSec As Integer) Implements LMACallbackLib.ILMAUserCallback3.CallbackProc
      Dim ptrData As IntPtr = New IntPtr(pData)
      Dim i As Integer
      ' copy the data to a managed array, since VB does not support pointers.
      If lBitsPerSample = 16 Then
         Dim ptrData16(lDataSize) As Short
         ' Copy data from pData into ptrData16
         System.Runtime.InteropServices.Marshal.Copy(ptrData, ptrData16, 0, lDataSize)
         ' set the data to 0
         For i = 0 To lDataSize - 1
            ptrData16(i) = 0
         Next
         ' copy the data back into ptrData
         System.Runtime.InteropServices.Marshal.Copy(ptrData16, 0, ptrData, lDataSize)
      Else
         Dim ptrData8(lDataSize) As Byte
         ' Copy data from pData into ptrData8
         System.Runtime.InteropServices.Marshal.Copy(ptrData, ptrData8, 0, lDataSize)
         ' set the data to 0
         For i = 0 To lDataSize - 1
            ptrData8(i) = 0
         Next
         ' copy the data back into ptrData
         System.Runtime.InteropServices.Marshal.Copy(ptrData8, 0, ptrData, lDataSize)
      End If

   End Sub
End Class