sysapps / telephony

API to manage telephony calls
16 stars 12 forks source link

merge calls from different services/sim cards #208

Open hsinyi opened 10 years ago

hsinyi commented 10 years ago

This is a real-world user story provided by some dual-sim devices, that user is able to merge a call from sim1 and another call from sim2 into a conference call. However, the current conference call API could merge calls all on a single telephony service only.

zolkis commented 10 years ago

No, it is not the API implementation which does the merge, but the network. So it is up to the network whether the calls on the 2 SIM cards are joined. The API defines 'join' semantics, which is explained in the spec as joining all calls into a conference call. This includes the use case you mentioned. Please ack.

hsinyi commented 10 years ago

If user is going to merge the two calls from two different carriers, how the carriers/networks know that? I asked other developers with experiences in dual-sim phone development. I was told that in this case, it's the API implementation to take care of that. But as you said, if 'createConference()' merges all calls even from different sim cards, then the API (serviceId version) indeed supports that.

However I am still not very sure about how the "telephony service object" proposal addresses this user story. Will |telephonyService1.getCalls()[0].createConference()| join calls from other services, such as telephonyService2? And once the conference call is created, which TelephonyService holds this conference call? Thank you.

zolkis commented 10 years ago

This is a real-world user story provided by some dual-sim devices, that user is able to merge a call from sim1 and another call from sim2 into a conference call.

Could you please share an AT command reference about the modem that can join simultaneous calls from different SIM cards? Then, based on what assumed network feature?

Even if a modem would do that (none I know of), it is not a wide spread feature in order to be included as an API for joining 2 given calls - and that API would make no sense in GSM, since you can only join "all calls", not 2 specific calls.

The join() operation is usually based on the AT+CHLD command and it works on all calls within a single telephony service. I think it is a safe assumption that in the current context of the Telephony API (GSM: Call Hold, MultiParty and Explicit Call Transfer +CDMA: 3-way call, both working with notions of Hold and Join) this should be enough.

The implementation cannot merge calls unless the modem and the network(s) support it. You cannot possibly do anything in implementation space for that, unless we are talking about a client-side merge, like mixing the audio e.g. between a VoIP call and a CS call and sharing the microphone. Is that the use case? If yes, then that is where my previous proposal would be better: I have argued that it would be easy to implement a client-side (helper) API around addParticipant() semantics. It would be an implementation choice whether is it implemented based on GSM join, or VoIP conference, or client-side merge. The apps would work in the same way, request adding participants, which will fail if the modem/service does not support it. That would support your use case above.

Otherwise we need to keep the 'join' semantics so that it is up to the network to join all calls. So we should not have an API call like join(call1, call2) since it is erroneous, but use 'join()' without parameters (plus eventually an additional 'addParticipant()' method).

zolkis commented 10 years ago

The new draft on https://etherpad.mozilla.org/5AnQEPnpvI attempts to solve all these issues for me. It goes back to the older API style (specifying serviceId's), but still supports TelephonyService objects. Conference handling has been changed. In this version, there is a unified way how to do conference calls, either in cellular use cases, multi-sim scenario, VoIP and hybrid client-side merge.

Use cases through examples:

// create normal call
call1 = telephony.dial('+123456789', {serviceId:"sim1-sha"});
// creating a second call will put the first on hold
call2 = telephony.dial('+457656766', {serviceId:"sim1-sha"});
// now join the calls into a conference
conf1 = call2.createConference();  // works by joining active and held calls
// (works the same way both in cellular and VoIP)
// calling call1.createConference() would be equivalent

// once a conf call created, one can add more participants:
call3 = conf1.addParticipant('+155598765');

// now dial a SIP call
call4 = telephony.dial('sipid1@my-sip.org', {serviceId:"service2-sha"});
// conf1 and all call1..3 are put on hold

// create a SIP conference by inviting one more participant:
conf2 = call4.createConference('sipid2@my-sip.org', {serviceId:"service2-sha"});
// this also creates a call object in the background, retrievable by
call5 = telephony.getCall('sipid2@my-sip.org'); // may fail, too

// we can add more participants
call6 = conf2.addParticipant('sipid3@my-sip.org');

// of course at any point it is possible to do the cellular way:
// dial a new number
call7 = telephony.dial('sipid4@my-sip.org', {serviceId:"service2-sha"});
// this will put conf2 + call4 + call5 + call6 on hold, too
// then, join all SIP calls again into (the existing) conference call
conf3 = call6.createConference(); // note that conf3 === conf2

// now it's also possible to client-side-merge a SIP call (conf) with a CS call (conf)
// or a VoIP call (conf) from a different service
call8 = conf1.addParticipant('sipid3@my-sip.org');
// implementation will do getCall() first, finding call6 at service2
// so call8 === call6
// which is already in a conference on that different service,
// so the 2 conferences are merged on client side

// to add a single participant from other service:
call9 = conf2.addParticipant('sipid5@my-sip.org');
// this will do getCall() with no effect, then dial sipid5 
// then add it to conf2

// now split a CS participant
conf1.split(call2); // the implementation puts everything else on hold

Of course it is not expected that someone implements all these, but it is possible to do with the API, if someone wants to implement it. Plain old cellular use cases also work as demonstrated above, without any modifications.

As discussed on the Madrid F2F, at the moment we are fine using a createConference() with no parameters, and no 'addParticipant' method at ConferenceCall, since the API would be forward compatible with this one. Multi-SIM use cases would work fine as far as the API is concerned; real support depending on the implementation of course.

// create normal call
call1 = telephony.dial('+123456789', {serviceId:"sim1-sha"});
// creating a second call on the same service would put the first on hold
// creating it on a different SIM may disconnect the first call
call2 = telephony.dial('+457656766', {serviceId:"sim2-sha"});

// now try joining the calls into a conference
conf1 = call2.createConference();  
// possible outcomes include:
// 1. call1 is disconnected, and the createConference() will fail, so conf1 === null
// 2. call1 is on hold, but conf is not supported, 
//     so call states are not changed but conf1 === null
// 3. call1 is on hold and conf is supported and made

Please tell what do you think.

zolkis commented 10 years ago

Yes, getCalls() returns now a sequence of Call objects - thanks for noticing it.

The use case you talk about was given as an example in my previous comment, at the end. If conference is supported, then all calls are joined.

If you want to do client-side-merge of just two calls (i.e. your desired merge(call1, call2) functionality), you could do it this way:

// create normal call on SIM1
call1 = telephony.dial('+123456789', {serviceId:"sim1-sha"});

// create another normal call on SIM1
call2 = telephony.dial('+155566789', {serviceId:"sim1-sha"});
// this puts call1 on hold

// create a call on a different SIM may disconnect call1 and call2
// but let's assume it doesn't
call3 = telephony.dial('+457656766', {serviceId:"sim2-sha"});

// now try joining only call1 and call3 into a conference
conf1 = call1.createConference('+457656766');  // use the same phone number
// implementation checks on the number, sees call3, and figures out it's on SIM2
// it finds out that the platform does not support network conferencing between these
// at this point could return an error, but some implementations may continue:
// and try client-side-merge of call1 and call2
// first call2 becomes held and call1 active
// then mix audio between call1 and call3 and share the microphone
// the result is handled via a conference call object

// if the user unholds call2, that will put conf 1 (call1 + call3) on hold
call2.resume();
// now talking on call2

// we can go on and try adding another participant from a 3rd service
call3 = conf1.addParticipant('sip-id1@my-sip.com', { serviceId: "my-sip-service-sha" });
// checks on the remote party, there are no ongoing calls, service is active, makes the call
// puts call2 on hold
// now the call is active, and speech can already go on
// checks and finds that no service side conferencing is supported
// this also goes in the end to client-side-merge
// resumes conf1 with mixing audio and sharing the microphone
// the individual call objects are still maintained and are splittable any time

I think this satisfies the use case. One thing to note is that client-side conference support goes deep into the call management implementation since call state, hold state and conference state logic has to be maintained.

If you ask why don't we have another method, like merge(call1, call2), it's because:

hsinyi commented 10 years ago

Yup, I noticed your example at the end of the last comment after I sent out my comment. But I think you have revised the comment, haven't you? Anyway, sorry for not noticing the example before my previous comment :)

And I also support having only one entry point for creating a conference call. Thank you.

zolkis commented 10 years ago

Thanks hsinyi - does this mean we could continue with this draft then? There are a few issues which need to be discussed, but this seems to work pretty well with most use cases - including extensibility for supporting other cellular functionality.

hsinyi commented 10 years ago

Zoltan, yup, I am fine with the conference call proposal which meets our user story well. Let's continue. Thank you very much. :)

bossfirethegreat commented 9 years ago

Hello dear ZOlkis Very informative and interesting topic I found in your conversation I am currently studying in ICT but going to take telephony for my project besides I got a project from odesk that one of the client wants to transfer 100+ calls from a single SIM!!! normally it is not possible but one of his competitor is doing thatthat . and I have seen the live traffic even I have tested which is working perperfectly . can you please explain how can it be possible??