play busy and dial tones
This commit is contained in:
parent
07911b2094
commit
fc4397e5b9
|
@ -50,9 +50,10 @@ import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
|
|||
import rocks.xmpp.addr.Jid;
|
||||
|
||||
public class JingleConnectionManager extends AbstractConnectionManager {
|
||||
private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
|
||||
public static final ScheduledExecutorService SCHEDULED_EXECUTOR_SERVICE = Executors.newSingleThreadScheduledExecutor();
|
||||
public final ToneManager toneManager = new ToneManager();
|
||||
private final HashMap<RtpSessionProposal, DeviceDiscoveryState> rtpSessionProposals = new HashMap<>();
|
||||
private final Map<AbstractJingleConnection.Id, AbstractJingleConnection> connections = new ConcurrentHashMap<>();
|
||||
private final ConcurrentHashMap<AbstractJingleConnection.Id, AbstractJingleConnection> connections = new ConcurrentHashMap<>();
|
||||
|
||||
private final Cache<PersistableSessionId, JingleRtpConnection.State> endedSessions = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(30, TimeUnit.MINUTES)
|
||||
|
@ -141,7 +142,7 @@ public class JingleConnectionManager extends AbstractConnectionManager {
|
|||
}
|
||||
|
||||
ScheduledFuture<?> schedule(final Runnable runnable, final long delay, final TimeUnit timeUnit) {
|
||||
return this.scheduledExecutorService.schedule(runnable, delay, timeUnit);
|
||||
return this.SCHEDULED_EXECUTOR_SERVICE.schedule(runnable, delay, timeUnit);
|
||||
}
|
||||
|
||||
void respondWithJingleError(final Account account, final IqPacket original, String jingleCondition, String condition, String conditionType) {
|
||||
|
@ -268,6 +269,7 @@ public class JingleConnectionManager extends AbstractConnectionManager {
|
|||
synchronized (rtpSessionProposals) {
|
||||
if (rtpSessionProposals.remove(proposal) != null) {
|
||||
writeLogMissedOutgoing(account, proposal.with, proposal.sessionId, serverMsgId, timestamp);
|
||||
toneManager.transition(true, RtpEndUserState.DECLINED_OR_BUSY);
|
||||
mXmppConnectionService.notifyJingleRtpConnectionUpdate(account, proposal.with, proposal.sessionId, RtpEndUserState.DECLINED_OR_BUSY);
|
||||
} else {
|
||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": no rtp session proposal found for " + from + " to deliver reject");
|
||||
|
@ -352,7 +354,7 @@ public class JingleConnectionManager extends AbstractConnectionManager {
|
|||
}
|
||||
|
||||
public Optional<AbstractJingleConnection.Id> getOngoingRtpConnection(final Contact contact) {
|
||||
for(final Map.Entry<AbstractJingleConnection.Id,AbstractJingleConnection> entry : this.connections.entrySet()) {
|
||||
for (final Map.Entry<AbstractJingleConnection.Id, AbstractJingleConnection> entry : this.connections.entrySet()) {
|
||||
if (entry.getValue() instanceof JingleRtpConnection) {
|
||||
final AbstractJingleConnection.Id id = entry.getKey();
|
||||
if (id.account == contact.getAccount() && id.with.asBareJid().equals(contact.getJid().asBareJid())) {
|
||||
|
@ -423,6 +425,7 @@ public class JingleConnectionManager extends AbstractConnectionManager {
|
|||
}
|
||||
}
|
||||
if (matchingProposal != null) {
|
||||
toneManager.transition(true, RtpEndUserState.ENDED);
|
||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": retracting rtp session proposal with " + with);
|
||||
this.rtpSessionProposals.remove(matchingProposal);
|
||||
final MessagePacket messagePacket = mXmppConnectionService.getMessageGenerator().sessionRetract(matchingProposal);
|
||||
|
@ -439,11 +442,13 @@ public class JingleConnectionManager extends AbstractConnectionManager {
|
|||
if (proposal.account == account && with.asBareJid().equals(proposal.with)) {
|
||||
final DeviceDiscoveryState preexistingState = entry.getValue();
|
||||
if (preexistingState != null && preexistingState != DeviceDiscoveryState.FAILED) {
|
||||
final RtpEndUserState endUserState = preexistingState.toEndUserState();
|
||||
toneManager.transition(true, endUserState);
|
||||
mXmppConnectionService.notifyJingleRtpConnectionUpdate(
|
||||
account,
|
||||
with,
|
||||
proposal.sessionId,
|
||||
preexistingState.toEndUserState()
|
||||
endUserState
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
@ -529,7 +534,9 @@ public class JingleConnectionManager extends AbstractConnectionManager {
|
|||
return;
|
||||
}
|
||||
this.rtpSessionProposals.put(sessionProposal, target);
|
||||
mXmppConnectionService.notifyJingleRtpConnectionUpdate(account, sessionProposal.with, sessionProposal.sessionId, target.toEndUserState());
|
||||
final RtpEndUserState endUserState = target.toEndUserState();
|
||||
toneManager.transition(true, endUserState);
|
||||
mXmppConnectionService.notifyJingleRtpConnectionUpdate(account, sessionProposal.with, sessionProposal.sessionId, endUserState);
|
||||
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": flagging session " + sessionId + " as " + target);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1027,7 +1027,11 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
|
|||
}
|
||||
|
||||
private void updateEndUserState() {
|
||||
xmppConnectionService.notifyJingleRtpConnectionUpdate(id.account, id.with, id.sessionId, getEndUserState());
|
||||
final RtpEndUserState endUserState = getEndUserState();
|
||||
final RtpContentMap contentMap = initiatorRtpContentMap;
|
||||
final Set<Media> media = contentMap == null ? Collections.emptySet() : contentMap.getMedia();
|
||||
jingleConnectionManager.toneManager.transition(isInitiator(), endUserState, media);
|
||||
xmppConnectionService.notifyJingleRtpConnectionUpdate(id.account, id.with, id.sessionId, endUserState);
|
||||
}
|
||||
|
||||
private void updateOngoingCallNotification() {
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
package eu.siacs.conversations.xmpp.jingle;
|
||||
|
||||
import android.media.AudioManager;
|
||||
import android.media.ToneGenerator;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import eu.siacs.conversations.Config;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class ToneManager {
|
||||
|
||||
private final ToneGenerator toneGenerator;
|
||||
|
||||
private ToneState state = null;
|
||||
private ScheduledFuture<?> currentTone;
|
||||
|
||||
public ToneManager() {
|
||||
this.toneGenerator = new ToneGenerator(AudioManager.STREAM_VOICE_CALL, 35);
|
||||
}
|
||||
|
||||
public void transition(final boolean isInitiator, final RtpEndUserState state) {
|
||||
transition(of(isInitiator, state, Collections.emptySet()));
|
||||
}
|
||||
|
||||
public void transition(final boolean isInitiator, final RtpEndUserState state, final Set<Media> media) {
|
||||
transition(of(isInitiator, state, media));
|
||||
}
|
||||
|
||||
private static ToneState of(final boolean isInitiator, final RtpEndUserState state, final Set<Media> media) {
|
||||
if (isInitiator) {
|
||||
if (asList(RtpEndUserState.RINGING, RtpEndUserState.CONNECTING).contains(state)) {
|
||||
return ToneState.RINGING;
|
||||
}
|
||||
if (state == RtpEndUserState.DECLINED_OR_BUSY) {
|
||||
return ToneState.BUSY;
|
||||
}
|
||||
}
|
||||
if (state == RtpEndUserState.ENDING_CALL) {
|
||||
if (media.contains(Media.VIDEO)) {
|
||||
return ToneState.NULL;
|
||||
} else {
|
||||
return ToneState.ENDING_CALL;
|
||||
}
|
||||
}
|
||||
return ToneState.NULL;
|
||||
}
|
||||
|
||||
private synchronized void transition(ToneState state) {
|
||||
if (this.state == state) {
|
||||
return;
|
||||
}
|
||||
if (state == ToneState.NULL && this.state == ToneState.ENDING_CALL) {
|
||||
return;
|
||||
}
|
||||
cancelCurrentTone();
|
||||
Log.d(Config.LOGTAG, getClass().getName() + ".transition(" + state + ")");
|
||||
switch (state) {
|
||||
case RINGING:
|
||||
scheduleWaitingTone();
|
||||
break;
|
||||
case BUSY:
|
||||
scheduleBusy();
|
||||
break;
|
||||
case ENDING_CALL:
|
||||
scheduleEnding();
|
||||
break;
|
||||
}
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
private void scheduleEnding() {
|
||||
this.currentTone = JingleConnectionManager.SCHEDULED_EXECUTOR_SERVICE.schedule(() -> {
|
||||
this.toneGenerator.startTone(ToneGenerator.TONE_CDMA_CONFIRM, 600);
|
||||
}, 0, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void scheduleBusy() {
|
||||
this.currentTone = JingleConnectionManager.SCHEDULED_EXECUTOR_SERVICE.schedule(() -> {
|
||||
this.toneGenerator.startTone(ToneGenerator.TONE_CDMA_NETWORK_BUSY, 2500);
|
||||
}, 0, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void scheduleWaitingTone() {
|
||||
this.currentTone = JingleConnectionManager.SCHEDULED_EXECUTOR_SERVICE.scheduleAtFixedRate(() -> {
|
||||
this.toneGenerator.startTone(ToneGenerator.TONE_CDMA_DIAL_TONE_LITE, 750);
|
||||
}, 0, 3, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void cancelCurrentTone() {
|
||||
if (currentTone != null) {
|
||||
currentTone.cancel(true);
|
||||
}
|
||||
toneGenerator.stopTone();
|
||||
}
|
||||
|
||||
private enum ToneState {
|
||||
NULL, RINGING, BUSY, ENDING_CALL
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue