/* The mediastreamer library aims at providing modular media processing and I/O for linphone, but also for any telephony application. Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H #include #endif #include "ms.h" #include "sndcard.h" #include "mscodec.h" #include #include #include #include #include #include #ifdef VIDEO_ENABLED extern void ms_video_source_register_all(); #endif #ifdef HAVE_ILBC extern void ms_ilbc_codec_init(); #endif /** * ms_init: * * * Initialize the mediastreamer. This must be the first function called in a program * using the mediastreamer library. * * */ void ms_init() { if (!g_thread_supported()) g_thread_init (NULL); #ifdef HAVE_GLIB if (!g_module_supported()){ g_error("GModule is not supported."); } #endif /* initialize the oss subsystem */ snd_card_manager_init(snd_card_manager); /* register the statically linked codecs */ ms_codec_register_all(); #ifdef VIDEO_ENABLED ms_video_source_register_all(); #endif #ifdef HAVE_ILBC ms_ilbc_codec_init(); #endif } static gint compare(gconstpointer a, gconstpointer b) { MSFilter *f1=(MSFilter*)a,*f2=(MSFilter*)b; if (f1->klassklass) return -1; if (f1->klass==f2->klass) return 0; /* if f1->klass>f2->klass ....*/ return 1; } static GList *g_list_append_if_new(GList *l,gpointer data) { GList *res=l; if (g_list_find(res,data)==NULL) res=g_list_append(res,data); return(res); } static GList *get_nexts(MSFilter *f,GList *l) { int i; MSFifo *fifo; MSQueue *q; GList *res=l; /* check fifos*/ for (i=0;i klass->max_foutputs;i++) { fifo=f->outfifos[i]; if (fifo!=NULL) res=g_list_append_if_new(res,(gpointer)fifo->next_data); } /* check queues*/ for (i=0;i klass->max_qoutputs;i++) { q=f->outqueues[i]; if (q!=NULL) res=g_list_append_if_new(res,(gpointer)q->next_data); } return(res); } /* compile graphs attached to a sync source*/ int ms_compile(MSSync *sync) { int i; GList *list1=NULL,*list2=NULL,*elem; GList *proc_chain=NULL; MSFilter *f; /* first free the old list if we are just updating*/ if (sync->execution_list!=NULL) g_list_free(sync->execution_list); /* get the list of filters attached to this sync*/ for (i=0;ifilters;i++) { /* //printf("found filter !\n"); */ list1=g_list_append(list1,sync->attached_filters[i]); } /* find the processing chain */ while (list1!=NULL) { list2=NULL; /* sort the list by types of filter*/ list1=g_list_sort(list1,compare); /* save into the processing chain list*/ /* //printf("list1 :%i elements\n",g_list_length(list1)); */ proc_chain=g_list_concat(proc_chain,list1); /* get all following filters. They are appended to list2*/ elem=list1; while (elem!=NULL) { f=(MSFilter*)(elem->data); /* check if filter 's status */ if (f->klass->attributes & FILTER_CAN_SYNC) { sync->samples_per_tick=0; } list2=get_nexts(f,list2); elem=g_list_next(elem); } list1=list2; } sync->execution_list=proc_chain; sync->flags&=~MS_SYNC_NEED_UPDATE; ms_trace("%i filters successfully compiled in a processing chain.",g_list_length(sync->execution_list)); return 0; } /*execute the processing chain attached to a sync source. It is called as a thread by ms_main()*/ void *ms_thread_run(void *sync_ptr) { MSSync *sync=(MSSync*) sync_ptr; GList *filter; MSFilter *f; ms_sync_lock(sync); while(sync->run) { /* //g_message("sync->run=%i",sync->run); */ if (sync->samples_per_tick==0) ms_sync_suspend(sync); if (sync->flags & MS_SYNC_NEED_UPDATE){ ms_compile(sync); ms_sync_setup(sync); } filter=sync->execution_list; ms_sync_unlock(sync); /* //ms_trace("Calling synchronisation"); */ ms_sync_synchronize(sync); while(filter!=NULL) { f=(MSFilter*)filter->data; if (MS_FILTER_GET_CLASS(f)->attributes & FILTER_IS_SOURCE) { /* execute it once */ ms_trace("Running source filter %s.",f->klass->name); ms_filter_process(f); } else { /* make the filter process its input data until it has no more */ while ( ms_filter_fifos_have_data(f) || ms_filter_queues_have_data(f) ) { ms_trace("Running filter %s.",f->klass->name); ms_filter_process(f); } } filter=g_list_next(filter); } ms_sync_lock(sync); } g_cond_signal(sync->stop_cond); /* signal that the sync thread has finished */ ms_sync_unlock(sync); g_message("Mediastreamer processing thread is exiting."); return NULL; } /* stop the processing chain attached to a sync source.*/ void ms_thread_stop(MSSync *sync) { if (sync->thread!=NULL) { if (sync->samples_per_tick==0) { /* to wakeup the thread */ /* //g_cond_signal(sync->thread_cond); */ } g_mutex_lock(sync->lock); sync->run=0; sync->thread=NULL; g_cond_wait(sync->stop_cond,sync->lock); g_mutex_unlock(sync->lock); } /* //g_message("ms_thread_stop() finished."); */ } /** * ms_start: * @sync: A synchronisation source to be started. * * Starts a thread that will shedule all processing chains attached to the synchronisation source @sync. * * */ void ms_start(MSSync *sync) { if (sync->run==1) return; /*already running*/ ms_compile(sync); ms_sync_setup(sync); /* this is to avoid race conditions, for example: ms_start(sync); ms_oss_write_start(ossw); here tge ossw filter need to be compiled to run ms_oss_write_start() */ ms_trace("ms_start: creating new thread."); sync->run=1; sync->thread=g_thread_create((GThreadFunc)ms_thread_run,(gpointer)sync,TRUE,NULL); if (sync->thread==NULL){ g_warning("Could not create thread !"); } } /** * ms_stop: * @sync: A synchronisation source to be stopped. * * Stop the thread that was sheduling the processing chains attached to the synchronisation source @sync. * The processing chains are kept unchanged, no object is freed. The synchronisation source can be restarted using ms_start(). * * */ void ms_stop(MSSync *sync) { ms_thread_stop(sync); ms_sync_unsetup(sync); } gint ms_load_plugin(gchar *path) { #ifdef HAVE_GLIB g_module_open(path,0); #endif return 0; } gchar * ms_proc_get_param(gchar *parameter) { gchar *file; int fd; int err,len; gchar *p,*begin,*end; gchar *ret; fd=open("/proc/cpuinfo",O_RDONLY); if (fd<0){ g_warning("Could not open /proc/cpuinfo."); return NULL; } file=g_malloc(1024); err=read(fd,file,1024); file[err-1]='\0'; /* find the parameter */ p=strstr(file,parameter); if (p==NULL){ /* parameter not found */ g_free(file); return NULL; } /* find the following ':' */ p=strchr(p,':'); if (p==NULL){ g_free(file); return NULL; } /* find the value*/ begin=p+2; end=strchr(begin,'\n'); if (end==NULL) end=strchr(begin,'\0'); len=end-begin+1; ret=g_malloc(len+1); snprintf(ret,len,"%s",begin); /* //printf("%s=%s\n",parameter,ret); */ g_free(file); return ret; } gint ms_proc_get_type() { static int proc_type=0; gchar *value; if (proc_type==0){ value=ms_proc_get_param("cpu family"); if (value!=NULL) { proc_type=atoi(value); g_free(value); }else return -1; } return proc_type; } gint ms_proc_get_speed() { char *value; static int proc_speed=0; if (proc_speed==0){ value=ms_proc_get_param("cpu MHz"); if (value!=NULL){ proc_speed=atoi(value); g_free(value); }else return -1; } /* //printf("proc_speed=%i\n",proc_speed); */ return proc_speed; }