📄 audiobuffer.c
字号:
/* * MPEG2-TS over IEEE 1394 decoder - receive and decode MPEG-2 transport * streams according to IEC 61883-4 * * Copyright (C) 2000-2007, Manfred Weihs <mweihs@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <stdlib.h>#include <stdio.h>#include <pthread.h>#include "synchronisation.h"#include "audiobuffer.h"#include "common.h"extern int debug;struct audiobuffer_entry audiobuffer[AUDIOFRAMESINBUFFER];volatile int audiobufferstart,audiobufferend;sem_t audiobuffer_sem;void play_frame(struct frame *);int initmpegaudioplayer(struct frame *fr);int donempegaudioplayer();long int get_audio_delay(struct audio_info_struct *ai);//FIXME: put this into .h-filevoid audio_buffer_fill(struct audio_info_struct *ai,long long int delay);extern struct audio_info_struct ai;extern struct bitstream_info bsi;extern unsigned char *bsbuf, *bsbufold;extern int fsizeold,ssize;static struct frame fr; /* standard-frame */static pthread_t audio_decoder_thread;static volatile int terminate_decoder;#if ! SIMPLE_SYNCHRONISATIONstatic long long int integrator;#define PLL_I_CONSTANT 100000#define PLL_P_CONSTANT 1000#endif#define MAX_DEVIATION 9000int prepareandplayframe(){ if (audiobufferstart == audiobufferend) /* should never happen, since we use semaphore */ { fprintf(stderr,"no frame in buffer\n"); return 0; } else { struct audiobuffer_entry *aubufakt=&audiobuffer[audiobufferstart], *aubufold=&audiobuffer[(audiobufferstart+AUDIOFRAMESINBUFFER-1) % AUDIOFRAMESINBUFFER]; bsbuf=aubufakt->buffer+512; bsbufold=aubufold->buffer+512; bsi.bitindex=0; bsi.wordpointer= bsbuf; ssize=aubufakt->ssize; fsizeold= aubufold->fr.framesize;/* These parts of frame are changed by play_frame and must therefore be saved between the frames aubufakt->fr.alloc=aubufold->fr.alloc; aubufakt->fr.II_sblimit=aubufold->fr.II_sblimit; aubufakt->fr.jsbound=aubufold->fr.jsbound; aubufakt->fr.single=aubufold->fr.single; aubufakt->fr.down_sample=aubufold->fr.down_sample; aubufakt->fr.down_sample_sblimit=aubufold->fr.down_sample_sblimit; aubufakt->fr.synth=aubufold->fr.synth; aubufakt->fr.synth_mono=aubufold->fr.synth_mono;*//* These parts of frame are set by decoder and must be put into the frame data which is used to play the frame */ fr.stereo=aubufakt->fr.stereo; fr.lsf=aubufakt->fr.lsf; fr.mpeg25=aubufakt->fr.mpeg25; fr.header_change=aubufakt->fr.header_change; fr.lay=aubufakt->fr.lay; fr.do_layer=aubufakt->fr.do_layer; fr.error_protection=aubufakt->fr.error_protection; fr.bitrate_index=aubufakt->fr.bitrate_index; fr.sampling_frequency=aubufakt->fr.sampling_frequency; fr.padding=aubufakt->fr.padding; fr.extension=aubufakt->fr.extension; fr.mode=aubufakt->fr.mode; fr.mode_ext=aubufakt->fr.mode_ext; fr.copyright=aubufakt->fr.copyright; fr.original=aubufakt->fr.original; fr.emphasis=aubufakt->fr.emphasis; fr.framesize=aubufakt->fr.framesize; if (aubufakt->havepts && is_sync_enabled()) /* check synchronisation */ { long long stc = getSTC(); long long int deviation=(long long int) aubufakt->pts - stc; /* how long shall we delay this frame */ long long int audio_delay; /* fprintf(stderr,"Audio deviation uncompensated: %Li , pts: %Li, stc: %Li ",deviation,aubufakt->pts,stc); */ /* compensate overflow in pcr or dts */ /* bring difference into the interval [-4294967296;4294967295] */ if (deviation < -4294967296ll) /* is in [-8589934591;-4294967297] */ deviation +=8589934592ll; else if (deviation > 4294967295ll) /* is in [4294967296;8589934591] */ deviation -= 8589934592ll; audio_delay=get_audio_delay(&ai); /* fprintf(stderr," audio buffer delay: %Li, ",audio_delay); */ deviation -= audio_delay; /* add delay of kernel audio driver buffer */ if (debug) { fprintf(stdout,"Audio deviation: %Li ,",deviation); } if (deviation > MAX_DEVIATION) /* we are 0,1 s to early */ { if (deviation > (90000*3)) { /* more than 3 second too early */ fprintf(stderr,"Audio frame more than 3 seconds too early, it seems we lost synchronisation, comensating just 0.1 s.\n"); audio_buffer_fill(&ai,9000); /* fill the audio buffer with zeros to compensate deviation */ } else { audio_buffer_fill(&ai,deviation); /* fill the audio buffer with zeros to compensate deviation */ } /* now the deviation is compensated, so we now can play the frame at its scheduled time */ play_frame(&fr); //play the frame } else if (deviation < -MAX_DEVIATION) /* we are 0,1 s late */ { //drop this frame if (fr.lay == 3) // I do not know, why we need this for layer III, ... set_pointer(512);// but since mpg123 does it when dropping frames, it should be correct... fprintf(stderr,"Audio frame dropped, because we are decoding too slowly (synchronisation)\n"); } else /* if |deviation| is < MAX_DEVIATION, we use the PI-controller */ {#if ! SIMPLE_SYNCHRONISATION /* this code acts as a PLL. It implements a kind of PI-controller */ integrator += deviation; /* integrate deviations -> this should stay approximately constant, when we have the correct frequency */ if (debug) { fprintf(stdout," integrator: %Li ,",integrator); } if (integrator > freqs[fr.sampling_frequency] * PLL_I_CONSTANT / 5) /* limit I-component to 20% of dsp sample rate */ {integrator= freqs[fr.sampling_frequency] * PLL_I_CONSTANT / 5;if (debug) fprintf(stdout,"integrator limited upper bound,");} else if (integrator < -freqs[fr.sampling_frequency] * PLL_I_CONSTANT / 5) {integrator= -freqs[fr.sampling_frequency] * PLL_I_CONSTANT / 5;if (debug) fprintf(stdout,"integrator limited lower bound,");} if (deviation > freqs[fr.sampling_frequency] * PLL_P_CONSTANT / 5) /* limit P-component to 20% of dsp sample rate */ {deviation= freqs[fr.sampling_frequency] * PLL_P_CONSTANT / 5;if (debug) fprintf(stdout,"p component limited upper bound,");} else if (deviation < -freqs[fr.sampling_frequency] * PLL_P_CONSTANT / 5) {deviation= -freqs[fr.sampling_frequency] * PLL_P_CONSTANT / 5;if (debug) fprintf(stdout,"p component limited lower bound,");} long n = freqs[fr.sampling_frequency] - (integrator / PLL_I_CONSTANT) - (deviation / PLL_P_CONSTANT); long m = ai.rate; synth_ntom_set_step(n,m); if(n>m) { fr.down_sample_sblimit = SBLIMIT * m; fr.down_sample_sblimit /= n; if (debug) { fprintf(stdout,"Audio sampling set to: %2.4f:1 conversion",(float)n/(float)m); } } else { fr.down_sample_sblimit = SBLIMIT; if (debug) { fprintf(stderr,"Audio sampling set to: 1:%2.4f conversion",(float)m/(float)n); } } init_layer3(fr.down_sample_sblimit);#endif if (debug) { fprintf(stdout,"\n"); } play_frame(&fr); } } else /* if we have no sync info (dts), we just play the frame */ play_frame(&fr); audiobufferstart=(audiobufferstart+1) % AUDIOFRAMESINBUFFER; return 1; }}static void* audio_decoder_thread_function(void *arg){ while (!terminate_decoder) { if (sem_wait(&audiobuffer_sem)) /* wait for frame in buffer */ { fprintf(stderr,"Cannot P semaphore\n"); exit(0); } if (!terminate_decoder) /* if we shall not yet terminate the decoder */ (void) prepareandplayframe(); } donempegaudioplayer(); return 0; /* terminate thread */}int audio_system_init(){ if (!initmpegaudioplayer(&fr)) { fprintf(stderr,"Cannot initialize audio subsystem"); exit(1); } audiobufferstart=audiobufferend=0; terminate_decoder=0;#if ! SIMPLE_SYNCHRONISATION integrator=0; /* initialize PLL */#endif if (sem_init(&audiobuffer_sem,0,0)) { fprintf(stderr,"Cannot create audio semaphore\n"); exit(1); } if (pthread_create(&audio_decoder_thread,NULL,audio_decoder_thread_function,0)) { fprintf(stderr,"Cannot create audio decoder thread\n"); exit(1); } return 1;}int audio_system_done(){ void *result; terminate_decoder=1; if (sem_post(&audiobuffer_sem)) /* we do this to ensure that the thread is activated */ { fprintf(stderr,"Cannot V semaphore\n"); exit(0); } if (pthread_join(audio_decoder_thread,&result)) /* wait for thread to exit */ { fprintf(stderr,"Cannot join audio decoder thread\n"); exit(1); } if (debug) { fprintf(stdout,"Audio decoder terminated\n");fflush(stdout); } if (sem_destroy(&audiobuffer_sem)) { fprintf(stderr,"Cannot destroy audio semaphore\n"); exit(1); } return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -