Blog Entry

Understanding GStreamer: GstMixer and GstMixerTrack

domingo, septiembre 02, 2007 by , under

Introduction
On this post I will address the basic use of GstMixer and GstMixer track. I will base my explanation on my previous post,The objective of the example I am going to build is to list all available details possible from the mixer and all it's tracks.

In the last example we learned how to get a list of all the available audio mixers. This was done using the function gst_audio_default_registry_mixer_filter() from gstaudiomixerutils. Upon examination of the returned list we learned how to use GstElementFactory to get extended information of the mixer. Now we will learn how to use the GstMixer interface to get a list of all the tracks that a Mixer can contain.

The GstMixer interface.

The function gst_audio_default_registry_mixer_filter() returns a GList of GstElements. All these GstElements implement the GstMixer interface, so we can use GstMixer methods to control the Mixer objects.

Based on our example we will do the following for every mixer in our list:
  • Print the GstElement's name
  • Obtain a reference to it's GstElementFactory and print long name, class, description and author.
  • Set the state of the mixer to READY in order to get the device-name. If we don't change it's state to READY, then we won't have a chance to get the "device-name" property (it would be null).
  • Print device and device name
  • Get a list of the tracks that the mixer can control and print information about each track
The most important part here is how do we get the list of the tracks that the mixer can control? We use this sentence:
tracks = gst_mixer_list_tracks(GST_MIXER(mixer));
This function returns a GList consisting on zero or more GstMixerTrack. The gst/interfaces/mixertrack.h header file defines a mixer track as the following:

* A track is a single input/output stream (e.g. line-in,
* microphone, etc.). Channels are then single streams
* within a track. A mono stream has one channel, a stereo
* stream has two, etc.
*
* Input tracks can have 'recording' enabled, which means
* that any input will be hearable into the speakers that
* are attached to the output. Mute is obvious. A track
* flagged as master is the master volume track on this
* mixer, which means that setting this track will change
* the hearable volume on any output.
In order to know if a track has some flag activated we will use GST_MIXER_TRACK_HAS_FLAG(channel, flag). The list of possible flags is contained in the enumeration GstMixerTrackFlags.

typedef enum {
GST_MIXER_TRACK_INPUT = (1<<0),
GST_MIXER_TRACK_OUTPUT = (1<<1),
GST_MIXER_TRACK_MUTE = (1<<2),
GST_MIXER_TRACK_RECORD = (1<<3),
GST_MIXER_TRACK_MASTER = (1<<4),
GST_MIXER_TRACK_SOFTWARE = (1<<5)
} GstMixerTrackFlags;

Once we get a list of the tracks that a mixer can control, the next step is to walk through the list and print all the information we can get:

/* mixer_tracks.c
* Copyright (c) 2007 Noe Misael Nieto Arroyo
*
* This program will get a list of available mixers for the system and then list
* all the available tracks of each mixer.
* compile with:
* gcc -o mixer_tracks mixer_tracks.c `pkg-config --libs --cflags glib-2.0 gstreamer-plugins-base-0.10` -lgstinterfaces-0.10 -lgstaudio-0.10
*/

#include <gst/gst.h>
#include <gst/interfaces/mixer.h>
#include <glib.h>

void print_track_information (gpointer data, gpointer extra_data){
GstMixer *mixer = GST_MIXER(extra_data);
GstMixerTrack *mixer_track = GST_MIXER_TRACK(data);
gint volumes[2]; /*An array of volumes*/
gint i;

if (GST_IS_MIXER(mixer) && GST_IS_MIXER_TRACK(mixer_track)){
g_print("\t =>Track Label: %s\n",mixer_track->label);
g_print("\t\t*%s%i\n\t\t*%s%i\n\t\t*%s%i\n",
"Number of channels: ", mixer_track->num_channels,
"Min volume: ",mixer_track->min_volume,
"Max volume: ",mixer_track->max_volume);
g_print("\t\t=>%s%s\n\t\t=>%s%s\n\t\t=>%s%s\n\t\t=>%s%s\n\t\t=>%s%s\n\t\t=>%s%s\n",
"GST_MIXER_TRACK_INPUT: ",
GST_MIXER_TRACK_HAS_FLAG(mixer_track,GST_MIXER_TRACK_INPUT)? "YES":"NO",
"GST_MIXER_TRACK_OUTPUT: ",
GST_MIXER_TRACK_HAS_FLAG(mixer_track,GST_MIXER_TRACK_OUTPUT)? "YES":"NO",
"GST_MIXER_TRACK_MUTE: ",
GST_MIXER_TRACK_HAS_FLAG(mixer_track,GST_MIXER_TRACK_MUTE)? "YES":"NO",
"GST_MIXER_TRACK_RECORD: ",
GST_MIXER_TRACK_HAS_FLAG(mixer_track,GST_MIXER_TRACK_RECORD)? "YES":"NO",
"GST_MIXER_TRACK_MASTER: ",
GST_MIXER_TRACK_HAS_FLAG(mixer_track,GST_MIXER_TRACK_MASTER)? "YES":"NO",
"GST_MIXER_TRACK_SOFTWARE: ",
GST_MIXER_TRACK_HAS_FLAG(mixer_track,GST_MIXER_TRACK_SOFTWARE)? "YES":"NO");

gst_mixer_get_volume(mixer, mixer_track,volumes);
if (mixer_track->num_channels < 2) {
g_print("\t\t=>Volume for mono channel is %i\n", volumes[0]);
}
else {
for (i=0; i < mixer_track->num_channels; i++){
g_print("\t\t=>Volume for channel %i of this track is %i\n", i,volumes[0]);
}
}
}
}

void print_mixer_information(gpointer data, gpointer extra_data){
GstElement *mixer = GST_ELEMENT(data);
GstElementFactory *fac;
gchar *device;
gchar *devicename;
GList *tracks = NULL;

if (GST_IS_ELEMENT(mixer)){
g_print("(*========================================================*)\n");
g_print("GstElement name: %s\n",GST_ELEMENT_NAME(mixer));
/*The GstElement has a GstElementFactory associated. This
GstElementFactory has, as well, another structure associated:
GstElementDetails.
Maybe there is another way:
GST_ELEMENT_GET_CLASS(element)->details
*/
fac = gst_element_get_factory(mixer);
g_print("More details about this element:\n\t%s: %s\n\t%s: %s\n\t%s: %s\n\t%s: %s\n",
"Long name: ", gst_element_factory_get_longname(fac),
"klass: ", gst_element_factory_get_klass(fac),
"Description: ", gst_element_factory_get_description(fac),
"Author: ", gst_element_factory_get_author(fac));
/*Set the state of the mixer to READY in order to get the device-name.
If we don't use this sentence, the "device-name" property will be null*/
gst_element_set_state(mixer,GST_STATE_READY);
g_object_get(G_OBJECT(mixer),
"device",&device,
"device-name",&amp;amp;devicename,
NULL);
g_print("\t%s: %s\n\t%s: %s\n",
"device: ",device,
"device name: ",devicename);

/*This function returns an static GList: we don't have to free it when
we finish to work on it*/
tracks = gst_mixer_list_tracks(GST_MIXER(mixer));
if (tracks != NULL){
g_print("\t*)This mixer has %i tracks\n",g_list_length(tracks));
g_list_foreach(tracks,print_track_information,mixer);
}
else {
g_print("\tCould not get the list of tracks for this element.\n");
}

/*We must free each element by setting it to it's NULL state and then
decrementing it's counting reference.*/

gst_element_set_state(mixer,GST_STATE_NULL);
g_object_unref(G_OBJECT(mixer));
g_free(device);
g_free(devicename);
}
}



int main (int argc, char **argv){
guint major,minor,micro,nano;
GList *mixers=NULL;

/*GStreamer Library Initalization*/
gst_init(&argc,&amp;amp;argv);
gst_version(&major,&amp;amp;minor,µ,&nano);

g_print("mixer_scan by Noe Nieto. Copyright (c) 2007.\n");
g_print("This program will try to list the available mixers and ");
g_print("display it's information in the console.\n");
g_print("This version was linked against GStreamer version %d.%d.%d-%d\n",
major,minor,micro,nano);

g_print("\n**Traverse the default plugin registry in order of plugin rank and find usable audio mixer ...\n");

mixers = gst_audio_default_registry_mixer_filter(NULL, /*No filter function*/
FALSE, /*We want all the available mixers*/
NULL); /*No extra data, 'cos no filter function*/
if (!mixers) {
g_print("**There are no registered mixers in the default plugin registry.\n");
return(1);
}

/**Walk through the list printing all available information*/
/* gst_audio_default_registry_mixer_filter() creates it's elements using
gst_element_factory_create()*/
g_list_foreach(mixers,print_mixer_information,NULL);

/**All GstElements set to NULL state and decreased it's reference count*/
g_list_free(mixers);
return 0;
}


Final notes

We have explored the GstMixer and GstMixerTrack interfaces. We know how to get access to each individual track inside the Mixer. The functions that control the behavior of the tracks are listed in the Gstreamer API.

2 Responses to 'Understanding GStreamer: GstMixer and GstMixerTrack'

7:56 p. m.

Comment by Omar Cruz.

I like this blog is fantastic, is really good written. Congratulation. Do you want to see something more? Read it...: Costa Rica is a country with a extremely sense of freedom. The landscapes are for much the most green in whole center america.The chances of investement are way to high, the average of Americans, European and people of the entire planet who is buying here is up in the sky !!!
Great investment opportunity in Costa Rica: condos, costa rica real estate, costa rica property. Visit us for more info at: http://www.jaco-bay.com/

12:03 a. m.


Tengo un rato intentando hacer un programa en el que se grabe lo q sale de una tarjeta capturadora, había tenido algunos problemas con las interfaces de gstreamer, tu entrada en el blog me ayudo a resolverlas.
ahora solo me queda el problema q al grabar el video y audio, el archivo resultante no puede adelantarse o atrasarse, creo q eso se debe a q no cree un clock para el halaudiosrc, q es el elemento q utilizo para capturar el audio. Quería saber si podrías darme una idea del camino a seguir para resolver el problema q tengo.

de antemano Gracias