From 99252460f478d0a1d002af9c3e4062e91ead101c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Mon, 30 Nov 2015 11:02:49 +0100 Subject: [PATCH] Create a C++ interface in order to abstract conference systems The actual conference system has been transposed as an implementation of the freshly created interface --- coreapi/CMakeLists.txt | 3 +- coreapi/conference.cc | 527 +++++++++++++++++++++++++++++++++++++++++ coreapi/conference.h | 65 +++++ coreapi/linphonecall.c | 8 +- coreapi/linphonecore.c | 84 ++++++- coreapi/private.h | 21 +- 6 files changed, 679 insertions(+), 29 deletions(-) create mode 100644 coreapi/conference.cc create mode 100644 coreapi/conference.h diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index 2f2d59712..4f7174ab5 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -73,7 +73,6 @@ set(LINPHONE_SOURCE_FILES_C call_params.c chat.c chat_file_transfer.c - conference.c contactprovider.c content.c dict.c @@ -111,7 +110,7 @@ set(LINPHONE_SOURCE_FILES_C xmlrpc.c vtables.c ) -set(LINPHONE_SOURCE_FILES_CXX ) +set(LINPHONE_SOURCE_FILES_CXX conference.cc) if(ENABLE_TUNNEL) list(APPEND LINPHONE_SOURCE_FILES_CXX diff --git a/coreapi/conference.cc b/coreapi/conference.cc new file mode 100644 index 000000000..676c61596 --- /dev/null +++ b/coreapi/conference.cc @@ -0,0 +1,527 @@ +/******************************************************************************* + * conference.cc + * + * Thu Nov 26, 2015 + * Copyright 2015 Belledonne Communications + * Author: Linphone's team + * Email info@belledonne-communications.com + ******************************************************************************/ + +/* + * 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 "private.h" +#include "conference.h" +#include + +namespace Linphone { +class Conference { +public: + enum Method { + Unknown = 0, + Media = 1, + Transport = 2 + }; + + Conference(LinphoneCore *core, Method method); + virtual ~Conference() {}; + + virtual int addCall(LinphoneCall *call) = 0; + virtual int removeCall(LinphoneCall *call) = 0; + virtual int terminate() = 0; + + virtual int addLocalParticipant() = 0; + virtual int removeLocalParticipant() = 0; + virtual bool localParticipantIsIn() const = 0; + virtual AudioStream *getAudioStream() const = 0; + + virtual int muteMicrophone(bool val) = 0; + virtual bool microphoneIsMuted() const = 0; + virtual float getInputVolume() const = 0; + virtual int getParticipantCount() const = 0; + Method getMethod() const {return m_method;} + + virtual int startRecording(const char *path) = 0; + virtual int stopRecording() = 0; + + virtual void onCallStreamStarting(LinphoneCall *call, bool isPausedByRemote) {}; + virtual void onCallStreamStopping(LinphoneCall *call) {}; + virtual void onCallTerminating(LinphoneCall *call) {}; + + static Conference *make(LinphoneCore *core, Conference::Method method); + +protected: + LinphoneCore *m_core; + Method m_method; +}; +}; + +using namespace Linphone; + +Conference::Conference(LinphoneCore *core, Conference::Method type) : + m_core(core), + m_method(type) { +} + + +namespace Linphone { +class MediaConference: public Conference { +public: + MediaConference(LinphoneCore *core); + virtual ~MediaConference(); + + virtual int addCall(LinphoneCall *call); + virtual int addAllCalls(LinphoneCall &call); + virtual int removeCall(LinphoneCall *call); + virtual int terminate(); + + virtual int addLocalParticipant(); + virtual int removeLocalParticipant(); + virtual bool localParticipantIsIn() const {return m_localParticipant!=NULL;} + virtual AudioStream *getAudioStream() const {return m_localParticipant;} + + virtual int muteMicrophone(bool val); + virtual bool microphoneIsMuted() const {return m_localMuted;} + virtual float getInputVolume() const; + virtual int getParticipantCount() const; + + virtual int startRecording(const char *path); + virtual int stopRecording(); + + void onCallStreamStarting(LinphoneCall *call, bool isPausedByRemote); + void onCallStreamStopping(LinphoneCall *call); + void onCallTerminating(LinphoneCall *call); + +private: + void addLocalEndpoint(); + int remoteParticipantsCount(); + void removeLocalEndpoint(); + int removeFromConference(LinphoneCall *call, bool_t active); + int convertConferenceToCall(); + static RtpProfile *sMakeDummyProfile(int samplerate); + + MSAudioConference *m_conf; + AudioStream *m_localParticipant; + MSAudioEndpoint *m_localEndpoint; + MSAudioEndpoint *m_recordEndpoint; + RtpProfile *m_localDummyProfile; + bool_t m_localMuted; + bool_t m_terminated; +}; +}; + +MediaConference::MediaConference(LinphoneCore *core): Conference(core, Media), + m_conf(NULL), + m_localParticipant(NULL), + m_localEndpoint(NULL), + m_recordEndpoint(NULL), + m_localDummyProfile(NULL), + m_localMuted(FALSE), + m_terminated(FALSE) { + MSAudioConferenceParams params; + params.samplerate = lp_config_get_int(m_core->config, "sound","conference_rate",16000); + m_conf=ms_audio_conference_new(¶ms); +} + +MediaConference::~MediaConference() { + if(m_conf) terminate(); +} + +RtpProfile *MediaConference::sMakeDummyProfile(int samplerate){ + RtpProfile *prof=rtp_profile_new("dummy"); + PayloadType *pt=payload_type_clone(&payload_type_l16_mono); + pt->clock_rate=samplerate; + rtp_profile_set_payload(prof,0,pt); + return prof; +} + +void MediaConference::addLocalEndpoint() { + /*create a dummy audiostream in order to extract the local part of it */ + /* network address and ports have no meaning and are not used here. */ + AudioStream *st=audio_stream_new(65000,65001,FALSE); + MSSndCard *playcard=m_core->sound_conf.lsd_card ? + m_core->sound_conf.lsd_card : m_core->sound_conf.play_sndcard; + MSSndCard *captcard=m_core->sound_conf.capt_sndcard; + const MSAudioConferenceParams *params=ms_audio_conference_get_params(m_conf); + m_localDummyProfile=sMakeDummyProfile(params->samplerate); + + audio_stream_start_full(st, m_localDummyProfile, + "127.0.0.1", + 65000, + "127.0.0.1", + 65001, + 0, + 40, + NULL, + NULL, + playcard, + captcard, + linphone_core_echo_cancellation_enabled(m_core) + ); + _post_configure_audio_stream(st,m_core,FALSE); + m_localParticipant=st; + m_localEndpoint=ms_audio_endpoint_get_from_stream(st,FALSE); + ms_audio_conference_add_member(m_conf,m_localEndpoint); +} + +int MediaConference::addCall(LinphoneCall *call) { + if (call->current_params->in_conference){ + ms_error("Already in conference"); + return -1; + } + + if (call->state==LinphoneCallPaused){ + call->params->in_conference=TRUE; + call->params->has_video=FALSE; + linphone_core_resume_call(m_core,call); + }else if (call->state==LinphoneCallStreamsRunning){ + LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call)); + params->in_conference=TRUE; + params->has_video=FALSE; + + if (call->audiostream || call->videostream){ + linphone_call_stop_media_streams(call); /*free the audio & video local resources*/ + linphone_call_init_media_streams(call); + } + if (call==m_core->current_call){ + m_core->current_call=NULL; + } + /*this will trigger a reINVITE that will later redraw the streams */ + /*FIXME probably a bit too much to just redraw streams !*/ + linphone_core_update_call(m_core,call,params); + linphone_call_params_destroy(params); + addLocalEndpoint(); + }else{ + ms_error("Call is in state %s, it cannot be added to the conference.",linphone_call_state_to_string(call->state)); + return -1; + } + return 0; +} + +int MediaConference::addAllCalls(LinphoneCall &call) { + MSList *calls=m_core->calls; + while (calls) { + LinphoneCall *call=(LinphoneCall*)calls->data; + calls=calls->next; + if (!call->current_params->in_conference) addCall(call); + } + addLocalParticipant(); + return 0; +} + +int MediaConference::removeFromConference(LinphoneCall *call, bool_t active){ + int err=0; + char *str; + + if (!call->current_params->in_conference){ + if (call->params->in_conference){ + ms_warning("Not (yet) in conference, be patient"); + return -1; + }else{ + ms_error("Not in a conference."); + return -1; + } + } + call->params->in_conference=FALSE; + + str=linphone_call_get_remote_address_as_string(call); + ms_message("%s will be removed from conference", str); + ms_free(str); + if (active){ + LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call)); + params->in_conference=FALSE; + // reconnect local audio with this call + if (localParticipantIsIn()){ + ms_message("Leaving conference for reconnecting with unique call."); + removeLocalParticipant(); + } + ms_message("Updating call to actually remove from conference"); + err=linphone_core_update_call(m_core,call,params); + linphone_call_params_destroy(params); + } else{ + ms_message("Pausing call to actually remove from conference"); + err=_linphone_core_pause_call(m_core,call); + } + return err; +} + +int MediaConference::remoteParticipantsCount() { + int count=getParticipantCount(); + if (count==0) return 0; + if (!m_localParticipant) return count; + return count -1; +} + +int MediaConference::convertConferenceToCall(){ + int err=0; + MSList *calls=m_core->calls; + + if (remoteParticipantsCount()!=1){ + ms_error("No unique call remaining in conference."); + return -1; + } + + while (calls) { + LinphoneCall *rc=(LinphoneCall*)calls->data; + calls=calls->next; + if (rc->params->in_conference) { // not using current_param + bool_t active_after_removed=localParticipantIsIn(); + err=removeFromConference(rc, active_after_removed); + break; + } + } + return err; +} + +int MediaConference::removeCall(LinphoneCall *call) { + int err; + char * str=linphone_call_get_remote_address_as_string(call); + ms_message("Removing call %s from the conference", str); + ms_free(str); + err=removeFromConference(call, FALSE); + if (err){ + ms_error("Error removing participant from conference."); + return err; + } + + if (remoteParticipantsCount()==1){ + ms_message("conference size is 1: need to be converted to plain call"); + err=convertConferenceToCall(); + } else { + ms_message("the conference need not to be converted as size is %i", remoteParticipantsCount()); + } + return err; +} + +int MediaConference::terminate() { + MSList *calls=m_core->calls; + m_terminated=TRUE; + + while (calls) { + LinphoneCall *call=(LinphoneCall*)calls->data; + calls=calls->next; + if (call->current_params->in_conference) { + linphone_core_terminate_call(m_core, call); + } + } + return 0; +} + +int MediaConference::addLocalParticipant() { + if (linphone_core_sound_resources_locked(m_core)) { + return -1; + } + if (m_core->current_call != NULL) { + _linphone_core_pause_call(m_core, m_core->current_call); + } + if (m_localParticipant==NULL) addLocalEndpoint(); + return 0; +} + +void MediaConference::removeLocalEndpoint(){ + if (m_localEndpoint){ + ms_audio_conference_remove_member(m_conf,m_localEndpoint); + ms_audio_endpoint_release_from_stream(m_localEndpoint); + m_localEndpoint=NULL; + audio_stream_stop(m_localParticipant); + m_localParticipant=NULL; + rtp_profile_destroy(m_localDummyProfile); + } +} + +int MediaConference::removeLocalParticipant() { + if (localParticipantIsIn()) + removeLocalEndpoint(); + return 0; +} + +int MediaConference::muteMicrophone(bool val) { + if (val) { + audio_stream_set_mic_gain(m_localParticipant, 0); + } else { + audio_stream_set_mic_gain_db(m_localParticipant, m_core->sound_conf.soft_mic_lev); + } + if ( linphone_core_get_rtp_no_xmit_on_audio_mute(m_core) ){ + audio_stream_mute_rtp(m_localParticipant, val); + } + m_localMuted=val; + return 0; +} + +float MediaConference::getInputVolume() const { + AudioStream *st=m_localParticipant; + if (st && st->volsend && !m_localMuted){ + float vol=0; + ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol); + return vol; + + } + return LINPHONE_VOLUME_DB_LOWEST; +} + +int MediaConference::getParticipantCount() const { + if (m_conf == NULL) { + return 0; + } + return ms_audio_conference_get_size(m_conf) - (m_recordEndpoint ? 1 : 0); +} + +int MediaConference::startRecording(const char *path) { + if (m_conf == NULL) { + ms_warning("linphone_core_start_conference_recording(): no conference now."); + return -1; + } + if (m_recordEndpoint==NULL){ + m_recordEndpoint=ms_audio_endpoint_new_recorder(); + ms_audio_conference_add_member(m_conf,m_recordEndpoint); + } + ms_audio_recorder_endpoint_start(m_recordEndpoint,path); + return 0; +} + +int MediaConference::stopRecording() { + if (m_conf == NULL) { + ms_warning("linphone_core_stop_conference_recording(): no conference now."); + return -1; + } + if (m_recordEndpoint==NULL){ + ms_warning("linphone_core_stop_conference_recording(): no record active."); + return -1; + } + ms_audio_recorder_endpoint_stop(m_recordEndpoint); + return 0; +} + +Conference *Conference::make(LinphoneCore *core, Conference::Method type) { + switch(type) { + case Media: + return new MediaConference(core); + default: + return NULL; + } +} + +void MediaConference::onCallStreamStarting(LinphoneCall *call, bool isPausedByRemote) { + call->params->has_video = FALSE; + call->camera_enabled = FALSE; + MSAudioEndpoint *ep=ms_audio_endpoint_get_from_stream(call->audiostream,TRUE); + ms_audio_conference_add_member(m_conf,ep); + ms_audio_conference_mute_member(m_conf,ep,isPausedByRemote); + call->endpoint=ep; +} + +void MediaConference::onCallStreamStopping(LinphoneCall *call) { + ms_audio_conference_remove_member(m_conf,call->endpoint); + ms_audio_endpoint_release_from_stream(call->endpoint); + call->endpoint=NULL; +} + +void MediaConference::onCallTerminating(LinphoneCall *call) { + int remote_count=remoteParticipantsCount(); + ms_message("conference_check_uninit(): size=%i", getParticipantCount()); + if (remote_count==1 && !m_terminated){ + convertConferenceToCall(); + } + if (remote_count==0){ + if (m_localParticipant) + removeLocalEndpoint(); + if (m_recordEndpoint){ + ms_audio_conference_remove_member(m_conf, m_recordEndpoint); + ms_audio_endpoint_destroy(m_recordEndpoint); + } + } + if (ms_audio_conference_get_size(m_conf)==0){ + ms_audio_conference_destroy(m_conf); + m_core->conf_ctx = NULL; + delete this; + } +} + +LinphoneConference *linphone_conference_make(LinphoneCore *core, LinphoneConferenceType type) { + return Conference::make(core, (Conference::Method)type); +} + +void linphone_conference_free(LinphoneConference *obj) { + delete (Conference *)obj; +} + +int linphone_conference_add_call(LinphoneConference *obj, LinphoneCall *call) { + return ((Conference *)obj)->addCall(call); +} + +int linphone_conference_remove_call(LinphoneConference *obj, LinphoneCall *call) { + return ((Conference *)obj)->removeCall(call); +} + +int linphone_conference_terminate(LinphoneConference *obj) { + return ((Conference *)obj)->terminate(); +} + +int linphone_conference_add_local_participant(LinphoneConference *obj) { + return ((Conference *)obj)->addLocalParticipant(); +} + +int linphone_conference_remove_local_participant(LinphoneConference *obj) { + return ((Conference *)obj)->removeLocalParticipant(); +} + +bool_t linphone_conference_local_participant_is_in(const LinphoneConference *obj) { + return ((Conference *)obj)->localParticipantIsIn() ? TRUE : FALSE; +} + +AudioStream *linphone_conference_get_audio_stream(const LinphoneConference *obj) { + return ((Conference *)obj)->getAudioStream(); +} + +int linphone_conference_mute_microphone(LinphoneConference *obj, bool_t val) { + return ((Conference *)obj)->muteMicrophone(val); +} + +bool_t linphone_conference_microphone_is_muted(const LinphoneConference *obj) { + return ((Conference *)obj)->microphoneIsMuted(); +} + +float linphone_conference_get_input_volume(const LinphoneConference *obj) { + return ((Conference *)obj)->getInputVolume(); +} + +int linphone_conference_get_participant_count(const LinphoneConference *obj) { + return ((Conference *)obj)->getParticipantCount(); +} + +LinphoneConferenceType linphone_conference_get_method(const LinphoneConference *obj) { + return (LinphoneConferenceType)((Conference *)obj)->getMethod(); +} + +int linphone_conference_start_recording(LinphoneConference *obj, const char *path) { + return ((Conference *)obj)->startRecording(path); +} + +int linphone_conference_stop_recording(LinphoneConference *obj) { + return ((Conference *)obj)->stopRecording(); +} + +void linphone_conference_on_call_stream_starting(LinphoneConference *obj, LinphoneCall *call, bool_t is_paused_by_remote) { + ((Conference *)obj)->onCallStreamStarting(call, is_paused_by_remote); +} + +void linphone_conference_on_call_stream_stopping(LinphoneConference *obj, LinphoneCall *call) { + ((Conference *)obj)->onCallStreamStopping(call); +} + +void linphone_conference_on_call_terminating(LinphoneConference *obj, LinphoneCall *call) { + ((Conference *)obj)->onCallTerminating(call); +} diff --git a/coreapi/conference.h b/coreapi/conference.h new file mode 100644 index 000000000..c592e8fb7 --- /dev/null +++ b/coreapi/conference.h @@ -0,0 +1,65 @@ +/******************************************************************************* + * conference.cc + * + * Thu Nov 26, 2015 + * Copyright 2015 Belledonne Communications + * Author: Linphone's team + * Email info@belledonne-communications.com + ******************************************************************************/ + +/* + * 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. + */ + +#ifndef CONFERENCE_H +#define CONFERENCE_H + +#include "linphonecore.h" + +typedef enum _LinphoneConferenceType { + LinphoneConferenceTypeUnknown = 0, + LinphoneConferenceTypeMedia = 1, + LinphoneConferenceTypeTransport = 2 +} LinphoneConferenceType; + + +typedef void LinphoneConference; + +LinphoneConference *linphone_conference_make(LinphoneCore *core, LinphoneConferenceType type); +void linphone_conference_free(LinphoneConference *obj); + +int linphone_conference_add_call(LinphoneConference *obj, LinphoneCall *call); +int linphone_conference_remove_call(LinphoneConference *obj, LinphoneCall *call); +int linphone_conference_terminate(LinphoneConference *obj); + +int linphone_conference_add_local_participant(LinphoneConference *obj); +int linphone_conference_remove_local_participant(LinphoneConference *obj); +bool_t linphone_conference_local_participant_is_in(const LinphoneConference *obj); +AudioStream *linphone_conference_get_audio_stream(const LinphoneConference *obj); + +int linphone_conference_mute_microphone(LinphoneConference *obj, bool_t val); +bool_t linphone_conference_microphone_is_muted(const LinphoneConference *obj); +float linphone_conference_get_input_volume(const LinphoneConference *obj); +int linphone_conference_get_participant_count(const LinphoneConference *obj); +LinphoneConferenceType linphone_conference_get_method(const LinphoneConference *obj); + +int linphone_conference_start_recording(LinphoneConference *obj, const char *path); +int linphone_conference_stop_recording(LinphoneConference *obj); + +void linphone_conference_on_call_stream_starting(LinphoneConference *obj, LinphoneCall *call, bool_t is_paused_by_remote); +void linphone_conference_on_call_stream_stopping(LinphoneConference *obj, LinphoneCall *call); +void linphone_conference_on_call_terminating(LinphoneConference *obj, LinphoneCall *call); + +#endif // CONFERENCE_H diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index a0b20ec63..35a2c2c6a 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1424,7 +1424,7 @@ static void linphone_call_set_terminated(LinphoneCall *call){ if (linphone_core_del_call(lc,call) != 0){ ms_error("Could not remove the call from the list !!!"); } - linphone_core_conference_check_uninit(lc); + if(lc->conf_ctx) linphone_conference_on_call_terminating(lc->conf_ctx, call); if (call->ringing_beep){ linphone_core_stop_dtmf(lc); call->ringing_beep=FALSE; @@ -3091,7 +3091,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, LinphoneCallSta if (call->params->in_conference){ /*transform the graph to connect it to the conference filter */ mute = stream->dir==SalStreamRecvOnly; - linphone_call_add_to_conf(call, mute); + linphone_conference_on_call_stream_starting(lc->conf_ctx, call, mute); } call->current_params->in_conference=call->params->in_conference; call->current_params->low_bandwidth=call->params->low_bandwidth; @@ -3575,6 +3575,7 @@ static void update_rtp_stats(LinphoneCall *call, int stream_index) { } static void linphone_call_stop_audio_stream(LinphoneCall *call) { + LinphoneCore *lc = call->core; if (call->audiostream!=NULL) { linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_AUDIO); media_stream_reclaim_sessions(&call->audiostream->ms,&call->sessions[call->main_audio_stream_index]); @@ -3590,7 +3591,7 @@ static void linphone_call_stop_audio_stream(LinphoneCall *call) { audio_stream_get_local_rtp_stats(call->audiostream,&call->log->local_stats); linphone_call_log_fill_stats (call->log,(MediaStream*)call->audiostream); if (call->endpoint){ - linphone_call_remove_from_conf(call); + linphone_conference_on_call_stream_stopping(lc->conf_ctx, call); } update_rtp_stats(call, call->main_audio_stream_index); audio_stream_stop(call->audiostream); @@ -4851,4 +4852,3 @@ void linphone_call_refresh_sockets(LinphoneCall *call){ } } } - diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 38da0256e..64531e463 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4853,8 +4853,7 @@ void linphone_core_mute_mic(LinphoneCore *lc, bool_t val){ const MSList *elem; if (linphone_core_is_in_conference(lc)){ - lc->conf_ctx.local_muted=val; - linphone_core_mute_audio_stream(lc, lc->conf_ctx.local_participant, val); + linphone_conference_mute_microphone(lc->conf_ctx, val); } list = linphone_core_get_calls(lc); for (elem = list; elem != NULL; elem = elem->next) { @@ -4867,7 +4866,7 @@ void linphone_core_mute_mic(LinphoneCore *lc, bool_t val){ bool_t linphone_core_is_mic_muted(LinphoneCore *lc) { LinphoneCall *call=linphone_core_get_current_call(lc); if (linphone_core_is_in_conference(lc)){ - return lc->conf_ctx.local_muted; + return linphone_conference_microphone_is_muted(lc->conf_ctx); }else if (call==NULL){ ms_warning("linphone_core_is_mic_muted(): No current call !"); return FALSE; @@ -5896,7 +5895,7 @@ static MSFilter *get_audio_resource(LinphoneCore *lc, LinphoneAudioResourceType if (call){ stream=call->audiostream; }else if (linphone_core_is_in_conference(lc)){ - stream=lc->conf_ctx.local_participant; + stream=linphone_conference_get_audio_stream(lc->conf_ctx); } if (stream){ if (rtype==LinphoneToneGenerator) return stream->dtmfgen; @@ -7397,3 +7396,80 @@ const char *linphone_stream_type_to_string(const LinphoneStreamType type) { } return "INVALID"; } + +int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call) { + const char *conf_method_name; + LinphoneConferenceType method; + if(lc->conf_ctx == NULL) { + conf_method_name = lp_config_get_string(lc->config, "misc", "conference_method", "media"); + if(strcasecmp(conf_method_name, "media") == 0) { + method = LinphoneConferenceTypeMedia; + } else if(strcasecmp(conf_method_name, "transport") == 0) { + method = LinphoneConferenceTypeTransport; + } else { + ms_error("'%s' is not a valid conference method", conf_method_name); + return -1; + } + lc->conf_ctx = linphone_conference_make(lc, method); + } + return linphone_conference_add_call(lc->conf_ctx, call); +} + +int linphone_core_add_all_to_conference(LinphoneCore *lc) { + MSList *calls=lc->calls; + while (calls) { + LinphoneCall *call=(LinphoneCall*)calls->data; + calls=calls->next; + linphone_core_add_to_conference(lc, call); + } + linphone_core_enter_conference(lc); + return 0; +} + +int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call) { + if(lc->conf_ctx) return linphone_conference_remove_call(lc->conf_ctx, call); + else return -1; +} + +int linphone_core_terminate_conference(LinphoneCore *lc) { + if(lc->conf_ctx == NULL) return -1; + linphone_conference_terminate(lc->conf_ctx); + linphone_conference_free(lc->conf_ctx); + lc->conf_ctx = NULL; + return 0; +} + +int linphone_core_enter_conference(LinphoneCore *lc) { + if(lc->conf_ctx) return linphone_conference_add_local_participant(lc->conf_ctx); + else return -1; +} + +int linphone_core_leave_conference(LinphoneCore *lc) { + if(lc->conf_ctx) return linphone_conference_remove_local_participant(lc->conf_ctx); + else return -1; +} + +bool_t linphone_core_is_in_conference(const LinphoneCore *lc) { + if(lc->conf_ctx) return linphone_conference_local_participant_is_in(lc->conf_ctx); + else return FALSE; +} + +int linphone_core_get_conference_size(LinphoneCore *lc) { + if(lc->conf_ctx) return linphone_conference_get_participant_count(lc->conf_ctx); + return 0; +} + +float linphone_core_get_conference_local_input_volume(LinphoneCore *lc) { + if(lc->conf_ctx) return linphone_conference_get_input_volume(lc->conf_ctx); + else return -1.0; +} + +int linphone_core_start_conference_recording(LinphoneCore *lc, const char *path) { + if(lc->conf_ctx) return linphone_conference_start_recording(lc->conf_ctx, path); + return -1; +} + +int linphone_core_stop_conference_recording(LinphoneCore *lc) { + if(lc->conf_ctx) return linphone_conference_stop_recording(lc->conf_ctx); + return -1; +} diff --git a/coreapi/private.h b/coreapi/private.h index 84d26357e..ddefa75cc 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -32,6 +32,7 @@ extern "C" { #include "linphonefriend.h" #include "linphone_tunnel.h" #include "linphonecore_utils.h" +#include "conference.h" #include "sal/sal.h" #include "sipsetup.h" #include "quality_reporting.h" @@ -783,16 +784,6 @@ typedef struct autoreplier_config const char *message; /* the path of the file to be played */ }autoreplier_config_t; -struct _LinphoneConference{ - MSAudioConference *conf; - AudioStream *local_participant; - MSAudioEndpoint *local_endpoint; - MSAudioEndpoint *record_endpoint; - RtpProfile *local_dummy_profile; - bool_t local_muted; - bool_t terminated; -}; - typedef struct _LinphoneToneDescription{ LinphoneReason reason; @@ -807,7 +798,6 @@ void linphone_core_play_call_error_tone(LinphoneCore *lc, LinphoneReason reason) void _linphone_core_set_tone(LinphoneCore *lc, LinphoneReason reason, LinphoneToneID id, const char *audiofile); const char *linphone_core_get_tone_file(const LinphoneCore *lc, LinphoneToneID id); int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params, LinphoneCallState next_state, const char *state_info); -typedef struct _LinphoneConference LinphoneConference; typedef struct _LinphoneTaskList{ MSList *hooks; @@ -869,7 +859,7 @@ struct _LinphoneCore time_t netup_time; /*time when network went reachable */ struct _EcCalibrator *ecc; LinphoneTaskList hooks; /*tasks periodically executed in linphone_core_iterate()*/ - LinphoneConference conf_ctx; + LinphoneConference *conf_ctx; char* zrtp_secrets_cache; char* user_certificates_path; LinphoneVideoPolicy video_policy; @@ -1000,13 +990,6 @@ int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call); /*conferencing subsystem*/ void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted); -/* When a conference participant pause the conference he may send a music. - * We don't want to hear that music or to send it to the other participants. - * Use muted=yes to handle this case. - */ -void linphone_call_add_to_conf(LinphoneCall *call, bool_t muted); -void linphone_call_remove_from_conf(LinphoneCall *call); -void linphone_core_conference_check_uninit(LinphoneCore *lc); bool_t linphone_core_sound_resources_available(LinphoneCore *lc); void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, LinphoneCall *newcall); unsigned int linphone_core_get_audio_features(LinphoneCore *lc);