LCOV - code coverage report
Current view: top level - compositor - mpeg4_audio.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 258 292 88.4 %
Date: 2021-04-29 23:48:07 Functions: 22 23 95.7 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2012
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / Scene Compositor sub-project
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : 
      27             : #include "nodes_stacks.h"
      28             : 
      29             : #ifndef GPAC_DISABLE_VRML
      30             : 
      31             : 
      32         190 : static void audioclip_activate(AudioClipStack *st, M_AudioClip *ac)
      33             : {
      34         190 :         if (gf_sc_audio_open(&st->input, &ac->url, 0, -1, GF_FALSE) != GF_OK) {
      35         184 :                 st->failure = GF_TRUE;
      36         184 :                 return;
      37             :         }
      38           6 :         ac->isActive = 1;
      39           6 :         gf_node_event_out((GF_Node *)ac, 7/*"isActive"*/);
      40             : 
      41           6 :         gf_mo_set_speed(st->input.stream, st->input.speed);
      42             :         /*traverse all graph to get parent audio group*/
      43           6 :         gf_sc_invalidate(st->input.compositor, NULL);
      44             : }
      45             : 
      46             : static void audioclip_deactivate(AudioClipStack *st, M_AudioClip *ac)
      47             : {
      48           1 :         gf_sc_audio_stop(&st->input);
      49           1 :         ac->isActive = 0;
      50           1 :         gf_node_event_out((GF_Node *)ac, 7/*"isActive"*/);
      51             : 
      52           1 :         st->time_handle.needs_unregister = GF_TRUE;
      53             : }
      54             : 
      55        2091 : static void audioclip_traverse(GF_Node *node, void *rs, Bool is_destroy)
      56             : {
      57             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
      58             :         M_AudioClip *ac = (M_AudioClip *)node;
      59        2091 :         AudioClipStack *st = (AudioClipStack *)gf_node_get_private(node);
      60             : 
      61        2091 :         if (is_destroy) {
      62         218 :                 gf_sc_audio_predestroy(&st->input);
      63         218 :                 if (st->time_handle.is_registered) {
      64          34 :                         gf_sc_unregister_time_node(st->input.compositor, &st->time_handle);
      65             :                 }
      66         218 :                 gf_free(st);
      67         218 :                 return;
      68             :         }
      69        1873 :         if (st->failure) return;
      70             : 
      71             :         /*check end of stream*/
      72         480 :         if (st->input.stream && st->input.stream_finished) {
      73           6 :                 if (gf_mo_get_loop(st->input.stream, ac->loop)) {
      74           6 :                         gf_sc_audio_restart(&st->input);
      75           0 :                 } else if (ac->isActive && gf_mo_should_deactivate(st->input.stream)) {
      76             :                         /*deactivate*/
      77             :                         audioclip_deactivate(st, ac);
      78             :                 }
      79             :         }
      80         480 :         if (ac->isActive) {
      81         469 :                 gf_sc_audio_register(&st->input, (GF_TraverseState*)rs);
      82             :         }
      83         480 :         if (st->set_duration && st->input.stream && st->input.stream->odm) {
      84           5 :                 ac->duration_changed = gf_mo_get_duration(st->input.stream);
      85           5 :                 gf_node_event_out(node, 6/*"duration_changed"*/);
      86           5 :                 st->set_duration = GF_FALSE;
      87             :         }
      88             : 
      89             :         /*store mute flag*/
      90         480 :         st->input.is_muted = tr_state->switched_off;
      91             : }
      92             : 
      93        1070 : static void audioclip_update_time(GF_TimeNode *tn)
      94             : {
      95             :         Double time;
      96        1070 :         M_AudioClip *ac = (M_AudioClip *)tn->udta;
      97        1070 :         AudioClipStack *st = (AudioClipStack *)gf_node_get_private((GF_Node*)tn->udta);
      98             : 
      99        1070 :         if (st->failure) {
     100         184 :                 st->time_handle.needs_unregister = GF_TRUE;
     101         184 :                 return;
     102             :         }
     103         886 :         if (! ac->isActive) {
     104         190 :                 st->start_time = ac->startTime;
     105         190 :                 st->input.speed = ac->pitch;
     106             :         }
     107         886 :         time = gf_node_get_scene_time((GF_Node*)tn->udta);
     108         886 :         if ((time<st->start_time) || (st->start_time<0)) return;
     109             : 
     110         886 :         if (ac->isActive) {
     111         696 :                 if ( (ac->stopTime > st->start_time) && (time>=ac->stopTime)) {
     112             :                         audioclip_deactivate(st, ac);
     113             :                         return;
     114             :                 }
     115             :         }
     116         885 :         if (!ac->isActive) audioclip_activate(st, ac);
     117             : }
     118             : 
     119             : 
     120         218 : void compositor_init_audioclip(GF_Compositor *compositor, GF_Node *node)
     121             : {
     122             :         AudioClipStack *st;
     123         218 :         GF_SAFEALLOC(st, AudioClipStack);
     124         218 :         if (!st) {
     125           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate style group stack\n"));
     126             :                 return;
     127             :         }
     128         218 :         gf_sc_audio_setup(&st->input, compositor, node);
     129             : 
     130         218 :         st->time_handle.UpdateTimeNode = audioclip_update_time;
     131         218 :         st->time_handle.udta = node;
     132         218 :         st->set_duration = GF_TRUE;
     133             : 
     134         218 :         gf_node_set_private(node, st);
     135         218 :         gf_node_set_callback_function(node, audioclip_traverse);
     136         218 :         gf_sc_register_time_node(compositor, &st->time_handle);
     137             : }
     138             : 
     139             : 
     140           4 : void compositor_audioclip_modified(GF_Node *node)
     141             : {
     142             :         M_AudioClip *ac = (M_AudioClip *)node;
     143           4 :         AudioClipStack *st = (AudioClipStack *) gf_node_get_private(node);
     144           4 :         if (!st) return;
     145             : 
     146           4 :         st->failure = GF_FALSE;
     147             : 
     148             :         /*MPEG4 spec is not clear about that , so this is not forbidden*/
     149           4 :         if (st->input.is_open) {
     150           3 :                 if (gf_sc_audio_check_url(&st->input, &ac->url)) {
     151           1 :                         gf_sc_audio_stop(&st->input);
     152           1 :                         gf_sc_audio_open(&st->input, &ac->url, 0, -1, GF_FALSE);
     153             :                         /*force unregister to resetup audio cfg*/
     154           1 :                         gf_sc_audio_unregister(&st->input);
     155           1 :                         gf_sc_invalidate(st->input.compositor, NULL);
     156             :                 }
     157             :         }
     158             : 
     159             :         //update state if we're active
     160           4 :         if (ac->isActive) {
     161           3 :                 audioclip_update_time(&st->time_handle);
     162             :                 /*we're no longer active fon't check for reactivation*/
     163           3 :                 if (!ac->isActive) return;
     164             :         }
     165             : 
     166             :         /*make sure we are still registered*/
     167           3 :         if (!st->time_handle.is_registered && !st->time_handle.needs_unregister)
     168           1 :                 gf_sc_register_time_node(st->input.compositor, &st->time_handle);
     169             :         else
     170           2 :                 st->time_handle.needs_unregister = GF_FALSE;
     171             : }
     172             : 
     173             : 
     174         373 : static void audiosource_activate(AudioSourceStack *st, M_AudioSource *as)
     175             : {
     176         373 :         if (gf_sc_audio_open(&st->input, &as->url, 0, -1, GF_FALSE) != GF_OK)
     177             :                 return;
     178          13 :         st->is_active = GF_TRUE;
     179          13 :         gf_mo_set_speed(st->input.stream, st->input.speed);
     180             :         /*traverse all graph to get parent audio group*/
     181          13 :         gf_sc_invalidate(st->input.compositor, NULL);
     182             : }
     183             : 
     184             : static void audiosource_deactivate(AudioSourceStack *st, M_AudioSource *as)
     185             : {
     186           2 :         gf_sc_audio_stop(&st->input);
     187           2 :         st->is_active = GF_FALSE;
     188           2 :         st->time_handle.needs_unregister = GF_TRUE;
     189             : }
     190             : 
     191        1195 : static void audiosource_traverse(GF_Node *node, void *rs, Bool is_destroy)
     192             : {
     193             :         GF_TraverseState*tr_state = (GF_TraverseState*)rs;
     194             :         M_AudioSource *as = (M_AudioSource *)node;
     195        1195 :         AudioSourceStack *st = (AudioSourceStack *)gf_node_get_private(node);
     196             : 
     197             : 
     198        1195 :         if (is_destroy) {
     199          16 :                 gf_sc_audio_predestroy(&st->input);
     200          16 :                 if (st->time_handle.is_registered) {
     201          15 :                         gf_sc_unregister_time_node(st->input.compositor, &st->time_handle);
     202             :                 }
     203          16 :                 gf_free(st);
     204          16 :                 return;
     205             :         }
     206             : 
     207             : 
     208             :         /*check end of stream*/
     209        1179 :         if (st->input.stream && st->input.stream_finished) {
     210          35 :                 if (gf_mo_get_loop(st->input.stream, GF_FALSE)) {
     211           0 :                         gf_sc_audio_restart(&st->input);
     212          35 :                 } else if (st->is_active && gf_mo_should_deactivate(st->input.stream)) {
     213             :                         /*deactivate*/
     214             :                         audiosource_deactivate(st, as);
     215             :                 }
     216             :         }
     217        1179 :         if (st->is_active) {
     218        1055 :                 gf_sc_audio_register(&st->input, (GF_TraverseState*)rs);
     219             :         }
     220             : 
     221             :         /*store mute flag*/
     222        1179 :         st->input.is_muted = tr_state->switched_off;
     223             : }
     224             : 
     225        1919 : static void audiosource_update_time(GF_TimeNode *tn)
     226             : {
     227             :         Double time;
     228        1919 :         M_AudioSource *as = (M_AudioSource *)tn->udta;
     229        1919 :         AudioSourceStack *st = (AudioSourceStack *)gf_node_get_private((GF_Node*)tn->udta);
     230             : 
     231        1919 :         if (! st->is_active) {
     232         373 :                 st->start_time = as->startTime;
     233         373 :                 st->input.speed = as->speed;
     234             :         }
     235        1919 :         time = gf_node_get_scene_time((GF_Node*)tn->udta);
     236        1919 :         if ((time<st->start_time) || (st->start_time<0)) return;
     237             : 
     238        1919 :         if (st->input.input_ifce.GetSpeed(st->input.input_ifce.callback) && st->is_active) {
     239        1539 :                 if ( (as->stopTime > st->start_time) && (time>=as->stopTime)) {
     240             :                         audiosource_deactivate(st, as);
     241             :                         return;
     242             :                 }
     243             :         }
     244        1917 :         if (!st->is_active) audiosource_activate(st, as);
     245             : }
     246             : 
     247             : 
     248          16 : void compositor_init_audiosource(GF_Compositor *compositor, GF_Node *node)
     249             : {
     250             :         AudioSourceStack *st;
     251          16 :         GF_SAFEALLOC(st, AudioSourceStack);
     252          16 :         if (!st) {
     253           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate style group stack\n"));
     254             :                 return;
     255             :         }
     256          16 :         gf_sc_audio_setup(&st->input, compositor, node);
     257             : 
     258          16 :         st->time_handle.UpdateTimeNode = audiosource_update_time;
     259          16 :         st->time_handle.udta = node;
     260             : 
     261          16 :         gf_node_set_private(node, st);
     262          16 :         gf_node_set_callback_function(node, audiosource_traverse);
     263          16 :         gf_sc_register_time_node(compositor, &st->time_handle);
     264             : }
     265             : 
     266             : 
     267           6 : void compositor_audiosource_modified(GF_Node *node)
     268             : {
     269             :         M_AudioSource *as = (M_AudioSource *)node;
     270           6 :         AudioSourceStack *st = (AudioSourceStack *) gf_node_get_private(node);
     271           6 :         if (!st) return;
     272             : 
     273             :         /*MPEG4 spec is not clear about that , so this is not forbidden*/
     274           6 :         if (gf_sc_audio_check_url(&st->input, &as->url)) {
     275           1 :                 if (st->input.is_open) gf_sc_audio_stop(&st->input);
     276             :                 /*force unregister to resetup audio cfg*/
     277           1 :                 gf_sc_audio_unregister(&st->input);
     278           1 :                 gf_sc_invalidate(st->input.compositor, NULL);
     279             : 
     280           1 :                 if (st->is_active) gf_sc_audio_open(&st->input, &as->url, 0, -1, GF_FALSE);
     281             :         }
     282             : 
     283             :         //update state if we're active
     284           6 :         if (st->is_active) {
     285           3 :                 audiosource_update_time(&st->time_handle);
     286           3 :                 if (!st->is_active) return;
     287             :         }
     288             : 
     289             :         /*make sure we are still registered*/
     290           5 :         if (!st->time_handle.is_registered && !st->time_handle.needs_unregister)
     291           1 :                 gf_sc_register_time_node(st->input.compositor, &st->time_handle);
     292             :         else
     293           4 :                 st->time_handle.needs_unregister = GF_FALSE;
     294             : }
     295             : 
     296             : 
     297             : typedef struct
     298             : {
     299             :         AUDIO_GROUP_NODE
     300             : 
     301             :         GF_TimeNode time_handle;
     302             :         Double start_time;
     303             :         Bool set_duration;
     304             :         /*AudioBuffer mixes its children*/
     305             :         GF_AudioMixer *am;
     306             :         Bool is_init, is_muted;
     307             :         /*buffer audio data*/
     308             :         char *buffer;
     309             :         u32 buffer_size;
     310             : 
     311             :         Bool done;
     312             :         /*read/write position in buffer and associated read time (CTS)*/
     313             :         u32 read_pos, write_pos, cur_cts;
     314             :         /*list of audio children after a traverse*/
     315             :         GF_List *new_inputs;
     316             : } AudioBufferStack;
     317             : 
     318             : 
     319             : 
     320             : /*we have no choice but always browsing the children, since a src can be replaced by a new one
     321             : without the parent being modified. We just collect the src and check against the current mixer inputs
     322             : to reset the mixer or not - the spec is not clear about that btw, shall rebuffering happen if a source is modified or not ...*/
     323          40 : static void audiobuffer_traverse(GF_Node *node, void *rs, Bool is_destroy)
     324             : {
     325             :         u32 j;
     326             :         Bool update_mixer;
     327             :         GF_ChildNodeItem *l;
     328             :         GF_AudioGroup *parent;
     329          40 :         AudioBufferStack *st = (AudioBufferStack *)gf_node_get_private(node);
     330             :         M_AudioBuffer *ab = (M_AudioBuffer *)node;
     331             :         GF_TraverseState*tr_state = (GF_TraverseState*) rs;
     332             : 
     333          40 :         if (is_destroy) {
     334           5 :                 gf_sc_audio_unregister(&st->output);
     335           5 :                 if (st->time_handle.is_registered)
     336           5 :                         gf_sc_unregister_time_node(st->output.compositor, &st->time_handle);
     337             : 
     338           5 :                 gf_mixer_del(st->am);
     339           5 :                 if (st->buffer) gf_free(st->buffer);
     340           5 :                 gf_list_del(st->new_inputs);
     341           5 :                 gf_free(st);
     342           5 :                 return;
     343             :         }
     344          35 :         parent = tr_state->audio_parent;
     345          35 :         tr_state->audio_parent = (GF_AudioGroup *) st;
     346          35 :         l = ab->children;
     347         105 :         while (l) {
     348          35 :                 gf_node_traverse(l->node, tr_state);
     349          35 :                 l = l->next;
     350             :         }
     351             : 
     352          35 :         gf_mixer_lock(st->am, GF_TRUE);
     353             : 
     354             :         /*if no new inputs don't change mixer config*/
     355          35 :         update_mixer = gf_list_count(st->new_inputs) ? GF_TRUE : GF_FALSE;
     356             : 
     357          35 :         if (gf_mixer_get_src_count(st->am) == gf_list_count(st->new_inputs)) {
     358           0 :                 u32 count = gf_list_count(st->new_inputs);
     359             :                 update_mixer = GF_FALSE;
     360           0 :                 for (j=0; j<count; j++) {
     361           0 :                         GF_AudioInput *cur = (GF_AudioInput *)gf_list_get(st->new_inputs, j);
     362           0 :                         if (!gf_mixer_is_src_present(st->am, &cur->input_ifce)) {
     363             :                                 update_mixer = GF_TRUE;
     364             :                                 break;
     365             :                         }
     366             :                 }
     367             :         }
     368             : 
     369          35 :         if (update_mixer) {
     370           1 :                 gf_mixer_remove_all(st->am);
     371           1 :                 gf_mixer_force_channel_out(st->am, ab->numChan);
     372             :         }
     373             : 
     374          36 :         while (gf_list_count(st->new_inputs)) {
     375           1 :                 GF_AudioInput *src = (GF_AudioInput *)gf_list_get(st->new_inputs, 0);
     376           1 :                 gf_list_rem(st->new_inputs, 0);
     377           1 :                 if (update_mixer) gf_mixer_add_input(st->am, &src->input_ifce);
     378             :         }
     379             : 
     380          35 :         gf_mixer_lock(st->am, GF_FALSE);
     381          35 :         tr_state->audio_parent = parent;
     382             : 
     383             :         /*Note the audio buffer is ALWAYS registered until destroyed since buffer filling shall happen even when inactive*/
     384          35 :         if (!st->output.register_with_parent || !st->output.register_with_renderer)
     385          35 :                 gf_sc_audio_register(&st->output, tr_state);
     386             : 
     387             :         /*store mute flag*/
     388          35 :         st->is_muted = tr_state->switched_off;
     389             : }
     390             : 
     391             : 
     392             : 
     393           5 : static void audiobuffer_activate(AudioBufferStack *st, M_AudioBuffer *ab)
     394             : {
     395           5 :         ab->isActive = 1;
     396           5 :         gf_node_event_out((GF_Node *)ab, 17/*"isActive"*/);
     397             :         /*rerender all graph to get parent audio group*/
     398           5 :         gf_sc_invalidate(st->output.compositor, NULL);
     399           5 :         st->done = GF_FALSE;
     400           5 :         st->read_pos = 0;
     401           5 : }
     402             : 
     403             : static void audiobuffer_deactivate(AudioBufferStack *st, M_AudioBuffer *ab)
     404             : {
     405           0 :         ab->isActive = 0;
     406           0 :         gf_node_event_out((GF_Node *)ab, 17/*"isActive"*/);
     407           0 :         st->time_handle.needs_unregister = GF_TRUE;
     408             : }
     409             : 
     410         512 : static void audiobuffer_update_time(GF_TimeNode *tn)
     411             : {
     412             :         Double time;
     413         512 :         M_AudioBuffer *ab = (M_AudioBuffer *)tn->udta;
     414         512 :         AudioBufferStack *st = (AudioBufferStack *)gf_node_get_private((GF_Node*)tn->udta);
     415             : 
     416         512 :         if (! ab->isActive) {
     417           5 :                 st->start_time = ab->startTime;
     418             :         }
     419         512 :         time = gf_node_get_scene_time((GF_Node*)tn->udta);
     420         512 :         if ((time<st->start_time) || (st->start_time<0)) return;
     421             : 
     422         512 :         if (ab->isActive) {
     423         507 :                 if ( (ab->stopTime > st->start_time) && (time>=ab->stopTime)) {
     424             :                         audiobuffer_deactivate(st, ab);
     425             :                         return;
     426             :                 }
     427             :                 /*THIS IS NOT NORMATIVE*/
     428         507 :                 if ( !ab->loop && st->done) {
     429             :                         audiobuffer_deactivate(st, ab);
     430             :                         return;
     431             :                 }
     432             :         }
     433         512 :         if (!ab->isActive) audiobuffer_activate(st, ab);
     434             : }
     435             : 
     436             : 
     437             : 
     438             : 
     439         151 : static u8 *audiobuffer_fetch_frame(void *callback, u32 *size, u32 *planar_stride, u32 audio_delay_ms)
     440             : {
     441             :         u32 blockAlign;
     442         151 :         AudioBufferStack *st = (AudioBufferStack *) gf_node_get_private( ((GF_AudioInput *) callback)->owner);
     443         151 :         M_AudioBuffer *ab = (M_AudioBuffer*)st->output.owner;
     444             : 
     445         151 :         if (!st->is_init) return NULL;
     446         151 :         if (!st->buffer) {
     447           1 :                 st->done = GF_FALSE;
     448           1 :                 st->buffer_size = (u32) ceil(FIX2FLT(ab->length) * gf_audio_fmt_bit_depth(st->output.input_ifce.afmt) * st->output.input_ifce.samplerate*st->output.input_ifce.chan/8);
     449           1 :                 blockAlign = gf_mixer_get_block_align(st->am);
     450             :                 /*BLOCK ALIGN*/
     451           1 :                 while (st->buffer_size%blockAlign) st->buffer_size++;
     452           1 :                 st->buffer = (char*)gf_malloc(sizeof(char) * st->buffer_size);
     453           1 :                 memset(st->buffer, 0, sizeof(char) * st->buffer_size);
     454           1 :                 st->read_pos = st->write_pos = 0;
     455             :         }
     456         151 :         if (st->done) return NULL;
     457             : 
     458             :         /*even if not active, fill the buffer*/
     459         151 :         if (st->write_pos < st->buffer_size) {
     460             :                 u32 written;
     461             :                 while (1) {
     462             :                         /*just try to completely fill it*/
     463          21 :                         written = gf_mixer_get_output(st->am, st->buffer + st->write_pos, st->buffer_size - st->write_pos, 0);
     464          16 :                         if (!written) break;
     465           5 :                         st->write_pos += written;
     466             :                         assert(st->write_pos<=st->buffer_size);
     467             :                 }
     468             :         }
     469             :         /*not playing*/
     470         151 :         if (! ab->isActive) return NULL;
     471         151 :         *size = st->write_pos - st->read_pos;
     472         151 :         return st->buffer + st->read_pos;
     473             : }
     474             : 
     475         145 : static void audiobuffer_release_frame(void *callback, u32 nb_bytes)
     476             : {
     477         145 :         AudioBufferStack *st = (AudioBufferStack *) gf_node_get_private( ((GF_AudioInput *) callback)->owner);
     478         145 :         st->read_pos += nb_bytes;
     479             :         assert(st->read_pos<=st->write_pos);
     480         145 :         if (st->read_pos==st->write_pos) {
     481           1 :                 if (st->write_pos<st->buffer_size) {
     482             :                         /*reading faster than buffering - let's still attempt to fill the buffer*/
     483             : #if 0
     484             :                         st->write_pos = st->buffer_size;
     485             :                         GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[AudioBuffer] done playing before buffer filling done\n"));
     486             : #endif
     487           1 :                 } else if ( ((M_AudioBuffer*)st->output.owner)->loop) {
     488           1 :                         st->read_pos = 0;
     489             :                 } else {
     490           0 :                         st->done = GF_TRUE;
     491             :                 }
     492             :         }
     493         145 : }
     494             : 
     495             : 
     496         181 : static Fixed audiobuffer_get_speed(void *callback)
     497             : {
     498         181 :         M_AudioBuffer *ab = (M_AudioBuffer *) ((GF_AudioInput *) callback)->owner;
     499         181 :         return ab->pitch;
     500             : }
     501             : 
     502         150 : static Bool audiobuffer_get_volume(void *callback, Fixed *vol)
     503             : {
     504             :         GF_AudioInput *ai = (GF_AudioInput *) callback;
     505         150 :         if (ai->snd->GetChannelVolume) {
     506         150 :                 return ai->snd->GetChannelVolume(ai->snd->owner, vol);
     507             :         } else {
     508             : //              u32 i;
     509             : //              for (i=0; i<GF_AUDIO_MIXER_MAX_CHANNELS; i++) vol[i] = FIX_ONE;
     510             :                 return GF_FALSE;
     511             :         }
     512             : }
     513             : 
     514         212 : static Bool audiobuffer_is_muted(void *callback)
     515             : {
     516         212 :         AudioBufferStack *st = (AudioBufferStack *) gf_node_get_private( ((GF_AudioInput *) callback)->owner);
     517         212 :         return st->is_muted;
     518             : }
     519             : 
     520         188 : static Bool audiobuffer_get_config(GF_AudioInterface *aifc, Bool for_reconf)
     521             : {
     522         188 :         AudioBufferStack *st = (AudioBufferStack *) gf_node_get_private( ((GF_AudioInput *) aifc->callback)->owner);
     523             : 
     524         188 :         if (gf_mixer_must_reconfig(st->am)) {
     525             :                 Bool force_config = GF_TRUE;
     526           6 :                 if (gf_mixer_reconfig(st->am)) {
     527           0 :                         if (st->buffer) gf_free(st->buffer);
     528           0 :                         st->buffer = NULL;
     529           0 :                         st->buffer_size = 0;
     530             :                 }
     531             : 
     532           6 :                 gf_mixer_get_config(st->am, &aifc->samplerate, &aifc->chan, &aifc->afmt, &aifc->ch_layout);
     533             :                 //we only work with packed formats
     534           6 :                 switch (aifc->afmt) {
     535           0 :                 case GF_AUDIO_FMT_U8P:
     536           0 :                         aifc->afmt = GF_AUDIO_FMT_U8;
     537             :                         break;
     538           0 :                 case GF_AUDIO_FMT_S16P:
     539           0 :                         aifc->afmt = GF_AUDIO_FMT_S16;
     540             :                         break;
     541           0 :                 case GF_AUDIO_FMT_S24P:
     542           0 :                         aifc->afmt = GF_AUDIO_FMT_S24;
     543             :                         break;
     544           0 :                 case GF_AUDIO_FMT_S32P:
     545           0 :                         aifc->afmt = GF_AUDIO_FMT_S32;
     546             :                         break;
     547           0 :                 case GF_AUDIO_FMT_FLTP:
     548           0 :                         aifc->afmt = GF_AUDIO_FMT_FLT;
     549             :                         break;
     550           0 :                 case GF_AUDIO_FMT_DBLP:
     551           0 :                         aifc->afmt = GF_AUDIO_FMT_DBL;
     552             :                         break;
     553             :                 default:
     554             :                         force_config = GF_FALSE;
     555             :                         break;
     556             :                 }
     557             :                 if (force_config) {
     558           0 :                         gf_mixer_set_config(st->am, aifc->samplerate, aifc->chan, aifc->afmt, aifc->ch_layout);
     559             :                 }
     560           6 :                 st->is_init = (aifc->samplerate && aifc->chan && aifc->afmt) ? GF_TRUE : GF_FALSE;
     561             :                 assert(st->is_init);
     562           6 :                 if (!st->is_init) {
     563           0 :                         aifc->samplerate = aifc->chan = aifc->afmt = 0;
     564           0 :                         aifc->ch_layout = 0;
     565             :                 }
     566             :                 /*this will force invalidation*/
     567           6 :                 return (for_reconf && st->is_init) ? GF_TRUE : GF_FALSE;
     568             :         }
     569         182 :         return st->is_init;
     570             : }
     571             : 
     572           1 : void audiobuffer_add_source(GF_AudioGroup *_this, GF_AudioInput *src)
     573             : {
     574             :         AudioBufferStack *st = (AudioBufferStack *)_this;
     575           1 :         if (!src) return;
     576             :         /*just collect the input, reconfig is done once all children are rendered*/
     577           1 :         gf_list_add(st->new_inputs, src);
     578             : }
     579             : 
     580             : 
     581           0 : void setup_audiobuffer(GF_AudioInput *ai, GF_Compositor *compositor, GF_Node *node)
     582             : {
     583             :         memset(ai, 0, sizeof(GF_AudioInput));
     584           5 :         ai->owner = node;
     585           5 :         ai->compositor = compositor;
     586             :         /*NEVER used for audio buffer*/
     587           5 :         ai->stream = NULL;
     588             :         /*setup io interface*/
     589           5 :         ai->input_ifce.FetchFrame = audiobuffer_fetch_frame;
     590           5 :         ai->input_ifce.ReleaseFrame = audiobuffer_release_frame;
     591           5 :         ai->input_ifce.GetConfig = audiobuffer_get_config;
     592           5 :         ai->input_ifce.GetChannelVolume = audiobuffer_get_volume;
     593           5 :         ai->input_ifce.GetSpeed = audiobuffer_get_speed;
     594           5 :         ai->input_ifce.IsMuted = audiobuffer_is_muted;
     595           5 :         ai->input_ifce.callback = ai;
     596           5 :         ai->speed = FIX_ONE;
     597           0 : }
     598             : 
     599           5 : void compositor_init_audiobuffer(GF_Compositor *compositor, GF_Node *node)
     600             : {
     601             :         AudioBufferStack *st;
     602           5 :         GF_SAFEALLOC(st, AudioBufferStack);
     603           5 :         if (!st) {
     604           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate audiobuffer stack\n"));
     605             :                 return;
     606             :         }
     607             : 
     608             :         /*use our private input*/
     609           5 :         setup_audiobuffer(&st->output, compositor, node);
     610           5 :         st->add_source = audiobuffer_add_source;
     611             : 
     612           5 :         st->time_handle.UpdateTimeNode = audiobuffer_update_time;
     613           5 :         st->time_handle.udta = node;
     614           5 :         st->set_duration = GF_TRUE;
     615             : 
     616           5 :         st->am = gf_mixer_new(NULL);
     617           5 :         st->new_inputs = gf_list_new();
     618             : 
     619           5 :         gf_node_set_private(node, st);
     620           5 :         gf_node_set_callback_function(node, audiobuffer_traverse);
     621           5 :         gf_sc_register_time_node(compositor, &st->time_handle);
     622             : }
     623             : 
     624             : 
     625           1 : void compositor_audiobuffer_modified(GF_Node *node)
     626             : {
     627             :         M_AudioBuffer *ab = (M_AudioBuffer *)node;
     628           1 :         AudioBufferStack *st = (AudioBufferStack *) gf_node_get_private(node);
     629           1 :         if (!st) return;
     630             : 
     631             :         //update state if we're active
     632           1 :         if (ab->isActive)
     633           1 :                 audiobuffer_update_time(&st->time_handle);
     634             : 
     635             :         /*make sure we are still registered*/
     636           1 :         if (!st->time_handle.is_registered && !st->time_handle.needs_unregister)
     637           0 :                 gf_sc_register_time_node(st->output.compositor, &st->time_handle);
     638             :         else
     639           1 :                 st->time_handle.needs_unregister = GF_FALSE;
     640             : }
     641             : 
     642             : #endif /*GPAC_DISABLE_VRML*/

Generated by: LCOV version 1.13