The Filter Pin List

TPinList

So far, in our project, we've used the System Device Enumerator to enumerate the Video input filters and the Audio input filters. As we saw at the end of the last part, we now need to enumerate all the input pins on the audio filter. We do this using a PinList which the DSPack documentation describes as "Helper class to enumerate pins on a filter." To see how it works, here's our Form again. I've added a ComboBox to which we can assign the names of the audio filter's input pins.

PinList

 

Ok, so we need to add a few variables the the ListBox2Click event and create our PinList. I've declared the PinList outside the procedure in order to widen its scope as we'll be using it in more than one procedure.

var
  Form1: TForm1;
  SysDev: TSysDevEnum;
  AudioDevEnum: TSysDevEnum;
  PinList: TPinList 

Don't forget to Free the PinList in the Form's OnCloseQuery event.

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  FilterGraph1.Active:= False;
  FilterGraph1.ClearGraph;
  PinList.Free; 
end;

We create the PinList in the ListBox2Click event but, before we create it, we must activate the FilterGraph:

procedure TForm1.ListBox2Click(Sender: TObject);
var
   i: Integer;
   aBool: LongBool;

begin
   if ListBox2.ItemIndex = -1 then Exit;
   Filter2.BaseFilter.Moniker:= AudioDevEnum.GetMoniker(ListBox2.ItemIndex);
   Filter2.FilterGraph:= FilterGraph1;

   FilterGraph1.Active:= True;
   PinList:= TPinList.Create(Filter2 as IBaseFilter);

In addition to the input pins, the filter also has an output pin, of course, and that will also be included in the PinList. As we don't want that pin included in the list we display to our project's users, we need to locate it in the list and delete it.

(There are actually many output pins corresponding to the audio formats the filter is capable of - we'll cover that in more detail on the next page but, for now, we simply need to delete them.):

   i:= 0;
   while i < PinList.Count do
   begin
     if PinList.PinInfo[i].dir = PINDIR_OUTPUT then
       PinList.Delete(i)
     else
       inc(i);
   end;

In the code above, we used the PinList.PinInfo[index].dir property to look for the output pin (PINDIR_OUTPUT). If we use Delphi's code insight, we can check other properties. (You can find the msdn library reference here). The other property we're interested in at the moment is achName (audio channel Name) which is simply the name of the pin (CD Player, Microphone, etc).

Ok, now that we have the PinList sorted out (ie, deleted the output pin from the list), we can copy the items to ComboBox1 on our Form:

   for i:= 0 to PinList.Count - 1 do
   begin
     ComboBox1.Items.Add(PinList.PinInfo[i].achName);
   end;

To add a "nice touch", as we loop through the PinList to populate the ComboBox, we can check the Windows audio mixer panel to see which input is currently selected and set the ComboBox's current ItemIndex to it. Of course, a user can now also select a different input pin's achName from the ComboBox and so change its ItemIndex but, initially at least, the ComboBox will be showing the current input.

   for i:= 0 to PinList.Count - 1 do
   begin
     ComboBox1.Items.Add(PinList.PinInfo[i].achName);
     with (PinList.Items[i] as IAMAudioInputMixer) do get_Enable(aBool);
     if aBool then ComboBox1.ItemIndex:= i;
   end;

Note that we cast the PinList Item as IAMAudioInputMixer. This is a 'pointer' the the Windows audio mixer and we are able to determine if that particular PinList Item is currently selected in the mixer with the function get_Enable(aBool: LongBool) which returns True (in aBool) if the item is selected. We can then set Combobox1.ItemIndex to that item.

Ok, so below is the full ListBox2Click procedure

procedure TForm1.ListBox2Click(Sender: TObject);
var
   PinList: TPinList;
   i: Integer;
   aBool: LongBool;

begin
   if ListBox2.ItemIndex = -1 then Exit;
   Filter2.BaseFilter.Moniker:= AudioDevEnum.GetMoniker(ListBox2.ItemIndex);
   Filter2.FilterGraph:= FilterGraph1;

   FilterGraph1.Active:= True;
   PinList:= TPinList.Create(Filter2 as IBaseFilter);

   i:= 0;
   while i < PinList.Count do
   begin
     if PinList.PinInfo[i].dir = PINDIR_OUTPUT then
       PinList.Delete(i)
     else
       inc(i);
   end;

   for i:= 0 to PinList.Count - 1 do
   begin
     ComboBox1.Items.Add(PinList.PinInfo[i].achName);
     with (PinList.Items[i] as IAMAudioInputMixer) do get_Enable(aBool);
     if aBool then ComboBox1.ItemIndex:= i;
   end;
end;

We're almost there! All we need to do no is assign the new PinList achName (assuming the user selected a different input) to the Windows audio input mixer. The best place to do that is in the ListBox1Click event just before we build the Filter Graph.

procedure TForm1.ListBox1Click(Sender: TObject);

   :

   if ListBox1.ItemIndex > -1 then
   begin
     Filter1.BaseFilter.Moniker:= SysDev.GetMoniker(ListBox1.ItemIndex);
     FilterGraph1.Active:= True;

      if ComboBox1.ItemIndex = -1 then
      begin 
        ShowMessage('No audio device selected');
        FilterGraph1.Active:= False;  
        Exit;  
      end  
      else  
        with (PinList.Items[ComboBox1.ItemIndex] as IAMAudioInputMixer) do
         put_Enable(True);  

     FilterGraph1.Mode:= gmCapture;
     Filter2.FilterGraph:= FilterGraph1;

     with FilterGraph1 as ICaptureGraphBuilder2 do
     begin
   
   :

So, there we have it. One aspect of audio input we haven't touched on is the sampling rate and whether we're using one or two channels. We'll look at that in the next section and, if you want to have a closer look at the IAMAudioInputMixer, you'll find it at msdn here.

previous page | next page

1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12


This site and its contents are © Copyright 2005 - All Rights Reserved.