diff --git a/CMakeLists.txt b/CMakeLists.txt index c9a1db469..4311101fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,13 @@ endif() find_package(BelleSIP REQUIRED) find_package(MS2 REQUIRED) find_package(XML2 REQUIRED) +if(ENABLE_TUNNEL) + find_package(Tunnel) + if(NOT TUNNEL_FOUND) + message(WARNING "Could not find the tunnel library!") + set(ENABLE_TUNNEL OFF CACHE BOOL "Enable tunnel support" FORCE) + endif() +endif() include_directories( @@ -72,6 +79,9 @@ include_directories( ${MS2_INCLUDE_DIRS} ${XML2_INCLUDE_DIRS} ) +if(ENABLE_TUNNEL) + include_directories(${TUNNEL_INCLUDE_DIRS}) +endif() if(MSVC) include_directories(${CMAKE_PREFIX_PATH}/include/MSVC) @@ -94,6 +104,9 @@ add_definitions(-DHAVE_CONFIG_H) add_subdirectory(coreapi) add_subdirectory(share) +if(ENABLE_TOOLS) + add_subdirectory(tools) +endif() install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/FindLinphone.cmake diff --git a/README.mingw b/README.mingw index 57c0851c4..5e859680b 100644 --- a/README.mingw +++ b/README.mingw @@ -60,6 +60,8 @@ General rules for compilation - all other commands (configure, autogen.sh, make) must be done within the mingw shell (msys). In both msys and msys-git windows, change into the directory you created for sources: cd /c/sources +- make sure pkg-config works by adding this env variable to your terminal: + export PKG_CONFIG_PATH=/usr/lib/pkgconfig Building belle-sip ****************** diff --git a/configure.ac b/configure.ac index f584f5b9a..e7caf35b9 100644 --- a/configure.ac +++ b/configure.ac @@ -898,8 +898,8 @@ dnl ################################################## dnl # Check for doxygen dnl ################################################## -AC_PATH_PROG(DOXYGEN,doxygen,false) -AM_CONDITIONAL(HAVE_DOXYGEN, test $DOXYGEN != false) +AC_CHECK_PROG(DOXYGEN,doxygen,doxygen,false) +AM_CONDITIONAL(HAVE_DOXYGEN, test "$DOXYGEN" != "false") AC_CONFIG_FILES([ diff --git a/console/commands.c b/console/commands.c index 7c5b519d8..9f6d0c1c2 100644 --- a/console/commands.c +++ b/console/commands.c @@ -1601,7 +1601,7 @@ linphonec_proxy_add(LinphoneCore *lc) */ if ( enable_register==TRUE ) { - long int expires=0; + int expires=0; while (1) { char *input=linphonec_readline("Specify register expiration time" @@ -1613,13 +1613,8 @@ linphonec_proxy_add(LinphoneCore *lc) return; } - expires=strtol(input, (char **)NULL, 10); - if ( expires == LONG_MIN || expires == LONG_MAX ) - { - linphonec_out("Invalid value: %s\n", strerror(errno)); - free(input); - continue; - } + expires=atoi(input); + if (expires==0) expires=600; linphone_proxy_config_set_expires(cfg, expires); linphonec_out("Expiration: %d seconds\n", linphone_proxy_config_get_expires (cfg)); diff --git a/console/linphonec.c b/console/linphonec.c index 1a800fd2b..439702b85 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -500,7 +500,6 @@ static void *pipe_thread(void*p){ } static void start_pipe_reader(void){ - ms_mutex_init(&prompt_mutex,NULL); pipe_reader_run=TRUE; ortp_thread_create(&pipe_reader_th,NULL,pipe_thread,NULL); } @@ -805,6 +804,7 @@ linphonec_finish(int exit_status) if (mylogfile != NULL && mylogfile != stdout) { fclose (mylogfile); + mylogfile=stdout; } printf("\n"); exit(exit_status); diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index df753c11e..8ed8185ab 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -53,7 +53,6 @@ set(SOURCE_FILES info.c linphonecall.c linphonecore.c - linphone_tunnel_stubs.c linphone_tunnel_config.c lpconfig.c lsd.c @@ -89,6 +88,8 @@ if(ENABLE_TUNNEL) TunnelManager.cc ) add_definitions(-DTUNNEL_ENABLED) +else() + list(APPEND SOURCE_FILES linphone_tunnel_stubs.c) endif() set(GENERATED_SOURCE_FILES @@ -116,6 +117,9 @@ set(LIBS ${MS2_LIBRARIES} ${XML2_LIBRARIES} ) +if(ENABLE_TUNNEL) + list(APPEND LIBS ${TUNNEL_LIBRARIES}) +endif() if(WIN32) list(APPEND LIBS shlwapi) endif() diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index b13f8c5c7..7e47f0bcf 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -63,6 +63,7 @@ liblinphone_la_SOURCES=\ call_log.c \ call_params.c \ player.c \ + fileplayer.c \ $(GITVERSION_FILE) if BUILD_UPNP diff --git a/coreapi/TunnelManager.cc b/coreapi/TunnelManager.cc index d88212c68..a0158a88a 100644 --- a/coreapi/TunnelManager.cc +++ b/coreapi/TunnelManager.cc @@ -96,6 +96,7 @@ RtpTransport *TunnelManager::createRtpTransport(int port){ } void TunnelManager::startClient() { + ms_message("TunnelManager: Starting tunnel client"); if (mTunnelClient == NULL) { mTunnelClient = new TunnelClient(); mTunnelClient->setCallback((TunnelClientController::StateCallback)tunnelCallback,this); @@ -111,9 +112,11 @@ void TunnelManager::startClient() { if(mTunnelizeSipPackets) { sal_enable_tunnel(mCore->sal, mTunnelClient); } + mConnecting = true; } void TunnelManager::stopClient(){ + ms_message("TunnelManager: Stopping tunnel client"); linphone_core_set_rtp_transport_factories(mCore,NULL); sal_disable_tunnel(mCore->sal); if (mTunnelClient){ @@ -148,11 +151,12 @@ TunnelManager::TunnelManager(LinphoneCore* lc) : mExosipTransport(NULL), #endif mMode(LinphoneTunnelModeDisable), - mTunnelClient(NULL), - mIsConnected(false), - mHttpProxyPort(0), - mPreviousRegistrationEnabled(false), + mAutoDetecting(false), + mConnecting(false), + mScheduledRegistration(false), mTunnelizeSipPackets(true), + mTunnelClient(NULL), + mHttpProxyPort(0), mVTable(NULL) { linphone_core_add_iterate_hook(mCore,(LinphoneCoreIterateHook)sOnIterate,this); @@ -170,84 +174,61 @@ TunnelManager::TunnelManager(LinphoneCore* lc) : } TunnelManager::~TunnelManager(){ + for(UdpMirrorClientList::iterator udpMirror = mUdpMirrorClients.begin(); udpMirror != mUdpMirrorClients.end(); udpMirror++) { + udpMirror->stop(); + } stopClient(); linphone_core_remove_listener(mCore, mVTable); linphone_vtable_destroy(mVTable); } -void TunnelManager::registration(){ - // registration occurs always after an unregistation has been made. First we - // need to reset the previous registration mode - LinphoneProxyConfig* lProxy; - linphone_core_get_default_proxy(mCore, &lProxy); - if (lProxy) { - linphone_proxy_config_edit(lProxy); - linphone_proxy_config_enable_register(lProxy,mPreviousRegistrationEnabled); - linphone_proxy_config_done(lProxy); +void TunnelManager::doRegistration(){ + if(mTunnelizeSipPackets) { + LinphoneProxyConfig* lProxy; + linphone_core_get_default_proxy(mCore, &lProxy); + if (lProxy) { + ms_message("TunnelManager: need to register"); + if(linphone_proxy_config_get_state(lProxy) != LinphoneRegistrationProgress) { + linphone_proxy_config_refresh_register(lProxy); + mScheduledRegistration = false; + } else { + ms_warning("TunnelManager: register difered. There is already a registration in progress"); + mScheduledRegistration = true; + } + } else { + mScheduledRegistration = false; + } } } void TunnelManager::processTunnelEvent(const Event &ev){ if (ev.mData.mConnected){ - ms_message("Tunnel is up, registering now"); - registration(); + ms_message("Tunnel is connected"); + doRegistration(); } else { ms_error("Tunnel has been disconnected"); } + mConnecting = false; } -void TunnelManager::waitUnRegistration() { - LinphoneProxyConfig* lProxy; - - linphone_core_get_default_proxy(mCore, &lProxy); - if (lProxy){ - mPreviousRegistrationEnabled=linphone_proxy_config_register_enabled(lProxy); - if (linphone_proxy_config_is_registered(lProxy)) { - int i=0; - linphone_proxy_config_edit(lProxy); - linphone_proxy_config_enable_register(lProxy,FALSE); - linphone_proxy_config_done(lProxy); - sal_unregister(lProxy->op); - //make sure unregister is sent and authenticated - do{ - linphone_core_iterate(mCore); - ms_usleep(20000); - if (i>100){ - ms_message("tunnel: timeout for unregistration expired, giving up"); - break; - } - i++; - }while(linphone_proxy_config_is_registered(lProxy)); - ms_message("Unregistration %s", linphone_proxy_config_is_registered(lProxy)?"failed":"succeeded"); - }else{ - ms_message("No registration pending"); - } - } -} - -/*Each time tunnel is enabled/disabled, we need to unregister previous session and re-register. Since tunnel initialization -is asynchronous, we temporary disable auto register while tunnel sets up, and reenable it when re-registering. */ void TunnelManager::setMode(LinphoneTunnelMode mode) { if(mMode != mode) { - waitUnRegistration(); + ms_message("TunnelManager: Switching mode from %s to %s", + tunnel_mode_to_string(mMode), + tunnel_mode_to_string(mode)); switch(mode) { case LinphoneTunnelModeEnable: mMode = mode; startClient(); - /* registration is done by proccessTunnelEvent() when the tunnel - the tunnel succeed to connect */ break; case LinphoneTunnelModeDisable: mMode = mode; stopClient(); - registration(); + doRegistration(); break; case LinphoneTunnelModeAuto: mMode = mode; autoDetect(); - /* Registration is not needed because processUdpMirrorEvent() will - call either connect() or disconnect(). Should disconnect() is called, - processUdpMirrorEvent() care to call registratin() */ break; default: ms_error("TunnelManager::setMode(): invalid mode (%d)", mode); @@ -263,6 +244,10 @@ void TunnelManager::tunnelCallback(bool connected, TunnelManager *zis){ } void TunnelManager::onIterate(){ + if(mScheduledRegistration) { + ms_message("Apply difered registration"); + doRegistration(); + } mMutex.lock(); while(!mEvq.empty()){ Event ev=mEvq.front(); @@ -329,20 +314,21 @@ LinphoneTunnelMode TunnelManager::getMode() const { void TunnelManager::processUdpMirrorEvent(const Event &ev){ if (ev.mData.mHaveUdp) { - LOGI("Tunnel is not required, disabling"); + ms_message("TunnelManager: auto detection test succeed"); stopClient(); - registration(); + doRegistration(); + mAutoDetecting = false; } else { + ms_message("TunnelManager: auto detection test failed"); mCurrentUdpMirrorClient++; if (mCurrentUdpMirrorClient !=mUdpMirrorClients.end()) { - // enable tunnel but also try backup server - LOGI("Tunnel is required, enabling; Trying backup udp mirror"); - + ms_message("TunnelManager: trying another udp mirror"); UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient; lUdpMirrorClient.start(TunnelManager::sUdpMirrorClientCallback,(void*)this); } else { - LOGI("Tunnel is required, enabling; no backup udp mirror available"); + ms_message("TunnelManager: all auto detection failed. Need ti enable tunnel"); startClient(); + mAutoDetecting = false; } } } @@ -369,14 +355,18 @@ void TunnelManager::networkReachableCb(LinphoneCore *lc, bool_t reachable) { } void TunnelManager::autoDetect() { - // first check if udp mirrors was provisionned + if(mAutoDetecting) { + ms_error("TunnelManager: Cannot start auto detection. One auto detection is going on"); + return; + } if (mUdpMirrorClients.empty()) { - LOGE("No UDP mirror server configured aborting auto detection"); + ms_error("TunnelManager: No UDP mirror server configured aborting auto detection"); return; } mCurrentUdpMirrorClient = mUdpMirrorClients.begin(); UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient; lUdpMirrorClient.start(TunnelManager::sUdpMirrorClientCallback,(void*)this); + mAutoDetecting = true; } void TunnelManager::setHttpProxyAuthInfo(const char* username,const char* passwd) { @@ -386,15 +376,7 @@ void TunnelManager::setHttpProxyAuthInfo(const char* username,const char* passwd } void TunnelManager::tunnelizeSipPackets(bool enable){ - if(enable != mTunnelizeSipPackets) { mTunnelizeSipPackets = enable; - if(isConnected()) { - waitUnRegistration(); - if(mTunnelizeSipPackets) sal_enable_tunnel(mCore->sal, mTunnelClient); - else sal_disable_tunnel(mCore->sal); - registration(); - } - } } bool TunnelManager::tunnelizeSipPacketsEnabled() const { diff --git a/coreapi/TunnelManager.hh b/coreapi/TunnelManager.hh index 38b6b90e3..9b1a4c3a9 100644 --- a/coreapi/TunnelManager.hh +++ b/coreapi/TunnelManager.hh @@ -167,37 +167,37 @@ namespace belledonnecomm { private: void onIterate(); - void registration(); - void waitUnRegistration(); - void processTunnelEvent(const Event &ev); - void processUdpMirrorEvent(const Event &ev); - void postEvent(const Event &ev); + void doRegistration(); void startClient(); void stopClient(); void autoDetect(); + void processTunnelEvent(const Event &ev); + void processUdpMirrorEvent(const Event &ev); + void postEvent(const Event &ev); private: LinphoneCore* mCore; -#ifndef USE_BELLESIP - TunnelSocket *mSipSocket; - eXosip_transport_hooks_t mExosipTransport; -#endif LinphoneTunnelMode mMode; - std::queue mEvq; - std::list mServerAddrs; - UdpMirrorClientList mUdpMirrorClients; - UdpMirrorClientList::iterator mCurrentUdpMirrorClient; + bool mAutoDetecting; + bool mConnecting; + bool mScheduledRegistration; + bool mTunnelizeSipPackets; TunnelClient* mTunnelClient; - Mutex mMutex; - bool mIsConnected; - LinphoneRtpTransportFactories mTransportFactories; std::string mHttpUserName; std::string mHttpPasswd; std::string mHttpProxyHost; int mHttpProxyPort; - bool mPreviousRegistrationEnabled; - bool mTunnelizeSipPackets; LinphoneCoreVTable *mVTable; + std::list mServerAddrs; + UdpMirrorClientList mUdpMirrorClients; + UdpMirrorClientList::iterator mCurrentUdpMirrorClient; + LinphoneRtpTransportFactories mTransportFactories; + Mutex mMutex; + std::queue mEvq; +#ifndef USE_BELLESIP + TunnelSocket *mSipSocket; + eXosip_transport_hooks_t mExosipTransport; +#endif }; /** diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 7c9c8026c..9efbbb7ee 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -318,6 +318,8 @@ static void call_process_transaction_terminated(void *user_ctx, const belle_sip_ belle_sip_server_transaction_t *server_transaction=belle_sip_transaction_terminated_event_get_server_transaction(event); belle_sip_request_t* req; belle_sip_response_t* resp; + bool_t release_call=FALSE; + if (client_transaction) { req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); resp=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(client_transaction)); @@ -328,9 +330,21 @@ static void call_process_transaction_terminated(void *user_ctx, const belle_sip_ if (op->state ==SalOpStateTerminating && strcmp("BYE",belle_sip_request_get_method(req))==0 && (!resp || (belle_sip_response_get_status_code(resp) !=401 - && belle_sip_response_get_status_code(resp) !=407))) { - if (op->dialog==NULL) call_set_released(op); + && belle_sip_response_get_status_code(resp) !=407)) + && op->dialog==NULL) { + release_call=TRUE; } + if (server_transaction){ + if (op->pending_server_trans==server_transaction){ + belle_sip_object_unref(op->pending_server_trans); + op->pending_server_trans=NULL; + } + if (op->pending_update_server_trans==server_transaction){ + belle_sip_object_unref(op->pending_update_server_trans); + op->pending_update_server_trans=NULL; + } + } + if (release_call) call_set_released(op); } static void call_terminated(SalOp* op,belle_sip_server_transaction_t* server_transaction, belle_sip_request_t* request,int status_code) { @@ -777,6 +791,7 @@ int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*opti belle_sip_response_t* response; belle_sip_header_contact_t* contact=NULL; int status=sal_reason_to_sip_code(reason); + belle_sip_transaction_t *trans; if (reason==SalReasonRedirect){ if (redirection!=NULL) { @@ -788,9 +803,15 @@ int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*opti ms_error("Cannot redirect to null"); } } - response = sal_op_create_response_from_request(op,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),status); + trans=(belle_sip_transaction_t*)op->pending_server_trans; + if (!trans) trans=(belle_sip_transaction_t*)op->pending_update_server_trans; + if (!trans){ + ms_error("sal_call_decline(): no pending transaction to decline."); + return -1; + } + response = sal_op_create_response_from_request(op,belle_sip_transaction_get_request(trans),status); if (contact) belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact)); - belle_sip_server_transaction_send_response(op->pending_server_trans,response); + belle_sip_server_transaction_send_response(BELLE_SIP_SERVER_TRANSACTION(trans),response); return 0; } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index ef17b080b..f60e230f8 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -152,7 +152,7 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia ms_message("Network parameters have changed, update them."); linphone_core_update_streams_destinations(lc, call, oldmd, new_md); } - if (md_changed & SAL_MEDIA_DESCRIPTION_CRYPTO_CHANGED) { + if (md_changed & SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED) { ms_message("Crypto parameters have changed, update them."); linphone_call_update_crypto_parameters(call, oldmd, new_md); } @@ -535,7 +535,7 @@ static void call_updated_by_remote(LinphoneCore *lc, LinphoneCall *call, bool_t } if (is_update && prev_result_desc && md){ int diff=sal_media_description_equals(prev_result_desc,md); - if (diff & (SAL_MEDIA_DESCRIPTION_CRYPTO_CHANGED|SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED)){ + if (diff & (SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED|SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED)){ ms_warning("Cannot accept this update, it is changing parameters that require user approval"); sal_call_decline(call->op,SalReasonNotAcceptable,NULL); /*FIXME should send 504 Cannot change the session parameters without prompting the user"*/ return; @@ -655,7 +655,6 @@ static void call_terminated(SalOp *op, const char *from){ } static int resume_call_after_failed_transfer(LinphoneCall *call){ - ms_message("!!!!!!!!!!resume_call_after_failed_transfer"); if (call->was_automatically_paused && call->state==LinphoneCallPausing) return BELLE_SIP_CONTINUE; /*was still in pausing state*/ @@ -663,7 +662,7 @@ static int resume_call_after_failed_transfer(LinphoneCall *call){ if (sal_op_is_idle(call->op)){ linphone_core_resume_call(call->core,call); }else { - ms_message("!!!!!!!!!!resume_call_after_failed_transfer, salop was busy"); + ms_message("resume_call_after_failed_transfer(), salop was busy"); return BELLE_SIP_CONTINUE; } } diff --git a/coreapi/chat.c b/coreapi/chat.c index d6986f1ec..37fce3225 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -424,7 +424,7 @@ LinphoneChatRoom * linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const static void linphone_chat_room_delete_composing_idle_timer(LinphoneChatRoom *cr) { if (cr->composing_idle_timer) { - if(cr->lc->sal) + if(cr-> lc && cr->lc->sal) sal_cancel_timer(cr->lc->sal, cr->composing_idle_timer); belle_sip_object_unref(cr->composing_idle_timer); cr->composing_idle_timer = NULL; @@ -433,7 +433,7 @@ static void linphone_chat_room_delete_composing_idle_timer(LinphoneChatRoom *cr) static void linphone_chat_room_delete_composing_refresh_timer(LinphoneChatRoom *cr) { if (cr->composing_refresh_timer) { - if(cr->lc->sal) + if(cr->lc && cr->lc->sal) sal_cancel_timer(cr->lc->sal, cr->composing_refresh_timer); belle_sip_object_unref(cr->composing_refresh_timer); cr->composing_refresh_timer = NULL; @@ -442,7 +442,7 @@ static void linphone_chat_room_delete_composing_refresh_timer(LinphoneChatRoom * static void linphone_chat_room_delete_remote_composing_refresh_timer(LinphoneChatRoom *cr) { if (cr->remote_composing_refresh_timer) { - if(cr->lc->sal) + if(cr->lc && cr->lc->sal) sal_cancel_timer(cr->lc->sal, cr->remote_composing_refresh_timer); belle_sip_object_unref(cr->remote_composing_refresh_timer); cr->remote_composing_refresh_timer = NULL; diff --git a/coreapi/fileplayer.c b/coreapi/fileplayer.c new file mode 100644 index 000000000..6752dc9e1 --- /dev/null +++ b/coreapi/fileplayer.c @@ -0,0 +1,65 @@ +#include "private.h" +#include +#include + +static int file_player_open(LinphonePlayer *obj, const char *filename); +static int file_player_start(LinphonePlayer *obj); +static int file_player_pause(LinphonePlayer *obj); +static int file_player_seek(LinphonePlayer *obj, int time_ms); +static MSPlayerState file_player_get_state(LinphonePlayer *obj); +static void file_player_close(LinphonePlayer *obj); +static void file_player_eof_callback(void *user_data); + +LinphonePlayer *linphone_core_create_file_player(LinphoneCore *lc, MSSndCard *snd_card, const char *video_out) { + LinphonePlayer *obj = ms_new0(LinphonePlayer, 1); + if(snd_card == NULL) snd_card = lc->sound_conf.play_sndcard; + if(video_out == NULL) video_out = linphone_core_get_video_display_filter(lc); + obj->impl = ms_file_player_new(snd_card, video_out); + obj->open = file_player_open; + obj->start = file_player_start; + obj->pause = file_player_pause; + obj->seek = file_player_seek; + obj->get_state = file_player_get_state; + obj->close = file_player_close; + ms_file_player_set_eof_callback((MSFilePlayer *)obj->impl, file_player_eof_callback, obj); + return obj; +} + +void linphone_file_player_destroy(LinphonePlayer *obj) { + ms_file_player_free((MSFilePlayer *)obj->impl); + ms_free(obj); +} + +bool_t linphone_file_player_matroska_supported(void) { + return ms_file_player_matroska_supported(); +} + +static int file_player_open(LinphonePlayer *obj, const char *filename) { + return ms_file_player_open((MSFilePlayer *)obj->impl, filename) ? 0 : -1; +} + +static int file_player_start(LinphonePlayer *obj) { + return ms_file_player_start((MSFilePlayer *)obj->impl) ? 0 : -1; +} + +static int file_player_pause(LinphonePlayer *obj) { + ms_file_player_pause((MSFilePlayer *)obj->impl); + return 0; +} + +static int file_player_seek(LinphonePlayer *obj, int time_ms) { + return ms_file_player_seek((MSFilePlayer *)obj->impl, time_ms) ? 0 : -1; +} + +static MSPlayerState file_player_get_state(LinphonePlayer *obj) { + return ms_file_player_get_state((MSFilePlayer *)obj->impl); +} + +static void file_player_close(LinphonePlayer *obj) { + ms_file_player_close((MSFilePlayer *)obj->impl); +} + +static void file_player_eof_callback(void *user_data) { + LinphonePlayer *obj = (LinphonePlayer *)user_data; + obj->cb(obj, obj->user_data); +} diff --git a/coreapi/linphone_tunnel.cc b/coreapi/linphone_tunnel.cc index 8abeb3b05..beabd43a8 100644 --- a/coreapi/linphone_tunnel.cc +++ b/coreapi/linphone_tunnel.cc @@ -31,9 +31,6 @@ static const char *_tunnel_mode_str[3] = { "disable", "enable", "auto" }; -static LinphoneTunnelMode _string_to_tunnel_mode(const char *string); -static const char *_tunnel_mode_to_string(LinphoneTunnelMode mode); - LinphoneTunnel* linphone_core_get_tunnel(const LinphoneCore *lc){ return lc->tunnel; } @@ -237,7 +234,7 @@ void linphone_tunnel_clean_servers(LinphoneTunnel *tunnel){ } void linphone_tunnel_set_mode(LinphoneTunnel *tunnel, LinphoneTunnelMode mode){ - lp_config_set_string(config(tunnel),"tunnel","mode", _tunnel_mode_to_string(mode)); + lp_config_set_string(config(tunnel),"tunnel","mode", tunnel_mode_to_string(mode)); bcTunnel(tunnel)->setMode(mode); } @@ -335,7 +332,7 @@ static void my_ortp_logv(OrtpLogLevel level, const char *fmt, va_list args){ ortp_logv(level,fmt,args); } -static LinphoneTunnelMode _string_to_tunnel_mode(const char *string) { +LinphoneTunnelMode string_to_tunnel_mode(const char *string) { if(string != NULL) { int i; for(i=0; i<3 && strcmp(string, _tunnel_mode_str[i]) != 0; i++); @@ -350,7 +347,7 @@ static LinphoneTunnelMode _string_to_tunnel_mode(const char *string) { } } -static const char *_tunnel_mode_to_string(LinphoneTunnelMode mode) { +const char *tunnel_mode_to_string(LinphoneTunnelMode mode) { return _tunnel_mode_str[mode]; } @@ -359,7 +356,7 @@ static const char *_tunnel_mode_to_string(LinphoneTunnelMode mode) { * Called internally from linphonecore at startup. */ void linphone_tunnel_configure(LinphoneTunnel *tunnel){ - LinphoneTunnelMode mode = _string_to_tunnel_mode(lp_config_get_string(config(tunnel), "tunnel", "mode", NULL)); + LinphoneTunnelMode mode = string_to_tunnel_mode(lp_config_get_string(config(tunnel), "tunnel", "mode", NULL)); bool_t tunnelizeSIPPackets = (bool_t)lp_config_get_int(config(tunnel), "tunnel", "sip", TRUE); linphone_tunnel_enable_logs_with_handler(tunnel,TRUE,my_ortp_logv); linphone_tunnel_load_config(tunnel); diff --git a/coreapi/linphone_tunnel.h b/coreapi/linphone_tunnel.h index 3a2c66330..8bf94fcef 100644 --- a/coreapi/linphone_tunnel.h +++ b/coreapi/linphone_tunnel.h @@ -50,12 +50,30 @@ extern "C" typedef struct _LinphoneTunnelConfig LinphoneTunnelConfig; +/** + * Enum describing the tunnel modes. +**/ typedef enum _LinphoneTunnelMode { - LinphoneTunnelModeDisable, - LinphoneTunnelModeEnable, - LinphoneTunnelModeAuto + LinphoneTunnelModeDisable, /**< The tunnel is disabled. */ + LinphoneTunnelModeEnable, /**< The tunnel is enabled. */ + LinphoneTunnelModeAuto /**< The tunnel is enabled automatically if it is required. */ } LinphoneTunnelMode; +/** + * @brief Convert a string into LinphoneTunnelMode enum + * @param string String to convert + * @return An LinphoneTunnelMode enum. If the passed string is NULL or + * does not match with any mode, the LinphoneTunnelModeDisable is returned. + */ +LINPHONE_PUBLIC LinphoneTunnelMode string_to_tunnel_mode(const char *string); + +/** + * @brief Convert a tunnel mode enum into string + * @param mode Enum to convert + * @return "disable", "enable" or "auto" + */ +LINPHONE_PUBLIC const char *tunnel_mode_to_string(LinphoneTunnelMode mode); + /** * Create a new tunnel configuration */ @@ -268,7 +286,6 @@ LINPHONE_PUBLIC void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel); */ LINPHONE_PUBLIC bool_t linphone_tunnel_auto_detect_enabled(LinphoneTunnel *tunnel); - /** * @} **/ diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 2517c4a4c..3e9066e1d 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1662,6 +1662,19 @@ static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){ } } +void set_mic_gain_db(AudioStream *st, float gain){ + if (st->volsend){ + ms_filter_call_method(st->volsend,MS_VOLUME_SET_DB_GAIN,&gain); + }else ms_warning("Could not apply mic gain: gain control wasn't activated."); +} + +void set_playback_gain_db(AudioStream *st, float gain){ + if (st->volrecv){ + ms_filter_call_method(st->volrecv,MS_VOLUME_SET_DB_GAIN,&gain); + }else ms_warning("Could not apply playback gain: gain control wasn't activated."); +} + +/*This function is not static because used internally in linphone-daemon project*/ void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){ float mic_gain=lc->sound_conf.soft_mic_lev; float thres = 0; @@ -1678,13 +1691,13 @@ void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t mute int spk_agc; if (!muted) - linphone_core_set_mic_gain_db (lc, mic_gain); + set_mic_gain_db(st,mic_gain); else audio_stream_set_mic_gain(st,0); recv_gain = lc->sound_conf.soft_play_lev; if (recv_gain != 0) { - linphone_core_set_playback_gain_db (lc,recv_gain); + set_playback_gain_db(st,recv_gain); } if (st->volsend){ @@ -1720,10 +1733,10 @@ void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t mute parametrize_equalizer(lc,st); } -static void post_configure_audio_streams(LinphoneCall*call){ +static void post_configure_audio_streams(LinphoneCall *call, bool_t muted){ AudioStream *st=call->audiostream; LinphoneCore *lc=call->core; - _post_configure_audio_stream(st,lc,call->audio_muted); + _post_configure_audio_stream(st,lc,muted); if (linphone_core_dtmf_received_has_listener(lc)){ audio_stream_play_received_dtmfs(call->audiostream,FALSE); } @@ -1996,10 +2009,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna captcard, use_ec ); - post_configure_audio_streams(call); - if (muted && !send_ringbacktone){ - audio_stream_set_mic_gain(call->audiostream,0); - } + post_configure_audio_streams(call, muted && !send_ringbacktone); if (stream->dir==SalStreamSendOnly && playfile!=NULL){ int pause_time=500; ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time); @@ -2220,7 +2230,7 @@ void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){ static bool_t update_stream_crypto_params(LinphoneCall *call, const SalStreamDescription *local_st_desc, SalStreamDescription *old_stream, SalStreamDescription *new_stream, MediaStream *ms){ int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag); if (crypto_idx >= 0) { - if (call->localdesc_changed & SAL_MEDIA_DESCRIPTION_CRYPTO_CHANGED) + if (call->localdesc_changed & SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED) media_stream_set_srtp_send_key(ms,new_stream->crypto[0].algo,local_st_desc->crypto[crypto_idx].master_key); if (strcmp(old_stream->crypto[0].master_key,new_stream->crypto[0].master_key)!=0){ media_stream_set_srtp_recv_key(ms,new_stream->crypto[0].algo,new_stream->crypto[0].master_key); @@ -2634,10 +2644,10 @@ uint64_t linphone_call_stats_get_late_packets_cumulative_number(const LinphoneCa if (!stats || !call) return 0; memset(&rtp_stats, 0, sizeof(rtp_stats)); - if (stats->type == LINPHONE_CALL_STATS_AUDIO) + if (stats->type == LINPHONE_CALL_STATS_AUDIO && call->audiostream != NULL) audio_stream_get_local_rtp_stats(call->audiostream, &rtp_stats); #ifdef VIDEO_ENABLED - else + else if (call->videostream != NULL) video_stream_get_local_rtp_stats(call->videostream, &rtp_stats); #endif return rtp_stats.outoftime; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 1cb00d513..6c173a342 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1630,8 +1630,7 @@ void linphone_core_set_use_rfc2833_for_dtmf(LinphoneCore *lc,bool_t use_rfc2833) * Deprecated: use linphone_core_get_sip_transports() instead. * @ingroup network_parameters **/ -int linphone_core_get_sip_port(LinphoneCore *lc) -{ +int linphone_core_get_sip_port(LinphoneCore *lc){ LCSipTransports tr; linphone_core_get_sip_transports_used(lc,&tr); return tr.udp_port>0 ? tr.udp_port : (tr.tcp_port > 0 ? tr.tcp_port : tr.tls_port); @@ -2857,6 +2856,7 @@ int linphone_core_accept_early_media(LinphoneCore* lc, LinphoneCall* call){ int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){ const char *subject; + int err; bool_t no_user_consent=call->params->no_user_consent; if (!no_user_consent) linphone_call_make_local_media_description(lc,call); @@ -2873,12 +2873,22 @@ int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){ subject="Refreshing"; } linphone_core_notify_display_status(lc,_("Modifying call parameters...")); - sal_call_set_local_media_description (call->op,call->localdesc); + if (!lc->sip_conf.sdp_200_ack){ + sal_call_set_local_media_description (call->op,call->localdesc); + } else { + sal_call_set_local_media_description (call->op,NULL); + } if (call->dest_proxy && call->dest_proxy->op){ /*give a chance to update the contact address if connectivity has changed*/ sal_op_set_contact_address(call->op,sal_op_get_contact_address(call->dest_proxy->op)); }else sal_op_set_contact_address(call->op,NULL); - return sal_call_update(call->op,subject,no_user_consent); + err= sal_call_update(call->op,subject,no_user_consent); + if (lc->sip_conf.sdp_200_ack){ + /*we are NOT offering, set local media description after sending the call so that we are ready to + process the remote offer when it will arrive*/ + sal_call_set_local_media_description(call->op,call->localdesc); + } + return err; } /** @@ -3789,9 +3799,7 @@ void linphone_core_set_mic_gain_db (LinphoneCore *lc, float gaindb){ ms_message("linphone_core_set_mic_gain_db(): no active call."); return; } - if (st->volsend){ - ms_filter_call_method(st->volsend,MS_VOLUME_SET_DB_GAIN,&gain); - }else ms_warning("Could not apply gain: gain control wasn't activated."); + set_mic_gain_db(st,gain); } /** @@ -3822,9 +3830,7 @@ void linphone_core_set_playback_gain_db (LinphoneCore *lc, float gaindb){ ms_message("linphone_core_set_playback_gain_db(): no active call."); return; } - if (st->volrecv){ - ms_filter_call_method(st->volrecv,MS_VOLUME_SET_DB_GAIN,&gain); - }else ms_warning("Could not apply gain: gain control wasn't activated."); + set_playback_gain_db(st,gain); } /** @@ -4467,11 +4473,11 @@ void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy lp_config_set_string(lc->config,"net","firewall_policy",policy); } -inline LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc) { +ORTP_INLINE LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc) { return _linphone_core_get_firewall_policy_with_lie(lc, FALSE); } -inline LinphoneFirewallPolicy _linphone_core_get_firewall_policy(const LinphoneCore *lc) { +ORTP_INLINE LinphoneFirewallPolicy _linphone_core_get_firewall_policy(const LinphoneCore *lc) { return _linphone_core_get_firewall_policy_with_lie(lc, TRUE); } @@ -5003,15 +5009,15 @@ int linphone_core_get_camera_sensor_rotation(LinphoneCore *lc) { } static MSVideoSizeDef supported_resolutions[]={ -#if !ANDROID & !TARGET_OS_IPHONE +#if !ANDROID && !TARGET_OS_IPHONE { { MS_VIDEO_SIZE_1080P_W, MS_VIDEO_SIZE_1080P_H } , "1080p" }, #endif -#if !ANDROID & !TARGET_OS_MAC /*limite to most common size because mac card cannot list supported resolutions*/ +#if !ANDROID && !TARGET_OS_MAC /*limit to most common sizes because mac video API cannot list supported resolutions*/ { { MS_VIDEO_SIZE_UXGA_W, MS_VIDEO_SIZE_UXGA_H } , "uxga" }, { { MS_VIDEO_SIZE_SXGA_MINUS_W, MS_VIDEO_SIZE_SXGA_MINUS_H } , "sxga-" }, #endif { { MS_VIDEO_SIZE_720P_W, MS_VIDEO_SIZE_720P_H } , "720p" }, -#if !ANDROID & !TARGET_OS_MAC +#if !ANDROID && !TARGET_OS_MAC { { MS_VIDEO_SIZE_XGA_W, MS_VIDEO_SIZE_XGA_H } , "xga" }, #endif #if !ANDROID && !TARGET_OS_IPHONE @@ -5043,23 +5049,33 @@ const MSVideoSizeDef *linphone_core_get_supported_video_sizes(LinphoneCore *lc){ static MSVideoSize video_size_get_by_name(const char *name){ MSVideoSizeDef *pdef=supported_resolutions; MSVideoSize null_vsize={0,0}; + MSVideoSize parsed; if (!name) return null_vsize; for(;pdef->name!=NULL;pdef++){ if (strcasecmp(name,pdef->name)==0){ return pdef->vsize; } } + if (sscanf(name,"%ix%i",&parsed.width,&parsed.height)==2){ + return parsed; + } ms_warning("Video resolution %s is not supported in linphone.",name); return null_vsize; } +/* warning: function not reentrant*/ static const char *video_size_get_name(MSVideoSize vsize){ MSVideoSizeDef *pdef=supported_resolutions; + static char customsize[64]={0}; for(;pdef->name!=NULL;pdef++){ if (pdef->vsize.width==vsize.width && pdef->vsize.height==vsize.height){ return pdef->name; } } + if (vsize.width && vsize.height){ + snprintf(customsize,sizeof(customsize)-1,"%ix%i",vsize.width,vsize.height); + return customsize; + } return NULL; } @@ -5108,6 +5124,7 @@ void linphone_core_set_preferred_video_size(LinphoneCore *lc, MSVideoSize vsize) * @param vsize the video resolution choosed for capuring and previewing. It can be (0,0) to not request any specific preview size and let the core optimize the processing. **/ void linphone_core_set_preview_video_size(LinphoneCore *lc, MSVideoSize vsize){ + MSVideoSize oldvsize; if (vsize.width==0 && vsize.height==0){ /*special case to reset the forced preview size mode*/ lc->video_conf.preview_vsize=vsize; @@ -5115,16 +5132,25 @@ void linphone_core_set_preview_video_size(LinphoneCore *lc, MSVideoSize vsize){ lp_config_set_string(lc->config,"video","preview_size",NULL); return; } - if (video_size_supported(vsize)){ - MSVideoSize oldvsize=lc->video_conf.preview_vsize; - lc->video_conf.preview_vsize=vsize; - if (!ms_video_size_equal(oldvsize,vsize) && lc->previewstream!=NULL){ - toggle_video_preview(lc,FALSE); - toggle_video_preview(lc,TRUE); - } - if (linphone_core_ready(lc)) - lp_config_set_string(lc->config,"video","preview_size",video_size_get_name(vsize)); + oldvsize=lc->video_conf.preview_vsize; + lc->video_conf.preview_vsize=vsize; + if (!ms_video_size_equal(oldvsize,vsize) && lc->previewstream!=NULL){ + toggle_video_preview(lc,FALSE); + toggle_video_preview(lc,TRUE); } + if (linphone_core_ready(lc)) + lp_config_set_string(lc->config,"video","preview_size",video_size_get_name(vsize)); +} + +/** + * Returns video size for the captured video if it was previously set by linphone_core_set_preview_video_size(), otherwise returns a 0,0 size. + * @see linphone_core_set_preview_video_size() + * @ingroup media_parameters + * @param lc the core + * @return a MSVideoSize +**/ +MSVideoSize linphone_core_get_preview_video_size(const LinphoneCore *lc){ + return lc->video_conf.preview_vsize; } /** diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 9ded4edaa..5c06f103e 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -596,6 +596,28 @@ int linphone_player_seek(LinphonePlayer *obj, int time_ms); MSPlayerState linphone_player_get_state(LinphonePlayer *obj); void linphone_player_close(LinphonePlayer *obj); +/** + * @brief Create an independent media file player. + * This player support WAVE and MATROSKA formats. + * @param lc A LinphoneCore + * @param snd_card Playback sound card. If NULL, the sound card set in LinphoneCore will be used + * @param video_out Video display. If NULL, the video display set in LinphoneCore will be used + * @return A pointer on the new instance. NULL if faild. + */ +LINPHONE_PUBLIC LinphonePlayer *linphone_core_create_file_player(LinphoneCore *lc, MSSndCard *snd_card, const char *video_out); + +/** + * @brief Destroy a file player + * @param obj File player to destroy + */ +LINPHONE_PUBLIC void linphone_file_player_destroy(LinphonePlayer *obj); + +/** + * @brief Check whether Matroksa format is supported by the player + * @return TRUE if it is supported + */ +LINPHONE_PUBLIC bool_t linphone_file_player_matroska_supported(void); + /** * LinphoneCallState enum represents the different state a call can reach into. * The application is notified of state changes through the LinphoneCoreVTable::call_state_changed callback. @@ -2536,6 +2558,7 @@ LINPHONE_PUBLIC const MSVideoSizeDef *linphone_core_get_supported_video_sizes(Li LINPHONE_PUBLIC void linphone_core_set_preferred_video_size(LinphoneCore *lc, MSVideoSize vsize); LINPHONE_PUBLIC void linphone_core_set_preview_video_size(LinphoneCore *lc, MSVideoSize vsize); LINPHONE_PUBLIC void linphone_core_set_preview_video_size_by_name(LinphoneCore *lc, const char *name); +LINPHONE_PUBLIC MSVideoSize linphone_core_get_preview_video_size(const LinphoneCore *lc); LINPHONE_PUBLIC MSVideoSize linphone_core_get_preferred_video_size(LinphoneCore *lc); LINPHONE_PUBLIC void linphone_core_set_preferred_video_size_by_name(LinphoneCore *lc, const char *name); LINPHONE_PUBLIC void linphone_core_set_preferred_framerate(LinphoneCore *lc, float fps); diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index a2838d4a4..c1ffea0fc 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -40,7 +40,11 @@ #endif /*_WIN32_WCE*/ #ifdef _MSC_VER +#ifdef WINAPI_FAMILY_PHONE_APP +#include +#else #include +#endif #else #include #endif @@ -666,9 +670,18 @@ const char* lp_config_get_default_string(const LpConfig *lpconfig, const char *s static char *_lp_config_dirname(char *path) { #ifdef _MSC_VER +#ifdef WINAPI_FAMILY_PHONE_APP + char drive[_MAX_DRIVE]; + char dir[_MAX_DIR]; + char fname[_MAX_FNAME]; + char ext[_MAX_EXT]; + _splitpath(path, drive, dir, fname, ext); + return ms_strdup_printf("%s%s", drive, dir); +#else char *dir = ms_strdup(path); PathRemoveFileSpec(dir); return dir; +#endif #else char *tmp = ms_strdup(path); char *dir = ms_strdup(dirname(tmp)); diff --git a/coreapi/misc.c b/coreapi/misc.c index a91d02432..30100a304 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -937,7 +937,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md){ int i; - for (i = 0; i < md->nb_streams; i++) { + for (i = 0; md && i < md->nb_streams; i++) { if (md->streams[i].type == SalVideo && md->streams[i].rtp_port!=0) return TRUE; } diff --git a/coreapi/player.c b/coreapi/player.c index df1641886..ed9d4095f 100644 --- a/coreapi/player.c +++ b/coreapi/player.c @@ -31,7 +31,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. int linphone_player_open(LinphonePlayer *obj, const char *filename, LinphonePlayerEofCallback cb, void *user_data){ obj->user_data=user_data; obj->cb=cb; - return obj->open(obj->impl,filename); + return obj->open(obj,filename); } /** @@ -40,7 +40,7 @@ int linphone_player_open(LinphonePlayer *obj, const char *filename, LinphonePlay * @return 0 if successful, -1 otherwise **/ int linphone_player_start(LinphonePlayer *obj){ - return obj->start(obj->impl); + return obj->start(obj); } /** @@ -49,7 +49,7 @@ int linphone_player_start(LinphonePlayer *obj){ * @return 0 if successful, -1 otherwise **/ int linphone_player_pause(LinphonePlayer *obj){ - return obj->pause(obj->impl); + return obj->pause(obj); } /** @@ -59,7 +59,7 @@ int linphone_player_pause(LinphonePlayer *obj){ * @return 0 if successful, -1 otherwise **/ int linphone_player_seek(LinphonePlayer *obj, int time_ms){ - return obj->seek(obj->impl,time_ms); + return obj->seek(obj,time_ms); } /** @@ -68,7 +68,7 @@ int linphone_player_seek(LinphonePlayer *obj, int time_ms){ * @return the state of the player within MSPlayerClosed, MSPlayerStarted, MSPlayerPaused. **/ MSPlayerState linphone_player_get_state(LinphonePlayer *obj){ - return obj->get_state(obj->impl); + return obj->get_state(obj); } /** @@ -76,7 +76,7 @@ MSPlayerState linphone_player_get_state(LinphonePlayer *obj){ * @param obj the player. **/ void linphone_player_close(LinphonePlayer *obj){ - return obj->close(obj->impl); + return obj->close(obj); } @@ -104,7 +104,7 @@ static bool_t call_player_check_state(LinphonePlayer *player, bool_t check_playe static void on_eof(void *user_data, MSFilter *f, unsigned int event_id, void *arg){ LinphonePlayer *player=(LinphonePlayer *)user_data; - if (player->cb) player->cb(player,user_data); + if (player->cb) player->cb(player,player->user_data); } static int call_player_open(LinphonePlayer* player, const char *filename){ @@ -146,7 +146,7 @@ static int call_player_seek(LinphonePlayer *player, int time_ms){ static void call_player_close(LinphonePlayer *player){ LinphoneCall *call=(LinphoneCall*)player->impl; if (!call_player_check_state(player,TRUE)) return; - ms_filter_call_method_noarg(call->audiostream->av_player.player,MS_PLAYER_CLOSE); + audio_stream_close_remote_play(call->audiostream); } diff --git a/coreapi/private.h b/coreapi/private.h index d4be0c301..caa290cb0 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -1021,7 +1021,8 @@ void linphone_core_notify_notify_received(LinphoneCore *lc, LinphoneEvent *lev, void linphone_core_notify_subscription_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state); void linphone_core_notify_publish_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphonePublishState state); - +void set_mic_gain_db(AudioStream *st, float gain); +void set_playback_gain_db(AudioStream *st, float gain); #ifdef __cplusplus } diff --git a/coreapi/proxy.c b/coreapi/proxy.c index eab2e70a7..13fa6e048 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1408,12 +1408,7 @@ static bool_t can_register(LinphoneProxyConfig *cfg){ } #endif //BUILD_UPNP if (lc->sip_conf.register_only_when_network_is_up){ - LinphoneTunnel *tunnel=linphone_core_get_tunnel(lc); - if (tunnel && linphone_tunnel_get_mode(tunnel)){ - return linphone_tunnel_connected(tunnel); - }else{ - return lc->network_reachable; - } + return lc->network_reachable; } return TRUE; } diff --git a/coreapi/sal.c b/coreapi/sal.c index ff252ca3d..b8395c897 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -280,9 +280,11 @@ int sal_stream_description_equals(const SalStreamDescription *sd1, const SalStre if (sd1->proto != sd2->proto) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) { if ((sd1->crypto[i].tag != sd2->crypto[i].tag) - || (sd1->crypto[i].algo != sd2->crypto[i].algo) - || (strncmp(sd1->crypto[i].master_key, sd2->crypto[i].master_key, sizeof(sd1->crypto[i].master_key) - 1))) { - result |= SAL_MEDIA_DESCRIPTION_CRYPTO_CHANGED; + || (sd1->crypto[i].algo != sd2->crypto[i].algo)){ + result|=SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED; + } + if ((strncmp(sd1->crypto[i].master_key, sd2->crypto[i].master_key, sizeof(sd1->crypto[i].master_key) - 1))) { + result |= SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED; } } diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 17653bf07..f979376ef 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -54,6 +54,7 @@ linphone_SOURCES= \ conference.c \ config-fetching.c \ audio_assistant.c \ + videowindow.c \ linphone.h if BUILD_WIZARD linphone_SOURCES+= \ diff --git a/gtk/incall_view.c b/gtk/incall_view.c index a9ef8e272..5329508b6 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -403,7 +403,7 @@ void linphone_gtk_create_in_call_view(LinphoneCall *call){ gtk_widget_hide(conf); button=linphone_gtk_get_widget(call_view,"terminate_call"); - image=create_pixmap("stopcall-small.png"); + image=create_pixmap (linphone_gtk_get_ui_config("stop_call_icon","stopcall-small.png")); gtk_button_set_label(GTK_BUTTON(button),_("Hang up")); gtk_button_set_image(GTK_BUTTON(button),image); gtk_widget_show(image); @@ -687,6 +687,14 @@ void linphone_gtk_in_call_view_show_encryption(LinphoneCall *call){ } } +char *linphone_gtk_address(const LinphoneAddress *addr){ + const char *displayname=linphone_address_get_display_name(addr); + if (!displayname) return linphone_address_as_string_uri_only(addr); + return ms_strdup(displayname); +} + + + void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){ GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status"); @@ -696,6 +704,8 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){ gboolean in_conf=linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call)); GtkWidget *call_stats=(GtkWidget*)g_object_get_data(G_OBJECT(callview),"call_stats"); + linphone_gtk_in_call_show_video(call); + display_peer_name_in_label(callee,linphone_call_get_remote_address (call)); gtk_widget_hide(linphone_gtk_get_widget(callview,"answer_decline_panel")); @@ -736,7 +746,7 @@ void linphone_gtk_in_call_view_set_paused(LinphoneCall *call){ GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status"); gtk_widget_hide(linphone_gtk_get_widget(callview,"answer_decline_panel")); gtk_label_set_markup(GTK_LABEL(status),_("Paused call")); - + linphone_gtk_in_call_show_video(call); linphone_gtk_in_call_set_animation_image(callview,GTK_STOCK_MEDIA_PAUSE,TRUE); } @@ -760,13 +770,15 @@ static gboolean in_call_view_terminated(LinphoneCall *call){ void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_msg){ GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); GtkWidget *status; + GtkWidget *video_window; gboolean in_conf; guint taskid; if(callview==NULL) return; + video_window=(GtkWidget*)g_object_get_data(G_OBJECT(callview),"video_window"); status=linphone_gtk_get_widget(callview,"in_call_status"); taskid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(callview),"taskid")); in_conf=linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call)); - + if (video_window) gtk_widget_destroy(video_window); if (status==NULL) return; if (error_msg==NULL) gtk_label_set_markup(GTK_LABEL(status),_("Call ended.")); diff --git a/gtk/linphone.h b/gtk/linphone.h index 2a256cab5..70f1c58e3 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -48,6 +48,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define LINPHONE_VERSION LINPHONE_VERSION_DATE #endif +#define LINPHONE_ICON "linphone.png" + enum { COMPLETION_HISTORY, COMPLETION_LDAP @@ -195,4 +197,6 @@ void linphone_gtk_set_configuration_uri(void); GtkWidget * linphone_gtk_show_config_fetching(void); void linphone_gtk_close_config_fetching(GtkWidget *w, LinphoneConfiguringState state); const char *linphone_gtk_get_sound_path(const char *file); +void linphone_gtk_in_call_show_video(LinphoneCall *call); +char *linphone_gtk_address(const LinphoneAddress *addr);/*return human readable identifier for a LinphoneAddress */ diff --git a/gtk/main.c b/gtk/main.c index 66cb27035..60c27e43b 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -48,7 +48,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifdef ENABLE_NLS #include #endif -#define LINPHONE_ICON "linphone.png" + const char *this_program_ident_string="linphone_ident_string=" LINPHONE_VERSION; @@ -318,6 +318,7 @@ static void linphone_gtk_init_liblinphone(const char *config_file, g_free(secrets_file); linphone_core_enable_video_capture(the_core, TRUE); linphone_core_enable_video_display(the_core, TRUE); + linphone_core_set_native_video_window_id(the_core,-1);/*don't create the window*/ if (no_video) { _linphone_gtk_enable_video(FALSE); linphone_gtk_set_ui_config_int("videoselfview",0); @@ -566,102 +567,6 @@ void linphone_gtk_show_about(){ gtk_widget_show(about); } -static void set_video_window_decorations(GdkWindow *w){ - const char *title=linphone_gtk_get_ui_config("title","Linphone"); - const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON); - char video_title[256]; - GdkPixbuf *pbuf=create_pixbuf(icon_path); - - if (!linphone_core_in_call(linphone_gtk_get_core())){ - snprintf(video_title,sizeof(video_title),"%s video",title); - /* When not in call, treat the video as a normal window */ - gdk_window_set_keep_above(w, FALSE); - }else{ - LinphoneAddress *uri = - linphone_address_clone(linphone_core_get_current_call_remote_address(linphone_gtk_get_core())); - char *display_name; - - linphone_address_clean(uri); - if (linphone_address_get_display_name(uri)!=NULL){ - display_name=ms_strdup(linphone_address_get_display_name(uri)); - }else{ - display_name=linphone_address_as_string(uri); - } - snprintf(video_title,sizeof(video_title),_("Call with %s"),display_name); - linphone_address_destroy(uri); - ms_free(display_name); - - /* During calls, bring up the video window, arrange so that - it is above all the other windows */ - gdk_window_deiconify(w); - gdk_window_set_keep_above(w,TRUE); - /* Maybe we should have the following, but then we want to - have a timer that turns it off after a little while. */ - /* gdk_window_set_urgency_hint(w,TRUE); */ - } - gdk_window_set_title(w,video_title); - /* Refrain the video window to be closed at all times. */ - gdk_window_set_functions(w, - GDK_FUNC_RESIZE|GDK_FUNC_MOVE| - GDK_FUNC_MINIMIZE|GDK_FUNC_MAXIMIZE); - if (pbuf){ - GList *l=NULL; - l=g_list_append(l,pbuf); - gdk_window_set_icon_list(w,l); - g_list_free(l); - g_object_unref(G_OBJECT(pbuf)); - } -} - -static gboolean video_needs_update=FALSE; - -static void update_video_title(){ - video_needs_update=TRUE; -} - -static void update_video_titles(LinphoneCore *lc){ - unsigned long id; - static unsigned long previd=0; - static unsigned long preview_previd=0; - id=linphone_core_get_native_video_window_id(lc); - if (id!=previd || video_needs_update){ - GdkWindow *w; - previd=id; - if (id!=0){ - ms_message("Updating window decorations"); -#ifndef WIN32 - w=gdk_window_foreign_new((GdkNativeWindow)id); -#else - w=gdk_window_foreign_new((HANDLE)id); -#endif - if (w) { - set_video_window_decorations(w); - g_object_unref(G_OBJECT(w)); - } - else ms_error("gdk_window_foreign_new() failed"); - if (video_needs_update) video_needs_update=FALSE; - } - } - id=linphone_core_get_native_preview_window_id (lc); - if (id!=preview_previd ){ - GdkWindow *w; - preview_previd=id; - if (id!=0){ - ms_message("Updating window decorations for preview"); -#ifndef WIN32 - w=gdk_window_foreign_new((GdkNativeWindow)id); -#else - w=gdk_window_foreign_new((HANDLE)id); -#endif - if (w) { - set_video_window_decorations(w); - g_object_unref(G_OBJECT(w)); - } - else ms_error("gdk_window_foreign_new() failed"); - if (video_needs_update) video_needs_update=FALSE; - } - } -} static gboolean linphone_gtk_iterate(LinphoneCore *lc){ static gboolean first_time=TRUE; @@ -677,7 +582,6 @@ static gboolean linphone_gtk_iterate(LinphoneCore *lc){ first_time=FALSE; } - update_video_titles(lc); if (addr_to_call!=NULL){ /*make sure we are not showing the login screen*/ GtkWidget *mw=linphone_gtk_get_main_window(); @@ -928,7 +832,6 @@ void linphone_gtk_call_terminated(LinphoneCall *call, const char *error){ } if (linphone_gtk_use_in_call_view() && call) linphone_gtk_in_call_view_terminate(call,error); - update_video_title(); } static void linphone_gtk_update_call_buttons(LinphoneCall *call){ @@ -971,7 +874,6 @@ static void linphone_gtk_update_call_buttons(LinphoneCall *call){ linphone_gtk_enable_transfer_button(lc,FALSE); linphone_gtk_enable_conference_button(lc,FALSE); } - update_video_title(); if (call) { linphone_gtk_update_video_button(call); } diff --git a/gtk/videowindow.c b/gtk/videowindow.c new file mode 100644 index 000000000..4a119faa9 --- /dev/null +++ b/gtk/videowindow.c @@ -0,0 +1,310 @@ +/* +linphone, gtk interface. +Copyright (C) 2014 Belledonne Communications SARL + +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 "linphone.h" + +#ifdef __linux +#include +#elif defined(WIN32) +#include +#elif defined(__APPLE__) +extern void *gdk_quartz_window_get_nswindow(GdkWindow *window); +extern void *gdk_quartz_window_get_nsview(GdkWindow *window); +#endif + +#include + +enum { + TARGET_STRING, + TARGET_TEXT, + TARGET_URILIST +}; + +static GtkTargetEntry targets[] = { + { "text/uri-list", GTK_TARGET_OTHER_APP, TARGET_URILIST }, +}; + +static void set_video_controls_position(GtkWidget *video_window); + +static void on_end_of_play(LinphonePlayer *player, void *user_data){ + linphone_player_close(player); +} + +static void drag_data_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y, + GtkSelectionData *selection_data, guint target_type, guint time, gpointer user_data){ + int datalen=gtk_selection_data_get_length(selection_data) >= 0; + const void *data=gtk_selection_data_get_data(selection_data); + LinphoneCall *call=g_object_get_data(G_OBJECT(widget),"call"); + + ms_message("target_type=%i, datalen=%i, data=%p",target_type,datalen,data); + if (target_type==TARGET_URILIST && data){ + LinphonePlayer *player=linphone_call_get_player(call); + const char *path=(const char*)data; + if (player){ + if (strstr(path,"file://")==path) path+=strlen("file://"); + if (linphone_player_open(player,path,on_end_of_play,NULL)==0){ + linphone_player_start(player); + }else{ + GtkWidget *warn=gtk_message_dialog_new(GTK_WINDOW(widget),GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE, + _("Cannot play %s."),path); + g_signal_connect(warn,"response",(GCallback)gtk_widget_destroy,NULL); + gtk_widget_show(warn); + } + } + + } + gtk_drag_finish (context, TRUE, FALSE, time); +} + +static gboolean drag_drop(GtkWidget *widget, GdkDragContext *drag_context, gint x, gint y, guint time, gpointer user_data){ +#if GTK_CHECK_VERSION(2,20,0) + GList *l=gdk_drag_context_list_targets(drag_context); + GList *elem; + + if (l){ + ms_message("drag_drop"); + /* Choose the best target type */ + for(elem=l;elem!=NULL;elem=g_list_next(elem)){ + char *name=gdk_atom_name(GDK_POINTER_TO_ATOM(elem->data)); + ms_message("target: %s",name); + g_free(name); + } + }else{ + ms_warning("drag_drop no targets"); + return FALSE; + } +#endif + return TRUE; +} + +unsigned long get_native_handle(GdkWindow *gdkw){ +#ifdef __linux + return (unsigned long)GDK_WINDOW_XID(gdkw); +#elif defined(WIN32) + return (unsigned long)GDK_WINDOW_HWND(gdkw); +#elif defined(__APPLE__) + return (unsigned long)gdk_quartz_window_get_nsview(gdkw); +#endif + g_warning("No way to get the native handle from gdk window"); + return 0; +} + +static gint resize_video_window(LinphoneCall *call){ + const LinphoneCallParams *params=linphone_call_get_current_params(call); + if (params){ + MSVideoSize vsize=linphone_call_params_get_received_video_size(params); + if (vsize.width>0 && vsize.height>0){ + GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); + GtkWidget *video_window=(GtkWidget*)g_object_get_data(G_OBJECT(callview),"video_window"); + if (video_window){ + MSVideoSize cur; + gtk_window_get_size(GTK_WINDOW(video_window),&cur.width,&cur.height); + if (vsize.width*vsize.height > cur.width*cur.height || + ms_video_size_get_orientation(vsize)!=ms_video_size_get_orientation(cur) ){ + g_message("Resized to %ix%i",vsize.width,vsize.height); + gtk_window_resize(GTK_WINDOW(video_window),vsize.width,vsize.height); + } + } + } + } + return TRUE; +} + +static void on_video_window_destroy(GtkWidget *w, guint timeout){ + g_source_remove(timeout); + linphone_core_set_native_video_window_id(linphone_gtk_get_core(),(unsigned long)-1); +} + +static void video_window_set_fullscreen(GtkWidget *w, gboolean val){ + if (val){ + g_object_set_data(G_OBJECT(w),"fullscreen",GINT_TO_POINTER(1)); + gtk_window_fullscreen(GTK_WINDOW(w)); + }else{ + g_object_set_data(G_OBJECT(w),"fullscreen",GINT_TO_POINTER(0)); + gtk_window_unfullscreen(GTK_WINDOW(w)); + } +} +/*old names in old version of gdk*/ +#ifndef GDK_KEY_Escape +#define GDK_KEY_Escape GDK_Escape +#define GDK_KEY_F GDK_F +#define GDK_KEY_f GDK_f +#endif + +static void on_video_window_key_press(GtkWidget *w, GdkEvent *ev, gpointer up){ + g_message("Key press event"); + switch(ev->key.keyval){ + case GDK_KEY_f: + case GDK_KEY_F: + video_window_set_fullscreen(w,TRUE); + break; + case GDK_KEY_Escape: + video_window_set_fullscreen(w,FALSE); + break; + } +} + +static void on_controls_response(GtkWidget *dialog, int response_id, GtkWidget *video_window){ + + gtk_widget_destroy(dialog); + switch(response_id){ + case GTK_RESPONSE_YES: + video_window_set_fullscreen(video_window,TRUE); + break; + case GTK_RESPONSE_NO: + video_window_set_fullscreen(video_window,FALSE); + break; + case GTK_RESPONSE_REJECT: + { + LinphoneCall *call=(LinphoneCall*)g_object_get_data(G_OBJECT(video_window),"call"); + linphone_core_terminate_call(linphone_gtk_get_core(),call); + } + break; + } + +} + +static void on_controls_destroy(GtkWidget *w){ + GtkWidget *video_window=(GtkWidget*)g_object_get_data(G_OBJECT(w),"video_window"); + gint timeout=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"timeout")); + if (timeout!=0){ + g_source_remove(timeout); + g_object_set_data(G_OBJECT(w),"timeout",GINT_TO_POINTER(0)); + } + g_object_set_data(G_OBJECT(video_window),"controls",NULL); +} + +static gboolean _set_video_controls_position(GtkWidget *video_window){ + GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(video_window),"controls"); + if (w){ + gint vw,vh; + gint cw,ch; + gint x,y; + gtk_window_get_size(GTK_WINDOW(video_window),&vw,&vh); + gtk_window_get_position(GTK_WINDOW(video_window),&x,&y); + gtk_window_get_size(GTK_WINDOW(w),&cw,&ch); + gtk_window_move(GTK_WINDOW(w),x+vw/2 - cw/2, y + vh - ch); + } + return FALSE; +} + +static void set_video_controls_position(GtkWidget *video_window){ + /*do it a first time*/ + _set_video_controls_position(video_window); + /*and schedule to do it a second time in order to workaround a bug in fullscreen mode, where poistion is not taken into account the first time*/ + g_timeout_add(0,(GSourceFunc)_set_video_controls_position,video_window); +} + +static gboolean video_window_moved(GtkWidget *widget, GdkEvent *event, gpointer user_data){ + set_video_controls_position(widget); + return FALSE; +} + +static GtkWidget *show_video_controls(GtkWidget *video_window){ + GtkWidget *w; + w=(GtkWidget*)g_object_get_data(G_OBJECT(video_window),"controls"); + if (!w){ + gboolean isfullscreen=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(video_window),"fullscreen")); + const char *stock_button=isfullscreen ? GTK_STOCK_LEAVE_FULLSCREEN : GTK_STOCK_FULLSCREEN; + gint response_id=isfullscreen ? GTK_RESPONSE_NO : GTK_RESPONSE_YES ; + gint timeout; + GtkWidget *button; + w=gtk_dialog_new_with_buttons("",GTK_WINDOW(video_window),GTK_DIALOG_DESTROY_WITH_PARENT,stock_button,response_id,NULL); + gtk_window_set_opacity(GTK_WINDOW(w),0.5); + gtk_window_set_decorated(GTK_WINDOW(w),FALSE); + button=gtk_button_new_with_label(_("Hang up")); + gtk_button_set_image(GTK_BUTTON(button),create_pixmap (linphone_gtk_get_ui_config("stop_call_icon","stopcall-small.png"))); + gtk_widget_show(button); + gtk_dialog_add_action_widget(GTK_DIALOG(w),button,GTK_RESPONSE_REJECT); + g_signal_connect(w,"response",(GCallback)on_controls_response,video_window); + timeout=g_timeout_add(3000,(GSourceFunc)gtk_widget_destroy,w); + g_object_set_data(G_OBJECT(w),"timeout",GINT_TO_POINTER(timeout)); + g_signal_connect(w,"destroy",(GCallback)on_controls_destroy,NULL); + g_object_set_data(G_OBJECT(w),"video_window",video_window); + g_object_set_data(G_OBJECT(video_window),"controls",w); + set_video_controls_position(video_window); + gtk_widget_show(w); + }else{ + gint timeout=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"timeout")); + g_source_remove(timeout); + timeout=g_timeout_add(3000,(GSourceFunc)gtk_widget_destroy,w); + g_object_set_data(G_OBJECT(w),"timeout",GINT_TO_POINTER(timeout)); + } + return w; +} + +static GtkWidget *create_video_window(LinphoneCall *call){ + char *remote,*title; + GtkWidget *video_window; + const LinphoneAddress *addr; + const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON); + GdkPixbuf *pbuf=create_pixbuf(icon_path); + guint timeout; + MSVideoSize vsize=MS_VIDEO_SIZE_CIF; + GdkColor color; + + addr=linphone_call_get_remote_address(call); + remote=linphone_gtk_address(addr); + video_window=gtk_window_new(GTK_WINDOW_TOPLEVEL); + title=g_strdup_printf("%s - Video call with %s",linphone_gtk_get_ui_config("title","Linphone"),remote); + ms_free(remote); + gtk_window_set_title(GTK_WINDOW(video_window),title); + g_free(title); + if (pbuf){ + gtk_window_set_icon(GTK_WINDOW(video_window),pbuf); + } + gtk_window_resize(GTK_WINDOW(video_window),vsize.width,vsize.height); + gdk_color_parse("black",&color); + gtk_widget_modify_bg(video_window,GTK_STATE_NORMAL,&color); + + gtk_drag_dest_set(video_window, GTK_DEST_DEFAULT_ALL, targets, sizeof(targets)/sizeof(GtkTargetEntry), GDK_ACTION_COPY); + gtk_widget_show(video_window); + gdk_window_set_events(gtk_widget_get_window(video_window), + gdk_window_get_events(gtk_widget_get_window(video_window)) | GDK_POINTER_MOTION_MASK); + timeout=g_timeout_add(500,(GSourceFunc)resize_video_window,call); + g_signal_connect(video_window,"destroy",(GCallback)on_video_window_destroy,GINT_TO_POINTER(timeout)); + g_signal_connect(video_window,"key-press-event",(GCallback)on_video_window_key_press,NULL); + g_signal_connect_swapped(video_window,"motion-notify-event",(GCallback)show_video_controls,video_window); + g_signal_connect(video_window,"configure-event",(GCallback)video_window_moved,NULL); + g_signal_connect(video_window, "drag-data-received",(GCallback)drag_data_received, NULL); + g_signal_connect(video_window, "drag-drop",(GCallback)drag_drop, NULL); + g_object_set_data(G_OBJECT(video_window),"call",call); + return video_window; +} + +void linphone_gtk_in_call_show_video(LinphoneCall *call){ + GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); + GtkWidget *video_window=(GtkWidget*)g_object_get_data(G_OBJECT(callview),"video_window"); + const LinphoneCallParams *params=linphone_call_get_current_params(call); + LinphoneCore *lc=linphone_gtk_get_core(); + + if (linphone_call_get_state(call)!=LinphoneCallPaused && params && linphone_call_params_video_enabled(params)){ + if (video_window==NULL){ + video_window=create_video_window(call); + g_object_set_data(G_OBJECT(callview),"video_window",video_window); + } + linphone_core_set_native_video_window_id(lc,get_native_handle(gtk_widget_get_window(video_window))); + }else{ + if (video_window){ + gtk_widget_destroy(video_window); + g_object_set_data(G_OBJECT(callview),"video_window",NULL); + } + } +} diff --git a/include/sal/sal.h b/include/sal/sal.h index f15349151..3b6c08a9a 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -68,13 +68,15 @@ typedef enum { SalTransportDTLS /*DTLS*/ }SalTransport; -#define SAL_MEDIA_DESCRIPTION_UNCHANGED 0x00 -#define SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED 0x01 -#define SAL_MEDIA_DESCRIPTION_CODEC_CHANGED 0x02 -#define SAL_MEDIA_DESCRIPTION_CRYPTO_CHANGED 0x04 -#define SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED 0x08 +#define SAL_MEDIA_DESCRIPTION_UNCHANGED 0x00 +#define SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED (1) +#define SAL_MEDIA_DESCRIPTION_CODEC_CHANGED (1<<1) +#define SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED (1<<2) +#define SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED (1<<3) +#define SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED (1<<4) + #define SAL_MEDIA_DESCRIPTION_CHANGED (SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED | SAL_MEDIA_DESCRIPTION_CODEC_CHANGED |\ - SAL_MEDIA_DESCRIPTION_CRYPTO_CHANGED |SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED) + SAL_MEDIA_DESCRIPTION_CRYPTO_KEYS_CHANGED |SAL_MEDIA_DESCRIPTION_CRYPTO_POLICY_CHANGED | SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED) const char* sal_transport_to_string(SalTransport transport); SalTransport sal_transport_parse(const char*); diff --git a/mediastreamer2 b/mediastreamer2 index 21e35e89f..91f278207 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 21e35e89ffa8920bb0b5865d365b84471ecfa321 +Subproject commit 91f2782073c776b2d5ce3ab0a12561aea7610068 diff --git a/oRTP b/oRTP index 45da3ab75..540ee49bd 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 45da3ab75d39587189ea95829ee1cb92d61827be +Subproject commit 540ee49bd3f65139f7e5938cc6bc1f8a4353c3f7 diff --git a/tester/Makefile.am b/tester/Makefile.am index 6e52d21b5..d8877119d 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -22,7 +22,8 @@ liblinphonetester_la_SOURCES = tester.c \ stun_tester.c \ remote_provisioning_tester.c \ quality_reporting_tester.c \ - transport_tester.c + transport_tester.c \ + player_tester.c liblinphonetester_la_LDFLAGS= -no-undefined liblinphonetester_la_LIBADD= ../coreapi/liblinphone.la $(CUNIT_LIBS) diff --git a/tester/call_tester.c b/tester/call_tester.c index 35b4c2bdd..a2feaab92 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -25,10 +25,16 @@ #include "lpconfig.h" #include "private.h" #include "liblinphone_tester.h" +#include "mediastreamer2/dsptools.h" + +#ifdef WIN32 +#define unlink _unlink +#endif static void srtp_call(void); static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy); static void disable_all_audio_codecs_except_one(LinphoneCore *lc, const char *mime, int rate); +static char *create_filepath(const char *dir, const char *filename, const char *ext); // prototype definition for call_recording() #ifdef ANDROID @@ -775,6 +781,7 @@ static void call_with_no_sdp(void) { linphone_core_manager_destroy(pauline); } + static bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee, LinphoneIceState state) { LinphoneCall *c1,*c2; bool_t audio_success=FALSE; @@ -1878,6 +1885,114 @@ static void call_with_declined_srtp(void) { linphone_core_manager_destroy(pauline); } +static void on_eof(LinphonePlayer *player, void *user_data){ + LinphoneCoreManager *marie=(LinphoneCoreManager*)user_data; + marie->stat.number_of_player_eof++; +} + +static void call_with_file_player(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphonePlayer *player; + char hellopath[256]; + char *recordpath = create_filepath(liblinphone_tester_writable_dir_prefix, "record", "wav"); + double similar; + + /*make sure the record file doesn't already exists, otherwise this test will append new samples to it*/ + unlink(recordpath); + + snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix); + + /*caller uses soundcard*/ + + /*callee is recording and plays file*/ + linphone_core_use_files(pauline->lc,TRUE); + linphone_core_set_play_file(pauline->lc,hellopath); + linphone_core_set_record_file(pauline->lc,recordpath); + + CU_ASSERT_TRUE(call(marie,pauline)); + + player=linphone_call_get_player(linphone_core_get_current_call(marie->lc)); + CU_ASSERT_PTR_NOT_NULL(player); + if (player){ + CU_ASSERT_TRUE(linphone_player_open(player,hellopath,on_eof,marie)==0); + CU_ASSERT_TRUE(linphone_player_start(player)==0); + } + CU_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_player_eof,1,12000)); + + /*just to sleep*/ + linphone_core_terminate_all_calls(marie->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(ms_audio_diff(hellopath,recordpath,&similar,NULL,NULL)==0); + CU_ASSERT_TRUE(similar>0.9); + CU_ASSERT_TRUE(similar<=1.0); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + ms_free(recordpath); +} + +static bool_t is_format_supported(LinphoneCore *lc, const char *fmt){ + const char **formats=linphone_core_get_supported_file_formats(lc); + for(;*formats!=NULL;++formats){ + if (strcasecmp(*formats,fmt)==0) return TRUE; + } + return FALSE; +} + +static void call_with_mkv_file_player(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphonePlayer *player; + char hellomkv[256]; + char hellowav[256]; + char *recordpath; + double similar; + + if (!is_format_supported(marie->lc,"mkv")){ + ms_warning("Test skipped, no mkv support."); + goto end; + } + recordpath = create_filepath(liblinphone_tester_writable_dir_prefix, "record", "wav"); + /*make sure the record file doesn't already exists, otherwise this test will append new samples to it*/ + unlink(recordpath); + + snprintf(hellowav,sizeof(hellowav), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix); + snprintf(hellomkv,sizeof(hellomkv), "%s/sounds/hello8000.mkv", liblinphone_tester_file_prefix); + + /*caller uses soundcard*/ + + /*callee is recording and plays file*/ + linphone_core_use_files(pauline->lc,TRUE); + linphone_core_set_play_file(pauline->lc,hellowav); /*just to send something but we are not testing what is sent by pauline*/ + linphone_core_set_record_file(pauline->lc,recordpath); + + CU_ASSERT_TRUE(call(marie,pauline)); + + player=linphone_call_get_player(linphone_core_get_current_call(marie->lc)); + CU_ASSERT_PTR_NOT_NULL(player); + if (player){ + CU_ASSERT_TRUE(linphone_player_open(player,hellomkv,on_eof,marie)==0); + CU_ASSERT_TRUE(linphone_player_start(player)==0); + } + CU_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&marie->stat.number_of_player_eof,1,12000)); + + /*just to sleep*/ + linphone_core_terminate_all_calls(marie->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(ms_audio_diff(hellowav,recordpath,&similar,NULL,NULL)==0); + CU_ASSERT_TRUE(similar>0.9); + CU_ASSERT_TRUE(similar<=1.0); + ms_free(recordpath); + +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + +} + + static void call_base(LinphoneMediaEncryption mode, bool_t enable_video,bool_t enable_relay,LinphoneFirewallPolicy policy) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -2808,13 +2923,7 @@ static void savpf_to_savpf_call(void) { } static char *create_filepath(const char *dir, const char *filename, const char *ext) { - char *filepath = ms_new0(char, strlen(dir) + strlen(filename) + strlen(ext) + 3); - strcpy(filepath, dir); - strcat(filepath, "/"); - strcat(filepath, filename); - strcat(filepath, "."); - strcat(filepath, ext); - return filepath; + return ms_strdup_printf("%s/%s.%s",dir,filename,ext); } static void record_call(const char *filename, bool_t enableVideo) { @@ -2867,7 +2976,6 @@ static void record_call(const char *filename, bool_t enableVideo) { linphone_call_stop_recording(callInst); end_call(marie, pauline); CU_ASSERT_EQUAL(access(filepath, F_OK), 0); - remove(filepath); } ms_free(filepath); } @@ -2949,7 +3057,57 @@ static void call_with_in_dialog_update(void) { belle_sip_object_dump_active_objects(); } } +static void call_with_in_dialog_codec_change_base(bool_t no_sdp) { + int begin; + int leaked_objects; + int dummy=0; + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + LinphoneCallParams *params; + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + + marie = linphone_core_manager_new( "marie_rc"); + pauline = linphone_core_manager_new( "pauline_rc"); + CU_ASSERT_TRUE(call(pauline,marie)); + liblinphone_tester_check_rtcp(marie,pauline); + params=linphone_core_create_call_params(marie->lc,linphone_core_get_current_call(marie->lc)); + + linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMU",8000,1),FALSE); /*disable PCMU*/ + linphone_core_enable_payload_type(marie->lc,linphone_core_find_payload_type(marie->lc,"PCMU",8000,1),FALSE); /*disable PCMU*/ + linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMA",8000,1),TRUE); /*enable PCMA*/ + linphone_core_enable_payload_type(marie->lc,linphone_core_find_payload_type(marie->lc,"PCMA",8000,1),TRUE); /*enable PCMA*/ + if (no_sdp) { + linphone_core_enable_sdp_200_ack(marie->lc,TRUE); + } + linphone_core_update_call(marie->lc,linphone_core_get_current_call(marie->lc),params); + linphone_call_params_destroy(params); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,1)); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallUpdatedByRemote,1)); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + CU_ASSERT_STRING_EQUAL("PCMA",linphone_payload_type_get_mime_type(linphone_call_params_get_used_audio_codec(linphone_call_get_current_params(linphone_core_get_current_call(marie->lc))))); + wait_for_until(marie->lc, pauline->lc, &dummy, 1, 3000); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(marie->lc))->download_bandwidth>70); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(linphone_core_get_current_call(pauline->lc))->download_bandwidth>70); + + end_call(marie,pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + + leaked_objects=belle_sip_object_get_object_count()-begin; + CU_ASSERT_TRUE(leaked_objects==0); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } +} +static void call_with_in_dialog_codec_change(void) { + call_with_in_dialog_codec_change_base(FALSE); +} +static void call_with_in_dialog_codec_change_no_sdp(void) { + call_with_in_dialog_codec_change_base(TRUE); +} static void call_with_custom_supported_tags(void) { int begin; int leaked_objects; @@ -3015,6 +3173,8 @@ test_t call_tests[] = { { "ZRTP call",zrtp_call}, { "ZRTP video call",zrtp_video_call}, { "SRTP call with declined srtp", call_with_declined_srtp }, + { "Call with file player", call_with_file_player}, + { "Call with mkv file player", call_with_mkv_file_player}, #ifdef VIDEO_ENABLED { "Simple video call",video_call}, { "Simple video call using policy",video_call_using_policy}, @@ -3079,6 +3239,8 @@ test_t call_tests[] = { { "SAVPF to SAVP call", savpf_to_savp_call }, { "SAVPF to SAVPF call", savpf_to_savpf_call }, { "Call with in-dialog UPDATE request", call_with_in_dialog_update }, + { "Call with in-dialog codec change", call_with_in_dialog_codec_change }, + { "Call with in-dialog codec change no sdp", call_with_in_dialog_codec_change_no_sdp }, { "Call with custom supported tags", call_with_custom_supported_tags } }; diff --git a/tester/certificates/altname/agent.pem b/tester/certificates/altname/agent.pem index c75085728..edb7c9fa1 100644 --- a/tester/certificates/altname/agent.pem +++ b/tester/certificates/altname/agent.pem @@ -13,17 +13,16 @@ RPIGEkQ2wzG9AJq7iJ2Yy8+2kTvULajvhI0JrSqVbgS9Z9fUKgCN6oIZfvQsrxus UcIc3KjqaP1mLw7aIpUCQH5S0B+GOwKa8+RbuRcgBvksqkRwRZn6jawoNJJSBCDn gQJ5B9PvJXppTsbnulSD2srhUqCR1pzGfnl8bYV8b8Q= -----END RSA PRIVATE KEY----- - Certificate: Data: Version: 3 (0x2) - Serial Number: 5 (0x5) + Serial Number: 9 (0x9) Signature Algorithm: sha1WithRSAEncryption Issuer: C=FR, ST=Some-State, L=Grenoble, O=Belledonne Communications, OU=LAB, CN=Jehan Monnier/emailAddress=jehan.monnier@belledonne-communications.com Validity - Not Before: Sep 23 15:58:58 2013 GMT - Not After : Sep 23 15:58:58 2014 GMT - Subject: C=FR, ST=France, L=Grenoble, O=Belledonne Communications, OU=LAB, CN=See altname for DNS name/emailAddress=jehan.monnier@belledonne-communications.com + Not Before: Sep 25 16:12:35 2014 GMT + Not After : Sep 22 16:12:35 2024 GMT + Subject: C=FR, ST=France, L=Grenoble, O=Belledonne Communications, OU=LAB, CN=Jehan Monnier/emailAddress=jehan.monnier@belledonne-communications.com Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) @@ -46,31 +45,31 @@ Certificate: X509v3 Subject Alternative Name: DNS:altname.linphone.org, DNS:*.wildcard2.linphone.org Signature Algorithm: sha1WithRSAEncryption - 21:05:d3:36:82:5d:f4:f4:70:71:17:ac:06:12:49:0c:d6:c3: - 21:07:9c:2f:79:c8:14:da:e5:3a:92:04:22:5b:74:cf:53:3c: - 95:33:51:93:66:04:59:c6:3d:dd:22:cf:3f:f8:0e:24:93:6b: - 2a:02:f7:bf:ba:89:1b:72:9a:d4:1b:bf:22:3d:08:51:13:a4: - bf:43:d2:89:a1:c5:f2:e3:04:24:1e:d4:33:64:06:83:2d:b6: - 66:34:16:a9:f4:8d:6f:3f:71:86:ab:73:19:36:ae:43:29:7e: - 9d:6c:35:3a:75:f4:22:8b:c5:e3:1e:ee:c1:0d:d7:63:cc:95: - 4a:6a + 56:f5:23:64:4c:8d:85:6e:05:d6:42:a3:41:b2:6a:ab:a1:cd: + be:ae:4a:38:c5:23:4c:62:2c:06:4d:49:b7:fc:ad:86:1d:9b: + c0:7e:33:80:fa:7d:31:8b:ca:9c:28:44:b2:1c:f1:ed:73:5b: + d3:80:72:b0:6c:0b:20:2b:e5:2b:02:c6:be:14:ad:55:34:2f: + 6f:8e:bb:7b:61:ce:9c:af:85:a7:b0:cd:d1:4e:1e:17:e9:7e: + 61:ed:50:60:9a:de:d0:7a:6d:a5:ee:04:9a:5c:41:94:21:e5: + 05:61:a8:17:ab:eb:b4:cc:7f:90:9b:3a:0e:ca:31:fb:65:40: + 11:2d -----BEGIN CERTIFICATE----- -MIIDSjCCArOgAwIBAgIBBTANBgkqhkiG9w0BAQUFADCBuzELMAkGA1UEBhMCRlIx +MIIDPzCCAqigAwIBAgIBCTANBgkqhkiG9w0BAQUFADCBuzELMAkGA1UEBhMCRlIx EzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAcMCEdyZW5vYmxlMSIwIAYDVQQK DBlCZWxsZWRvbm5lIENvbW11bmljYXRpb25zMQwwCgYDVQQLDANMQUIxFjAUBgNV BAMMDUplaGFuIE1vbm5pZXIxOjA4BgkqhkiG9w0BCQEWK2plaGFuLm1vbm5pZXJA -YmVsbGVkb25uZS1jb21tdW5pY2F0aW9ucy5jb20wHhcNMTMwOTIzMTU1ODU4WhcN -MTQwOTIzMTU1ODU4WjCBwjELMAkGA1UEBhMCRlIxDzANBgNVBAgMBkZyYW5jZTER +YmVsbGVkb25uZS1jb21tdW5pY2F0aW9ucy5jb20wHhcNMTQwOTI1MTYxMjM1WhcN +MjQwOTIyMTYxMjM1WjCBtzELMAkGA1UEBhMCRlIxDzANBgNVBAgMBkZyYW5jZTER MA8GA1UEBwwIR3Jlbm9ibGUxIjAgBgNVBAoMGUJlbGxlZG9ubmUgQ29tbXVuaWNh -dGlvbnMxDDAKBgNVBAsMA0xBQjEhMB8GA1UEAwwYU2VlIGFsdG5hbWUgZm9yIERO -UyBuYW1lMTowOAYJKoZIhvcNAQkBFitqZWhhbi5tb25uaWVyQGJlbGxlZG9ubmUt -Y29tbXVuaWNhdGlvbnMuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDH -ZG78iwkkxJeq3ZPuQwY9DfdcNCvHXayW+5p5VUULV50ohJKtJJzhp5ysq4VH7q/d -mOnMnbYTACnqVSlph88zRdQJd/g0h6T4DyWa5Jxe+R1hwLWVfgeSXstCK8m9SwxK -qnqA5mPZxfARXg3r4XWkUK2A1lWIXCkZU3MMD4JJ4QIDAQABo1UwUzAJBgNVHRME -AjAAMAsGA1UdDwQEAwIF4DA5BgNVHREEMjAwghRhbHRuYW1lLmxpbnBob25lLm9y -Z4IYKi53aWxkY2FyZDIubGlucGhvbmUub3JnMA0GCSqGSIb3DQEBBQUAA4GBACEF -0zaCXfT0cHEXrAYSSQzWwyEHnC95yBTa5TqSBCJbdM9TPJUzUZNmBFnGPd0izz/4 -DiSTayoC97+6iRtymtQbvyI9CFETpL9D0omhxfLjBCQe1DNkBoMttmY0Fqn0jW8/ -cYarcxk2rkMpfp1sNTp19CKLxeMe7sEN12PMlUpq +dGlvbnMxDDAKBgNVBAsMA0xBQjEWMBQGA1UEAwwNSmVoYW4gTW9ubmllcjE6MDgG +CSqGSIb3DQEJARYramVoYW4ubW9ubmllckBiZWxsZWRvbm5lLWNvbW11bmljYXRp +b25zLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAx2Ru/IsJJMSXqt2T +7kMGPQ33XDQrx12slvuaeVVFC1edKISSrSSc4aecrKuFR+6v3ZjpzJ22EwAp6lUp +aYfPM0XUCXf4NIek+A8lmuScXvkdYcC1lX4Hkl7LQivJvUsMSqp6gOZj2cXwEV4N +6+F1pFCtgNZViFwpGVNzDA+CSeECAwEAAaNVMFMwCQYDVR0TBAIwADALBgNVHQ8E +BAMCBeAwOQYDVR0RBDIwMIIUYWx0bmFtZS5saW5waG9uZS5vcmeCGCoud2lsZGNh +cmQyLmxpbnBob25lLm9yZzANBgkqhkiG9w0BAQUFAAOBgQBW9SNkTI2FbgXWQqNB +smqroc2+rko4xSNMYiwGTUm3/K2GHZvAfjOA+n0xi8qcKESyHPHtc1vTgHKwbAsg +K+UrAsa+FK1VNC9vjrt7Yc6cr4WnsM3RTh4X6X5h7VBgmt7Qem2l7gSaXEGUIeUF +YagXq+u0zH+QmzoOyjH7ZUARLQ== -----END CERTIFICATE----- diff --git a/tester/certificates/altname/openssl-altname.cnf b/tester/certificates/altname/openssl-altname.cnf index c4edb6c7d..0dc82fbe7 100644 --- a/tester/certificates/altname/openssl-altname.cnf +++ b/tester/certificates/altname/openssl-altname.cnf @@ -39,7 +39,7 @@ default_ca = CA_default # The default ca section #################################################################### [ CA_default ] -dir = ./demoCA # Where everything is kept +dir = . # Where everything is kept certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. diff --git a/tester/certificates/cn/openssl-cn.cnf b/tester/certificates/cn/openssl-cn.cnf index c6262db31..908f6ed4c 100644 --- a/tester/certificates/cn/openssl-cn.cnf +++ b/tester/certificates/cn/openssl-cn.cnf @@ -39,7 +39,7 @@ default_ca = CA_default # The default ca section #################################################################### [ CA_default ] -dir = ./demoCA # Where everything is kept +dir = . # Where everything is kept certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 67b68f87c..9178bac8f 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -59,6 +59,7 @@ extern test_suite_t stun_test_suite; extern test_suite_t remote_provisioning_test_suite; extern test_suite_t quality_reporting_test_suite; extern test_suite_t transport_test_suite; +extern test_suite_t player_test_suite; extern int liblinphone_tester_nb_test_suites(void); @@ -195,6 +196,7 @@ typedef struct _stats { int number_of_LinphoneCallEncryptedOff; int number_of_NetworkReachableTrue; int number_of_NetworkReachableFalse; + int number_of_player_eof; LinphoneChatMessage* last_received_chat_message; }stats; diff --git a/tester/message_tester.c b/tester/message_tester.c index 058823403..fcbcf3919 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -281,7 +281,7 @@ static void text_message_with_privacy(void) { /* make sure lime is not enabled */ linphone_core_set_lime(marie->lc, 0); linphone_core_set_lime(pauline->lc, 0); - + to = linphone_address_as_string(marie->identity); chat_room = linphone_core_create_chat_room(pauline->lc,to); ms_free(to); diff --git a/tester/player_tester.c b/tester/player_tester.c new file mode 100644 index 000000000..59e648340 --- /dev/null +++ b/tester/player_tester.c @@ -0,0 +1,64 @@ +#include "liblinphone_tester.h" + +static bool_t wait_for_eof(bool_t *eof, int *time,int time_refresh, int timeout) { + while(*time < timeout && !*eof) { + usleep(time_refresh * 1000U); + *time += time_refresh; + } + return *time < timeout; +} + +static void eof_callback(LinphonePlayer *player, void *user_data) { + bool_t *eof = (bool_t *)user_data; + *eof = TRUE; +} + +static void play_file(const char *filename, bool_t unsupported_format) { + LinphoneCoreManager *lc_manager; + LinphonePlayer *player; + int res, time = 0; + bool_t eof = FALSE; + + lc_manager = linphone_core_manager_new("marie_rc"); + CU_ASSERT_PTR_NOT_NULL(lc_manager); + if(lc_manager == NULL) return; + + player = linphone_core_create_file_player(lc_manager->lc, ms_snd_card_manager_get_default_card(ms_snd_card_manager_get()), video_stream_get_default_video_renderer()); + CU_ASSERT_PTR_NOT_NULL(player); + if(player == NULL) goto fail; + + res = linphone_player_open(player, filename, eof_callback, &eof); + if(unsupported_format) { + CU_ASSERT_EQUAL(res, -1); + } else { + CU_ASSERT_EQUAL(res, 0); + } + if(res == -1) goto fail; + + CU_ASSERT_EQUAL((res = linphone_player_start(player)), 0); + if(res == -1) goto fail; + + CU_ASSERT_TRUE(wait_for_eof(&eof, &time, 100, 13000)); + + linphone_player_close(player); + + fail: + if(player) linphone_file_player_destroy(player); + if(lc_manager) linphone_core_manager_destroy(lc_manager); +} + +static void playing_test(void) { + play_file("sounds/hello_opus_h264.mkv", !linphone_file_player_matroska_supported()); +} + +test_t player_tests[] = { + { "Playing" , playing_test } +}; + +test_suite_t player_test_suite = { + "Player", + NULL, + NULL, + sizeof(player_tests) / sizeof(test_t), + player_tests +}; diff --git a/tester/sounds/hello8000.mkv b/tester/sounds/hello8000.mkv new file mode 100644 index 000000000..42fa387e5 Binary files /dev/null and b/tester/sounds/hello8000.mkv differ diff --git a/tester/sounds/hello_opus_h264.mkv b/tester/sounds/hello_opus_h264.mkv new file mode 100644 index 000000000..4aa5d338b Binary files /dev/null and b/tester/sounds/hello_opus_h264.mkv differ diff --git a/tester/tester.c b/tester/tester.c index 76a909606..97b45713d 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -388,6 +388,7 @@ void liblinphone_tester_init(void) { add_test_suite(&remote_provisioning_test_suite); add_test_suite(&quality_reporting_test_suite); add_test_suite(&transport_test_suite); + add_test_suite(&player_test_suite); } void liblinphone_tester_uninit(void) { diff --git a/tester/transport_tester.c b/tester/transport_tester.c index 014481f32..8f0673d60 100644 --- a/tester/transport_tester.c +++ b/tester/transport_tester.c @@ -59,7 +59,7 @@ static char* get_public_contact_ip(LinphoneCore* lc) { ms_free(contact); return ms_strdup(contact_host_ip); } -static void call_with_transport_base(bool_t use_tunnel, bool_t with_sip, LinphoneMediaEncryption encryption) { +static void call_with_transport_base(LinphoneTunnelMode tunnel_mode, bool_t with_sip, LinphoneMediaEncryption encryption) { if (linphone_core_tunnel_available()){ char *tmp_char; LinphoneCoreManager *pauline = linphone_core_manager_new( "pauline_rc"); @@ -69,7 +69,7 @@ static void call_with_transport_base(bool_t use_tunnel, bool_t with_sip, Linphon LinphoneAddress *server_addr = linphone_address_new(linphone_proxy_config_get_server_addr(proxy)); LinphoneAddress *route = linphone_address_new(linphone_proxy_config_get_route(proxy)); const char * tunnel_ip = get_ip_from_hostname("tunnel.linphone.org"); - char *public_ip; + char *public_ip, *public_ip2=NULL; CU_ASSERT_TRUE(wait_for(pauline->lc,NULL,&pauline->stat.number_of_LinphoneRegistrationOk,1)); public_ip = get_public_contact_ip(pauline->lc); @@ -77,7 +77,7 @@ static void call_with_transport_base(bool_t use_tunnel, bool_t with_sip, Linphon linphone_core_set_media_encryption(pauline->lc, encryption); - if (use_tunnel){ + if (tunnel_mode != LinphoneTunnelModeDisable){ LinphoneTunnel *tunnel = linphone_core_get_tunnel(pauline->lc); LinphoneTunnelConfig *config = linphone_tunnel_config_new(); @@ -91,24 +91,30 @@ static void call_with_transport_base(bool_t use_tunnel, bool_t with_sip, Linphon tmp_char = linphone_address_as_string(route); linphone_proxy_config_set_route(proxy, tmp_char); ms_free(tmp_char); - linphone_tunnel_set_mode(tunnel, LinphoneTunnelModeEnable); - if(with_sip) linphone_tunnel_enable_sip(tunnel, with_sip); linphone_tunnel_config_set_host(config, "tunnel.linphone.org"); linphone_tunnel_config_set_port(config, 443); + linphone_tunnel_config_set_remote_udp_mirror_port(config, 12345); linphone_tunnel_add_server(tunnel, config); + linphone_tunnel_set_mode(tunnel, tunnel_mode); + linphone_tunnel_enable_sip(tunnel, with_sip); linphone_proxy_config_done(proxy); /*enabling the tunnel cause another REGISTER to be made*/ CU_ASSERT_TRUE(wait_for(pauline->lc,NULL,&pauline->stat.number_of_LinphoneRegistrationOk,2)); - /* Ensure that we did use the tunnel. If so, we should see contact changed from: - Contact: ;.[...] - To: - Contact: ;[....] (91.121.209.194 must be tunnel.liphone.org) - */ - ms_free(public_ip); - public_ip = get_public_contact_ip(pauline->lc); - CU_ASSERT_STRING_EQUAL(public_ip, tunnel_ip); + if(tunnel_mode == LinphoneTunnelModeEnable) { + /* Ensure that we did use the tunnel. If so, we should see contact changed from: + Contact: ;.[...] + To: + Contact: ;[....] (91.121.209.194 must be tunnel.liphone.org) + */ + ms_free(public_ip); + public_ip = get_public_contact_ip(pauline->lc); + CU_ASSERT_STRING_EQUAL(public_ip, tunnel_ip); + } else { + public_ip2 = get_public_contact_ip(pauline->lc); + CU_ASSERT_STRING_EQUAL(public_ip, public_ip2); + } } CU_ASSERT_TRUE(call(pauline,marie)); @@ -121,6 +127,7 @@ static void call_with_transport_base(bool_t use_tunnel, bool_t with_sip, Linphon end_call(pauline,marie); ms_free(public_ip); + if(public_ip2 != NULL) ms_free(public_ip2); linphone_address_destroy(server_addr); linphone_address_destroy(route); linphone_core_manager_destroy(pauline); @@ -131,21 +138,31 @@ static void call_with_transport_base(bool_t use_tunnel, bool_t with_sip, Linphon } static void call_with_tunnel(void) { - call_with_transport_base(TRUE, TRUE, LinphoneMediaEncryptionNone); + call_with_transport_base(LinphoneTunnelModeEnable, TRUE, LinphoneMediaEncryptionNone); } static void call_with_tunnel_srtp(void) { - call_with_transport_base(TRUE, TRUE, LinphoneMediaEncryptionSRTP); + call_with_transport_base(LinphoneTunnelModeEnable, TRUE, LinphoneMediaEncryptionSRTP); } static void call_with_tunnel_without_sip(void) { - call_with_transport_base(TRUE, FALSE, LinphoneMediaEncryptionNone); + call_with_transport_base(LinphoneTunnelModeEnable, FALSE, LinphoneMediaEncryptionNone); +} + +static void call_with_tunnel_auto(void) { + call_with_transport_base(LinphoneTunnelModeAuto, TRUE, LinphoneMediaEncryptionNone); +} + +static void call_with_tunnel_auto_without_sip_with_srtp(void) { + call_with_transport_base(LinphoneTunnelModeAuto, FALSE, LinphoneMediaEncryptionSRTP); } test_t transport_tests[] = { { "Tunnel only", call_with_tunnel }, { "Tunnel with SRTP", call_with_tunnel_srtp }, - { "Tunnel without SIP", call_with_tunnel_without_sip } + { "Tunnel without SIP", call_with_tunnel_without_sip }, + { "Tunnel in automatic mode", call_with_tunnel_auto }, + { "Tunnel in automatic mode with SRTP without SIP", call_with_tunnel_auto_without_sip_with_srtp }, }; test_suite_t transport_test_suite = { diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt new file mode 100644 index 000000000..6d383a4a7 --- /dev/null +++ b/tools/CMakeLists.txt @@ -0,0 +1,55 @@ +############################################################################ +# CMakeLists.txt +# Copyright (C) 2014 Belledonne Communications, Grenoble France +# +############################################################################ +# +# 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. +# +############################################################################ + +if(MSVC) + find_library(LIBGCC NAMES gcc) + find_library(LIBMINGWEX NAMES mingwex) +endif() + +set(LP_GEN_WRAPPERS_SOURCE_FILES + generator.cc + generator.hh + genwrappers.cc + software-desc.cc + software-desc.hh +) + +add_definitions( + -DIN_LINPHONE +) + +set(LP_GEN_WRAPPERS_LIBS + ${LIBGCC} + ${LIBMINGWEX} + ${XML2_LIBRARIES} +) + +add_executable(lp-gen-wrappers ${LP_GEN_WRAPPERS_SOURCE_FILES}) +target_link_libraries(lp-gen-wrappers ${LP_GEN_WRAPPERS_LIBS}) + + +install(TARGETS lp-gen-wrappers + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE +) diff --git a/tools/python/apixml2python.py b/tools/python/apixml2python.py index 73fe2c257..b8f1bff2f 100755 --- a/tools/python/apixml2python.py +++ b/tools/python/apixml2python.py @@ -46,6 +46,7 @@ blacklisted_functions = [ 'linphone_chat_message_start_file_download', # to be handwritten because of callback 'linphone_chat_message_state_to_string', # There is no use to wrap this function 'linphone_chat_room_create_file_transfer_message', # missing LinphoneContent + 'linphone_core_add_listener', 'linphone_core_can_we_add_call', # private function 'linphone_core_get_audio_port_range', # to be handwritten because of result via arguments 'linphone_core_get_sip_transports', # missing LCSipTransports @@ -54,6 +55,7 @@ blacklisted_functions = [ 'linphone_core_get_video_policy', # missing LinphoneVideoPolicy 'linphone_core_get_video_port_range', # to be handwritten because of result via arguments 'linphone_core_publish', # missing LinphoneContent + 'linphone_core_remove_listener', 'linphone_core_serialize_logs', # There is no use to wrap this function 'linphone_core_set_log_file', # There is no use to wrap this function 'linphone_core_set_log_handler', # Hand-written but put directly in the linphone module