forked from mirrors/linphone-iphone
git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@148 3f6dc0c8-ddfe-455d-9043-3cd528dc4637
600 lines
13 KiB
C
600 lines
13 KiB
C
/*
|
|
mediastreamer2 library - modular sound and video processing and streaming
|
|
Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org)
|
|
|
|
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.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "mediastreamer-config.h"
|
|
#endif
|
|
|
|
#include "mediastreamer2/mscommon.h"
|
|
#include "mediastreamer2/msfilter.h"
|
|
|
|
#include "alldescs.h"
|
|
#include "mediastreamer2/mssndcard.h"
|
|
#include "mediastreamer2/mswebcam.h"
|
|
|
|
#if !defined(_WIN32_WCE)
|
|
#include <sys/types.h>
|
|
#endif
|
|
#ifndef WIN32
|
|
#include <dirent.h>
|
|
#else
|
|
#ifndef PACKAGE_PLUGINS_DIR
|
|
#if defined(WIN32) || defined(_WIN32_WCE)
|
|
#define PACKAGE_PLUGINS_DIR "plugins\\"
|
|
#else
|
|
#define PACKAGE_PLUGINS_DIR "."
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#ifdef HAVE_DLOPEN
|
|
#include <dlfcn.h>
|
|
#endif
|
|
|
|
#ifdef __APPLE__
|
|
#import <Cocoa/Cocoa.h>
|
|
#include <Foundation/Foundation.h>
|
|
#endif
|
|
|
|
MSList *ms_list_new(void *data){
|
|
MSList *new_elem=(MSList *)ms_new(MSList,1);
|
|
new_elem->prev=new_elem->next=NULL;
|
|
new_elem->data=data;
|
|
return new_elem;
|
|
}
|
|
|
|
MSList * ms_list_append(MSList *elem, void * data){
|
|
MSList *new_elem=ms_list_new(data);
|
|
MSList *it=elem;
|
|
if (elem==NULL) return new_elem;
|
|
while (it->next!=NULL) it=ms_list_next(it);
|
|
it->next=new_elem;
|
|
new_elem->prev=it;
|
|
return elem;
|
|
}
|
|
|
|
MSList * ms_list_prepend(MSList *elem, void *data){
|
|
MSList *new_elem=ms_list_new(data);
|
|
if (elem!=NULL) {
|
|
new_elem->next=elem;
|
|
elem->prev=new_elem;
|
|
}
|
|
return new_elem;
|
|
}
|
|
|
|
|
|
MSList * ms_list_concat(MSList *first, MSList *second){
|
|
MSList *it=first;
|
|
if (it==NULL) return second;
|
|
while(it->next!=NULL) it=ms_list_next(it);
|
|
it->next=second;
|
|
second->prev=it;
|
|
return first;
|
|
}
|
|
|
|
MSList * ms_list_free(MSList *list){
|
|
MSList *elem = list;
|
|
MSList *tmp;
|
|
if (list==NULL) return NULL;
|
|
while(elem->next!=NULL) {
|
|
tmp = elem;
|
|
elem = elem->next;
|
|
ms_free(tmp);
|
|
}
|
|
ms_free(elem);
|
|
return NULL;
|
|
}
|
|
|
|
MSList * ms_list_remove(MSList *first, void *data){
|
|
MSList *it;
|
|
it=ms_list_find(first,data);
|
|
if (it) return ms_list_remove_link(first,it);
|
|
else {
|
|
ms_warning("ms_list_remove: no element with %p data was in the list", data);
|
|
return first;
|
|
}
|
|
}
|
|
|
|
int ms_list_size(const MSList *first){
|
|
int n=0;
|
|
while(first!=NULL){
|
|
++n;
|
|
first=first->next;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
void ms_list_for_each(const MSList *list, void (*func)(void *)){
|
|
for(;list!=NULL;list=list->next){
|
|
func(list->data);
|
|
}
|
|
}
|
|
|
|
void ms_list_for_each2(const MSList *list, void (*func)(void *, void *), void *user_data){
|
|
for(;list!=NULL;list=list->next){
|
|
func(list->data,user_data);
|
|
}
|
|
}
|
|
|
|
MSList *ms_list_remove_link(MSList *list, MSList *elem){
|
|
MSList *ret;
|
|
if (elem==list){
|
|
ret=elem->next;
|
|
elem->prev=NULL;
|
|
elem->next=NULL;
|
|
if (ret!=NULL) ret->prev=NULL;
|
|
ms_free(elem);
|
|
return ret;
|
|
}
|
|
elem->prev->next=elem->next;
|
|
if (elem->next!=NULL) elem->next->prev=elem->prev;
|
|
elem->next=NULL;
|
|
elem->prev=NULL;
|
|
ms_free(elem);
|
|
return list;
|
|
}
|
|
|
|
MSList *ms_list_find(MSList *list, void *data){
|
|
for(;list!=NULL;list=list->next){
|
|
if (list->data==data) return list;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
MSList *ms_list_find_custom(MSList *list, int (*compare_func)(const void *, const void*), void *user_data){
|
|
for(;list!=NULL;list=list->next){
|
|
if (compare_func(list->data,user_data)==0) return list;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void * ms_list_nth_data(const MSList *list, int index){
|
|
int i;
|
|
for(i=0;list!=NULL;list=list->next,++i){
|
|
if (i==index) return list->data;
|
|
}
|
|
ms_error("ms_list_nth_data: no such index in list.");
|
|
return NULL;
|
|
}
|
|
|
|
int ms_list_position(const MSList *list, MSList *elem){
|
|
int i;
|
|
for(i=0;list!=NULL;list=list->next,++i){
|
|
if (elem==list) return i;
|
|
}
|
|
ms_error("ms_list_position: no such element in list.");
|
|
return -1;
|
|
}
|
|
|
|
int ms_list_index(const MSList *list, void *data){
|
|
int i;
|
|
for(i=0;list!=NULL;list=list->next,++i){
|
|
if (data==list->data) return i;
|
|
}
|
|
ms_error("ms_list_index: no such element in list.");
|
|
return -1;
|
|
}
|
|
|
|
MSList *ms_list_insert_sorted(MSList *list, void *data, int (*compare_func)(const void *, const void*)){
|
|
MSList *it,*previt=NULL;
|
|
MSList *nelem;
|
|
MSList *ret=list;
|
|
if (list==NULL) return ms_list_append(list,data);
|
|
else{
|
|
nelem=ms_list_new(data);
|
|
for(it=list;it!=NULL;it=it->next){
|
|
previt=it;
|
|
if (compare_func(data,it->data)<=0){
|
|
nelem->prev=it->prev;
|
|
nelem->next=it;
|
|
if (it->prev!=NULL)
|
|
it->prev->next=nelem;
|
|
else{
|
|
ret=nelem;
|
|
}
|
|
it->prev=nelem;
|
|
return ret;
|
|
}
|
|
}
|
|
previt->next=nelem;
|
|
nelem->prev=previt;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
MSList *ms_list_insert(MSList *list, MSList *before, void *data){
|
|
MSList *elem;
|
|
if (list==NULL || before==NULL) return ms_list_append(list,data);
|
|
for(elem=list;elem!=NULL;elem=ms_list_next(elem)){
|
|
if (elem==before){
|
|
if (elem->prev==NULL)
|
|
return ms_list_prepend(list,data);
|
|
else{
|
|
MSList *nelem=ms_list_new(data);
|
|
nelem->prev=elem->prev;
|
|
nelem->next=elem;
|
|
elem->prev->next=nelem;
|
|
elem->prev=nelem;
|
|
}
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
MSList *ms_list_copy(const MSList *list){
|
|
MSList *copy=NULL;
|
|
const MSList *iter;
|
|
for(iter=list;iter!=NULL;iter=ms_list_next(iter)){
|
|
copy=ms_list_append(copy,iter->data);
|
|
}
|
|
return copy;
|
|
}
|
|
|
|
|
|
#ifdef __APPLE__
|
|
#define PLUGINS_EXT ".dylib"
|
|
#else
|
|
#define PLUGINS_EXT ".so"
|
|
#endif
|
|
|
|
typedef void (*init_func_t)(void);
|
|
|
|
int ms_load_plugins(const char *dir){
|
|
int num=0;
|
|
#if defined(WIN32) && !defined(_WIN32_WCE)
|
|
WIN32_FIND_DATA FileData;
|
|
HANDLE hSearch;
|
|
char szDirPath[1024];
|
|
char szPluginFile[1024];
|
|
BOOL fFinished = FALSE;
|
|
|
|
snprintf(szDirPath, sizeof(szDirPath), "%s", dir);
|
|
// Create a new directory.
|
|
#if 0
|
|
if (!CreateDirectory(szDirPath, NULL))
|
|
{
|
|
ms_message("plugins directory already exist (%s).", szDirPath);
|
|
}
|
|
#endif
|
|
|
|
// Start searching for .TXT files in the current directory.
|
|
|
|
snprintf(szDirPath, sizeof(szDirPath), "%s\\*.dll", dir);
|
|
hSearch = FindFirstFile(szDirPath, &FileData);
|
|
if (hSearch == INVALID_HANDLE_VALUE)
|
|
{
|
|
ms_message("no plugin (*.dll) found in %s.", szDirPath);
|
|
return 0;
|
|
}
|
|
snprintf(szDirPath, sizeof(szDirPath), "%s", dir);
|
|
|
|
while (!fFinished)
|
|
{
|
|
/* load library */
|
|
HINSTANCE os_handle;
|
|
UINT em;
|
|
em = SetErrorMode (SEM_FAILCRITICALERRORS);
|
|
|
|
snprintf(szPluginFile, sizeof(szPluginFile), "%s\\%s", szDirPath, FileData.cFileName);
|
|
os_handle = LoadLibraryEx (szPluginFile, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
|
|
if (os_handle==NULL)
|
|
{
|
|
os_handle = LoadLibraryEx (szPluginFile, NULL, 0);
|
|
}
|
|
SetErrorMode (em);
|
|
if (os_handle==NULL)
|
|
ms_warning("Fail to load plugin %s :", szPluginFile);
|
|
else
|
|
{
|
|
init_func_t initroutine;
|
|
char szPluginName[256];
|
|
char szMethodName[256];
|
|
snprintf(szPluginName, 256, "%s", FileData.cFileName);
|
|
szPluginName[strlen(szPluginName)-4]='\0';
|
|
snprintf(szMethodName, 256, "%s_init", szPluginName);
|
|
initroutine = (init_func_t) GetProcAddress (os_handle, szMethodName);
|
|
if (initroutine!=NULL){
|
|
initroutine();
|
|
ms_message("Plugin loaded.");
|
|
num++;
|
|
}else{
|
|
ms_warning("Could not locate init routine of plugin %s", szPluginFile);
|
|
}
|
|
}
|
|
|
|
|
|
if (!FindNextFile(hSearch, &FileData))
|
|
{
|
|
if (GetLastError() == ERROR_NO_MORE_FILES)
|
|
{
|
|
fFinished = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ms_error("couldn't find next plugin dll.");
|
|
fFinished = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Close the search handle.
|
|
|
|
FindClose(hSearch);
|
|
|
|
#elif HAVE_DLOPEN
|
|
DIR *ds;
|
|
struct dirent *de;
|
|
char *fullpath;
|
|
ds=opendir(dir);
|
|
if (ds==NULL){
|
|
ms_message("Cannot open directory %s: %s",dir,strerror(errno));
|
|
return -1;
|
|
}
|
|
while( (de=readdir(ds))!=NULL){
|
|
if ((de->d_type==DT_REG && strstr(de->d_name,PLUGINS_EXT)!=NULL)
|
|
|| (de->d_type==DT_UNKNOWN && strstr(de->d_name,PLUGINS_EXT)==de->d_name+strlen(de->d_name)-strlen(PLUGINS_EXT))) {
|
|
void *handle;
|
|
fullpath=ms_strdup_printf("%s/%s",dir,de->d_name);
|
|
ms_message("Loading plugin %s...",fullpath);
|
|
|
|
if ( (handle=dlopen(fullpath,RTLD_NOW))==NULL){
|
|
ms_warning("Fail to load plugin %s : %s",fullpath,dlerror());
|
|
}else {
|
|
char *initroutine_name=ms_malloc0(strlen(de->d_name)+10);
|
|
char *p;
|
|
void *initroutine=NULL;
|
|
strcpy(initroutine_name,de->d_name);
|
|
p=strstr(initroutine_name,PLUGINS_EXT);
|
|
if (p!=NULL)
|
|
{
|
|
strcpy(p,"_init");
|
|
initroutine=dlsym(handle,initroutine_name);
|
|
}
|
|
|
|
#ifdef __APPLE__
|
|
if (initroutine==NULL){
|
|
/* on macosx: library name are libxxxx.1.2.3.dylib */
|
|
/* -> MUST remove the .1.2.3 */
|
|
p=strstr(initroutine_name,".");
|
|
if (p!=NULL)
|
|
{
|
|
strcpy(p,"_init");
|
|
initroutine=dlsym(handle,initroutine_name);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (initroutine!=NULL){
|
|
init_func_t func=(init_func_t)initroutine;
|
|
func();
|
|
ms_message("Plugin loaded.");
|
|
num++;
|
|
}else{
|
|
ms_warning("Could not locate init routine of plugin %s",de->d_name);
|
|
}
|
|
ms_free(initroutine_name);
|
|
}
|
|
ms_free(fullpath);
|
|
}
|
|
}
|
|
closedir(ds);
|
|
#else
|
|
ms_warning("no loadable plugin support: plugins cannot be loaded.");
|
|
num=-1;
|
|
#endif
|
|
return num;
|
|
}
|
|
|
|
|
|
#ifdef __ALSA_ENABLED__
|
|
extern MSSndCardDesc alsa_card_desc;
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_SOUNDCARD_H
|
|
extern MSSndCardDesc oss_card_desc;
|
|
#endif
|
|
|
|
#ifdef __ARTS_ENABLED__
|
|
extern MSSndCardDesc arts_card_desc;
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
extern MSSndCardDesc winsnd_card_desc;
|
|
#endif
|
|
|
|
#ifdef __DIRECTSOUND_ENABLED__
|
|
extern MSSndCardDesc winsndds_card_desc;
|
|
#endif
|
|
|
|
#ifdef __MACSND_ENABLED__
|
|
extern MSSndCardDesc ca_card_desc;
|
|
#endif
|
|
|
|
#ifdef __PORTAUDIO_ENABLED__
|
|
extern MSSndCardDesc pasnd_card_desc;
|
|
#endif
|
|
|
|
#ifdef __MAC_AQ_ENABLED__
|
|
extern MSSndCardDesc aq_card_desc;
|
|
#endif
|
|
|
|
static MSSndCardDesc * ms_snd_card_descs[]={
|
|
#ifdef __ALSA_ENABLED__
|
|
&alsa_card_desc,
|
|
#endif
|
|
#ifdef HAVE_SYS_SOUNDCARD_H
|
|
&oss_card_desc,
|
|
#endif
|
|
#ifdef __ARTS_ENABLED__
|
|
&arts_card_desc,
|
|
#endif
|
|
#ifdef WIN32
|
|
&winsnd_card_desc,
|
|
#endif
|
|
#ifdef __DIRECTSOUND_ENABLED__
|
|
&winsndds_card_desc,
|
|
#endif
|
|
#ifdef __PORTAUDIO_ENABLED__
|
|
&pasnd_card_desc,
|
|
#endif
|
|
#ifdef __MACSND_ENABLED__
|
|
&ca_card_desc,
|
|
#endif
|
|
#ifdef __MAC_AQ_ENABLED__
|
|
&aq_card_desc,
|
|
#endif
|
|
NULL
|
|
};
|
|
|
|
#ifdef VIDEO_ENABLED
|
|
|
|
#ifdef __linux
|
|
extern MSWebCamDesc v4l_desc;
|
|
#endif
|
|
|
|
#ifdef HAVE_LINUX_VIDEODEV2_H
|
|
extern MSWebCamDesc v4l2_desc;
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
extern MSWebCamDesc ms_vfw_cam_desc;
|
|
#endif
|
|
#if defined(WIN32) && defined(HAVE_DIRECTSHOW)
|
|
extern MSWebCamDesc ms_directx_cam_desc;
|
|
#endif
|
|
|
|
extern MSWebCamDesc static_image_desc;
|
|
extern MSWebCamDesc mire_desc;
|
|
|
|
static MSWebCamDesc * ms_web_cam_descs[]={
|
|
#ifdef HAVE_LINUX_VIDEODEV2_H
|
|
&v4l2_desc,
|
|
#endif
|
|
#ifdef __linux
|
|
&v4l_desc,
|
|
#endif
|
|
#if defined(WIN32) && defined(HAVE_DIRECTSHOW)
|
|
&ms_directx_cam_desc,
|
|
#endif
|
|
#if defined(WIN32) && !defined(HAVE_DIRECTSHOW)
|
|
&ms_vfw_cam_desc,
|
|
#endif
|
|
&mire_desc,
|
|
&static_image_desc,
|
|
NULL
|
|
};
|
|
|
|
#endif
|
|
|
|
void ms_init(){
|
|
int i;
|
|
MSSndCardManager *cm;
|
|
#ifdef __APPLE__
|
|
NSApplicationLoad();
|
|
#endif
|
|
|
|
#if !defined(_WIN32_WCE)
|
|
if (getenv("MEDIASTREAMER_DEBUG")!=NULL){
|
|
ortp_set_log_level_mask(ORTP_DEBUG|ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
|
|
}
|
|
#endif
|
|
ms_message("Registering all filters...");
|
|
/* register builtin MSFilter's */
|
|
for (i=0;ms_filter_descs[i]!=NULL;i++){
|
|
ms_filter_register(ms_filter_descs[i]);
|
|
}
|
|
ms_message("Registering all soundcard handlers");
|
|
cm=ms_snd_card_manager_get();
|
|
for (i=0;ms_snd_card_descs[i]!=NULL;i++){
|
|
ms_snd_card_manager_register_desc(cm,ms_snd_card_descs[i]);
|
|
}
|
|
|
|
#ifdef VIDEO_ENABLED
|
|
ms_message("Registering all webcam handlers");
|
|
{
|
|
MSWebCamManager *wm;
|
|
wm=ms_web_cam_manager_get();
|
|
for (i=0;ms_web_cam_descs[i]!=NULL;i++){
|
|
ms_web_cam_manager_register_desc(wm,ms_web_cam_descs[i]);
|
|
}
|
|
}
|
|
#endif
|
|
ms_message("Loading plugins");
|
|
ms_load_plugins(PACKAGE_PLUGINS_DIR);
|
|
ms_message("ms_init() done");
|
|
}
|
|
|
|
void ms_exit(){
|
|
ms_filter_unregister_all();
|
|
ms_snd_card_manager_destroy();
|
|
#ifdef VIDEO_ENABLED
|
|
ms_web_cam_manager_destroy();
|
|
#endif
|
|
}
|
|
|
|
void ms_reload_snd_card(MSSndCardDesc *snd_desc){
|
|
MSSndCardManager *cm;
|
|
int i;
|
|
|
|
ms_snd_card_manager_destroy();
|
|
|
|
ms_message("Registering all soundcard handlers");
|
|
if (snd_desc!=NULL)
|
|
{
|
|
cm=ms_snd_card_manager_get();
|
|
if (cm!=NULL)
|
|
ms_snd_card_manager_register_desc(cm,snd_desc);
|
|
return;
|
|
}
|
|
|
|
/*register SndCardDesc */
|
|
cm=ms_snd_card_manager_get();
|
|
for (i=0;ms_snd_card_descs[i]!=NULL;i++){
|
|
ms_snd_card_manager_register_desc(cm,ms_snd_card_descs[i]);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void ms_sleep(int seconds){
|
|
#ifdef WIN32
|
|
Sleep(seconds*1000);
|
|
#else
|
|
struct timespec ts,rem;
|
|
int err;
|
|
ts.tv_sec=seconds;
|
|
ts.tv_nsec=0;
|
|
do {
|
|
err=nanosleep(&ts,&rem);
|
|
ts=rem;
|
|
}while(err==-1 && errno==EINTR);
|
|
#endif
|
|
}
|
|
|
|
#define DEFAULT_MAX_PAYLOAD_SIZE 1440
|
|
|
|
static int max_payload_size=DEFAULT_MAX_PAYLOAD_SIZE;
|
|
|
|
int ms_get_payload_max_size(){
|
|
return max_payload_size;
|
|
}
|
|
|
|
void ms_set_payload_max_size(int size){
|
|
if (size<=0) size=DEFAULT_MAX_PAYLOAD_SIZE;
|
|
max_payload_size=size;
|
|
}
|