/*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; }
static u32 gf_ar_fill_output(void *ptr, char *buffer, u32 buffer_size) { u32 written; GF_AudioRenderer *ar = (GF_AudioRenderer *) ptr; if (!ar->need_reconfig) { u32 delay_ms = ar->disable_resync ? 0 : ar->audio_delay; if (ar->Frozen) { memset(buffer, 0, buffer_size); return buffer_size; } gf_mixer_lock(ar->mixer, GF_TRUE); if (ar->filter_chain.enable_filters) { char *ptr = buffer; written = 0; delay_ms += ar->filter_chain.delay_ms; while (buffer_size) { u32 to_copy; if (!ar->nb_used) { u32 nb_bytes; /*fill input block*/ nb_bytes = gf_mixer_get_output(ar->mixer, ar->filter_chain.tmp_block1, ar->filter_chain.min_block_size, delay_ms); if (!nb_bytes) return written; /*delay used to check for late frames - we only use it on the first call to gf_mixer_get_output()*/ delay_ms = 0; ar->nb_filled = gf_afc_process(&ar->filter_chain, nb_bytes); if (!ar->nb_filled) continue; } to_copy = ar->nb_filled - ar->nb_used; if (to_copy>buffer_size) to_copy = buffer_size; memcpy(ptr, ar->filter_chain.tmp_block1 + ar->nb_used, to_copy); ptr += to_copy; buffer_size -= to_copy; written += to_copy; ar->nb_used += to_copy; if (ar->nb_used==ar->nb_filled) ar->nb_used = 0; } } else { written = gf_mixer_get_output(ar->mixer, buffer, buffer_size, delay_ms); } gf_mixer_lock(ar->mixer, GF_FALSE); //done with one sim step, go back in pause if (ar->step_mode) { ar->step_mode = GF_FALSE; gf_ar_pause(ar, GF_TRUE, GF_FALSE, GF_FALSE); } if (!ar->need_reconfig) { if (ar->audio_listeners) { u32 k=0; GF_AudioListener *l; while ((l = (GF_AudioListener*)gf_list_enum(ar->audio_listeners, &k))) { l->on_audio_frame(l->udta, buffer, buffer_size, gf_sc_ar_get_clock(ar), delay_ms); } } ar->bytes_requested += buffer_size; ar->current_time = ar->time_at_last_config + (u32) (ar->bytes_requested * 1000 / ar->bytes_per_second); } //always return buffer size (eg requested input size to be filled), since the clock is always increased by buffer_size (cf above line) return buffer_size; } return 0; }
GF_EXPORT Bool gf_mixer_reconfig(GF_AudioMixer *am) { u32 i, count, numInit, max_sample_rate, max_channels, max_bps, cfg_changed, ch_cfg; gf_mixer_lock(am, GF_TRUE); if (am->isEmpty || !am->must_reconfig) { gf_mixer_lock(am, GF_FALSE); return GF_FALSE; } if (am->ar && am->ar->config_forced) { am->must_reconfig = GF_FALSE; gf_mixer_lock(am, GF_FALSE); return GF_FALSE; } numInit = 0; max_sample_rate = am->sample_rate; max_channels = am->nb_channels; max_bps = am->bits_per_sample; cfg_changed = 0; ch_cfg = 0; max_sample_rate = 0, count = gf_list_count(am->sources); assert(count); for (i=0; i<count; i++) { Bool has_cfg; MixerInput *in = (MixerInput *) gf_list_get(am->sources, i); has_cfg = in->src->GetConfig(in->src, GF_TRUE); if (has_cfg) { /*check same cfg...*/ if (in->src->samplerate * in->src->chan * in->src->bps == 8*in->bytes_per_sec) { numInit++; continue; } } else continue; /*update out cfg*/ if ((count==1) && (max_sample_rate != in->src->samplerate)) { // cfg_changed = 1; max_sample_rate = in->src->samplerate; } else if (max_sample_rate<in->src->samplerate) { // cfg_changed = 1; max_sample_rate = in->src->samplerate; } if ((count==1) && (max_bps!=in->src->bps)) { cfg_changed = 1; max_bps = in->src->bps; } else if (max_bps<in->src->bps) { cfg_changed = 1; max_bps = in->src->bps; } if (!am->force_channel_out) { if ((count==1) && (max_channels!=in->src->chan)) { cfg_changed = 1; max_channels = in->src->chan; if (in->src->chan>2) ch_cfg |= in->src->ch_cfg; } else if (max_channels < in->src->chan) { cfg_changed = 1; max_channels = in->src->chan; if (in->src->chan>2) ch_cfg |= in->src->ch_cfg; } } numInit++; in->bytes_per_sec = in->src->samplerate * in->src->chan * in->src->bps / 8; /*cfg has changed, we must reconfig everything*/ if (cfg_changed || (max_sample_rate != am->sample_rate) ) { in->has_prev = GF_FALSE; memset(&in->last_channels, 0, sizeof(s16)*GF_SR_MAX_CHANNELS); } } if (cfg_changed || (max_sample_rate && (max_sample_rate != am->sample_rate)) ) { if (max_channels>2) { if (ch_cfg != am->channel_cfg) { /*recompute num channel based on all input channels*/ max_channels = 0; if (ch_cfg & GF_AUDIO_CH_FRONT_LEFT) max_channels ++; if (ch_cfg & GF_AUDIO_CH_FRONT_RIGHT) max_channels ++; if (ch_cfg & GF_AUDIO_CH_FRONT_CENTER) max_channels ++; if (ch_cfg & GF_AUDIO_CH_LFE) max_channels ++; if (ch_cfg & GF_AUDIO_CH_BACK_LEFT) max_channels ++; if (ch_cfg & GF_AUDIO_CH_BACK_RIGHT) max_channels ++; if (ch_cfg & GF_AUDIO_CH_BACK_CENTER) max_channels ++; if (ch_cfg & GF_AUDIO_CH_SIDE_LEFT) max_channels ++; if (ch_cfg & GF_AUDIO_CH_SIDE_RIGHT) max_channels ++; } } else { ch_cfg = GF_AUDIO_CH_FRONT_LEFT; if (max_channels==2) ch_cfg |= GF_AUDIO_CH_FRONT_RIGHT; } gf_mixer_set_config(am, max_sample_rate, max_channels, max_bps, ch_cfg); } if (numInit == count) am->must_reconfig = GF_FALSE; if (am->ar) cfg_changed = 1; gf_mixer_lock(am, GF_FALSE); return cfg_changed; }
void gf_sr_lock_audio(GF_Renderer *sr, Bool doLock) { if (sr->audio_renderer) { gf_mixer_lock(sr->audio_renderer->mixer, doLock); } }