| 1 /* |
|
| 2 The mediastreamer library aims at providing modular media processing and I/O |
|
| 3 for linphone, but also for any telephony application. |
|
| 4 Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org |
|
| 5 |
|
| 6 This library is free software; you can redistribute it and/or |
|
| 7 modify it under the terms of the GNU Lesser General Public |
|
| 8 License as published by the Free Software Foundation; either |
|
| 9 version 2.1 of the License, or (at your option) any later version. |
|
| 10 |
|
| 11 This library is distributed in the hope that it will be useful, |
|
| 12 but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
| 14 Lesser General Public License for more details. |
|
| 15 |
|
| 16 You should have received a copy of the GNU Lesser General Public |
|
| 17 License along with this library; if not, write to the Free Software |
|
| 18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
| 19 */ |
|
| 20 #ifdef HAVE_CONFIG_H |
|
| 21 #include <config.h> |
|
| 22 #endif |
|
| 23 |
|
| 24 #include "ms.h" |
|
| 25 #include "sndcard.h" |
|
| 26 #include "mscodec.h" |
|
| 27 |
|
| 28 #include <sys/types.h> |
|
| 29 #include <fcntl.h> |
|
| 30 #include <unistd.h> |
|
| 31 #include <string.h> |
|
| 32 #include <stdio.h> |
|
| 33 #include <stdlib.h> |
|
| 34 |
|
| 35 #ifdef VIDEO_ENABLED |
|
| 36 extern void ms_video_source_register_all(); |
|
| 37 #endif |
|
| 38 #ifdef HAVE_ILBC |
|
| 39 extern void ms_ilbc_codec_init(); |
|
| 40 #endif |
|
| 41 |
|
| 42 /** |
|
| 43 * ms_init: |
|
| 44 * |
|
| 45 * |
|
| 46 * Initialize the mediastreamer. This must be the first function called in a program |
|
| 47 * using the mediastreamer library. |
|
| 48 * |
|
| 49 * |
|
| 50 */ |
|
| 51 void ms_init() |
|
| 52 { |
|
| 53 if (!g_thread_supported()) g_thread_init (NULL); |
|
| 54 #ifdef HAVE_GLIB |
|
| 55 if (!g_module_supported()){ |
|
| 56 g_error("GModule is not supported."); |
|
| 57 } |
|
| 58 #endif |
|
| 59 /* initialize the oss subsystem */ |
|
| 60 snd_card_manager_init(snd_card_manager); |
|
| 61 /* register the statically linked codecs */ |
|
| 62 ms_codec_register_all(); |
|
| 63 #ifdef VIDEO_ENABLED |
|
| 64 ms_video_source_register_all(); |
|
| 65 #endif |
|
| 66 #ifdef HAVE_ILBC |
|
| 67 ms_ilbc_codec_init(); |
|
| 68 #endif |
|
| 69 } |
|
| 70 |
|
| 71 |
|
| 72 static gint compare(gconstpointer a, gconstpointer b) |
|
| 73 { |
|
| 74 MSFilter *f1=(MSFilter*)a,*f2=(MSFilter*)b; |
|
| 75 if (f1->klass<f2->klass) return -1; |
|
| 76 if (f1->klass==f2->klass) return 0; |
|
| 77 /* if f1->klass>f2->klass ....*/ |
|
| 78 return 1; |
|
| 79 } |
|
| 80 |
|
| 81 static GList *g_list_append_if_new(GList *l,gpointer data) |
|
| 82 { |
|
| 83 GList *res=l; |
|
| 84 if (g_list_find(res,data)==NULL) |
|
| 85 res=g_list_append(res,data); |
|
| 86 return(res); |
|
| 87 } |
|
| 88 |
|
| 89 static GList *get_nexts(MSFilter *f,GList *l) |
|
| 90 { |
|
| 91 int i; |
|
| 92 MSFifo *fifo; |
|
| 93 MSQueue *q; |
|
| 94 GList *res=l; |
|
| 95 |
|
| 96 /* check fifos*/ |
|
| 97 for (i=0;i <f->klass->max_foutputs;i++) |
|
| 98 { |
|
| 99 fifo=f->outfifos[i]; |
|
| 100 if (fifo!=NULL) res=g_list_append_if_new(res,(gpointer)fifo->next_data); |
|
| 101 } |
|
| 102 /* check queues*/ |
|
| 103 for (i=0;i <f->klass->max_qoutputs;i++) |
|
| 104 { |
|
| 105 q=f->outqueues[i]; |
|
| 106 if (q!=NULL) res=g_list_append_if_new(res,(gpointer)q->next_data); |
|
| 107 } |
|
| 108 return(res); |
|
| 109 } |
|
| 110 |
|
| 111 /* compile graphs attached to a sync source*/ |
|
| 112 int ms_compile(MSSync *sync) |
|
| 113 { |
|
| 114 int i; |
|
| 115 GList *list1=NULL,*list2=NULL,*elem; |
|
| 116 GList *proc_chain=NULL; |
|
| 117 MSFilter *f; |
|
| 118 |
|
| 119 /* first free the old list if we are just updating*/ |
|
| 120 if (sync->execution_list!=NULL) g_list_free(sync->execution_list); |
|
| 121 /* get the list of filters attached to this sync*/ |
|
| 122 for (i=0;i<sync->filters;i++) |
|
| 123 { |
|
| 124 //printf("found filter !\n"); |
|
| 125 list1=g_list_append(list1,sync->attached_filters[i]); |
|
| 126 } |
|
| 127 /* find the processing chain */ |
|
| 128 while (list1!=NULL) |
|
| 129 { |
|
| 130 list2=NULL; |
|
| 131 /* sort the list by types of filter*/ |
|
| 132 list1=g_list_sort(list1,compare); |
|
| 133 /* save into the processing chain list*/ |
|
| 134 //printf("list1 :%i elements\n",g_list_length(list1)); |
|
| 135 proc_chain=g_list_concat(proc_chain,list1); |
|
| 136 /* get all following filters. They are appended to list2*/ |
|
| 137 elem=list1; |
|
| 138 while (elem!=NULL) |
|
| 139 { |
|
| 140 f=(MSFilter*)(elem->data); |
|
| 141 /* check if filter 's status */ |
|
| 142 if (f->klass->attributes & FILTER_CAN_SYNC) |
|
| 143 { |
|
| 144 sync->samples_per_tick=0; |
|
| 145 } |
|
| 146 list2=get_nexts(f,list2); |
|
| 147 elem=g_list_next(elem); |
|
| 148 } |
|
| 149 list1=list2; |
|
| 150 } |
|
| 151 sync->execution_list=proc_chain; |
|
| 152 sync->flags&=~MS_SYNC_NEED_UPDATE; |
|
| 153 ms_trace("%i filters successfully compiled in a processing chain.",g_list_length(sync->execution_list)); |
|
| 154 return 0; |
|
| 155 } |
|
| 156 |
|
| 157 /*execute the processing chain attached to a sync source. It is called as a thread by ms_main()*/ |
|
| 158 void *ms_thread_run(void *sync_ptr) |
|
| 159 { |
|
| 160 MSSync *sync=(MSSync*) sync_ptr; |
|
| 161 GList *filter; |
|
| 162 MSFilter *f; |
|
| 163 |
|
| 164 |
|
| 165 ms_sync_lock(sync); |
|
| 166 while(sync->run) |
|
| 167 { |
|
| 168 //g_message("sync->run=%i",sync->run); |
|
| 169 if (sync->samples_per_tick==0) ms_sync_suspend(sync); |
|
| 170 if (sync->flags & MS_SYNC_NEED_UPDATE){ |
|
| 171 ms_compile(sync); |
|
| 172 ms_sync_setup(sync); |
|
| 173 } |
|
| 174 filter=sync->execution_list; |
|
| 175 ms_sync_unlock(sync); |
|
| 176 //ms_trace("Calling synchronisation"); |
|
| 177 ms_sync_synchronize(sync); |
|
| 178 while(filter!=NULL) |
|
| 179 { |
|
| 180 f=(MSFilter*)filter->data; |
|
| 181 if (MS_FILTER_GET_CLASS(f)->attributes & FILTER_IS_SOURCE) |
|
| 182 { |
|
| 183 /* execute it once */ |
|
| 184 ms_trace("Running source filter %s.",f->klass->name); |
|
| 185 ms_filter_process(f); |
|
| 186 } |
|
| 187 else |
|
| 188 { |
|
| 189 /* make the filter process its input data until it has no more */ |
|
| 190 while ( ms_filter_fifos_have_data(f) || ms_filter_queues_have_data(f) ) |
|
| 191 { |
|
| 192 ms_trace("Running filter %s.",f->klass->name); |
|
| 193 ms_filter_process(f); |
|
| 194 } |
|
| 195 } |
|
| 196 filter=g_list_next(filter); |
|
| 197 } |
|
| 198 ms_sync_lock(sync); |
|
| 199 } |
|
| 200 g_cond_signal(sync->stop_cond); /* signal that the sync thread has finished */ |
|
| 201 ms_sync_unlock(sync); |
|
| 202 g_message("Mediastreamer processing thread is exiting."); |
|
| 203 return NULL; |
|
| 204 } |
|
| 205 |
|
| 206 /* stop the processing chain attached to a sync source.*/ |
|
| 207 void ms_thread_stop(MSSync *sync) |
|
| 208 { |
|
| 209 if (sync->thread!=NULL) |
|
| 210 { |
|
| 211 if (sync->samples_per_tick==0) |
|
| 212 { |
|
| 213 /* to wakeup the thread */ |
|
| 214 //g_cond_signal(sync->thread_cond); |
|
| 215 } |
|
| 216 g_mutex_lock(sync->lock); |
|
| 217 sync->run=0; |
|
| 218 sync->thread=NULL; |
|
| 219 g_cond_wait(sync->stop_cond,sync->lock); |
|
| 220 g_mutex_unlock(sync->lock); |
|
| 221 } |
|
| 222 //g_message("ms_thread_stop() finished."); |
|
| 223 } |
|
| 224 |
|
| 225 /** |
|
| 226 * ms_start: |
|
| 227 * @sync: A synchronisation source to be started. |
|
| 228 * |
|
| 229 * Starts a thread that will shedule all processing chains attached to the synchronisation source @sync. |
|
| 230 * |
|
| 231 * |
|
| 232 */ |
|
| 233 void ms_start(MSSync *sync) |
|
| 234 { |
|
| 235 if (sync->run==1) return; /*already running*/ |
|
| 236 ms_compile(sync); |
|
| 237 ms_sync_setup(sync); |
|
| 238 /* this is to avoid race conditions, for example: |
|
| 239 ms_start(sync); |
|
| 240 ms_oss_write_start(ossw); |
|
| 241 here tge ossw filter need to be compiled to run ms_oss_write_start() |
|
| 242 */ |
|
| 243 ms_trace("ms_start: creating new thread."); |
|
| 244 sync->run=1; |
|
| 245 sync->thread=g_thread_create((GThreadFunc)ms_thread_run,(gpointer)sync,TRUE,NULL); |
|
| 246 if (sync->thread==NULL){ |
|
| 247 g_warning("Could not create thread !"); |
|
| 248 } |
|
| 249 } |
|
| 250 |
|
| 251 /** |
|
| 252 * ms_stop: |
|
| 253 * @sync: A synchronisation source to be stopped. |
|
| 254 * |
|
| 255 * Stop the thread that was sheduling the processing chains attached to the synchronisation source @sync. |
|
| 256 * The processing chains are kept unchanged, no object is freed. The synchronisation source can be restarted using ms_start(). |
|
| 257 * |
|
| 258 * |
|
| 259 */ |
|
| 260 void ms_stop(MSSync *sync) |
|
| 261 { |
|
| 262 ms_thread_stop(sync); |
|
| 263 ms_sync_unsetup(sync); |
|
| 264 } |
|
| 265 |
|
| 266 |
|
| 267 gint ms_load_plugin(gchar *path) |
|
| 268 { |
|
| 269 #ifdef HAVE_GLIB |
|
| 270 g_module_open(path,0); |
|
| 271 #endif |
|
| 272 return 0; |
|
| 273 } |
|
| 274 |
|
| 275 gchar * ms_proc_get_param(gchar *parameter) |
|
| 276 { |
|
| 277 gchar *file; |
|
| 278 int fd; |
|
| 279 int err,len; |
|
| 280 gchar *p,*begin,*end; |
|
| 281 gchar *ret; |
|
| 282 fd=open("/proc/cpuinfo",O_RDONLY); |
|
| 283 if (fd<0){ |
|
| 284 g_warning("Could not open /proc/cpuinfo."); |
|
| 285 return NULL; |
|
| 286 } |
|
| 287 file=g_malloc(1024); |
|
| 288 err=read(fd,file,1024); |
|
| 289 file[err-1]='\0'; |
|
| 290 /* find the parameter */ |
|
| 291 p=strstr(file,parameter); |
|
| 292 if (p==NULL){ |
|
| 293 /* parameter not found */ |
|
| 294 g_free(file); |
|
| 295 return NULL; |
|
| 296 } |
|
| 297 /* find the following ':' */ |
|
| 298 p=strchr(p,':'); |
|
| 299 if (p==NULL){ |
|
| 300 g_free(file); |
|
| 301 return NULL; |
|
| 302 } |
|
| 303 /* find the value*/ |
|
| 304 begin=p+2; |
|
| 305 end=strchr(begin,'\n'); |
|
| 306 if (end==NULL) end=strchr(begin,'\0'); |
|
| 307 len=end-begin+1; |
|
| 308 ret=g_malloc(len+1); |
|
| 309 snprintf(ret,len,"%s",begin); |
|
| 310 //printf("%s=%s\n",parameter,ret); |
|
| 311 g_free(file); |
|
| 312 return ret; |
|
| 313 } |
|
| 314 |
|
| 315 gint ms_proc_get_type() |
|
| 316 { |
|
| 317 static int proc_type=0; |
|
| 318 gchar *value; |
|
| 319 if (proc_type==0){ |
|
| 320 value=ms_proc_get_param("cpu family"); |
|
| 321 if (value!=NULL) { |
|
| 322 proc_type=atoi(value); |
|
| 323 g_free(value); |
|
| 324 }else return -1; |
|
| 325 } |
|
| 326 return proc_type; |
|
| 327 } |
|
| 328 |
|
| 329 gint ms_proc_get_speed() |
|
| 330 { |
|
| 331 char *value; |
|
| 332 static int proc_speed=0; |
|
| 333 if (proc_speed==0){ |
|
| 334 value=ms_proc_get_param("cpu MHz"); |
|
| 335 if (value!=NULL){ |
|
| 336 proc_speed=atoi(value); |
|
| 337 g_free(value); |
|
| 338 }else return -1; |
|
| 339 } |
|
| 340 //printf("proc_speed=%i\n",proc_speed); |
|
| 341 return proc_speed; |
|
| 342 } |
|