diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index d7b6c0c1d..481fb4cbd 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -375,70 +375,98 @@ SalReason sal_reason_to_sip_code(SalReason r){ case SalReasonNoMatch: ret=481; break; + case SalReasonRequestTimeout: + ret=408; + break; + case SalReasonMovedPermanently: + ret=301; + break; + case SalReasonGone: + ret=410; + break; + case SalReasonAddressIncomplete: + ret=484; + break; + case SalReasonNotImplemented: + ret=501; + break; + case SalReasonServerTimeout: + ret=504; + break; + case SalReasonBadGateway: + ret=502; + break; } return ret; } void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) { + *sal_err=SalErrorFailure; switch(code) { + case 301: + *sal_reason=SalReasonMovedPermanently; + break; case 302: *sal_reason=SalReasonRedirect; - *sal_err=SalErrorFailure; - break; - case 400: - *sal_err=SalErrorUnknown; break; case 401: case 407: - *sal_err=SalErrorFailure; *sal_reason=SalReasonUnauthorized; break; case 403: - *sal_err=SalErrorFailure; *sal_reason=SalReasonForbidden; break; case 404: - *sal_err=SalErrorFailure; *sal_reason=SalReasonNotFound; break; + case 408: + *sal_reason=SalReasonRequestTimeout; + break; + case 410: + *sal_reason=SalReasonGone; + break; case 415: - *sal_err=SalErrorFailure; *sal_reason=SalReasonUnsupportedContent; break; case 422: ms_error ("422 not implemented yet");; break; case 480: - *sal_err=SalErrorFailure; *sal_reason=SalReasonTemporarilyUnavailable; break; case 481: - *sal_err=SalErrorFailure; *sal_reason=SalReasonNoMatch; + break; + case 484: + *sal_reason=SalReasonAddressIncomplete; + break; case 486: - *sal_err=SalErrorFailure; *sal_reason=SalReasonBusy; break; case 487: break; case 488: - *sal_err=SalErrorFailure; *sal_reason=SalReasonNotAcceptable; break; case 491: - *sal_err=SalErrorFailure; *sal_reason=SalReasonRequestPending; break; + case 501: + *sal_reason=SalReasonNotImplemented; + break; + case 502: + *sal_reason=SalReasonBadGateway; + break; + case 504: + *sal_reason=SalReasonServerTimeout; + break; case 600: - *sal_err=SalErrorFailure; *sal_reason=SalReasonDoNotDisturb; break; case 603: - *sal_err=SalErrorFailure; *sal_reason=SalReasonDeclined; break; case 503: - *sal_err=SalErrorFailure; *sal_reason=SalReasonServiceUnavailable; break; default: diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 1da9b56a9..55685af59 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -721,9 +721,8 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de linphone_call_set_state(call,LinphoneCallEnd,"Call declined."); }else{ linphone_call_set_state(call,LinphoneCallError,details); - if (sr==SalReasonBusy) - linphone_core_play_named_tone(lc,LinphoneToneBusy); } + linphone_core_play_call_error_tone(lc,call->reason); if (referer){ /*notify referer of the failure*/ diff --git a/coreapi/ec-calibrator.c b/coreapi/ec-calibrator.c index dbb6d857a..bff0a00f1 100644 --- a/coreapi/ec-calibrator.c +++ b/coreapi/ec-calibrator.c @@ -154,7 +154,7 @@ static void ecc_play_tones(EcCalibrator *ecc){ memset(&tone,0,sizeof(tone)); memset(&expected_tone,0,sizeof(expected_tone)); - ms_filter_set_notify_callback(ecc->det,on_tone_received,ecc); + ms_filter_add_notify_callback(ecc->det,on_tone_received,ecc,TRUE); /* configure the tones to be scanned */ @@ -188,7 +188,7 @@ static void ecc_play_tones(EcCalibrator *ecc){ ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone); ms_sleep(2); - ms_filter_set_notify_callback(ecc->gen,on_tone_sent,ecc); + ms_filter_add_notify_callback(ecc->gen,on_tone_sent,ecc,TRUE); /* play the three tones*/ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index ca770b15e..be418d2dd 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -609,6 +609,8 @@ static void sound_config_read(LinphoneCore *lc) /*just parse requested stream feature once at start to print out eventual errors*/ linphone_core_get_audio_features(lc); + + _linphone_core_set_call_error_tone(lc,LinphoneReasonBusy,LinphoneToneBusy,NULL); } static void certificates_config_read(LinphoneCore *lc) @@ -5356,17 +5358,24 @@ void linphone_core_set_record_file(LinphoneCore *lc, const char *file){ } } +typedef enum{ + LinphoneToneGenerator, + LinphoneLocalPlayer +}LinphoneAudioResourceType; -static MSFilter *get_dtmf_gen(LinphoneCore *lc){ +static MSFilter *get_audio_resource(LinphoneCore *lc, LinphoneAudioResourceType rtype){ LinphoneCall *call=linphone_core_get_current_call (lc); AudioStream *stream=NULL; + RingStream *ringstream; if (call){ stream=call->audiostream; }else if (linphone_core_is_in_conference(lc)){ stream=lc->conf_ctx.local_participant; } if (stream){ - return stream->dtmfgen; + if (rtype==LinphoneToneGenerator) return stream->dtmfgen; + if (rtype==LinphoneLocalPlayer) return stream->local_player; + return NULL; } if (lc->ringstream==NULL){ float amp=lp_config_get_float(lc->config,"sound","dtmf_player_amp",0.1); @@ -5374,14 +5383,21 @@ static MSFilter *get_dtmf_gen(LinphoneCore *lc){ if (ringcard == NULL) return NULL; - lc->ringstream=ring_start(NULL,0,ringcard); + ringstream=lc->ringstream=ring_start(NULL,0,ringcard); ms_filter_call_method(lc->ringstream->gendtmf,MS_DTMF_GEN_SET_DEFAULT_AMPLITUDE,&); lc->dmfs_playing_start_time=time(NULL); }else{ + ringstream=lc->ringstream; if (lc->dmfs_playing_start_time!=0) lc->dmfs_playing_start_time=time(NULL); } - return lc->ringstream->gendtmf; + if (rtype==LinphoneToneGenerator) return ringstream->gendtmf; + if (rtype==LinphoneLocalPlayer) return ringstream->source; + return NULL; +} + +static MSFilter *get_dtmf_gen(LinphoneCore *lc){ + return get_audio_resource(lc,LinphoneToneGenerator); } /** @@ -5403,6 +5419,26 @@ void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms){ else ms_filter_call_method(f, MS_DTMF_GEN_START, &dtmf); } +/** + * Plays an audio file to the local user. + * This function works at any time, during calls, or when no calls are running. + * It doesn't request the underlying audio system to support multiple playback streams. + * @param lc the linphone core + * @param audiofile path to audio file in wav PCM 16 bit format. + * @ingroup misc +**/ +int linphone_core_play_local(LinphoneCore *lc, const char *audiofile){ + MSFilter *f=get_audio_resource(lc,LinphoneLocalPlayer); + int loopms=-1; + if (!f) return -1; + ms_filter_call_method(f,MS_PLAYER_SET_LOOP,&loopms); + if (ms_filter_call_method(f,MS_PLAYER_OPEN,(void*)audiofile)!=0){ + return -1; + } + ms_filter_call_method_noarg(f,MS_PLAYER_START); + return 0; +} + void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID toneid){ if (linphone_core_tone_indications_enabled(lc)){ MSFilter *f=get_dtmf_gen(lc); @@ -5443,6 +5479,19 @@ void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID toneid){ } } +void linphone_core_play_call_error_tone(LinphoneCore *lc, LinphoneReason reason){ + if (linphone_core_tone_indications_enabled(lc)){ + LinphoneToneDescription *tone=linphone_core_get_call_error_tone(lc,reason); + if (tone){ + if (tone->audiofile){ + linphone_core_play_local(lc,tone->audiofile); + }else if (tone->toneid!=LinphoneToneUndefined){ + linphone_core_play_named_tone(lc,tone->toneid); + } + } + } +} + /** * @ingroup media_parameters * @@ -5672,7 +5721,7 @@ static void sound_config_uninit(LinphoneCore *lc) if (config->local_ring) ms_free(config->local_ring); if (config->remote_ring) ms_free(config->remote_ring); - + lc->tones=ms_list_free_with_data(lc->tones, (void (*)(void*))linphone_tone_description_destroy); } static void video_config_uninit(LinphoneCore *lc) @@ -6057,7 +6106,7 @@ const char *linphone_reason_to_string(LinphoneReason err){ return "No error"; case LinphoneReasonNoResponse: return "No response"; - case LinphoneReasonBadCredentials: + case LinphoneReasonForbidden: return "Bad credentials"; case LinphoneReasonDeclined: return "Call declined"; @@ -6079,6 +6128,20 @@ const char *linphone_reason_to_string(LinphoneReason err){ return "Not acceptable here"; case LinphoneReasonNoMatch: return "No match"; + case LinphoneReasonMovedPermanently: + return "Moved permanently"; + case LinphoneReasonGone: + return "Gone"; + case LinphoneReasonTemporarilyUnavailable: + return "Temporarily unavailable"; + case LinphoneReasonAddressIncomplete: + return "Address incomplete"; + case LinphoneReasonNotImplemented: + return "Not implemented"; + case LinphoneReasonBadGateway: + return "Bad gateway"; + case LinphoneReasonServerTimeout: + return "Server timeout"; } return "unknown error"; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index f70a13ad0..32a092176 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -164,19 +164,28 @@ typedef struct _LinphoneCall LinphoneCall; enum _LinphoneReason{ LinphoneReasonNone, LinphoneReasonNoResponse, /**player,lsd_player_on_eop,b); + ms_filter_add_notify_callback (b->player,lsd_player_on_eop,b,FALSE); lsd_player_configure(b); ms_filter_call_method_noarg (b->player,MS_PLAYER_START); return 0; @@ -249,7 +249,7 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname, int rate, mp.pin=0; lsd_player_init(&lsd->branches[0],mp,MS_ITC_SOURCE_ID,lsd); - ms_filter_set_notify_callback(lsd->branches[0].player,(MSFilterNotifyFunc)lsd_player_configure,&lsd->branches[0]); + ms_filter_add_notify_callback(lsd->branches[0].player,(MSFilterNotifyFunc)lsd_player_configure,&lsd->branches[0],FALSE); for(i=1;ibranches[i],mp,MS_FILE_PLAYER_ID,lsd); diff --git a/coreapi/misc.c b/coreapi/misc.c index c64d51160..a61809464 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -1099,13 +1099,13 @@ SalReason linphone_reason_to_sal(LinphoneReason reason){ return SalReasonUnknown; case LinphoneReasonNoResponse: return SalReasonUnknown; - case LinphoneReasonBadCredentials: + case LinphoneReasonForbidden: return SalReasonForbidden; case LinphoneReasonDeclined: return SalReasonDeclined; case LinphoneReasonNotFound: return SalReasonNotFound; - case LinphoneReasonNotAnswered: + case LinphoneReasonTemporarilyUnavailable: return SalReasonTemporarilyUnavailable; case LinphoneReasonBusy: return SalReasonBusy; @@ -1121,6 +1121,20 @@ SalReason linphone_reason_to_sal(LinphoneReason reason){ return SalReasonUnsupportedContent; case LinphoneReasonNoMatch: return SalReasonNoMatch; + case LinphoneReasonMovedPermanently: + return SalReasonMovedPermanently; + case LinphoneReasonGone: + return SalReasonGone; + case LinphoneReasonAddressIncomplete: + return SalReasonAddressIncomplete; + case LinphoneReasonNotImplemented: + return SalReasonNotImplemented; + case LinphoneReasonBadGateway: + return SalReasonBadGateway; + case LinphoneReasonServerTimeout: + return SalReasonServerTimeout; + case LinphoneReasonNotAnswered: + return SalReasonRequestTimeout; } return SalReasonUnknown; } @@ -1153,7 +1167,7 @@ LinphoneReason linphone_reason_from_sal(SalReason r){ ret=LinphoneReasonNone; break; case SalReasonTemporarilyUnavailable: - ret=LinphoneReasonNone; + ret=LinphoneReasonTemporarilyUnavailable; break; case SalReasonServiceUnavailable: ret=LinphoneReasonIOError; @@ -1170,6 +1184,27 @@ LinphoneReason linphone_reason_from_sal(SalReason r){ case SalReasonNoMatch: ret=LinphoneReasonNoMatch; break; + case SalReasonRequestTimeout: + ret=LinphoneReasonNotAnswered; + break; + case SalReasonMovedPermanently: + ret=LinphoneReasonMovedPermanently; + break; + case SalReasonGone: + ret=LinphoneReasonGone; + break; + case SalReasonAddressIncomplete: + ret=LinphoneReasonAddressIncomplete; + break; + case SalReasonNotImplemented: + ret=LinphoneReasonNotImplemented; + break; + case SalReasonBadGateway: + ret=LinphoneReasonBadGateway; + break; + case SalReasonServerTimeout: + ret=LinphoneReasonServerTimeout; + break; } return ret; } @@ -1275,4 +1310,45 @@ int linphone_core_migrate_to_multi_transport(LinphoneCore *lc){ return 0; } +LinphoneToneDescription * linphone_tone_description_new(LinphoneReason reason, LinphoneToneID id, const char *audiofile){ + LinphoneToneDescription *obj=ms_new0(LinphoneToneDescription,1); + obj->reason=reason; + obj->toneid=id; + obj->audiofile=audiofile ? ms_strdup(audiofile) : NULL; + return obj; +} +void linphone_tone_description_destroy(LinphoneToneDescription *obj){ + if (obj->audiofile) ms_free(obj->audiofile); + ms_free(obj); +} + +LinphoneToneDescription *linphone_core_get_call_error_tone(const LinphoneCore *lc, LinphoneReason reason){ + const MSList *elem; + for (elem=lc->tones;elem!=NULL;elem=elem->next){ + LinphoneToneDescription *tone=(LinphoneToneDescription*)elem->data; + if (tone->reason==reason) return tone; + } + return NULL; +} + +void _linphone_core_set_call_error_tone(LinphoneCore *lc, LinphoneReason reason, LinphoneToneID id, const char *audiofile){ + LinphoneToneDescription *tone=linphone_core_get_call_error_tone(lc,reason); + if (tone){ + lc->tones=ms_list_remove(lc->tones,tone); + linphone_tone_description_destroy(tone); + } + tone=linphone_tone_description_new(reason,id,audiofile); + lc->tones=ms_list_append(lc->tones,tone); +} + +/** + * Assign an audio file to played locally upon call failure, for a given reason. + * @param lc the core + * @param reason the #LinphoneReason representing the failure error code. + * @param audiofile a wav file to be played when such call failure happens. + * @ingroup misc +**/ +void linphone_core_set_call_error_tone(LinphoneCore *lc, LinphoneReason reason, const char *audiofile){ + _linphone_core_set_call_error_tone(lc,reason,LinphoneToneUndefined, audiofile); +} diff --git a/coreapi/private.h b/coreapi/private.h index 21a62e334..7539e3bca 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -343,8 +343,6 @@ int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *msg); void linphone_core_is_composing_received(LinphoneCore *lc, SalOp *op, const SalIsComposing *is_composing); -void linphone_core_play_tone(LinphoneCore *lc); - void linphone_call_init_stats(LinphoneCallStats *stats, int type); void linphone_call_fix_call_parameters(LinphoneCall *call); void linphone_call_init_audio_stream(LinphoneCall *call); @@ -588,6 +586,26 @@ struct _LinphoneConference{ bool_t local_muted; }; +typedef enum _LinphoneToneID{ + LinphoneToneUndefined, + LinphoneToneBusy, + LinphoneToneCallWaiting, + LinphoneToneCallOnHold, + LinphoneToneCallFailed +}LinphoneToneID; + +typedef struct _LinphoneToneDescription{ + LinphoneReason reason; + LinphoneToneID toneid; + char *audiofile; +}LinphoneToneDescription; + +LinphoneToneDescription * linphone_tone_description_new(LinphoneReason reason, LinphoneToneID id, const char *audiofile); +void linphone_tone_description_destroy(LinphoneToneDescription *obj); +LinphoneToneDescription *linphone_core_get_call_error_tone(const LinphoneCore *lc, LinphoneReason reason); +void linphone_core_play_call_error_tone(LinphoneCore *lc, LinphoneReason reason); +void _linphone_core_set_call_error_tone(LinphoneCore *lc, LinphoneReason reason, LinphoneToneID id, const char *audiofile); + typedef struct _LinphoneConference LinphoneConference; struct _LinphoneCore @@ -653,10 +671,10 @@ struct _LinphoneCore bool_t use_preview_window; time_t network_last_check; + bool_t network_last_status; - bool_t ringstream_autorelease; - bool_t pad[3]; + bool_t pad[2]; int device_rotation; int max_calls; LinphoneTunnel *tunnel; @@ -670,6 +688,7 @@ struct _LinphoneCore UpnpContext *upnp; #endif //BUILD_UPNP belle_http_provider_t *http_provider; + MSList *tones; }; @@ -779,12 +798,6 @@ void linphone_chat_message_store_state(LinphoneChatMessage *msg); void linphone_core_message_storage_init(LinphoneCore *lc); void linphone_core_message_storage_close(LinphoneCore *lc); -typedef enum _LinphoneToneID{ - LinphoneToneBusy, - LinphoneToneCallWaiting, - LinphoneToneCallOnHold, - LinphoneToneCallFailed -}LinphoneToneID; void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID id); bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc); const char *linphone_core_create_uuid(LinphoneCore *lc); diff --git a/gtk/chat.c b/gtk/chat.c index 0c9aa400b..9f6e21943 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -528,6 +528,7 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room, linphone_gtk_push_text ( w,linphone_chat_message_get_from ( msg ), FALSE,room,msg,FALSE ); } + linphone_core_play_local(lc,linphone_gtk_get_sound_path("incoming_chat.wav")); linphone_gtk_show_friends(); } diff --git a/gtk/linphone.h b/gtk/linphone.h index 7c85367bc..e1df87ab3 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -170,4 +170,5 @@ void linphone_gtk_schedule_restart(void); 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); diff --git a/gtk/support.c b/gtk/support.c index de6c3a910..81754bb45 100644 --- a/gtk/support.c +++ b/gtk/support.c @@ -203,6 +203,27 @@ void linphone_gtk_set_ui_config(const char *key , const char * val){ lp_config_set_string(cfg,"GtkUi",key,val); } +const char *linphone_gtk_get_sound_path(const char *name){ + static char *ret=NULL; + const char *file; + file=linphone_gtk_get_ui_config(name,NULL); + if (file==NULL){ + char *dirname=g_path_get_dirname(name); + if (strcmp(dirname,".")!=0){ + g_free(dirname); + return name; + } + g_free(dirname); + file=name; + } + if (ret){ + g_free(ret); + ret=NULL; + } + ret=g_build_filename(PACKAGE_SOUND_DIR,name,NULL); + return ret; +} + static void parse_item(const char *item, const char *window_name, GtkWidget *w, gboolean show){ char tmp[64]; char *dot; diff --git a/include/sal/sal.h b/include/sal/sal.h index ccb013b85..7bbdb0d0a 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -314,6 +314,7 @@ typedef enum SalReason{ SalReasonBusy, SalReasonRedirect, SalReasonTemporarilyUnavailable, + SalReasonRequestTimeout, SalReasonNotFound, SalReasonDoNotDisturb, SalReasonUnsupportedContent, @@ -323,7 +324,13 @@ typedef enum SalReason{ SalReasonRequestPending, SalReasonUnauthorized, SalReasonNotAcceptable, - SalReasonNoMatch /*equivalent to 481 Transaction/Call leg does not exist*/ + SalReasonNoMatch, /*equivalent to 481 Transaction/Call leg does not exist*/ + SalReasonMovedPermanently, + SalReasonGone, + SalReasonAddressIncomplete, + SalReasonNotImplemented, + SalReasonBadGateway, + SalReasonServerTimeout }SalReason; const char* sal_reason_to_string(const SalReason reason); diff --git a/mediastreamer2 b/mediastreamer2 index 0e6be4c7c..9cd81464a 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 0e6be4c7cad7ce3d3cb4feed9a6ad52439ba365e +Subproject commit 9cd81464a916a95a5e4157276ae661d68ed3a7ee diff --git a/share/Makefile.am b/share/Makefile.am index 85c1ab11b..63f15dfe4 100644 --- a/share/Makefile.am +++ b/share/Makefile.am @@ -1,7 +1,7 @@ SUBDIRS=C fr it ja cs xml -LINPHONE_SOUNDS=ringback.wav hello8000.wav hello16000.wav +LINPHONE_SOUNDS=ringback.wav hello8000.wav hello16000.wav incoming_chat.wav LINPHONE_RINGS=rings/orig.wav \ rings/oldphone.wav \ rings/oldphone-mono.wav \ diff --git a/share/incoming_chat.wav b/share/incoming_chat.wav new file mode 100644 index 000000000..99a2e7dfc Binary files /dev/null and b/share/incoming_chat.wav differ