mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-02-07 14:18:25 +00:00
Add a property to LinphoneCalls storing the reference to the conference in which the call is part of. That property is NULL if the call is part of no conference That commit also add some documentation on several functions
751 lines
22 KiB
C++
751 lines
22 KiB
C++
/*******************************************************************************
|
|
* 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 <mediastreamer2/msvolume.h>
|
|
#include <typeinfo>
|
|
|
|
namespace Linphone {
|
|
class Conference {
|
|
public:
|
|
Conference(LinphoneCore *core);
|
|
virtual ~Conference() {};
|
|
|
|
virtual int addCall(LinphoneCall *call) = 0;
|
|
virtual int removeCall(LinphoneCall *call) = 0;
|
|
virtual int terminate() = 0;
|
|
|
|
virtual int enter() = 0;
|
|
virtual int leave() = 0;
|
|
virtual bool isIn() const = 0;
|
|
|
|
AudioStream *getAudioStream() const {return m_localParticipantStream;}
|
|
int muteMicrophone(bool val);
|
|
bool microphoneIsMuted() const {return m_isMuted;}
|
|
float getInputVolume() const;
|
|
|
|
virtual int getParticipantCount() const = 0;
|
|
|
|
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) {};
|
|
|
|
protected:
|
|
LinphoneCore *m_core;
|
|
AudioStream *m_localParticipantStream;
|
|
bool m_isMuted;
|
|
};
|
|
};
|
|
|
|
using namespace Linphone;
|
|
|
|
Conference::Conference(LinphoneCore *core) :
|
|
m_core(core),
|
|
m_localParticipantStream(NULL),
|
|
m_isMuted(false) {
|
|
}
|
|
|
|
int Conference::addCall(LinphoneCall *call) {
|
|
call->conf_ref = (LinphoneConference *)this;
|
|
return 0;
|
|
}
|
|
|
|
int Conference::removeCall(LinphoneCall *call) {
|
|
call->conf_ref = NULL;
|
|
return 0;
|
|
}
|
|
|
|
int Conference::muteMicrophone(bool val) {
|
|
if (val) {
|
|
audio_stream_set_mic_gain(m_localParticipantStream, 0);
|
|
} else {
|
|
audio_stream_set_mic_gain_db(m_localParticipantStream, m_core->sound_conf.soft_mic_lev);
|
|
}
|
|
if ( linphone_core_get_rtp_no_xmit_on_audio_mute(m_core) ){
|
|
audio_stream_mute_rtp(m_localParticipantStream, val);
|
|
}
|
|
m_isMuted=val;
|
|
return 0;
|
|
}
|
|
|
|
float Conference::getInputVolume() const {
|
|
AudioStream *st=m_localParticipantStream;
|
|
if (st && st->volsend && !m_isMuted){
|
|
float vol=0;
|
|
ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
|
|
return vol;
|
|
|
|
}
|
|
return LINPHONE_VOLUME_DB_LOWEST;
|
|
}
|
|
|
|
|
|
namespace Linphone {
|
|
class MediaConference: public Conference {
|
|
public:
|
|
MediaConference(LinphoneCore *core);
|
|
virtual ~MediaConference();
|
|
|
|
virtual int addCall(LinphoneCall *call);
|
|
virtual int removeCall(LinphoneCall *call);
|
|
virtual int terminate();
|
|
|
|
virtual int enter();
|
|
virtual int leave();
|
|
virtual bool isIn() const {return m_localParticipantStream!=NULL;}
|
|
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;
|
|
MSAudioEndpoint *m_localEndpoint;
|
|
MSAudioEndpoint *m_recordEndpoint;
|
|
RtpProfile *m_localDummyProfile;
|
|
bool_t m_terminated;
|
|
};
|
|
};
|
|
|
|
MediaConference::MediaConference(LinphoneCore *core): Conference(core),
|
|
m_conf(NULL),
|
|
m_localEndpoint(NULL),
|
|
m_recordEndpoint(NULL),
|
|
m_localDummyProfile(NULL),
|
|
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_localParticipantStream=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::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 (isIn()){
|
|
ms_message("Leaving conference for reconnecting with unique call.");
|
|
leave();
|
|
}
|
|
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_localParticipantStream) 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=isIn();
|
|
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::enter() {
|
|
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_localParticipantStream==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_localParticipantStream);
|
|
m_localParticipantStream=NULL;
|
|
rtp_profile_destroy(m_localDummyProfile);
|
|
}
|
|
}
|
|
|
|
int MediaConference::leave() {
|
|
if (isIn())
|
|
removeLocalEndpoint();
|
|
return 0;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
Conference::addCall(call);
|
|
}
|
|
|
|
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;
|
|
Conference::removeCall(call);
|
|
}
|
|
|
|
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_localParticipantStream)
|
|
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;
|
|
}
|
|
}
|
|
|
|
namespace Linphone {
|
|
class TransportConference: public Conference {
|
|
public:
|
|
TransportConference(LinphoneCore *core);
|
|
virtual ~TransportConference();
|
|
|
|
virtual int addCall(LinphoneCall *call);
|
|
virtual int removeCall(LinphoneCall *call) {return 0;}
|
|
virtual int terminate();
|
|
|
|
virtual int enter();
|
|
virtual int leave();
|
|
virtual bool isIn() const;
|
|
virtual int getParticipantCount() const {return -1;}
|
|
|
|
virtual int startRecording(const char *path) {return 0;}
|
|
virtual int stopRecording() {return 0;}
|
|
|
|
private:
|
|
enum State {
|
|
NotConnectedToFocus,
|
|
ConnectingToFocus,
|
|
ConnectedToFocus,
|
|
};
|
|
static const char *stateToString(State state);
|
|
|
|
void onFocusCallSateChanged(LinphoneCallState state);
|
|
void onPendingCallStateChanged(LinphoneCall *call, LinphoneCallState state);
|
|
|
|
static void callStateChangedCb(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message);
|
|
static void transferStateChanged(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state);
|
|
|
|
const char *m_focusAddr;
|
|
const char *m_focusContact;
|
|
LinphoneCall *m_focusCall;
|
|
State m_state;
|
|
LinphoneCoreVTable *m_vtable;
|
|
MSList *m_pendingCalls;
|
|
MSList *m_transferingCalls;
|
|
};
|
|
};
|
|
|
|
TransportConference::TransportConference(LinphoneCore *core):
|
|
Conference(core),
|
|
m_focusAddr(NULL),
|
|
m_focusContact(NULL),
|
|
m_focusCall(NULL),
|
|
m_state(NotConnectedToFocus),
|
|
m_vtable(NULL),
|
|
m_pendingCalls(NULL),
|
|
m_transferingCalls(NULL) {
|
|
m_focusAddr = lp_config_get_string(m_core->config, "misc", "conference_focus_addr", "");
|
|
m_vtable = linphone_core_v_table_new();
|
|
m_vtable->call_state_changed = callStateChangedCb;
|
|
m_vtable->transfer_state_changed = transferStateChanged;
|
|
linphone_core_v_table_set_user_data(m_vtable, this);
|
|
linphone_core_add_listener(m_core, m_vtable);
|
|
}
|
|
|
|
TransportConference::~TransportConference() {
|
|
linphone_core_remove_listener(m_core, m_vtable);
|
|
linphone_core_v_table_destroy(m_vtable);
|
|
if(m_pendingCalls) ms_list_free(m_pendingCalls);
|
|
}
|
|
|
|
int TransportConference::addCall(LinphoneCall *call) {
|
|
LinphoneAddress *addr;
|
|
|
|
switch(m_state) {
|
|
case NotConnectedToFocus:
|
|
ms_message("Calling the conference focus (%s)", m_focusAddr);
|
|
addr = linphone_address_new(m_focusAddr);
|
|
if(addr) {
|
|
m_focusCall = linphone_core_invite_address(m_core, addr);
|
|
m_localParticipantStream = m_focusCall->audiostream;
|
|
m_pendingCalls = ms_list_append(m_pendingCalls, call);
|
|
m_state = ConnectingToFocus;
|
|
linphone_address_unref(addr);
|
|
return 0;
|
|
} else return -1;
|
|
|
|
case ConnectedToFocus:
|
|
linphone_core_transfer_call(m_core, call, m_focusContact);
|
|
m_transferingCalls = ms_list_append(m_transferingCalls, call);
|
|
return 0;
|
|
|
|
default:
|
|
ms_error("Could not add call %p to the conference. Bad conference state (%s)", call, stateToString(m_state));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int TransportConference::terminate() {
|
|
switch(m_state) {
|
|
case ConnectingToFocus:
|
|
case ConnectedToFocus:
|
|
linphone_core_terminate_call(m_core, m_focusCall);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int TransportConference::enter() {
|
|
if(m_state != ConnectedToFocus) {
|
|
ms_error("Could not enter in the conference: bad conference state (%s)", stateToString(m_state));
|
|
return -1;
|
|
}
|
|
LinphoneCallState callState = linphone_call_get_state(m_focusCall);
|
|
switch(callState) {
|
|
case LinphoneCallStreamsRunning: break;
|
|
case LinphoneCallPaused:
|
|
linphone_core_resume_call(m_core, m_focusCall);
|
|
break;
|
|
default:
|
|
ms_error("Could not join the conference: bad focus call state (%s)", linphone_call_state_to_string(callState));
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int TransportConference::leave() {
|
|
if(m_state != ConnectedToFocus) {
|
|
ms_error("Could not leave the conference: bad conference state (%s)", stateToString(m_state));
|
|
return -1;
|
|
}
|
|
LinphoneCallState callState = linphone_call_get_state(m_focusCall);
|
|
switch(callState) {
|
|
case LinphoneCallPaused: break;
|
|
case LinphoneCallStreamsRunning:
|
|
linphone_core_pause_call(m_core, m_focusCall);
|
|
break;
|
|
default:
|
|
ms_error("Could not leave the conference: bad focus call state (%s)", linphone_call_state_to_string(callState));
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool TransportConference::isIn() const {
|
|
if(m_state != ConnectedToFocus) return false;
|
|
LinphoneCallState callState = linphone_call_get_state(m_focusCall);
|
|
return callState == LinphoneCallStreamsRunning;
|
|
}
|
|
|
|
const char *TransportConference::stateToString(TransportConference::State state) {
|
|
switch(state) {
|
|
case NotConnectedToFocus: return "NotConnectedToFocus";
|
|
case ConnectingToFocus: return "ConnectingToFocus";
|
|
case ConnectedToFocus: return "ConnectedToFocus";
|
|
default: return "Unknown";
|
|
}
|
|
}
|
|
|
|
void TransportConference::onFocusCallSateChanged(LinphoneCallState state) {
|
|
switch (state) {
|
|
case LinphoneCallConnected:
|
|
Conference::addCall(m_focusCall);
|
|
m_state = ConnectedToFocus;
|
|
m_focusContact = linphone_call_get_remote_contact(m_focusCall);
|
|
for (MSList *it = m_pendingCalls; it; it = it->next) {
|
|
LinphoneCall *pendingCall = (LinphoneCall *)it->data;
|
|
LinphoneCallState pendingCallState = linphone_call_get_state(pendingCall);
|
|
if(pendingCallState == LinphoneCallStreamsRunning || pendingCallState == LinphoneCallPaused) {
|
|
MSList *current_elem = it;
|
|
it = it->next;
|
|
linphone_core_transfer_call(m_core, pendingCall, m_focusContact);
|
|
m_pendingCalls = ms_list_remove_link(m_pendingCalls, current_elem);
|
|
m_transferingCalls = ms_list_append(m_transferingCalls, pendingCall);
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case LinphoneCallError:
|
|
case LinphoneCallEnd:
|
|
Conference::removeCall(m_focusCall);
|
|
m_state = NotConnectedToFocus;
|
|
m_focusCall = NULL;
|
|
m_localParticipantStream = NULL;
|
|
m_focusContact = NULL;
|
|
m_pendingCalls = ms_list_free(m_pendingCalls);
|
|
m_transferingCalls = ms_list_free(m_transferingCalls);
|
|
break;
|
|
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
void TransportConference::onPendingCallStateChanged(LinphoneCall *call, LinphoneCallState state) {
|
|
switch(state) {
|
|
case LinphoneCallStreamsRunning:
|
|
case LinphoneCallPaused:
|
|
if(m_state == ConnectedToFocus) {
|
|
linphone_core_transfer_call(m_core, call, m_focusContact);
|
|
m_pendingCalls = ms_list_remove(m_pendingCalls, call);
|
|
m_transferingCalls = ms_list_append(m_transferingCalls, call);
|
|
}
|
|
break;
|
|
|
|
case LinphoneCallError:
|
|
case LinphoneCallEnd:
|
|
m_pendingCalls = ms_list_remove(m_pendingCalls, call);
|
|
break;
|
|
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
void TransportConference::callStateChangedCb(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message) {
|
|
LinphoneCoreVTable *vtable = linphone_core_get_current_vtable(lc);
|
|
TransportConference *conf = (TransportConference *)linphone_core_v_table_get_user_data(vtable);
|
|
if (call == conf->m_focusCall) {
|
|
conf->onFocusCallSateChanged(cstate);
|
|
} else if(ms_list_find(conf->m_pendingCalls, call)) {
|
|
conf->onPendingCallStateChanged(call, cstate);
|
|
}
|
|
}
|
|
|
|
void TransportConference::transferStateChanged(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state) {
|
|
LinphoneCoreVTable *vtable = linphone_core_get_current_vtable(lc);
|
|
TransportConference *conf = (TransportConference *)linphone_core_v_table_get_user_data(vtable);
|
|
if (ms_list_find(conf->m_transferingCalls, transfered)) {
|
|
switch (new_call_state) {
|
|
case LinphoneCallConnected:
|
|
case LinphoneCallError:
|
|
conf->m_transferingCalls = ms_list_remove(conf->m_transferingCalls, transfered);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
LinphoneConference *linphone_media_conference_new(LinphoneCore *core) {
|
|
return (LinphoneConference *) new MediaConference(core);
|
|
}
|
|
|
|
LinphoneConference *linphone_transport_conference_new(LinphoneCore *core) {
|
|
return (LinphoneConference *) new TransportConference(core);
|
|
}
|
|
|
|
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)->enter();
|
|
}
|
|
|
|
int linphone_conference_remove_local_participant(LinphoneConference *obj) {
|
|
return ((Conference *)obj)->leave();
|
|
}
|
|
|
|
bool_t linphone_conference_local_participant_is_in(const LinphoneConference *obj) {
|
|
return ((Conference *)obj)->isIn() ? 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();
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
bool_t linphone_conference_check_class(LinphoneConference *obj, LinphoneConferenceClass _class) {
|
|
switch(_class) {
|
|
case LinphoneConferenceClassMedia: return typeid(obj) == typeid(MediaConference);
|
|
case LinphoneConferenceClassTransport: return typeid(obj) == typeid(TransportConference);
|
|
default: return FALSE;
|
|
}
|
|
}
|