Why is the reference count of sink element 0 when it is disconnected from a pipeline?

I have a audio pipeline with a sink. When I switch audio devices, I want to replace the sink only. What I did in the code are,

  1. set pipeline state to NULL

  2. disconnect sink element from the pipeline

  3. unref it <===problem here: reference count is 0 and can not unref it. Why?

  4. create a new sink element and link it to pipeline

  5. set pipeline state to PLAYING

    the pipeline works fine with the new sink. But why can not the old sink be deleted?

    thanks for your help,

    Joe

Got an answer from Nicolas Dufresne: Thanks.

When you create an element from factory, it’s created with a floating ref. As a side effect, when the element get added to the pipeline, the pipeline will get the floating ref, effectively passing ownership. In your case, you have dropped the last reference when you removed the element from the bin/pipeline. Use ref_sink if you want to prevent that.

Nicolas

Wait, Nicolas. I have a few other elements. After the pipeline is unlinked and a new sink is created, I link all elements again.

Basically, only the sink is replaced. Why can other elements still be used if their ref counts are 0 as well?

Another weird thing happened when I switched the audio devices too quickly. The ref count of the sink was 6 once. This is very strange.

We can certainly discuss around some code if you have your code public :slight_smile: But refcount can be daunting. For now I only thought it was worth mentioning the floating ref machinery. But in short, be aware that refcount is used for 2 purposes:

  1. Ownership (usually owned by the parent Bin)
  2. Thread safety

The second is interesting, in the sense that sometimes, the only thread safety one needs to be guaranteed an object won’t be freed while in use. So taking a ref (which is always thread safe) is a good way. You can then drop offending mutex for the rest of your operation and drop the ref when done.

m_pipeline = gst_pipeline_new("audiorx");   
m_audioMixer = gst_element_factory_make("audiomixer", "rx_mixer");
gst_bin_add(GST_BIN(m_pipeline), m_audioMixer);

m_queue = gst_element_factory_make("queue", "rx_queue");
gst_bin_add(GST_BIN(m_pipeline), m_queue);

m_converter = gst_element_factory_make("audioconvert", "rx_convert");
gst_bin_add(GST_BIN(m_pipeline), m_converter);

m_resample = gst_element_factory_make("audioresample", "rx_resample");
gst_bin_add(GST_BIN(m_pipeline), m_resample );

m_sink = gst_element_factory_make("alsasink", "rx_sink");
gst_bin_add(GST_BIN(m_pipeline), m_sink );
g_object_set( m_sink,  "device", m_speaker_str, "sync", FALSE, nullptr );

gst_element_link_many(m_audioMixer, m_queue, m_converter, m_resample, m_sink, nullptr );
gst_element_set_state(m_pipeline, GST_STATE_PLAYING  );

when audio devices change, do the following:

/* stop first */
gst_element_set_state(m_pipeline, GST_STATE_NULL  );
/* unlink mixer */ 
gst_element_unlink_many(m_audioMixer, m_queue, m_converter, m_resample, m_sink, nullptr );

/* clear sink */
gst_bin_remove( GST_BIN( m_pipeline ), m_sink );
gst_object_unref(  m_sink );
m_sink = nullptr;

/* create new sink */
m_sink = gst_element_factory_make("alsasink", "rx_sink");
gst_bin_add(GST_BIN(m_pipeline), m_sink );
g_object_set( m_sink,  "device", m_speaker_str, "sync", FALSE, nullptr );
/* relink */
gst_element_link_many(m_audioMixer, m_queue, m_converter, m_resample, m_sink, nullptr );
/* restart */
gst_element_set_state(m_pipeline, GST_STATE_PLAYING  );

gst_element_factory_make() gave you a floating ref, that you then passed to gst_bin_add(), meaning you m_sink does not hold a reference. Later:

gst_bin_remove() ask m_pipeline to drop the last ref of m_sink, and youre call to gst_object_unref() is illegal since you don’t own any ref. Drop this line, and it will work better.

1 Like

Actually, I added the following:

gst_bin_remove( GST_BIN( m_pipeline ), m_sink );
int count = GST_OBJECT_REFCOUNT( m_sink );
if ( count > 0 ) {
    gst_object_unref(  m_sink );   
}

But once I got count = 6. What is going on? The code above works in most cases. But when I switch the audio devices quickly, somehow there is corrupt memory in the pipeline. Eventually, my gui code will crash.

Without switch of audio devices, my gui works fine. The problem shows up only when I change audio devices quickly.

In general, you should never unref based on the recount read, the ability to read the refcount is only for debugging purpose.

What may happen is that you have bus message queued. Bus messages have a pointer to the src element, and takes a ref to prevent use after free. Other child objects may need to take a ref for similar reasons.

2 Likes

Good point. I will check the bus messages out. Thanks a lot!