void gf_sc_ar_del(GF_AudioRenderer *ar) { if (!ar) return; GF_LOG(GF_LOG_DEBUG, GF_LOG_AUDIO, ("[AudioRender] Destroying compositor\n")); /*resume if paused (might cause deadlock otherwise)*/ if (ar->Frozen) gf_sc_ar_control(ar, GF_SC_AR_RESUME); /*stop and shutdown*/ if (ar->audio_out) { /*kill audio thread*/ if (!ar->audio_out->SelfThreaded) { GF_LOG(GF_LOG_DEBUG, GF_LOG_AUDIO, ("[AudioRender] stopping audio thread\n")); ar->audio_th_state = 2; while (ar->audio_th_state != 3) { gf_sleep(33); } GF_LOG(GF_LOG_DEBUG, GF_LOG_AUDIO, ("[AudioRender] audio thread stopped\n")); gf_th_del(ar->th); GF_LOG(GF_LOG_DEBUG, GF_LOG_AUDIO, ("[AudioRender] audio thread destroyed\n")); } /*lock access before shutdown and emulate a reconfig (avoids mixer lock from self-threaded modules)*/ ar->need_reconfig = GF_TRUE; gf_mixer_lock(ar->mixer, GF_TRUE); if (ar->audio_out->SelfThreaded) ar->audio_out->Shutdown(ar->audio_out); gf_modules_close_interface((GF_BaseInterface *)ar->audio_out); ar->audio_out = NULL; gf_mixer_lock(ar->mixer, GF_FALSE); } gf_mixer_del(ar->mixer); if (ar->audio_listeners) gf_list_del(ar->audio_listeners); gf_afc_unload(&ar->filter_chain); gf_free(ar); GF_LOG(GF_LOG_DEBUG, GF_LOG_AUDIO, ("[AudioRender] Renderer destroyed\n")); }
/*we have no choice but always browsing the children, since a src can be replaced by a new one without the parent being modified. We just collect the src and check against the current mixer inputs to reset the mixer or not - the spec is not clear about that btw, shall rebuffering happen if a source is modified or not ...*/ static void audiobuffer_traverse(GF_Node *node, void *rs, Bool is_destroy) { u32 j; Bool update_mixer; GF_ChildNodeItem *l; GF_AudioGroup *parent; AudioBufferStack *st = (AudioBufferStack *)gf_node_get_private(node); M_AudioBuffer *ab = (M_AudioBuffer *)node; GF_TraverseState*tr_state = (GF_TraverseState*) rs; if (is_destroy) { gf_sc_audio_unregister(&st->output); if (st->time_handle.is_registered) gf_sc_unregister_time_node(st->output.compositor, &st->time_handle); gf_mixer_del(st->am); if (st->buffer) gf_free(st->buffer); gf_list_del(st->new_inputs); gf_free(st); return; } parent = tr_state->audio_parent; tr_state->audio_parent = (GF_AudioGroup *) st; l = ab->children; while (l) { gf_node_traverse(l->node, tr_state); l = l->next; } gf_mixer_lock(st->am, 1); /*if no new inputs don't change mixer config*/ update_mixer = gf_list_count(st->new_inputs) ? 1 : 0; if (gf_mixer_get_src_count(st->am) == gf_list_count(st->new_inputs)) { u32 count = gf_list_count(st->new_inputs); update_mixer = 0; for (j=0; j<count; j++) { GF_AudioInput *cur = (GF_AudioInput *)gf_list_get(st->new_inputs, j); if (!gf_mixer_is_src_present(st->am, &cur->input_ifce)) { update_mixer = 1; break; } } } if (update_mixer) { gf_mixer_remove_all(st->am); gf_mixer_force_chanel_out(st->am, ab->numChan); } while (gf_list_count(st->new_inputs)) { GF_AudioInput *src = (GF_AudioInput *)gf_list_get(st->new_inputs, 0); gf_list_rem(st->new_inputs, 0); if (update_mixer) gf_mixer_add_input(st->am, &src->input_ifce); } gf_mixer_lock(st->am, 0); tr_state->audio_parent = parent; /*Note the audio buffer is ALWAYS registered untill destroyed since buffer filling shall happen even when inactive*/ if (!st->output.register_with_parent || !st->output.register_with_renderer) gf_sc_audio_register(&st->output, tr_state); /*store mute flag*/ st->is_muted = tr_state->switched_off; }