summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChung-yih Wang <cywang@google.com>2010-10-07 07:09:58 +0800
committerChung-yih Wang <cywang@google.com>2010-10-07 07:09:58 +0800
commit5a336104824785dcae1e7aaa67d49fa051857ec9 (patch)
treed3868e9c5794dd936116e9d02c36448bbba21ec9
parent68513a76ebaacdff0a837ae2e743078f2bb5d514 (diff)
downloadandroid_external_nist-sip-5a336104824785dcae1e7aaa67d49fa051857ec9.tar.gz
android_external_nist-sip-5a336104824785dcae1e7aaa67d49fa051857ec9.tar.bz2
android_external_nist-sip-5a336104824785dcae1e7aaa67d49fa051857ec9.zip
Removed unused files. Do not merge.
Change-Id: I73c451b2cff2a683fefc581e2b63b502e11b764d
-rw-r--r--src/android/net/sip/SdpSessionDescription.java226
-rw-r--r--src/android/net/sip/SessionDescription.java24
-rw-r--r--src/android/net/sip/SipHelper.java450
-rw-r--r--src/android/net/sip/SipProfile.java175
-rw-r--r--src/android/net/sip/SipSession.java37
-rw-r--r--src/android/net/sip/SipSessionGroup.java858
-rw-r--r--src/android/net/sip/SipSessionLayer.java81
-rw-r--r--src/android/net/sip/SipSessionListener.java33
-rw-r--r--src/android/net/sip/SipSessionState.java37
-rw-r--r--src/com/android/sip/SipAudioCall.java461
-rw-r--r--src/com/android/sip/SipMain.java557
-rw-r--r--src/com/android/sip/media/Decoder.java34
-rw-r--r--src/com/android/sip/media/Encoder.java31
-rw-r--r--src/com/android/sip/media/G711ACodec.java87
-rw-r--r--src/com/android/sip/media/G711UCodec.java77
-rw-r--r--src/com/android/sip/media/RtpAudioSession.java656
-rw-r--r--src/com/android/sip/media/RtpFactory.java54
-rw-r--r--src/com/android/sip/media/RtpPacket.java134
-rw-r--r--src/com/android/sip/media/RtpSession.java30
19 files changed, 0 insertions, 4042 deletions
diff --git a/src/android/net/sip/SdpSessionDescription.java b/src/android/net/sip/SdpSessionDescription.java
deleted file mode 100644
index 8ce2ddd..0000000
--- a/src/android/net/sip/SdpSessionDescription.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.sip;
-
-import gov.nist.javax.sdp.SessionDescriptionImpl;
-import gov.nist.javax.sdp.fields.AttributeField;
-import gov.nist.javax.sdp.fields.ConnectionField;
-import gov.nist.javax.sdp.fields.MediaField;
-import gov.nist.javax.sdp.fields.OriginField;
-import gov.nist.javax.sdp.fields.ProtoVersionField;
-import gov.nist.javax.sdp.fields.SessionNameField;
-import gov.nist.javax.sdp.fields.TimeField;
-import gov.nist.javax.sdp.parser.SDPAnnounceParser;
-
-import java.text.ParseException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Vector;
-import javax.sdp.Connection;
-import javax.sdp.MediaDescription;
-import javax.sdp.SdpException;
-import javax.sip.SipException;
-
-public class SdpSessionDescription implements SessionDescription {
- private SessionDescriptionImpl mSessionDescription;
- private String mPeerMediaAddress;
- private int mPeerMediaPort;
-
- public static class Builder {
- private SdpSessionDescription mSdp = new SdpSessionDescription();
- private SessionDescriptionImpl mSessionDescription;
-
- public Builder(String sessionName) throws SdpException {
- mSessionDescription = new SessionDescriptionImpl();
- try {
- ProtoVersionField proto = new ProtoVersionField();
- proto.setVersion(0);
- mSessionDescription.addField(proto);
-
- TimeField time = new TimeField();
- time.setZero();
- mSessionDescription.addField(time);
-
- SessionNameField session = new SessionNameField();
- session.setValue(sessionName);
- mSessionDescription.addField(session);
- } catch (Exception e) {
- throw new SdpException(e.toString(), e);
- }
- }
-
- public Builder setConnectionInfo(String netType, String addrType,
- String addr) throws SdpException {
- try {
- ConnectionField connection = new ConnectionField();
- connection.setNetworkType(netType);
- connection.setAddressType(addrType);
- connection.setAddress(addr);
- mSessionDescription.addField(connection);
- } catch (Exception e) {
- throw new SdpException(e.toString(), e);
- }
- return this;
- }
-
- public Builder setOrigin(SipProfile user, long sessionId,
- long sessionVersion, String networkType, String addressType,
- String address) throws SdpException {
- try {
- OriginField origin = new OriginField();
- origin.setUsername(user.getUserName());
- origin.setSessionId(sessionId);
- origin.setSessionVersion(sessionVersion);
- origin.setAddressType(addressType);
- origin.setNetworkType(networkType);
- origin.setAddress(address);
- mSessionDescription.addField(origin);
- } catch (Exception e) {
- throw new SdpException(e.toString(), e);
- }
- return this;
- }
-
- public Builder addMedia(String media, int port, int numPorts,
- String transport, Integer... types) throws SdpException {
- MediaField field = new MediaField();
- Vector<Integer> typeVector = new Vector<Integer>();
- Collections.addAll(typeVector, types);
- try {
- field.setMediaType(media);
- field.setMediaPort(port);
- field.setPortCount(numPorts);
- field.setProtocol(transport);
- field.setMediaFormats(typeVector);
- mSessionDescription.addField(field);
- } catch (Exception e) {
- throw new SdpException(e.toString(), e);
- }
- return this;
- }
-
- public Builder addMediaAttribute(String name, String value)
- throws SdpException {
- try {
- if (mSessionDescription.getMediaDescriptions(false) == null) {
- throw new SdpException("Should add media first!");
- }
- AttributeField attribute = new AttributeField();
- attribute.setName(name);
- attribute.setValueAllowNull(value);
- mSessionDescription.addField(attribute);
- } catch (Exception e) {
- throw new SdpException(e.toString(), e);
- }
- return this;
- }
-
- public Builder addSessionAttribute(String name, String value)
- throws SdpException {
- try {
- AttributeField attribute = new AttributeField();
- attribute.setName(name);
- attribute.setValueAllowNull(value);
- mSessionDescription.addField(attribute);
- } catch (Exception e) {
- throw new SdpException(e.toString(), e);
- }
- return this;
- }
-
- public SdpSessionDescription build() {
- mSdp.mSessionDescription = mSessionDescription;
- return mSdp;
- }
- }
-
- private SdpSessionDescription() {
- }
-
- public SdpSessionDescription(String sdpString) throws SdpException {
- try {
- mSessionDescription = new SDPAnnounceParser(sdpString).parse();
- } catch (ParseException e) {
- throw new SdpException(e.toString(), e);
- }
- init();
- }
-
- public SdpSessionDescription(byte[] content) throws SdpException {
- this(new String(content));
- }
-
- public String getPeerMediaAddress() {
- return mPeerMediaAddress;
- }
-
- public int getPeerMediaPort() {
- return mPeerMediaPort;
- }
-
- public List<Integer> getMediaFormats() {
- MediaDescription md = getMediaDescription();
- Vector<String> formatVector = (md == null)
- ? null
- : md.getMedia().getFormats();
- if (formatVector == null) formatVector = new Vector<String>();
- List<Integer> formats = new ArrayList<Integer>();
- for (String id : formatVector) {
- try {
- formats.add(Integer.parseInt(id));
- } catch (NumberFormatException e) {
- // ignore
- }
- }
- return formats;
- }
-
- private void init() throws SdpException {
- MediaDescription md = getMediaDescription();
- mPeerMediaPort = md.getMedia().getMediaPort();
-
- Connection connection = md.getConnection();
- if (connection == null) {
- connection = mSessionDescription.getConnection();
- }
- mPeerMediaAddress = connection.getAddress();
- }
-
- private MediaDescription getMediaDescription() {
- try {
- Vector vector = mSessionDescription.getMediaDescriptions(false);
- // FIXME: how to handle multiple media descriptions
- return (MediaDescription) vector.firstElement();
- } catch (SdpException e) {
- android.util.Log.e("SdpSessionDescription", e.toString());
- return null;
- }
- }
-
- public String getType() {
- return "sdp";
- }
-
- public byte[] getContent() {
- return mSessionDescription.toString().getBytes();
- }
-
- public String toString() {
- return mSessionDescription.toString();
- }
-}
diff --git a/src/android/net/sip/SessionDescription.java b/src/android/net/sip/SessionDescription.java
deleted file mode 100644
index c43e0c7..0000000
--- a/src/android/net/sip/SessionDescription.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.sip;
-
-import javax.sip.SipException;
-
-public interface SessionDescription {
- String getType();
- byte[] getContent();
-}
diff --git a/src/android/net/sip/SipHelper.java b/src/android/net/sip/SipHelper.java
deleted file mode 100644
index 606b2fc..0000000
--- a/src/android/net/sip/SipHelper.java
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.sip;
-
-import android.util.Log;
-
-import gov.nist.javax.sip.SipStackExt;
-import gov.nist.javax.sip.clientauthutils.AccountManager;
-import gov.nist.javax.sip.clientauthutils.AuthenticationHelper;
-import gov.nist.javax.sip.clientauthutils.UserCredentials;
-
-import java.text.ParseException;
-import java.util.ArrayList;
-import java.util.EventObject;
-import java.util.List;
-import javax.sip.ClientTransaction;
-import javax.sip.Dialog;
-import javax.sip.DialogTerminatedEvent;
-import javax.sip.InvalidArgumentException;
-import javax.sip.ListeningPoint;
-import javax.sip.PeerUnavailableException;
-import javax.sip.RequestEvent;
-import javax.sip.ResponseEvent;
-import javax.sip.ServerTransaction;
-import javax.sip.SipException;
-import javax.sip.SipFactory;
-import javax.sip.SipProvider;
-import javax.sip.SipStack;
-import javax.sip.Transaction;
-import javax.sip.TransactionAlreadyExistsException;
-import javax.sip.TransactionTerminatedEvent;
-import javax.sip.TransactionUnavailableException;
-import javax.sip.TransactionState;
-import javax.sip.address.Address;
-import javax.sip.address.AddressFactory;
-import javax.sip.address.SipURI;
-import javax.sip.header.CSeqHeader;
-import javax.sip.header.CallIdHeader;
-import javax.sip.header.ContactHeader;
-import javax.sip.header.FromHeader;
-import javax.sip.header.Header;
-import javax.sip.header.HeaderFactory;
-import javax.sip.header.MaxForwardsHeader;
-import javax.sip.header.ToHeader;
-import javax.sip.header.ViaHeader;
-import javax.sip.message.Message;
-import javax.sip.message.MessageFactory;
-import javax.sip.message.Request;
-import javax.sip.message.Response;
-
-/**
- * Helper class for holding SIP stack related classes and for various low-level
- * SIP tasks like sending messages.
- */
-class SipHelper {
- private static final String TAG = SipHelper.class.getSimpleName();
-
- private SipStack mSipStack;
- private SipProvider mSipProvider;
- private AddressFactory mAddressFactory;
- private HeaderFactory mHeaderFactory;
- private MessageFactory mMessageFactory;
-
- public SipHelper(SipStack sipStack, SipProvider sipProvider)
- throws PeerUnavailableException {
- mSipStack = sipStack;
- mSipProvider = sipProvider;
-
- SipFactory sipFactory = SipFactory.getInstance();
- mAddressFactory = sipFactory.createAddressFactory();
- mHeaderFactory = sipFactory.createHeaderFactory();
- mMessageFactory = sipFactory.createMessageFactory();
- }
-
- private FromHeader createFromHeader(SipProfile profile, String tag)
- throws ParseException {
- return mHeaderFactory.createFromHeader(profile.getSipAddress(), tag);
- }
-
- private ToHeader createToHeader(SipProfile profile) throws ParseException {
- return createToHeader(profile, null);
- }
-
- private ToHeader createToHeader(SipProfile profile, String tag)
- throws ParseException {
- return mHeaderFactory.createToHeader(profile.getSipAddress(), tag);
- }
-
- private CallIdHeader createCallIdHeader() {
- return mSipProvider.getNewCallId();
- }
-
- private CSeqHeader createCSeqHeader(String method)
- throws ParseException, InvalidArgumentException {
- long sequence = (long) (Math.random() * 10000);
- return mHeaderFactory.createCSeqHeader(sequence, method);
- }
-
- private MaxForwardsHeader createMaxForwardsHeader()
- throws InvalidArgumentException {
- return mHeaderFactory.createMaxForwardsHeader(70);
- }
-
- private MaxForwardsHeader createMaxForwardsHeader(int max)
- throws InvalidArgumentException {
- return mHeaderFactory.createMaxForwardsHeader(max);
- }
-
- private List<ViaHeader> createViaHeaders()
- throws ParseException, InvalidArgumentException {
- List<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(1);
- ListeningPoint lp = mSipProvider.getListeningPoint("udp");
- viaHeaders.add(mHeaderFactory.createViaHeader(lp.getIPAddress(),
- lp.getPort(), "udp", null));
- return viaHeaders;
- }
-
- private ContactHeader createContactHeader(SipProfile profile)
- throws ParseException, InvalidArgumentException {
- ListeningPoint lp = mSipProvider.getListeningPoint("udp");
- SipURI contactURI = createSipUri(profile.getUserName(), lp);
-
- Address contactAddress = mAddressFactory.createAddress(contactURI);
- contactAddress.setDisplayName(profile.getDisplayName());
-
- return mHeaderFactory.createContactHeader(contactAddress);
- }
-
- private SipURI createSipUri(String username, ListeningPoint lp)
- throws ParseException {
- SipURI uri = mAddressFactory.createSipURI(username, lp.getIPAddress());
- try {
- uri.setPort(lp.getPort());
- } catch (InvalidArgumentException e) {
- throw new RuntimeException(e);
- }
- return uri;
- }
-
- public ClientTransaction sendRegister(SipProfile userProfile, String tag,
- int expiry) throws SipException {
- try {
- FromHeader fromHeader = createFromHeader(userProfile, tag);
- ToHeader toHeader = createToHeader(userProfile);
- SipURI requestURI = mAddressFactory.createSipURI("sip:"
- + userProfile.getSipDomain());
- List<ViaHeader> viaHeaders = createViaHeaders();
- CallIdHeader callIdHeader = createCallIdHeader();
- CSeqHeader cSeqHeader = createCSeqHeader(Request.REGISTER);
- MaxForwardsHeader maxForwards = createMaxForwardsHeader();
-
- Request request = mMessageFactory.createRequest(requestURI,
- Request.REGISTER, callIdHeader, cSeqHeader, fromHeader,
- toHeader, viaHeaders, maxForwards);
-
- request.addHeader(createContactHeader(userProfile));
- request.addHeader(mHeaderFactory.createExpiresHeader(expiry));
- Header userAgentHeader = mHeaderFactory.createHeader("User-Agent",
- "AndroidSip/0.1.001");
- request.addHeader(userAgentHeader);
-
- ClientTransaction clientTransaction =
- mSipProvider.getNewClientTransaction(request);
- clientTransaction.sendRequest();
- return clientTransaction;
- } catch (ParseException e) {
- throw new SipException("sendRegister()", e);
- }
- }
-
- public ClientTransaction handleChallenge(ResponseEvent responseEvent,
- final SipProfile userProfile) throws SipException {
- AccountManager accountManager = new AccountManager() {
- public UserCredentials getCredentials(ClientTransaction
- challengedTransaction, String realm) {
- return userProfile;
- }
- };
- AuthenticationHelper authenticationHelper =
- ((SipStackExt) mSipStack).getAuthenticationHelper(
- accountManager, mHeaderFactory);
- ClientTransaction tid = responseEvent.getClientTransaction();
- ClientTransaction ct = authenticationHelper.handleChallenge(
- responseEvent.getResponse(), tid, mSipProvider, 5);
- ct.sendRequest();
- return ct;
- }
-
- public ClientTransaction sendInvite(SipProfile caller, SipProfile callee,
- SessionDescription sessionDescription, String tag)
- throws SipException {
- try {
- FromHeader fromHeader = createFromHeader(caller, tag);
- ToHeader toHeader = createToHeader(callee);
- SipURI requestURI = callee.getUri();
- List<ViaHeader> viaHeaders = createViaHeaders();
- CallIdHeader callIdHeader = createCallIdHeader();
- CSeqHeader cSeqHeader = createCSeqHeader(Request.INVITE);
- MaxForwardsHeader maxForwards = createMaxForwardsHeader();
-
- Request request = mMessageFactory.createRequest(requestURI,
- Request.INVITE, callIdHeader, cSeqHeader, fromHeader,
- toHeader, viaHeaders, maxForwards);
-
- request.addHeader(createContactHeader(caller));
- request.setContent(sessionDescription.getContent(),
- mHeaderFactory.createContentTypeHeader(
- "application", sessionDescription.getType()));
-
- ClientTransaction clientTransaction =
- mSipProvider.getNewClientTransaction(request);
- clientTransaction.sendRequest();
- return clientTransaction;
- } catch (ParseException e) {
- throw new SipException("sendInvite()", e);
- }
- }
-
- public ClientTransaction sendReinvite(Dialog dialog,
- SessionDescription sessionDescription) throws SipException {
- try {
- dialog.incrementLocalSequenceNumber();
- Request request = dialog.createRequest(Request.INVITE);
- request.setContent(sessionDescription.getContent(),
- mHeaderFactory.createContentTypeHeader(
- "application", sessionDescription.getType()));
-
- ClientTransaction clientTransaction =
- mSipProvider.getNewClientTransaction(request);
- clientTransaction.sendRequest();
- return clientTransaction;
- } catch (ParseException e) {
- throw new SipException("sendReinvite()", e);
- }
- }
-
- private ServerTransaction getServerTransaction(RequestEvent event)
- throws SipException {
- ServerTransaction transaction = event.getServerTransaction();
- if (transaction == null) {
- Request request = event.getRequest();
- return mSipProvider.getNewServerTransaction(request);
- } else {
- return transaction;
- }
- }
-
- /**
- * @param event the INVITE request event
- */
- public ServerTransaction sendRinging(RequestEvent event)
- throws SipException {
- try {
- Request request = event.getRequest();
- ServerTransaction transaction = getServerTransaction(event);
- transaction.sendResponse(
- mMessageFactory.createResponse(Response.RINGING, request));
- return transaction;
- } catch (ParseException e) {
- throw new SipException("sendRinging()", e);
- }
- }
-
- /**
- * @param event the INVITE request event
- */
- public void sendInviteOk(RequestEvent event, SipProfile localProfile,
- SessionDescription sessionDescription, String tag,
- ServerTransaction inviteTransaction) throws SipException {
- try {
- Request request = event.getRequest();
- Response response = mMessageFactory.createResponse(Response.OK,
- request);
- response.addHeader(createContactHeader(localProfile));
- ToHeader toHeader = (ToHeader) response.getHeader(ToHeader.NAME);
- toHeader.setTag(tag);
- response.addHeader(toHeader);
-
- response.setContent(sessionDescription.getContent(),
- mHeaderFactory.createContentTypeHeader(
- "application", sessionDescription.getType()));
-
- if (inviteTransaction.getState() != TransactionState.COMPLETED) {
- inviteTransaction.sendResponse(response);
- }
- } catch (ParseException e) {
- throw new SipException("sendInviteOk()", e);
- }
- }
-
- /**
- * @param event the INVITE request event
- */
- public void sendReInviteOk(RequestEvent event, SipProfile localProfile)
- throws SipException {
- try {
- Request request = event.getRequest();
- Response response = mMessageFactory.createResponse(Response.OK,
- request);
- response.addHeader(createContactHeader(localProfile));
- ServerTransaction transaction = event.getServerTransaction();
-
- if (transaction.getState() != TransactionState.COMPLETED) {
- transaction.sendResponse(response);
- }
- } catch (ParseException e) {
- throw new SipException("sendReInviteOk()", e);
- }
- }
-
- public void sendInviteBusyHere(RequestEvent event,
- ServerTransaction inviteTransaction) throws SipException {
- try {
- Request request = event.getRequest();
- Response response = mMessageFactory.createResponse(
- Response.BUSY_HERE, request);
-
- if (inviteTransaction.getState() != TransactionState.COMPLETED) {
- inviteTransaction.sendResponse(response);
- }
- } catch (ParseException e) {
- throw new SipException("sendInviteBusyHere()", e);
- }
- }
-
- /**
- * @param event the INVITE ACK request event
- */
- public void sendInviteAck(ResponseEvent event, Dialog dialog)
- throws SipException {
- Response response = event.getResponse();
- long cseq = ((CSeqHeader) response.getHeader(CSeqHeader.NAME))
- .getSeqNumber();
- dialog.sendAck(dialog.createAck(cseq));
- }
-
- public void sendBye(Dialog dialog) throws SipException {
- // SipStack increases seq number automatically
- // so no need to call dialog.incrementLocalSequenceNumber().
- Request byeRequest = dialog.createRequest(Request.BYE);
- Log.v(TAG, "send BYE: " + byeRequest);
- dialog.sendRequest(mSipProvider.getNewClientTransaction(byeRequest));
- }
-
- public void sendCancel(ClientTransaction inviteTransaction)
- throws SipException {
- // The cancel request must use the same CSeq as the request to cancel
- // so no need to call dialog.incrementLocalSequenceNumber().
- Request cancelRequest = inviteTransaction.createCancel();
- mSipProvider.getNewClientTransaction(cancelRequest).sendRequest();
- }
-
- public void sendResponse(RequestEvent event, int responseCode)
- throws SipException {
- try {
- getServerTransaction(event).sendResponse(
- mMessageFactory.createResponse(
- responseCode, event.getRequest()));
- } catch (ParseException e) {
- throw new SipException("sendResponse()", e);
- }
- }
-
- public void sendInviteRequestTerminated(Request inviteRequest,
- ServerTransaction inviteTransaction) throws SipException {
- try {
- inviteTransaction.sendResponse(mMessageFactory.createResponse(
- Response.REQUEST_TERMINATED, inviteRequest));
- } catch (ParseException e) {
- throw new SipException("sendInviteRequestTerminated()", e);
- }
- }
-
- public String getSessionKey(SipSession session) {
- Dialog dialog = session.getDialog();
- return (dialog == null
- ? getSessionKey(session.getLocalProfile().getSipAddress())
- : dialog.getCallId().getCallId());
- }
-
- public static String[] getPossibleSessionKeys(EventObject event) {
- if (event instanceof RequestEvent) {
- return getPossibleSessionKeys(((RequestEvent) event).getRequest());
- } else if (event instanceof ResponseEvent) {
- return getPossibleSessionKeys(
- ((ResponseEvent) event).getResponse());
- } else if (event instanceof DialogTerminatedEvent) {
- Dialog dialog = ((DialogTerminatedEvent) event).getDialog();
- return getPossibleSessionKeys(
- ((DialogTerminatedEvent) event).getDialog());
- } else if (event instanceof TransactionTerminatedEvent) {
- TransactionTerminatedEvent e = (TransactionTerminatedEvent) event;
- return getPossibleSessionKeys(e.isServerTransaction()
- ? e.getServerTransaction()
- : e.getClientTransaction());
- } else {
- Object source = event.getSource();
- if (source instanceof Transaction) {
- return getPossibleSessionKeys(((Transaction) source));
- } else if (source instanceof Dialog) {
- return getPossibleSessionKeys((Dialog) source);
- }
- }
- return new String[0];
- }
-
- private static String[] getPossibleSessionKeys(Message message) {
- CallIdHeader callIdHeader =
- (CallIdHeader) message.getHeader(CallIdHeader.NAME);
- FromHeader fromHeader = (FromHeader) message.getHeader(FromHeader.NAME);
- ToHeader toHeader = (ToHeader) message.getHeader(ToHeader.NAME);
- return new String[] {callIdHeader.getCallId(),
- getSessionKey(fromHeader.getAddress()),
- getSessionKey(toHeader.getAddress())};
- }
-
- private static String[] getPossibleSessionKeys(Transaction transaction) {
- return getPossibleSessionKeys(transaction.getRequest());
- }
-
- private static String[] getPossibleSessionKeys(Dialog dialog) {
- return new String[] {dialog.getCallId().getCallId()};
- }
-
- private static String getSessionKey(Address address) {
- Address clonedAddress = (Address) address.clone();
- // remove all optional fields
- try {
- clonedAddress.setDisplayName(null);
- ((SipURI) clonedAddress.getURI()).setUserPassword(null);
- } catch (ParseException e) {
- // ignored
- }
- return clonedAddress.toString();
- }
-}
diff --git a/src/android/net/sip/SipProfile.java b/src/android/net/sip/SipProfile.java
deleted file mode 100644
index 039c850..0000000
--- a/src/android/net/sip/SipProfile.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.sip;
-
-import gov.nist.javax.sip.clientauthutils.UserCredentials;
-
-import android.text.TextUtils;
-
-import java.text.ParseException;
-import javax.sip.InvalidArgumentException;
-import javax.sip.ListeningPoint;
-import javax.sip.PeerUnavailableException;
-import javax.sip.SipFactory;
-import javax.sip.address.Address;
-import javax.sip.address.AddressFactory;
-import javax.sip.address.SipURI;
-import javax.sip.address.URI;
-
-/**
- */
-public class SipProfile implements UserCredentials {
- private Address mAddress;
- private String mOutboundProxy;
- private String mPassword;
- private String mDomain;
- private String mProtocol = ListeningPoint.UDP;
-
- public static class Builder {
- private AddressFactory mAddressFactory;
- private SipProfile mProfile = new SipProfile();
- private SipURI mUri;
- private String mDisplayName;
- private String mOutboundProxy;
-
- {
- try {
- mAddressFactory =
- SipFactory.getInstance().createAddressFactory();
- } catch (PeerUnavailableException e) {
- throw new RuntimeException(e);
- }
- }
-
- public Builder(String uriString) throws ParseException {
- URI uri = mAddressFactory.createURI(fix(uriString));
- if (uri instanceof SipURI) {
- mUri = (SipURI) uri;
- } else {
- throw new ParseException(uriString + " is not a SIP URI", 0);
- }
- mProfile.mDomain = mUri.getHost();
- }
-
- public Builder(String username, String serverAddress)
- throws ParseException {
- mUri = mAddressFactory.createSipURI(username, serverAddress);
- mProfile.mDomain = serverAddress;
- }
-
- private String fix(String uriString) {
- return (uriString.trim().toLowerCase().startsWith("sip:")
- ? uriString
- : "sip:" + uriString);
- }
-
- public Builder setPassword(String password) {
- mUri.setUserPassword(password);
- return this;
- }
-
- public Builder setPort(int port) throws InvalidArgumentException {
- mUri.setPort(port);
- return this;
- }
-
- public Builder setDomain(String domain) {
- mProfile.mDomain = domain;
- return this;
- }
-
- public Builder setProtocol(String protocol) {
- // TODO: verify
- mProfile.mProtocol = protocol;
- return this;
- }
-
- public Builder setOutboundProxy(String outboundProxy) {
- mOutboundProxy = outboundProxy;
- return this;
- }
-
- public Builder setDisplayName(String displayName) throws ParseException {
- mDisplayName = displayName;
- return this;
- }
-
- public SipProfile build() {
- // remove password from URI
- mProfile.mPassword = mUri.getUserPassword();
- mUri.setUserPassword(null);
- try {
- mProfile.mAddress = mAddressFactory.createAddress(
- mDisplayName, mUri);
- if (!TextUtils.isEmpty(mOutboundProxy)) {
- SipURI uri = (SipURI)
- mAddressFactory.createURI(fix(mOutboundProxy));
- mProfile.mOutboundProxy = uri.getHost() + ":"
- + uri.getPort() + "/UDP";
- }
- } catch (ParseException e) {
- // must not occur
- throw new RuntimeException(e);
- }
- return mProfile;
- }
- }
-
- private SipProfile() {
- }
-
- public SipURI getUri() {
- return (SipURI) mAddress.getURI();
- }
-
- public Address getSipAddress() {
- return mAddress;
- }
-
- public String getDisplayName() {
- return mAddress.getDisplayName();
- }
-
- /* UserCredentials APIs */
- public String getUserName() {
- return getUri().getUser();
- }
-
- public String getPassword() {
- return mPassword;
- }
-
- public String getSipDomain() {
- return mDomain;
- }
-
- public String getServerAddress() {
- return getUri().getHost();
- }
-
- public int getPort() {
- return getUri().getPort();
- }
-
- public String getProtocol() {
- return mProtocol;
- }
-
- public String getOutboundProxy() {
- return mOutboundProxy;
- }
-}
diff --git a/src/android/net/sip/SipSession.java b/src/android/net/sip/SipSession.java
deleted file mode 100644
index ea243dd..0000000
--- a/src/android/net/sip/SipSession.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.sip;
-
-import javax.sip.Dialog;
-import javax.sip.SipException;
-
-public interface SipSession {
- SipProfile getLocalProfile();
- SipProfile getPeerProfile();
- SipSessionState getState();
- Dialog getDialog();
-
- void makeCall(SipProfile party, SessionDescription sessionDescription)
- throws SipException;
- void answerCall(SessionDescription sessionDescription) throws SipException;
- void endCall() throws SipException;
-
- void changeCall(SessionDescription sessionDescription) throws SipException;
-
- void register() throws SipException;
- void deRegister() throws SipException;
-}
diff --git a/src/android/net/sip/SipSessionGroup.java b/src/android/net/sip/SipSessionGroup.java
deleted file mode 100644
index 0acd5a6..0000000
--- a/src/android/net/sip/SipSessionGroup.java
+++ /dev/null
@@ -1,858 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.sip;
-
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.io.IOException;
-import java.net.DatagramSocket;
-import java.text.ParseException;
-import java.util.EventObject;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Timer;
-import java.util.TimerTask;
-import java.util.TooManyListenersException;
-
-import javax.sip.ClientTransaction;
-import javax.sip.Dialog;
-import javax.sip.DialogTerminatedEvent;
-import javax.sip.IOExceptionEvent;
-import javax.sip.InvalidArgumentException;
-import javax.sip.ListeningPoint;
-import javax.sip.RequestEvent;
-import javax.sip.ResponseEvent;
-import javax.sip.ServerTransaction;
-import javax.sip.SipException;
-import javax.sip.SipFactory;
-import javax.sip.SipListener;
-import javax.sip.SipProvider;
-import javax.sip.SipStack;
-import javax.sip.TimeoutEvent;
-import javax.sip.Transaction;
-import javax.sip.TransactionTerminatedEvent;
-import javax.sip.address.Address;
-import javax.sip.address.SipURI;
-import javax.sip.header.CSeqHeader;
-import javax.sip.header.ExpiresHeader;
-import javax.sip.header.FromHeader;
-import javax.sip.message.Message;
-import javax.sip.message.Request;
-import javax.sip.message.Response;
-
-/**
- * Manages SipSession's for a SIP account.
- */
-class SipSessionGroup implements SipListener {
- private static final String TAG = SipSessionGroup.class.getSimpleName();
- private static final int EXPIRY_TIME = 3600;
-
- private static final EventObject REGISTER = new EventObject("Register");
- private static final EventObject DEREGISTER = new EventObject("Deregister");
- private static final EventObject END_CALL = new EventObject("End call");
- private static final EventObject HOLD_CALL = new EventObject("Hold call");
- private static final EventObject CONTINUE_CALL
- = new EventObject("Continue call");
-
- private static final String STACK_NAME = "A SIP STACK";
-
- private SipStack mSipStack;
- private SipHelper mSipHelper;
- private SipProfile mLocalProfile;
-
- // default session that processes all the un-attended messages received
- // from the UDP port
- private SipSessionImpl mDefaultSession;
-
- // call-id-to-SipSession map
- private Map<String, SipSessionImpl> mSessionMap =
- new HashMap<String, SipSessionImpl>();
-
- SipSessionGroup(String localIp, SipProfile myself,
- SipSessionListener listener) throws SipException {
- SipFactory sipFactory = SipFactory.getInstance();
- Properties properties = new Properties();
- properties.setProperty("javax.sip.STACK_NAME", STACK_NAME);
- String outboundProxy = myself.getOutboundProxy();
- if (!TextUtils.isEmpty(outboundProxy)) {
- properties.setProperty("javax.sip.OUTBOUND_PROXY", outboundProxy);
- }
- SipStack stack = mSipStack = sipFactory.createSipStack(properties);
- stack.start();
-
- SipProvider provider = stack.createSipProvider(
- stack.createListeningPoint(localIp, allocateLocalPort(),
- ListeningPoint.UDP));
- try {
- provider.addSipListener(this);
- } catch (TooManyListenersException e) {
- // must never happen
- throw new SipException("SipSessionGroup constructor", e);
- }
- mSipHelper = new SipHelper(stack, provider);
- mLocalProfile = myself;
- mDefaultSession = new SipSessionImpl(listener);
- }
-
- public synchronized void close() {
- if (mSipStack != null) {
- mSipStack.stop();
- mSipStack = null;
- }
- }
-
- SipSession getDefaultSession() {
- return mDefaultSession;
- }
-
- private static int allocateLocalPort() throws SipException {
- try {
- DatagramSocket s = new DatagramSocket();
- int localPort = s.getLocalPort();
- s.close();
- return localPort;
- } catch (IOException e) {
- throw new SipException("allocateLocalPort()", e);
- }
- }
-
- private synchronized SipSessionImpl getSipSession(EventObject event) {
- String[] keys = mSipHelper.getPossibleSessionKeys(event);
- Log.v(TAG, " possible keys " + keys.length + " for evt: " + event);
- for (String key : keys) Log.v(TAG, " '" + key + "'");
- Log.v(TAG, " active sessions:");
- for (String k : mSessionMap.keySet()) {
- Log.v(TAG, " ----- '" + k + "': " + mSessionMap.get(k));
- }
- for (String uri : mSipHelper.getPossibleSessionKeys(event)) {
- SipSessionImpl callSession = mSessionMap.get(uri);
- // return first match
- if (callSession != null) return callSession;
- }
- return mDefaultSession;
- }
-
- private synchronized void addSipSession(SipSessionImpl newSession) {
- String key = mSipHelper.getSessionKey(newSession);
- Log.v(TAG, " +++++ add a session with key: '" + key + "'");
- mSessionMap.put(key, newSession);
- for (String k : mSessionMap.keySet()) {
- Log.v(TAG, " ..... " + k + ": " + mSessionMap.get(k));
- }
- }
-
- private synchronized void removeSipSession(SipSessionImpl session) {
- String key = mSipHelper.getSessionKey(session);
- SipSessionImpl s = mSessionMap.remove(key);
- // sanity check
- if ((s != null) && (s != session)) {
- Log.w(TAG, "session " + session + " is not associated with key '"
- + key + "'");
- mSessionMap.put(key, s);
- } else {
- Log.v(TAG, " remove session " + session + " with key '" + key
- + "'");
- }
- for (String k : mSessionMap.keySet()) {
- Log.v(TAG, " ..... " + k + ": " + mSessionMap.get(k));
- }
- }
-
- public void processRequest(RequestEvent event) {
- process(event);
- }
-
- public void processResponse(ResponseEvent event) {
- process(event);
- }
-
- public void processIOException(IOExceptionEvent event) {
- // TODO: find proper listener to pass the exception
- process(event);
- }
-
- public void processTimeout(TimeoutEvent event) {
- // TODO: find proper listener to pass the exception
- process(event);
- }
-
- public void processTransactionTerminated(TransactionTerminatedEvent event) {
- // TODO: clean up if session is in in-transaction states
- //process(event);
- }
-
- public void processDialogTerminated(DialogTerminatedEvent event) {
- process(event);
- }
-
- private void process(EventObject event) {
- SipSessionImpl session = getSipSession(event);
- if (session == null) {
- Log.w(TAG, "event not processed: " + event);
- return;
- }
- try {
- session.process(event);
- } catch (Throwable e) {
- Log.e(TAG, "event process error: " + event, e);
- session.mListener.onError(session, e);
- }
- }
-
- private class SipSessionImpl implements SipSession {
- private SipProfile mPeerProfile;
- private SipSessionListener mListener;
- private SipSessionState mState = SipSessionState.READY_FOR_CALL;
- private RequestEvent mInviteReceived;
- private Dialog mDialog;
- private ServerTransaction mServerTransaction;
- private ClientTransaction mClientTransaction;
- private byte[] mPeerSessionDescription;
-
- SipSessionImpl(SipSessionListener listener) {
- mListener = listener;
- }
-
- private void reset() {
- mPeerProfile = null;
- mState = SipSessionState.READY_FOR_CALL;
- mInviteReceived = null;
- mDialog = null;
- mServerTransaction = null;
- mClientTransaction = null;
- mPeerSessionDescription = null;
- }
-
- public SipProfile getLocalProfile() {
- return mLocalProfile;
- }
-
- public synchronized SipProfile getPeerProfile() {
- return mPeerProfile;
- }
-
- public synchronized Dialog getDialog() {
- return mDialog;
- }
-
- public synchronized SipSessionState getState() {
- return mState;
- }
-
- public void makeCall(SipProfile peerProfile,
- SessionDescription sessionDescription) throws SipException {
- process(new MakeCallCommand(peerProfile, sessionDescription));
- }
-
- public void answerCall(SessionDescription sessionDescription)
- throws SipException {
- process(new MakeCallCommand(mPeerProfile, sessionDescription));
- }
-
- public void endCall() throws SipException {
- process(END_CALL);
- }
-
- // http://www.tech-invite.com/Ti-sip-service-1.html#fig5
- public void changeCall(SessionDescription sessionDescription)
- throws SipException {
- process(new MakeCallCommand(mPeerProfile, sessionDescription));
- }
-
- public void register() throws SipException {
- process(REGISTER);
- }
-
- public void deRegister() throws SipException {
- process(DEREGISTER);
- }
-
- private void scheduleNextRegistration(
- ExpiresHeader expiresHeader) {
- int expires = EXPIRY_TIME;
- if (expiresHeader != null) expires = expiresHeader.getExpires();
- Log.v(TAG, "Refresh registration " + expires + "s later.");
- new Timer().schedule(new TimerTask() {
- public void run() {
- try {
- process(REGISTER);
- } catch (SipException e) {
- Log.e(TAG, "", e);
- }
- }}, expires * 1000L);
- }
-
- private String generateTag() {
- // TODO: based on myself's profile
- return String.valueOf((long) (Math.random() * 1000000L));
- }
-
- private String log(EventObject evt) {
- if (evt instanceof RequestEvent) {
- return ((RequestEvent) evt).getRequest().toString();
- } else if (evt instanceof ResponseEvent) {
- return ((ResponseEvent) evt).getResponse().toString();
- } else {
- return evt.toString();
- }
- }
-
- public String toString() {
- try {
- String s = super.toString();
- return s.substring(s.indexOf("@")) + ":" + mState;
- } catch (Throwable e) {
- return super.toString();
- }
- }
-
- synchronized void process(EventObject evt) throws SipException {
- Log.v(TAG, " ~~~~~ " + this + ": " + mState + ": processing "
- + log(evt));
- boolean processed;
-
- switch (mState) {
- case REGISTERING:
- case DEREGISTERING:
- processed = registeringToReady(evt);
- break;
- case READY_FOR_CALL:
- processed = readyForCall(evt);
- break;
- case INCOMING_CALL:
- processed = incomingCall(evt);
- break;
- case INCOMING_CALL_ANSWERING:
- processed = incomingCallToInCall(evt);
- break;
- case OUTGOING_CALL:
- case OUTGOING_CALL_RING_BACK:
- processed = outgoingCall(evt);
- break;
- case OUTGOING_CALL_CANCELING:
- processed = outgoingCallToReady(evt);
- break;
- case IN_CALL:
- processed = inCall(evt);
- break;
- case IN_CALL_ANSWERING:
- processed = inCallAnsweringToInCall(evt);
- break;
- case IN_CALL_CHANGING:
- processed = inCallChanging(evt);
- break;
- case IN_CALL_CHANGING_CANCELING:
- processed = inCallChangingToInCall(evt);
- break;
- default:
- processed = false;
- }
- if (!processed && !processExceptions(evt)) {
- Log.w(TAG, "event not processed: " + evt);
- } else {
- Log.v(TAG, " ~~~~~ new state: " + mState);
- }
- }
-
- private boolean processExceptions(EventObject evt) throws SipException {
- // process INVITE and CANCEL
- if (isRequestEvent(Request.INVITE, evt)) {
- mSipHelper.sendResponse((RequestEvent) evt, Response.BUSY_HERE);
- return true;
- } else if (isRequestEvent(Request.CANCEL, evt)) {
- mSipHelper.sendResponse((RequestEvent) evt,
- Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST);
- return true;
- } else if (evt instanceof TransactionTerminatedEvent) {
- if (evt instanceof TimeoutEvent) {
- processTimeout((TimeoutEvent) evt);
- } else {
- // TODO: any clean up?
- }
- return true;
- } else if (evt instanceof DialogTerminatedEvent) {
- processDialogTerminated((DialogTerminatedEvent) evt);
- return true;
- }
- return false;
- }
-
- private void processDialogTerminated(DialogTerminatedEvent event) {
- if (mDialog == event.getDialog()) {
- endCall(isInCall());
- } else {
- Log.d(TAG, "not the current dialog; current=" + mDialog
- + ", terminated=" + event.getDialog());
- }
- }
-
- private void processTimeout(TimeoutEvent event) {
- Log.d(TAG, "processing Timeout..." + event);
- Transaction current = event.isServerTransaction()
- ? mServerTransaction
- : mClientTransaction;
- Transaction target = event.isServerTransaction()
- ? event.getServerTransaction()
- : event.getClientTransaction();
-
- if (current != target) {
- Log.d(TAG, "not the current transaction; current=" + current
- + ", timed out=" + target);
- return;
- }
- switch (mState) {
- case REGISTERING:
- case INCOMING_CALL:
- case INCOMING_CALL_ANSWERING:
- case OUTGOING_CALL:
- case OUTGOING_CALL_RING_BACK:
- case OUTGOING_CALL_CANCELING:
- case IN_CALL_CHANGING:
- // rfc3261#section-14.1
- // if re-invite gets timed out, terminate the dialog
- endCallOnError((mState == SipSessionState.IN_CALL_CHANGING),
- new SipException("timed out"));
- break;
- case IN_CALL_ANSWERING:
- case IN_CALL_CHANGING_CANCELING:
- mState = SipSessionState.IN_CALL;
- mListener.onError(this, new SipException("timed out"));
- break;
- default:
- // do nothing
- break;
- }
- }
-
- private boolean registeringToReady(EventObject evt)
- throws SipException {
- if (expectResponse(Request.REGISTER, evt)) {
- ResponseEvent event = (ResponseEvent) evt;
- Response response = event.getResponse();
-
- int statusCode = response.getStatusCode();
- switch (statusCode) {
- case Response.OK:
- if (mState == SipSessionState.REGISTERING) {
- scheduleNextRegistration((ExpiresHeader)
- ((ResponseEvent) evt).getResponse().getHeader(
- ExpiresHeader.NAME));
- }
- reset();
- mListener.onRegistrationDone(this);
- return true;
- case Response.UNAUTHORIZED:
- case Response.PROXY_AUTHENTICATION_REQUIRED:
- mSipHelper.handleChallenge((ResponseEvent)evt, mLocalProfile);
- return true;
- default:
- if (statusCode >= 500) {
- reset();
- mListener.onRegistrationFailed(this,
- createCallbackException(response));
- return true;
- }
- }
- }
- return false;
- }
-
- private boolean readyForCall(EventObject evt) throws SipException {
- // expect MakeCallCommand, Invite
- if (evt instanceof MakeCallCommand) {
- MakeCallCommand cmd = (MakeCallCommand) evt;
- mPeerProfile = cmd.getPeerProfile();
- SessionDescription sessionDescription =
- cmd.getSessionDescription();
- mClientTransaction = mSipHelper.sendInvite(mLocalProfile,
- mPeerProfile, sessionDescription, generateTag());
- mDialog = mClientTransaction.getDialog();
- mState = SipSessionState.OUTGOING_CALL;
- mListener.onCalling(SipSessionImpl.this);
- return true;
- } else if (isRequestEvent(Request.INVITE, evt)) {
- RequestEvent event = (RequestEvent) evt;
- mServerTransaction = mSipHelper.sendRinging(event);
- mDialog = mServerTransaction.getDialog();
- mInviteReceived = event;
- mPeerProfile = createPeerProfile(event.getRequest());
- mState = SipSessionState.INCOMING_CALL;
- mPeerSessionDescription = event.getRequest().getRawContent();
- mListener.onRinging(SipSessionImpl.this, mPeerProfile,
- mPeerSessionDescription);
- return true;
- } else if (REGISTER == evt) {
- mClientTransaction = mSipHelper.sendRegister(mLocalProfile,
- generateTag(), EXPIRY_TIME);
- mDialog = mClientTransaction.getDialog();
- mState = SipSessionState.REGISTERING;
- return true;
- } else if (DEREGISTER == evt) {
- mClientTransaction = mSipHelper.sendRegister(mLocalProfile,
- generateTag(), 0);
- mState = SipSessionState.DEREGISTERING;
- return true;
- }
- return false;
- }
-
- private boolean incomingCall(EventObject evt) throws SipException {
- // expect MakeCallCommand(answering) , END_CALL cmd , Cancel
- if (evt instanceof MakeCallCommand) {
- // answer call
- mSipHelper.sendInviteOk(mInviteReceived, mLocalProfile,
- ((MakeCallCommand) evt).getSessionDescription(),
- generateTag(), mServerTransaction);
- mState = SipSessionState.INCOMING_CALL_ANSWERING;
- return true;
- } else if (END_CALL == evt) {
- mSipHelper.sendInviteBusyHere(mInviteReceived,
- mServerTransaction);
- endCall(false);
- return true;
- } else if (isRequestEvent(Request.CANCEL, evt)) {
- RequestEvent event = (RequestEvent) evt;
- mSipHelper.sendResponse(event, Response.OK);
- mSipHelper.sendInviteRequestTerminated(
- mInviteReceived.getRequest(), mServerTransaction);
- endCall(false);
- return true;
- }
- return false;
- }
-
- private boolean incomingCallToInCall(EventObject evt)
- throws SipException {
- // expect ACK, CANCEL request
- if (isRequestEvent(Request.ACK, evt)) {
- establishCall(false);
- return true;
- } else if (isRequestEvent(Request.CANCEL, evt)) {
- RequestEvent event = (RequestEvent) evt;
- // TODO: what to do here? what happens when racing between
- // OK-to-invite from callee and Cancel from caller
- return true;
- }
- return false;
- }
-
- private boolean outgoingCall(EventObject evt) throws SipException {
- if (expectResponse(Request.INVITE, evt)) {
- ResponseEvent event = (ResponseEvent) evt;
- Response response = event.getResponse();
-
- int statusCode = response.getStatusCode();
- switch (statusCode) {
- case Response.RINGING:
- if (mState == SipSessionState.OUTGOING_CALL) {
- mState = SipSessionState.OUTGOING_CALL_RING_BACK;
- mListener.onRingingBack(this);
- }
- return true;
- case Response.OK:
- mSipHelper.sendInviteAck(event, mDialog);
- mPeerSessionDescription = response.getRawContent();
- establishCall(false);
- return true;
- case Response.PROXY_AUTHENTICATION_REQUIRED:
- mClientTransaction = mSipHelper.handleChallenge(
- (ResponseEvent)evt, mLocalProfile);
- mDialog = mClientTransaction.getDialog();
- return true;
- default:
- if (statusCode >= 400) {
- // error: an ack is sent automatically by the stack
- endCallOnError(false,
- createCallbackException(response));
- return true;
- } else if (statusCode >= 300) {
- // TODO: handle 3xx (redirect)
- } else {
- return true;
- }
- }
- return false;
- } else if (END_CALL == evt) {
- // RFC says that UA should not send out cancel when no
- // response comes back yet. We are cheating for not checking
- // response.
- mSipHelper.sendCancel(mClientTransaction);
- mState = SipSessionState.OUTGOING_CALL_CANCELING;
- return true;
- }
- return false;
- }
-
- private boolean outgoingCallToReady(EventObject evt)
- throws SipException {
- if (evt instanceof ResponseEvent) {
- ResponseEvent event = (ResponseEvent) evt;
- Response response = event.getResponse();
- int statusCode = response.getStatusCode();
- if (expectResponse(Request.CANCEL, evt)) {
- if (statusCode == Response.OK) {
- // do nothing; wait for REQUEST_TERMINATED
- return true;
- }
- } else if (expectResponse(Request.INVITE, evt)) {
- if (statusCode == Response.REQUEST_TERMINATED) {
- endCall(false);
- return true;
- }
- } else {
- return false;
- }
-
- if (statusCode >= 400) {
- endCallOnError(true, createCallbackException(response));
- return true;
- }
- }
- return false;
- }
-
- private boolean inCall(EventObject evt) throws SipException {
- // expect END_CALL cmd, BYE request, hold call (MakeCallCommand)
- // OK retransmission is handled in SipStack
- if (END_CALL == evt) {
- // rfc3261#section-15.1.1
- mSipHelper.sendBye(mDialog);
- endCall(true);
- return true;
- } else if (isRequestEvent(Request.INVITE, evt)) {
- // got Re-INVITE
- RequestEvent event = (RequestEvent) evt;
- mSipHelper.sendReInviteOk(event, mLocalProfile);
- mState = SipSessionState.IN_CALL_ANSWERING;
- mPeerSessionDescription = event.getRequest().getRawContent();
- mListener.onCallChanged(this, mPeerSessionDescription);
- return true;
- } else if (isRequestEvent(Request.BYE, evt)) {
- mSipHelper.sendResponse((RequestEvent) evt, Response.OK);
- endCall(true);
- return true;
- } else if (evt instanceof MakeCallCommand) {
- // to change call
- mClientTransaction = mSipHelper.sendReinvite(mDialog,
- ((MakeCallCommand) evt).getSessionDescription());
- mState = SipSessionState.IN_CALL_CHANGING;
- return true;
- }
- return false;
- }
-
- private boolean inCallChanging(EventObject evt)
- throws SipException {
- if (expectResponse(Request.INVITE, evt)) {
- ResponseEvent event = (ResponseEvent) evt;
- Response response = event.getResponse();
-
- int statusCode = response.getStatusCode();
- switch (statusCode) {
- case Response.OK:
- mSipHelper.sendInviteAck(event, mDialog);
- establishCall(true);
- return true;
- case Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST:
- case Response.REQUEST_TIMEOUT:
- // rfc3261#section-14.1: re-invite failed; terminate
- // the dialog
- endCallOnError(true, createCallbackException(response));
- return true;
- case Response.REQUEST_PENDING:
- // TODO:
- // rfc3261#section-14.1; re-schedule invite
- return true;
- default:
- if (statusCode >= 400) {
- // error: an ack is sent automatically by the stack
- mState = SipSessionState.IN_CALL;
- mListener.onError(this,
- createCallbackException(response));
- return true;
- } else if (statusCode >= 300) {
- // TODO: handle 3xx (redirect)
- } else {
- return true;
- }
- }
- return false;
- } else if (END_CALL == evt) {
- mSipHelper.sendCancel(mClientTransaction);
- mState = SipSessionState.IN_CALL_CHANGING_CANCELING;
- return true;
- }
- return false;
- }
-
- private boolean inCallChangingToInCall(EventObject evt)
- throws SipException {
- if (expectResponse(Response.OK, Request.CANCEL, evt)) {
- // do nothing; wait for REQUEST_TERMINATED
- return true;
- } else if (expectResponse(Response.OK, Request.INVITE, evt)) {
- inCallChanging(evt); // abort Cancel
- return true;
- } else if (expectResponse(Response.REQUEST_TERMINATED,
- Request.INVITE, evt)) {
- establishCall(true);
- return true;
- }
- return false;
- }
-
- private boolean inCallAnsweringToInCall(EventObject evt) {
- // expect ACK
- if (isRequestEvent(Request.ACK, evt)) {
- establishCall(true);
- return true;
- }
- return false;
- }
-
- private Exception createCallbackException(Response response) {
- return new SipException(String.format("Response: %s (%d)",
- response.getReasonPhrase(), response.getStatusCode()));
- }
-
- private void establishCall(boolean inCall) {
- if (inCall) {
- mState = SipSessionState.IN_CALL;
- mListener.onCallEstablished(this, mPeerSessionDescription);
- } else {
- SipSessionImpl newSession = createInCallSipSession();
- addSipSession(newSession);
- reset();
- newSession.establishCall(true);
- }
- }
-
- private void endCall(boolean inCall) {
- if (inCall) removeSipSession(this);
- reset();
- mListener.onCallEnded(this);
- }
-
- private void endCallOnError(
- boolean terminating, Throwable throwable) {
- if (terminating) removeSipSession(this);
- reset();
- mListener.onError(this, throwable);
- }
-
- private boolean isInCall() {
- return (mState.compareTo(SipSessionState.IN_CALL) >= 0);
- }
-
- private SipSessionImpl createInCallSipSession() {
- SipSessionImpl newSession = new SipSessionImpl(mListener);
- newSession.mPeerProfile = mPeerProfile;
- newSession.mState = SipSessionState.IN_CALL;
- newSession.mInviteReceived = mInviteReceived;
- newSession.mDialog = mDialog;
- newSession.mPeerSessionDescription = mPeerSessionDescription;
- return newSession;
- }
- }
-
- /**
- * @return true if the event is a request event matching the specified
- * method; false otherwise
- */
- private static boolean isRequestEvent(String method, EventObject event) {
- try {
- if (event instanceof RequestEvent) {
- RequestEvent requestEvent = (RequestEvent) event;
- return method.equals(requestEvent.getRequest().getMethod());
- }
- } catch (Throwable e) {
- }
- return false;
- }
-
- private static String getCseqMethod(Message message) {
- return ((CSeqHeader) message.getHeader(CSeqHeader.NAME)).getMethod();
- }
-
- /**
- * @return true if the event is a response event and the CSeqHeader method
- * match the given arguments; false otherwise
- */
- private static boolean expectResponse(
- String expectedMethod, EventObject evt) {
- if (evt instanceof ResponseEvent) {
- ResponseEvent event = (ResponseEvent) evt;
- Response response = event.getResponse();
- return expectedMethod.equalsIgnoreCase(getCseqMethod(response));
- }
- return false;
- }
-
- /**
- * @return true if the event is a response event and the response code and
- * CSeqHeader method match the given arguments; false otherwise
- */
- private static boolean expectResponse(
- int responseCode, String expectedMethod, EventObject evt) {
- if (evt instanceof ResponseEvent) {
- ResponseEvent event = (ResponseEvent) evt;
- Response response = event.getResponse();
- if (response.getStatusCode() == responseCode) {
- return expectedMethod.equalsIgnoreCase(getCseqMethod(response));
- }
- }
- return false;
- }
-
- private static SipProfile createPeerProfile(Request request)
- throws SipException {
- try {
- FromHeader fromHeader =
- (FromHeader) request.getHeader(FromHeader.NAME);
- Address address = fromHeader.getAddress();
- SipURI uri = (SipURI) address.getURI();
- return new SipProfile.Builder(uri.getUser(), uri.getHost())
- .setPort(uri.getPort())
- .setDisplayName(address.getDisplayName())
- .build();
- } catch (InvalidArgumentException e) {
- throw new SipException("createPeerProfile()", e);
- } catch (ParseException e) {
- throw new SipException("createPeerProfile()", e);
- }
- }
-
- private class MakeCallCommand extends EventObject {
- private SessionDescription mSessionDescription;
-
- MakeCallCommand(SipProfile peerProfile,
- SessionDescription sessionDescription) {
- super(peerProfile);
- mSessionDescription = sessionDescription;
- }
-
- SipProfile getPeerProfile() {
- return (SipProfile) getSource();
- }
-
- SessionDescription getSessionDescription() {
- return mSessionDescription;
- }
- }
-}
diff --git a/src/android/net/sip/SipSessionLayer.java b/src/android/net/sip/SipSessionLayer.java
deleted file mode 100644
index 83b31fe..0000000
--- a/src/android/net/sip/SipSessionLayer.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.sip;
-
-import android.util.Log;
-
-import java.io.IOException;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.sip.SipException;
-
-/**
- * @hide
- * Creates and manages multiple {@link SipSession}.
- */
-public class SipSessionLayer {
- private static final String TAG = SipSessionLayer.class.getSimpleName();
-
- private String mMyIp;
- private Map<String, SipSessionGroup> mGroupMap =
- new HashMap<String, SipSessionGroup>();
-
- public SipSessionLayer() throws SipException {
- try {
- mMyIp = getMyIp();
- } catch (IOException e) {
- throw new SipException("SipSessionLayer constructor", e);
- }
- }
-
- public String getLocalIp() {
- if (mMyIp != null) return mMyIp;
- try {
- return getMyIp();
- } catch (IOException e) {
- Log.w(TAG, "getLocalIp(): " + e);
- return "127.0.0.1";
- }
- }
-
- private String getMyIp() throws IOException {
- DatagramSocket s = new DatagramSocket();
- s.connect(InetAddress.getByName("192.168.1.1"), 80);
- return s.getLocalAddress().getHostAddress();
- }
-
- public synchronized void close() {
- for (String key : mGroupMap.keySet()) {
- mGroupMap.get(key).close();
- }
- mGroupMap.clear();
- }
-
- public synchronized SipSession createSipSession(SipProfile myself,
- SipSessionListener listener) throws SipException {
- String key = myself.getUri().toString();
- SipSessionGroup group = mGroupMap.get(key);
- if (group == null) {
- group = new SipSessionGroup(mMyIp, myself, listener);
- mGroupMap.put(key, group);
- }
- return group.getDefaultSession();
- }
-}
diff --git a/src/android/net/sip/SipSessionListener.java b/src/android/net/sip/SipSessionListener.java
deleted file mode 100644
index 98a5d53..0000000
--- a/src/android/net/sip/SipSessionListener.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.sip;
-
-public interface SipSessionListener {
- void onCalling(SipSession session);
- void onRinging(SipSession session, SipProfile caller,
- byte[] sessionDescription);
- void onRingingBack(SipSession session);
- void onCallEstablished(SipSession session, byte[] sessionDescription);
- void onCallEnded(SipSession session);
- void onCallBusy(SipSession session);
- void onCallChanged(SipSession session, byte[] sessionDescription);
- void onError(SipSession session, Throwable e);
-
- void onRegistrationDone(SipSession session);
- void onRegistrationFailed(SipSession session, Throwable e);
- void onRegistrationTimeout(SipSession session);
-}
diff --git a/src/android/net/sip/SipSessionState.java b/src/android/net/sip/SipSessionState.java
deleted file mode 100644
index e9ab53d..0000000
--- a/src/android/net/sip/SipSessionState.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.sip;
-
-/**
- * Defines {@link SipSession} states.
- */
-public enum SipSessionState {
- READY_FOR_CALL,
- REGISTERING,
- DEREGISTERING,
- INCOMING_CALL,
- INCOMING_CALL_ANSWERING,
- OUTGOING_CALL,
- OUTGOING_CALL_RING_BACK,
- OUTGOING_CALL_CANCELING,
-
- // the states below must be after the session being established
- IN_CALL,
- IN_CALL_CHANGING,
- IN_CALL_CHANGING_CANCELING,
- IN_CALL_ANSWERING,
-}
diff --git a/src/com/android/sip/SipAudioCall.java b/src/com/android/sip/SipAudioCall.java
deleted file mode 100644
index e84f82f..0000000
--- a/src/com/android/sip/SipAudioCall.java
+++ /dev/null
@@ -1,461 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.sip;
-
-import gov.nist.javax.sdp.fields.SDPKeywords;
-
-import com.android.sip.media.RtpFactory;
-import com.android.sip.media.RtpSession;
-
-import android.content.Context;
-import android.media.AudioManager;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
-import android.media.ToneGenerator;
-import android.net.Uri;
-import android.net.sip.SdpSessionDescription;
-import android.net.sip.SessionDescription;
-import android.net.sip.SipProfile;
-import android.net.sip.SipSession;
-import android.net.sip.SipSessionLayer;
-import android.net.sip.SipSessionListener;
-import android.net.sip.SipSessionState;
-import android.os.Vibrator;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.io.IOException;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.text.ParseException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import javax.sdp.SdpException;
-import javax.sip.SipException;
-
-/**
- * Class that handles audio call over SIP.
- */
-public class SipAudioCall {
- private static final String TAG = SipAudioCall.class.getSimpleName();
-
- public interface Listener {
- void onReadyForCall(SipAudioCall call);
- void onCalling(SipAudioCall call);
- void onRinging(SipAudioCall call, SipProfile caller);
- void onRingingBack(SipAudioCall call);
- void onCallEstablished(SipAudioCall call);
- void onCallEnded(SipAudioCall call);
- void onCallBusy(SipAudioCall call);
- void onCallHeld(SipAudioCall call);
- void onError(SipAudioCall call, Throwable e);
- }
-
- private Context mContext;
- private SipProfile mLocalProfile;
- private Listener mListener;
- private SipSessionLayer mSipSessionLayer;
- private SipSession mSipSession;
- private SipSession mSipCallSession;
- private SdpSessionDescription mOfferSd;
-
- private RtpSession mRtpSession;
- private DatagramSocket mMediaSocket;
- private boolean mHolding = false;
-
- private boolean mRingbackToneEnabled = true;
- private boolean mRingtoneEnabled = true;
- private Ringtone mRingtone;
- private ToneGenerator mRingbackTone;
-
- private SipProfile mPendingCallRequest;
-
- public SipAudioCall(Context context, SipProfile localProfile,
- Listener listener) throws SipException {
- if (listener == null) {
- throw new NullPointerException("listener can't be null");
- }
- mContext = context;
- mLocalProfile = localProfile;
- mListener = listener;
- mSipSessionLayer = new SipSessionLayer();
- mSipSession = mSipSessionLayer.createSipSession(
- localProfile, createSipSessionListener());
- }
-
- // TODO: remove this after SipService is done
- public void register() throws SipException {
- if (mSipSession != null) mSipSession.register();
- }
-
- public void close() {
- if (mSipSessionLayer != null) {
- stopCall();
- mSipSessionLayer.close();
- mSipSessionLayer = null;
- mSipSession = null;
- }
- stopRingbackTone();
- stopRinging();
- }
-
- public SipSessionState getState() {
- return getActiveSession().getState();
- }
-
- private SipSession getActiveSession() {
- return ((mSipCallSession == null) ? mSipSession
- : mSipCallSession);
- }
-
- private SipSessionListener createSipSessionListener() {
- return new SipSessionListener() {
- public void onCalling(SipSession session) {
- Log.v(TAG, "calling... " + session);
- mListener.onCalling(SipAudioCall.this);
- }
-
- public void onRinging(SipSession session, SipProfile caller,
- byte[] sessionDescription) {
- startRinging();
- try {
- SdpSessionDescription sd = mOfferSd =
- new SdpSessionDescription(sessionDescription);
- Log.v(TAG, "sip call ringing: " + session + ": " + sd);
- } catch (SdpException e) {
- Log.e(TAG, "create SDP", e);
- }
- mListener.onRinging(SipAudioCall.this, caller);
- }
-
- public void onRingingBack(SipSession session) {
- Log.v(TAG, "sip call ringing back: " + session);
- startRingbackTone();
- mListener.onRingingBack(SipAudioCall.this);
- }
-
- public void onCallEstablished(
- SipSession session, byte[] sessionDescription) {
- stopRingbackTone();
- stopRinging();
- try {
- SdpSessionDescription sd =
- new SdpSessionDescription(sessionDescription);
- Log.v(TAG, "sip call established: " + session + ": " + sd);
- mSipCallSession = session;
- startCall(sd);
- } catch (SdpException e) {
- Log.e(TAG, "createSessionDescription()", e);
- }
- mListener.onCallEstablished(SipAudioCall.this);
- }
-
- public void onCallEnded(SipSession session) {
- Log.v(TAG, "sip call ended: " + session);
- stopCall();
- stopRingbackTone();
- stopRinging();
- mSipCallSession = null;
- mHolding = false;
- mListener.onCallEnded(SipAudioCall.this);
- }
-
- public void onCallBusy(SipSession session) {
- Log.v(TAG, "sip call busy: " + session);
- mListener.onCallBusy(SipAudioCall.this);
- }
-
- public void onCallChanged(
- SipSession session, byte[] sessionDescription) {
- String message = new String(sessionDescription);
- Log.v(TAG, "sip call " + message + ": " + session);
- mHolding = !mHolding;
- if (mHolding) {
- mListener.onCallHeld(SipAudioCall.this);
- } else {
- mListener.onCallEstablished(SipAudioCall.this);
- }
- }
-
- public void onError(SipSession session, Throwable e) {
- Log.v(TAG, "sip session error: " + e);
- stopRingbackTone();
- stopRinging();
- mHolding = false;
- mListener.onError(SipAudioCall.this, e);
- }
-
- public void onRegistrationDone(SipSession session) {
- Log.v(TAG, "sip registration done: " + session);
- synchronized (session) {
- if (mPendingCallRequest != null) {
- SipProfile peerProfile = mPendingCallRequest;
- mPendingCallRequest = null;
- try {
- makeCall(peerProfile);
- } catch (SipException e) {
- mListener.onError(SipAudioCall.this, e);
- return;
- }
- } else {
- mListener.onReadyForCall(SipAudioCall.this);
- }
- }
- }
-
- public void onRegistrationFailed(SipSession session, Throwable e) {
- Log.v(TAG, "sip registration failed: " + session + ": " + e);
- if (mPendingCallRequest != null) mPendingCallRequest = null;
- mListener.onError(SipAudioCall.this, e);
- }
-
- public void onRegistrationTimeout(SipSession session) {
- Log.v(TAG, "sip registration timed out: " + session);
- if (mPendingCallRequest != null) mPendingCallRequest = null;
- mListener.onError(SipAudioCall.this,
- new SipException("SIP registration timed out"));
- }
- };
- }
-
- public void makeCall(SipProfile peerProfile) throws SipException {
- synchronized (mSipSession) {
- if (mSipSession.getState() == SipSessionState.READY_FOR_CALL) {
- Log.v(TAG, "making call...");
- mSipSession.makeCall(
- peerProfile, createOfferSessionDescription());
- } else {
- Log.v(TAG, "hold the call request...");
- mPendingCallRequest = peerProfile;
- }
- }
- }
-
- public void endCall() throws SipException {
- stopRinging();
- getActiveSession().endCall();
- }
-
- public void holdCall() throws SipException {
- if (mHolding) return;
- getActiveSession().changeCall(createHoldSessionDescription());
- mHolding = true;
- }
-
- public void answerCall() throws SipException {
- stopRinging();
- getActiveSession().answerCall(createAnswerSessionDescription());
- }
-
- public void continueCall() throws SipException {
- if (!mHolding) return;
- getActiveSession().changeCall(createContinueSessionDescription());
- mHolding = false;
- }
-
- private SessionDescription createOfferSessionDescription() {
- RtpSession[] rtpSessions = RtpFactory.getSystemSupportedAudioSessions();
- return createSdpBuilder(rtpSessions).build();
- }
-
- private SessionDescription createAnswerSessionDescription() {
- // choose an acceptable media from mOfferSd to answer
- RtpSession rtpSession =
- RtpFactory.createAudioSession(getCodecId(mOfferSd));
- return createSdpBuilder(rtpSession).build();
- }
-
- private SessionDescription createHoldSessionDescription() {
- try {
- return createSdpBuilder(mRtpSession)
- .addMediaAttribute("sendonly", (String) null)
- .build();
- } catch (SdpException e) {
- throw new RuntimeException(e);
- }
- }
-
- private SessionDescription createContinueSessionDescription() {
- return createSdpBuilder(mRtpSession).build();
- }
-
- private String getMediaDescription(RtpSession session) {
- return String.format("%d %s/%d", session.getCodecId(),
- session.getName(), session.getSampleRate());
- }
-
- private SdpSessionDescription.Builder createSdpBuilder(RtpSession... rtpSessions) {
- String localIp = getLocalIp();
- SdpSessionDescription.Builder sdpBuilder;
- try {
- long sessionId = (long) (Math.random() * 10000000L);
- long sessionVersion = (long) (Math.random() * 10000000L);
- sdpBuilder = new SdpSessionDescription.Builder("SIP Call")
- .setOrigin(mLocalProfile, sessionId, sessionVersion,
- SDPKeywords.IN, SDPKeywords.IPV4, localIp)
- .setConnectionInfo(SDPKeywords.IN, SDPKeywords.IPV4,
- localIp);
- List<Integer> codecIds = new ArrayList<Integer>();
- for (RtpSession s : rtpSessions) {
- codecIds.add(s.getCodecId());
- }
- sdpBuilder.addMedia("audio", getLocalMediaPort(), 1, "RTP/AVP",
- codecIds.toArray(new Integer[codecIds.size()]));
- for (RtpSession s : rtpSessions) {
- sdpBuilder.addMediaAttribute("rtpmap", getMediaDescription(s));
- }
- sdpBuilder.addMediaAttribute("rtpmap", "101 telephone-event/8000");
- // FIXME: deal with vbr codec
- sdpBuilder.addMediaAttribute("ptime", "20");
- } catch (SdpException e) {
- throw new RuntimeException(e);
- }
- return sdpBuilder;
- }
-
- public void setInCallMode() {
- ((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE))
- .setMode(AudioManager.MODE_IN_CALL);
- }
-
- public void setSpeakerMode() {
- ((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE))
- .setMode(AudioManager.MODE_NORMAL);
- }
-
- private int getCodecId(SdpSessionDescription sd) {
- Set<Integer> acceptableFormats = new HashSet<Integer>();
- for (RtpSession session :
- RtpFactory.getSystemSupportedAudioSessions()) {
- acceptableFormats.add(session.getCodecId());
- }
- for (int id : sd.getMediaFormats()) {
- if (acceptableFormats.contains(id)) return id;
- }
- Log.w(TAG, "no common codec is found, use 0");
- return 0;
- }
-
- private void startCall(SdpSessionDescription sd) {
- String peerMediaAddress = sd.getPeerMediaAddress();
- // TODO: handle multiple media fields
- int peerMediaPort = sd.getPeerMediaPort();
- Log.i(TAG, "start audiocall " + peerMediaAddress + ":" + peerMediaPort);
-
- int localPort = getLocalMediaPort();
- int sampleRate = 8000;
- int frameSize = sampleRate / 50; // 160
- try {
- // TODO: get sample rate from sdp
- mMediaSocket.connect(InetAddress.getByName(peerMediaAddress),
- peerMediaPort);
- mRtpSession = RtpFactory.createAudioSession(getCodecId(sd));
- mRtpSession.start(sampleRate, mMediaSocket);
- setInCallMode();
- } catch (Exception e) {
- Log.e(TAG, "call()", e);
- }
- Log.v(TAG, " ~~~~~~~~~~~ start media: localPort=" + localPort
- + ", peer=" + peerMediaAddress + ":" + peerMediaPort);
- }
-
- public void stopCall() {
- Log.i(TAG, "stop audiocall");
- if (mRtpSession != null) {
- mRtpSession.stop();
- if (mMediaSocket != null) mMediaSocket.close();
- mMediaSocket = null;
- }
- setSpeakerMode();
- }
-
- public void sendDtmf() {
- SipSession activeSession = getActiveSession();
- if (SipSessionState.IN_CALL == activeSession.getState()) {
- mRtpSession.sendDtmf();
- }
- }
-
- private int getLocalMediaPort() {
- if (mMediaSocket != null) return mMediaSocket.getLocalPort();
- try {
- DatagramSocket s = mMediaSocket = new DatagramSocket();
- int localPort = s.getLocalPort();
- return localPort;
- } catch (IOException e) {
- Log.w(TAG, "getLocalMediaPort(): " + e);
- throw new RuntimeException(e);
- }
- }
-
- public String getLocalIp() {
- return mSipSessionLayer.getLocalIp();
- }
-
- public void setRingbackToneEnabled(boolean enabled) {
- mRingbackToneEnabled = enabled;
- }
-
- public void setRingtoneEnabled(boolean enabled) {
- mRingtoneEnabled = enabled;
- }
-
- private synchronized void startRingbackTone() {
- if (!mRingbackToneEnabled) return;
- if (mRingbackTone == null) {
- // The volume relative to other sounds in the stream
- int toneVolume = 80;
- mRingbackTone = new ToneGenerator(
- AudioManager.STREAM_MUSIC, toneVolume);
- }
- setInCallMode();
- mRingbackTone.startTone(ToneGenerator.TONE_CDMA_LOW_PBX_L);
- }
-
- private synchronized void stopRingbackTone() {
- if (mRingbackTone != null) {
- mRingbackTone.stopTone();
- setSpeakerMode();
- mRingbackTone.release();
- mRingbackTone = null;
- }
- }
-
- private synchronized void startRinging() {
- if (!mRingtoneEnabled) return;
- ((Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE))
- .vibrate(new long[] {0, 1000, 1000}, 1);
- AudioManager am = (AudioManager)
- mContext.getSystemService(Context.AUDIO_SERVICE);
- if (am.getStreamVolume(AudioManager.STREAM_RING) > 0) {
- String ringtoneUri =
- Settings.System.DEFAULT_RINGTONE_URI.toString();
- mRingtone = RingtoneManager.getRingtone(mContext,
- Uri.parse(ringtoneUri));
- mRingtone.play();
- }
- }
-
- private synchronized void stopRinging() {
- ((Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE))
- .cancel();
- if (mRingtone != null) mRingtone.stop();
- }
-}
diff --git a/src/com/android/sip/SipMain.java b/src/com/android/sip/SipMain.java
deleted file mode 100644
index 851620d..0000000
--- a/src/com/android/sip/SipMain.java
+++ /dev/null
@@ -1,557 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.sip;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.net.sip.SipProfile;
-import android.net.sip.SipSessionState;
-import android.os.Bundle;
-import android.preference.EditTextPreference;
-import android.preference.Preference;
-import android.preference.PreferenceActivity;
-import android.preference.PreferenceScreen;
-import android.preference.Preference.OnPreferenceClickListener;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-
-import java.io.IOException;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.text.ParseException;
-import javax.sip.SipException;
-
-/**
- */
-public class SipMain extends PreferenceActivity
- implements Preference.OnPreferenceChangeListener {
- private static final String TAG = SipMain.class.getSimpleName();
- private static final int MENU_REGISTER = Menu.FIRST;
- private static final int MENU_CALL = Menu.FIRST + 1;
- private static final int MENU_HANGUP = Menu.FIRST + 2;
- private static final int MENU_SEND_DTMF_1 = Menu.FIRST + 3;
- private static final int MENU_SPEAKER_MODE = Menu.FIRST + 4;
-
- private Preference mCallStatus;
- private EditTextPreference mPeerUri;
- private EditTextPreference mServerUri;
- private EditTextPreference mPassword;
- private EditTextPreference mDisplayName;
- private EditTextPreference mOutboundProxy;
- private Preference mMyIp;
-
- private SipProfile mLocalProfile;
- private SipAudioCall mAudioCall;
-
- private MyDialog mDialog;
- private boolean mHolding;
- private Throwable mError;
- private boolean mChanged;
- private boolean mSpeakerMode;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- addPreferencesFromResource(R.xml.dev_pref);
-
- mCallStatus = getPreferenceScreen().findPreference("call_status");
- mPeerUri = setupEditTextPreference("peer");
- mServerUri = setupEditTextPreference("server_address");
- mPassword = (EditTextPreference)
- getPreferenceScreen().findPreference("password");
- mPassword.setOnPreferenceChangeListener(this);
- mDisplayName = setupEditTextPreference("display_name");
- mOutboundProxy = setupEditTextPreference("proxy_address");
- mMyIp = getPreferenceScreen().findPreference("my_ip");
- mMyIp.setOnPreferenceClickListener(
- new OnPreferenceClickListener() {
- public boolean onPreferenceClick(Preference preference) {
- // for testing convenience: copy my IP to server address
- if (TextUtils.isEmpty(mServerUri.getText())) {
- String myIp = mMyIp.getSummary().toString();
- String uri = "test@" + myIp + ":5060";
- mServerUri.setText(uri);
- mServerUri.setSummary(uri);
- }
- return true;
- }
- });
-
- mCallStatus.setOnPreferenceClickListener(
- new OnPreferenceClickListener() {
- public boolean onPreferenceClick(Preference preference) {
- actOnCallStatus();
- return true;
- }
- });
- setCallStatus();
-
- new Thread(new Runnable() {
- public void run() {
- final String localIp = getLocalIp();
- runOnUiThread(new Runnable() {
- public void run() {
- mMyIp.setSummary(localIp);
- }
- });
- }
- }).start();
- }
-
- private void createSipAudioCall() throws SipException {
- if ((mAudioCall == null) || mChanged) {
- if (mAudioCall != null) mAudioCall.close();
- mAudioCall = new SipAudioCall(this, createLocalSipProfile(),
- createListener());
- mChanged = false;
- Log.v(TAG, "info changed; recreate AudioCall isntance");
- }
- }
-
- private EditTextPreference setupEditTextPreference(String key) {
- EditTextPreference pref = (EditTextPreference)
- getPreferenceScreen().findPreference(key);
- pref.setOnPreferenceChangeListener(this);
- pref.setSummary(pref.getText());
- return pref;
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- if (mAudioCall != null) mAudioCall.close();
- }
-
- public boolean onPreferenceChange(Preference pref, Object newValue) {
- String value = (String) newValue;
- if (value == null) value = "";
- if (pref != mPassword) pref.setSummary(value);
- if ((pref != mPeerUri)
- && !value.equals(((EditTextPreference) pref).getText())) {
- mChanged = true;
- }
- return true;
- }
-
- private String getText(EditTextPreference preference) {
- CharSequence text = preference.getText();
- return ((text == null) ? "" : text.toString());
- }
-
- private SipProfile createLocalSipProfile() throws SipException {
- try {
- if ((mLocalProfile == null) || mChanged) {
- String serverUri = getText(mServerUri);
- if (TextUtils.isEmpty(serverUri)) {
- throw new SipException("Server address missing");
- }
- mLocalProfile = new SipProfile.Builder(serverUri)
- .setPassword(getText(mPassword))
- .setDisplayName(getText(mDisplayName))
- .setOutboundProxy(getText(mOutboundProxy))
- .build();
- }
- return mLocalProfile;
- } catch (ParseException e) {
- throw new SipException("createLoalSipProfile", e);
- }
- }
-
- private SipProfile createPeerSipProfile() {
- try {
- return new SipProfile.Builder(getPeerUri()).build();
- } catch (ParseException e) {
- throw new RuntimeException(e);
- }
- }
-
- private void setCallStatus(Throwable e) {
- mError = e;
- setCallStatus();
- }
-
- private void setCallStatus() {
- runOnUiThread(new Runnable() {
- public void run() {
- mCallStatus.setSummary(getCallStatus());
- mError = null;
- }
- });
- }
-
- private void showCallNotificationDialog(SipProfile caller) {
- mDialog = new CallNotificationDialog(caller);
- runOnUiThread(new Runnable() {
- public void run() {
- showDialog(mDialog.getId());
- }
- });
- }
-
- private SipAudioCall.Listener createListener() {
- return new SipAudioCall.Listener() {
- public void onCalling(SipAudioCall call) {
- setCallStatus();
- }
-
- public void onReadyForCall(SipAudioCall call) {
- setCallStatus();
- }
-
- public void onRinging(SipAudioCall call, SipProfile caller) {
- showCallNotificationDialog(caller);
- setCallStatus();
- }
-
- public void onRingingBack(SipAudioCall call) {
- setCallStatus();
- }
-
- public void onCallEstablished(SipAudioCall call) {
- setAllPreferencesEnabled(false);
- setCallStatus();
- }
-
- public void onCallEnded(SipAudioCall call) {
- setCallStatus();
- setAllPreferencesEnabled(true);
- }
-
- public void onCallBusy(SipAudioCall call) {
- setCallStatus();
- }
-
- public void onCallHeld(SipAudioCall call) {
- setCallStatus();
- }
-
- public void onError(SipAudioCall call, Throwable e) {
- mError = e;
- setCallStatus();
- }
- };
- }
-
- private void register() {
- try {
- createSipAudioCall();
- mAudioCall.register();
- } catch (SipException e) {
- Log.e(TAG, "makeCall()", e);
- setCallStatus(e);
- }
- }
-
- private void makeCall() {
- try {
- createSipAudioCall();
- mAudioCall.makeCall(createPeerSipProfile());
- } catch (SipException e) {
- Log.e(TAG, "makeCall()", e);
- setCallStatus(e);
- }
- }
-
- private void endCall() {
- try {
- mAudioCall.endCall();
- mSpeakerMode = false;
- } catch (SipException e) {
- Log.e(TAG, "endCall()", e);
- setCallStatus(e);
- }
- }
-
- private void holdOrEndCall() {
- try {
- if (Math.random() > 0.4) {
- mAudioCall.holdCall();
- } else {
- mAudioCall.endCall();
- }
- } catch (SipException e) {
- Log.e(TAG, "holdOrEndCall()", e);
- setCallStatus(e);
- }
- }
-
- private void answerCall() {
- try {
- mAudioCall.answerCall();
- } catch (SipException e) {
- Log.e(TAG, "answerCall()", e);
- setCallStatus(e);
- }
- }
-
- private void answerOrEndCall() {
- if (Math.random() > 0) {
- answerCall();
- } else {
- endCall();
- }
- }
-
- private void continueCall() {
- try {
- mAudioCall.continueCall();
- } catch (SipException e) {
- Log.e(TAG, "continueCall()", e);
- setCallStatus(e);
- }
- }
-
-
- private void setAllPreferencesEnabled(final boolean enabled) {
- runOnUiThread(new Runnable() {
- public void run() {
- for (Preference preference : allPreferences()) {
- preference.setEnabled(enabled);
- }
- }
- });
- }
-
- private Preference[] allPreferences() {
- return new Preference[] {
- mCallStatus, mPeerUri, mServerUri, mPassword, mDisplayName, mOutboundProxy, mMyIp
- };
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- super.onPrepareOptionsMenu(menu);
- SipSessionState state = ((mAudioCall == null) || mChanged)
- ? SipSessionState.READY_FOR_CALL
- : mAudioCall.getState();
-
- Log.v(TAG, "actOnCallStatus(), status=" + state);
- menu.clear();
- switch (state) {
- case READY_FOR_CALL:
- menu.add(0, MENU_REGISTER, 0, R.string.menu_register);
- menu.add(0, MENU_CALL, 0, R.string.menu_call);
- break;
- case IN_CALL:
- menu.add(0, MENU_SPEAKER_MODE, 0, (mSpeakerMode ?
- R.string.menu_incall_mode : R.string.menu_speaker_mode));
- menu.add(0, MENU_SEND_DTMF_1, 0, R.string.menu_send_dtmf);
- /* pass through */
- default:
- menu.add(0, MENU_HANGUP, 0, R.string.menu_hangup);
- }
- return true;
- }
-
- @Override
- public synchronized boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case MENU_REGISTER:
- register();
- setCallStatus();
- return true;
-
- case MENU_CALL:
- makeCall();
- return true;
-
- case MENU_HANGUP:
- endCall();
- return true;
-
- case MENU_SPEAKER_MODE:
- mSpeakerMode = !mSpeakerMode;
- if (mSpeakerMode == true) {
- mAudioCall.setSpeakerMode();
- } else {
- mAudioCall.setInCallMode();
- }
- return true;
-
- case MENU_SEND_DTMF_1:
- mAudioCall.sendDtmf();
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- private String getPeerUri() {
- return getText(mPeerUri);
- }
-
- private void setValue(EditTextPreference pref, String value) {
- pref.setSummary((value == null) ? "" : value.trim());
- }
-
- private void setSummary(Preference pref, int fieldNameId, String v) {
- setSummary(pref, fieldNameId, v, true);
- }
-
- private void setSummary(Preference pref, int fieldNameId, String v,
- boolean required) {
- String formatString = required
- ? getString(R.string.field_not_set)
- : getString(R.string.field_not_set_optional);
- pref.setSummary(TextUtils.isEmpty(v)
- ? String.format(formatString, getString(fieldNameId))
- : v);
- }
-
- private String getCallStatus() {
- if (mError != null) return mError.getMessage();
- if (mAudioCall == null) return "Ready to call (not registered)";
- switch (mAudioCall.getState()) {
- case REGISTERING:
- return "Registering...";
- case READY_FOR_CALL:
- return "Ready for call";
- case INCOMING_CALL:
- return "Ringing...";
- case INCOMING_CALL_ANSWERING:
- return "Answering...";
- case OUTGOING_CALL:
- return "Calling...";
- case OUTGOING_CALL_RING_BACK:
- return "Ringing back...";
- case OUTGOING_CALL_CANCELING:
- return "Cancelling...";
- case IN_CALL:
- return (mHolding ? "On hold" : "Established");
- case IN_CALL_CHANGING:
- return "Changing session...";
- case IN_CALL_ANSWERING:
- return "Changing session answering...";
- default:
- return "Unknown";
- }
- }
-
- private void actOnCallStatus() {
- if ((mAudioCall == null) || mChanged) {
- register();
- } else {
- switch (mAudioCall.getState()) {
- case READY_FOR_CALL:
- makeCall();
- break;
- case INCOMING_CALL:
- answerOrEndCall();
- break;
- case OUTGOING_CALL_RING_BACK:
- case OUTGOING_CALL:
- case IN_CALL_CHANGING:
- endCall();
- break;
- case IN_CALL:
- if (!mHolding) {
- holdOrEndCall();
- } else {
- continueCall();
- }
- break;
- case OUTGOING_CALL_CANCELING:
- case REGISTERING:
- case INCOMING_CALL_ANSWERING:
- default:
- // do nothing
- break;
- }
- }
-
- setCallStatus();
- }
-
- @Override
- protected Dialog onCreateDialog (int id) {
- return ((mDialog == null) ? null : mDialog.createDialog(id));
- }
-
- @Override
- protected void onPrepareDialog (int id, Dialog dialog) {
- if (mDialog != null) mDialog.prepareDialog(id, dialog);
- }
-
- private class CallNotificationDialog implements MyDialog {
- private SipProfile mCaller;
-
- CallNotificationDialog(SipProfile caller) {
- mCaller = caller;
- }
-
- public int getId() {
- return 0;
- }
-
- private String getCallerName() {
- String name = mCaller.getDisplayName();
- if (TextUtils.isEmpty(name)) name = mCaller.getUri().toString();
- return name;
- }
-
- public Dialog createDialog(int id) {
- if (id != getId()) return null;
- Log.d(TAG, "create call notification dialog");
- return new AlertDialog.Builder(SipMain.this)
- .setTitle(getCallerName())
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setPositiveButton("Answer",
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int w) {
- answerCall();
- }
- })
- .setNegativeButton("Hang up",
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int w) {
- endCall();
- }
- })
- .setOnCancelListener(new DialogInterface.OnCancelListener() {
- public void onCancel(DialogInterface dialog) {
- endCall();
- }
- })
- .create();
- }
-
- public void prepareDialog(int id, Dialog dialog) {
- if (id != getId()) return;
- dialog.setTitle(getCallerName());
- }
- }
-
- private interface MyDialog {
- int getId();
- Dialog createDialog(int id);
- void prepareDialog(int id, Dialog dialog);
- }
-
- private String getLocalIp() {
- try {
- DatagramSocket s = new DatagramSocket();
- s.connect(InetAddress.getByName("192.168.1.1"), 80);
- return s.getLocalAddress().getHostAddress();
- } catch (IOException e) {
- Log.w(TAG, "getLocalIp(): " + e);
- return "127.0.0.1";
- }
- }
-}
diff --git a/src/com/android/sip/media/Decoder.java b/src/com/android/sip/media/Decoder.java
deleted file mode 100644
index c0f1060..0000000
--- a/src/com/android/sip/media/Decoder.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.sip.media;
-
-import java.io.IOException;
-
-public interface Decoder {
- int getSampleCount(int frameSize);
-
- /**
- * Decodes from the encoded data array.
- *
- * @param result the decoded result array
- * @param src encoded data
- * @param count valid data length in src
- * @param offset offset of data bytes in src
- */
- int decode(short[] result, byte[] src, int count, int offset)
- throws IOException;
-}
diff --git a/src/com/android/sip/media/Encoder.java b/src/com/android/sip/media/Encoder.java
deleted file mode 100644
index f1845e5..0000000
--- a/src/com/android/sip/media/Encoder.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.sip.media;
-
-public interface Encoder {
- int getSampleCount(int frameSize);
-
- /**
- * Encodes the sample data.
- *
- * @param src sample data
- * @param count valid data length in src
- * @param result the encoded result array
- * @param offset offset of data bytes in result
- */
- int encode(short[] src, int count, byte[] result, int offset);
-}
diff --git a/src/com/android/sip/media/G711ACodec.java b/src/com/android/sip/media/G711ACodec.java
deleted file mode 100644
index 52b2cb5..0000000
--- a/src/com/android/sip/media/G711ACodec.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.sip.media;
-
-/**
- * G.711 codec. This class provides a-law conversion.
- */
-public class G711ACodec implements Encoder, Decoder {
- // s0000000wxyz...s000wxyz
- // s0000001wxyz...s001wxyz
- // s000001wxyza...s010wxyz
- // s00001wxyzab...s011wxyz
- // s0001wxyzabc...s100wxyz
- // s001wxyzabcd...s101wxyz
- // s01wxyzabcde...s110wxyz
- // s1wxyzabcdef...s111wxyz
-
- private static byte[] table12to8 = new byte[4096];
- private static short[] table8to16 = new short[256];
-
- static {
- // b12 --> b8
- for (int m = 0; m < 16; m++) {
- int v = m ^ 0x55;
- table12to8[m] = (byte) v;
- table12to8[4095 - m] = (byte) (v + 128);
- }
- for (int p = 1, q = 0x10; p <= 0x40; p <<= 1, q+=0x10) {
- for (int i = 0, j = (p << 4); i < 16; i++, j += p) {
- int v = (i + q) ^ 0x55;
- byte value1 = (byte) v;
- byte value2 = (byte) (v + 128);
- for (int m = j, e = j + p; m < e; m++) {
- table12to8[m] = value1;
- table12to8[4095 - m] = value2;
- }
- }
- }
-
- // b8 --> b16
- for (int m = 0; m < 16; m++) {
- int v = m << 4;
- table8to16[m ^ 0x55] = (short) v;
- table8to16[(m + 128) ^ 0x55] = (short) (65536 - v);
- }
- for (int q = 1; q <= 7; q++) {
- for (int i = 0, m = (q << 4); i < 16; i++, m++) {
- int v = (i + 0x10) << (q + 3);
- table8to16[m ^ 0x55] = (short) v;
- table8to16[(m + 128) ^ 0x55] = (short) (65536 - v);
- }
- }
- }
-
- public int decode(short[] b16, byte[] b8, int count, int offset) {
- for (int i = 0, j = offset; i < count; i++, j++) {
- b16[i] = table8to16[b8[j] & 0xff];
- }
- return count;
- }
-
- public int encode(short[] b16, int count, byte[] b8, int offset) {
-
- for (int i = 0, j = offset; i < count; i++, j++) {
- b8[j] = table12to8[(b16[i] & 0xffff) >> 4];
- }
- return count;
- }
-
- public int getSampleCount(int frameSize) {
- return frameSize;
- }
-}
diff --git a/src/com/android/sip/media/G711UCodec.java b/src/com/android/sip/media/G711UCodec.java
deleted file mode 100644
index b8f681a..0000000
--- a/src/com/android/sip/media/G711UCodec.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.sip.media;
-
-/**
- * G.711 codec. This class provides u-law conversion.
- */
-public class G711UCodec implements Encoder, Decoder {
- // s00000001wxyz...s000wxyz
- // s0000001wxyza...s001wxyz
- // s000001wxyzab...s010wxyz
- // s00001wxyzabc...s011wxyz
- // s0001wxyzabcd...s100wxyz
- // s001wxyzabcde...s101wxyz
- // s01wxyzabcdef...s110wxyz
- // s1wxyzabcdefg...s111wxyz
-
- private static byte[] table13to8 = new byte[8192];
- private static short[] table8to16 = new short[256];
-
- static {
- // b13 --> b8
- for (int p = 1, q = 0; p <= 0x80; p <<= 1, q+=0x10) {
- for (int i = 0, j = (p << 4) - 0x10; i < 16; i++, j += p) {
- int v = (i + q) ^ 0x7F;
- byte value1 = (byte) v;
- byte value2 = (byte) (v + 128);
- for (int m = j, e = j + p; m < e; m++) {
- table13to8[m] = value1;
- table13to8[8191 - m] = value2;
- }
- }
- }
-
- // b8 --> b16
- for (int q = 0; q <= 7; q++) {
- for (int i = 0, m = (q << 4); i < 16; i++, m++) {
- int v = (((i + 0x10) << q) - 0x10) << 3;
- table8to16[m ^ 0x7F] = (short) v;
- table8to16[(m ^ 0x7F) + 128] = (short) (65536 - v);
- }
- }
- }
-
- public int decode(short[] b16, byte[] b8, int count, int offset) {
- for (int i = 0, j = offset; i < count; i++, j++) {
- b16[i] = table8to16[b8[j] & 0xFF];
- }
- return count;
- }
-
- public int encode(short[] b16, int count, byte[] b8, int offset) {
-
- for (int i = 0, j = offset; i < count; i++, j++) {
- b8[j] = table13to8[(b16[i] >> 4) & 0x1FFF];
- }
- return count;
- }
-
- public int getSampleCount(int frameSize) {
- return frameSize;
- }
-}
diff --git a/src/com/android/sip/media/RtpAudioSession.java b/src/com/android/sip/media/RtpAudioSession.java
deleted file mode 100644
index 0c7f616..0000000
--- a/src/com/android/sip/media/RtpAudioSession.java
+++ /dev/null
@@ -1,656 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.sip.media;
-
-import java.io.IOException;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-import android.media.AudioFormat;
-import android.media.AudioManager;
-import android.media.AudioRecord;
-import android.media.AudioTrack;
-import android.media.MediaRecorder;
-import android.os.Process;
-import android.util.Log;
-
-class RtpAudioSession implements RtpSession {
- private static final String TAG = RtpAudioSession.class.getSimpleName();
- private static final int AUDIO_SAMPLE_RATE = 8000;
- private static final int MAX_ALLOWABLE_LATENCY = 500; // ms
-
- private boolean mRunning = false;
- private RecordTask mRecordTask;
- private PlayTask mPlayTask;
-
- private DatagramSocket mSocket;
- private InetAddress mRemoteAddr;
- private int mRemotePort;
- private boolean mSendDtmf = false;
- private int mCodecId;
-
- private NoiseGenerator mNoiseGenerator = new NoiseGenerator();
-
- RtpAudioSession(int codecId) {
- mCodecId = codecId;
- }
-
- private void init(int remoteSampleRate, DatagramSocket socket) {
- mRemoteAddr = socket.getInetAddress();
- mRemotePort = socket.getPort();
- mSocket = socket;
- int localFrameSize = AUDIO_SAMPLE_RATE / 50; // 50 frames / sec
- mRecordTask = new RecordTask(AUDIO_SAMPLE_RATE, localFrameSize);
- mPlayTask = new PlayTask(remoteSampleRate, localFrameSize);
- Log.v(TAG, "create RtpSession: to connect to " + mRemoteAddr + ":"
- + mRemotePort + " using codec " + mCodecId);
- }
-
- public int getCodecId() {
- return mCodecId;
- }
-
- public int getSampleRate() {
- return AUDIO_SAMPLE_RATE;
- }
-
- public String getName() {
- switch (mCodecId) {
- case 8: return "PCMA";
- default: return "PCMU";
- }
- }
-
- public void start(int remoteSampleRate, DatagramSocket connectedSocket)
- throws IOException {
- init(remoteSampleRate, connectedSocket);
- if (mRunning) return;
-
- mRunning = true;
- Log.v(TAG, "start RtpSession: connect to " + mRemoteAddr + ":"
- + mRemotePort);
- if (mRemoteAddr != null) {
- mRecordTask.start(mRemoteAddr, mRemotePort);
- }
- mPlayTask.start();
- }
-
- public synchronized void stop() {
- mRunning = false;
- Log.v(TAG, "stop RtpSession: measured volume = "
- + mNoiseGenerator.mMeasuredVolume);
- // wait until player is stopped
- for (int i = 20; (i > 0) && !mPlayTask.isStopped(); i--) {
- Log.v(TAG, " wait for player to stop...");
- try {
- wait(20);
- } catch (InterruptedException e) {
- // ignored
- }
- }
- }
-
- public void sendDtmf() {
- mSendDtmf = true;
- }
-
- private void startRecordTask(InetAddress remoteAddr, int remotePort) {
- mRemoteAddr = remoteAddr;
- mRemotePort = remotePort;
- if ((mRemoteAddr != null) && mRunning && !mSocket.isConnected()) {
- mRecordTask.start(remoteAddr, remotePort);
- }
- }
-
- private class PlayTask implements Runnable {
- private int mSampleRate;
- private int mFrameSize;
- private AudioPlayer mPlayer;
-
- PlayTask(int sampleRate, int frameSize) {
- mSampleRate = sampleRate;
- mFrameSize = frameSize;
- }
-
- void start() {
- new Thread(this).start();
- }
-
- boolean isStopped() {
- return (mPlayer == null)
- || (mPlayer.getPlayState() == AudioTrack.PLAYSTATE_STOPPED);
- }
-
- public void run() {
- Decoder decoder = RtpFactory.createDecoder(mCodecId);
- int playBufferSize = decoder.getSampleCount(mFrameSize);
- short[] playBuffer = new short[playBufferSize];
-
- RtpReceiver receiver = new RtpReceiver(mFrameSize);
- byte[] buffer = receiver.getBuffer();
- int offset = receiver.getPayloadOffset();
-
- int minBufferSize = AudioTrack.getMinBufferSize(mSampleRate,
- AudioFormat.CHANNEL_CONFIGURATION_MONO,
- AudioFormat.ENCODING_PCM_16BIT) * 6;
- minBufferSize = Math.max(minBufferSize, playBufferSize);
- int bufferHighMark = minBufferSize / 2 * 8 / 10;
- Log.d(TAG, " play buffer = " + minBufferSize + ", high water mark="
- + bufferHighMark);
- AudioTrack aplayer = new AudioTrack(AudioManager.STREAM_MUSIC,
- mSampleRate, AudioFormat.CHANNEL_CONFIGURATION_MONO,
- AudioFormat.ENCODING_PCM_16BIT, minBufferSize,
- AudioTrack.MODE_STREAM);
- AudioPlayer player = mPlayer =
- new AudioPlayer(aplayer, minBufferSize, mFrameSize);
-
- Process.setThreadPriority(Process.THREAD_PRIORITY_AUDIO);
- player.play();
- int playState = player.getPlayState();
- boolean socketConnected = mSocket.isConnected();
- long receiveCount = 0;
- long cyclePeriod = mFrameSize * 1000L / mSampleRate;
- long cycleStart = 0;
- int seqNo = 0;
- int packetLossCount = 0;
- int bytesDropped = 0;
-
- player.flush();
- int writeHead = player.getPlaybackHeadPosition();
-
- // start measurement after first packet arrival
- try {
- receiver.receive();
- Log.d(TAG, "received first packet");
- } catch (IOException e) {
- Log.e(TAG, "receive error; stop player", e);
- player.stop();
- player.release();
- return;
- }
- cycleStart = System.currentTimeMillis();
- seqNo = receiver.getSequenceNumber();
-
- if (!socketConnected) {
- socketConnected = true;
- startRecordTask(receiver.getRemoteAddress(),
- receiver.getRemotePort());
- }
-
- long startTime = System.currentTimeMillis();
- long virtualClock = startTime;
- float delta = 0f;
-
- while (mRunning) {
- try {
- int count = receiver.receive();
- int decodeCount = decoder.decode(
- playBuffer, buffer, count, offset);
- mNoiseGenerator.measureVolume(playBuffer, 0, decodeCount);
- if (playState == AudioTrack.PLAYSTATE_STOPPED) {
- player.play();
- playState = player.getPlayState();
- }
-
- receiveCount ++;
- int sn = receiver.getSequenceNumber();
- int lossCount = sn - seqNo - 1;
- if (lossCount > 0) {
- packetLossCount += lossCount;
- virtualClock += lossCount * cyclePeriod;
- }
- virtualClock += cyclePeriod;
- long now = System.currentTimeMillis();
- long late = now - virtualClock;
- if (late < 0) virtualClock = now;
-
- delta = delta * 0.96f + late * 0.04f;
- if (delta > MAX_ALLOWABLE_LATENCY) {
- delta = MAX_ALLOWABLE_LATENCY;
- }
- late -= (long) delta;
-
- if (late > 100) {
- // drop
- bytesDropped += decodeCount;
- if (LogRateLimiter.allowLogging(now)) {
- Log.d(TAG, " drop " + sn + ":" + decodeCount
- + ", late: " + late + ", d=" + delta);
- }
- cycleStart = now;
- seqNo = sn;
- continue;
- }
- int buffered = writeHead - player.getPlaybackHeadPosition();
- if (buffered > bufferHighMark) {
- player.flush();
- buffered = 0;
- writeHead = player.getPlaybackHeadPosition();
- if (LogRateLimiter.allowLogging(now)) {
- Log.d(TAG, " ~~~ flush: set writeHead to "
- + writeHead);
- }
- }
-
- writeHead += player.write(playBuffer, 0, decodeCount);
-
- cycleStart = now;
- seqNo = sn;
- } catch (IOException e) {
- Log.w(TAG, "network disconnected; playback stopped", e);
- player.stop();
- playState = player.getPlayState();
- }
- }
- Log.d(TAG, " receiveCount = " + receiveCount);
- Log.d(TAG, " # packets lost =" + packetLossCount);
- Log.d(TAG, " bytes dropped =" + bytesDropped);
- Log.d(TAG, "stop sound playing...");
- player.stop();
- player.flush();
- player.release();
- }
- }
-
- private class RecordTask implements Runnable {
- private int mSampleRate;
- private int mFrameSize;
-
- RecordTask(int sampleRate, int frameSize) {
- mSampleRate = sampleRate;
- mFrameSize = frameSize;
- }
-
- void start(InetAddress addr, int port) {
- Log.d(TAG, "start RecordTask, connect to " + addr + ":" + port);
- mSocket.connect(addr, port);
- new Thread(this).start();
- }
-
- private void adjustMicGain(short[] buf, int len, int factor) {
- int i,j;
- for (i = 0; i < len; i++) {
- j = buf[i];
- if (j > 32768/factor) {
- buf[i] = 32767;
- } else if (j < -(32768/factor)) {
- buf[i] = -32767;
- } else {
- buf[i] = (short)(factor*j);
- }
- }
- }
-
- public void run() {
- Encoder encoder = RtpFactory.createEncoder(mCodecId);
- int recordBufferSize = encoder.getSampleCount(mFrameSize);
- short[] recordBuffer = new short[recordBufferSize];
- RtpSender sender = new RtpSender(mFrameSize);
- byte[] buffer = sender.getBuffer();
- int offset = sender.getPayloadOffset();
-
- int bufferSize = AudioRecord.getMinBufferSize(mSampleRate,
- AudioFormat.CHANNEL_CONFIGURATION_MONO,
- AudioFormat.ENCODING_PCM_16BIT) * 3 / 2;
-
- AudioRecord recorder = new AudioRecord(
- MediaRecorder.AudioSource.MIC, mSampleRate,
- AudioFormat.CHANNEL_CONFIGURATION_MONO,
- AudioFormat.ENCODING_PCM_16BIT, bufferSize);
-
- recorder.startRecording();
- Log.d(TAG, "start sound recording..." + recorder.getState());
-
- // skip the first read, kick off read pipeline
- recorder.read(recordBuffer, 0, recordBufferSize);
-
- long sendCount = 0;
- long startTime = System.currentTimeMillis();
-
- while (mRunning) {
- int count = recorder.read(recordBuffer, 0, recordBufferSize);
-
- // TODO: remove the mic gain if the issue is fixed on Passion.
- adjustMicGain(recordBuffer, count, 16);
-
- int encodeCount =
- encoder.encode(recordBuffer, count, buffer, offset);
- try {
- sender.send(encodeCount);
- if (mSendDtmf) {
- recorder.stop();
- sender.sendDtmf();
- mSendDtmf = false;
- recorder.startRecording();
- }
- } catch (IOException e) {
- if (mRunning) Log.e(TAG, "send error, stop sending", e);
- break;
- }
-
- sendCount ++;
- }
- long now = System.currentTimeMillis();
- Log.d(TAG, " sendCount = " + sendCount);
- Log.d(TAG, " avg send cycle ="
- + ((double) (now - startTime) / sendCount));
- Log.d(TAG, "stop sound recording...");
- recorder.stop();
- }
- }
-
- private class RtpReceiver {
- RtpPacket mPacket;
- DatagramPacket mDatagram;
-
- RtpReceiver(int size) {
- byte[] buffer = new byte[size + 12];
- mPacket = new RtpPacket(buffer);
- mPacket.setPayloadType(mCodecId);
- mDatagram = new DatagramPacket(buffer, buffer.length);
- }
-
- byte[] getBuffer() {
- return mPacket.getRawPacket();
- }
-
- int getPayloadOffset() {
- return 12;
- }
-
- // return received payload size
- int receive() throws IOException {
- DatagramPacket datagram = mDatagram;
- mSocket.receive(datagram);
- return datagram.getLength() - 12;
- }
-
- InetAddress getRemoteAddress() {
- return mDatagram.getAddress();
- }
-
- int getRemotePort() {
- return mDatagram.getPort();
- }
-
- int getSequenceNumber() {
- return mPacket.getSequenceNumber();
- }
- }
-
- private class RtpSender extends RtpReceiver {
- private int mSequence = 0;
- private long mTimeStamp = 0;
-
- RtpSender(int size) {
- super(size);
- }
-
- void sendDtmf() throws IOException {
- byte[] buffer = getBuffer();
-
- RtpPacket packet = mPacket;
- packet.setPayloadType(101);
- packet.setPayloadLength(4);
-
- mTimeStamp += 160;
- packet.setTimestamp(mTimeStamp);
- DatagramPacket datagram = mDatagram;
- datagram.setLength(packet.getPacketLength());
- int duration = 480;
- buffer[12] = 1;
- buffer[13] = 0;
- buffer[14] = (byte)(duration >> 8);
- buffer[15] = (byte)duration;
- for (int i = 0; i < 3; i++) {
- packet.setSequenceNumber(mSequence++);
- mSocket.send(datagram);
- try {
- Thread.sleep(20);
- } catch (Exception e) {
- }
- }
- mTimeStamp += 480;
- packet.setTimestamp(mTimeStamp);
- buffer[12] = 1;
- buffer[13] = (byte)0x80;
- buffer[14] = (byte)(duration >> 8);
- buffer[15] = (byte)duration;
- for (int i = 0; i < 3; i++) {
- packet.setSequenceNumber(mSequence++);
- mSocket.send(datagram);
- }
- }
-
- void send(int count) throws IOException {
- mTimeStamp += count;
- RtpPacket packet = mPacket;
- packet.setSequenceNumber(mSequence++);
- packet.setPayloadType(mCodecId);
- packet.setTimestamp(mTimeStamp);
- packet.setPayloadLength(count);
-
- DatagramPacket datagram = mDatagram;
- datagram.setLength(packet.getPacketLength());
- mSocket.send(datagram);
- }
- }
-
- private class NoiseGenerator {
- private static final int AMP = 1000;
- private static final int TURN_DOWN_RATE = 80;
- private static final int NOISE_LENGTH = 160;
-
- private short[] mNoiseBuffer = new short[NOISE_LENGTH];
- private int mMeasuredVolume = 0;
-
- short[] makeNoise() {
- final int len = NOISE_LENGTH;
- short volume = (short) (mMeasuredVolume / TURN_DOWN_RATE / AMP);
- double volume2 = volume * 2.0;
- int m = 8;
- for (int i = 0; i < len; i+=m) {
- short v = (short) (Math.random() * volume2);
- v -= volume;
- for (int j = 0, k = i; (j < m) && (k < len); j++, k++) {
- mNoiseBuffer[k] = v;
- }
- }
- return mNoiseBuffer;
- }
-
- void measureVolume(short[] audioData, int offset, int count) {
- for (int i = 0, j = offset; i < count; i++, j++) {
- mMeasuredVolume = (mMeasuredVolume * 9
- + Math.abs((int) audioData[j]) * AMP) / 10;
- }
- }
-
- int getNoiseLength() {
- return mNoiseBuffer.length;
- }
- }
-
- // Use another thread to play back to avoid playback blocks network
- // receiving thread
- private class AudioPlayer implements Runnable,
- AudioTrack.OnPlaybackPositionUpdateListener {
- private short[] mBuffer;
- private int mStartMarker;
- private int mEndMarker;
- private AudioTrack mTrack;
- private int mFrameSize;
- private int mOffset;
- private boolean mIsPlaying = false;
- private boolean mNotificationStarted = false;
-
- AudioPlayer(AudioTrack track, int bufferSize, int frameSize) {
- mTrack = track;
- mBuffer = new short[bufferSize];
- mFrameSize = frameSize;
- }
-
- synchronized int write(short[] buffer, int offset, int count) {
- int bufferSize = mBuffer.length;
- while (getBufferedDataSize() + count > bufferSize) {
- try {
- wait();
- } catch (Exception e) {
- //
- }
- }
-
- int end = mEndMarker % bufferSize;
- if (end + count > bufferSize) {
- int partialSize = bufferSize - end;
- System.arraycopy(buffer, offset, mBuffer, end, partialSize);
- System.arraycopy(buffer, offset + partialSize, mBuffer, 0,
- count - partialSize);
- } else {
- System.arraycopy(buffer, 0, mBuffer, end, count);
- }
- mEndMarker += count;
-
- return count;
- }
-
- synchronized void flush() {
- mEndMarker = mStartMarker;
- notify();
- }
-
- int getBufferedDataSize() {
- return mEndMarker - mStartMarker;
- }
-
- synchronized void play() {
- if (!mIsPlaying) {
- mTrack.setPositionNotificationPeriod(mFrameSize);
- mTrack.setPlaybackPositionUpdateListener(this);
- mIsPlaying = true;
- mTrack.play();
- mOffset = mTrack.getPlaybackHeadPosition();
-
- // start initial noise feed, to kick off periodic notification
- new Thread(this).start();
- }
- }
-
- synchronized void stop() {
- mIsPlaying = false;
- mTrack.stop();
- mTrack.flush();
- mTrack.setPlaybackPositionUpdateListener(null);
- }
-
- synchronized void release() {
- mTrack.release();
- }
-
- public synchronized void run() {
- Log.d(TAG, "start initial noise feed");
- int count = 0;
- long waitTime = mNoiseGenerator.getNoiseLength() / 8; // ms
- while (!mNotificationStarted && mIsPlaying) {
- feedNoise();
- count++;
- try {
- this.wait(waitTime);
- } catch (InterruptedException e) {
- Log.e(TAG, "initial noise feed error: " + e);
- break;
- }
- }
- Log.d(TAG, "stop initial noise feed: " + count);
- }
-
- int getPlaybackHeadPosition() {
- return mStartMarker;
- }
-
- int getPlayState() {
- return mTrack.getPlayState();
- }
-
- int getState() {
- return mTrack.getState();
- }
-
- // callback
- public void onMarkerReached(AudioTrack track) {
- }
-
- // callback
- public synchronized void onPeriodicNotification(AudioTrack track) {
- if (!mNotificationStarted) {
- mNotificationStarted = true;
- Log.d(TAG, " ~~~ notification callback started");
- } else if (!mIsPlaying) {
- Log.d(TAG, " ~x~ notification callback quit");
- return;
- }
- try {
- writeToTrack();
- } catch (IllegalStateException e) {
- Log.e(TAG, "writeToTrack()", e);
- }
- }
-
- private void feedNoise() {
- short[] noiseBuffer = mNoiseGenerator.makeNoise();
- mOffset += mTrack.write(noiseBuffer, 0, noiseBuffer.length);
- }
-
- private synchronized void writeToTrack() {
- if (mStartMarker == mEndMarker) {
- int head = mTrack.getPlaybackHeadPosition() - mOffset;
- if ((mStartMarker - head) <= 320) feedNoise();
- return;
- }
-
- int count = mFrameSize;
- if (count < getBufferedDataSize()) count = getBufferedDataSize();
-
- int bufferSize = mBuffer.length;
- int start = mStartMarker % bufferSize;
- if ((start + count) <= bufferSize) {
- mStartMarker += mTrack.write(mBuffer, start, count);
- } else {
- int partialSize = bufferSize - start;
- mStartMarker += mTrack.write(mBuffer, start, partialSize);
- mStartMarker += mTrack.write(mBuffer, 0, count - partialSize);
- }
- notify();
- }
- }
-
- private static class LogRateLimiter {
- private static final long MIN_TIME = 1000;
- private static long mLastTime;
-
- private static boolean allowLogging(long now) {
- if ((now - mLastTime) < MIN_TIME) {
- return false;
- } else {
- mLastTime = now;
- return true;
- }
- }
- }
-}
diff --git a/src/com/android/sip/media/RtpFactory.java b/src/com/android/sip/media/RtpFactory.java
deleted file mode 100644
index 8dc185f..0000000
--- a/src/com/android/sip/media/RtpFactory.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.sip.media;
-
-import android.util.Log;
-
-public class RtpFactory {
- public static RtpSession[] getSystemSupportedAudioSessions() {
- return new RtpSession[] {
- new RtpAudioSession(0), new RtpAudioSession(8)};
- }
-
- // returns null if codecId is not supported by the system
- public static RtpSession createAudioSession(int codecId) {
- for (RtpSession s : getSystemSupportedAudioSessions()) {
- if (s.getCodecId() == codecId) {
- return new RtpAudioSession(codecId);
- }
- }
- return null;
- }
-
- static Encoder createEncoder(int id) {
- switch (id) {
- case 8:
- return new G711ACodec();
- default:
- return new G711UCodec();
- }
- }
-
- static Decoder createDecoder(int id) {
- switch (id) {
- case 8:
- return new G711ACodec();
- default:
- return new G711UCodec();
- }
- }
-}
diff --git a/src/com/android/sip/media/RtpPacket.java b/src/com/android/sip/media/RtpPacket.java
deleted file mode 100644
index 60d79f2..0000000
--- a/src/com/android/sip/media/RtpPacket.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.sip.media;
-
-import java.util.Random;
-
-/**
- * RtpPacket implements a RTP packet.
- */
-public class RtpPacket {
- private static Random sRandom = new Random();
-
- // |0 0 1 2 |
- // |0.......8.......6.......4.......|
- // |V PXC MT Seqnum (16) |
- // |................................|
- // |Timestamp (32) |
- // | |
- // |................................|
- // | SSRC (32) |
- // | |
- // |................................|
- // | CSRC list (16 items x 32 bits) |
- // | |
- // |................................|
- // V: version, 2 bits
- // P: padding, 1 bit
- // X: extension, 1 bit
- // C: CSRC count, 4 bits
- // M: marker, 1 bit
- // T: payload type: 7 bits
-
- private byte[] packet; // RTP header + payload
- private int packetLength;
-
- public RtpPacket(byte[] buffer) {
- packet = buffer;
- setVersion(2);
- setPayloadType(0x0F);
- setSequenceNumber(sRandom.nextInt());
- setSscr(sRandom.nextLong());
- }
-
- /** Returns the RTP packet in raw bytes. */
- public byte[] getRawPacket() {
- return packet;
- }
-
- public int getPacketLength() {
- return packetLength;
- }
-
- public int getHeaderLength() {
- return (12 + 4 * getCscrCount());
- }
-
- public int getPayloadLength() {
- return (packetLength - getHeaderLength());
- }
-
- public void setPayloadLength(int length) {
- packetLength = getHeaderLength() + length;
- }
-
- public int getVersion() {
- return ((packet[0] >> 6) & 0x03);
- }
-
- public void setVersion(int v) {
- if (v > 3) throw new RuntimeException("illegal version: " + v);
- packet[0] = (byte) ((packet[0] & 0x3F) | ((v & 0x03) << 6));
- }
-
- int getCscrCount() {
- return (packet[0] & 0x0F);
- }
-
- public int getPayloadType() {
- return (packet[1] & 0x7F);
- }
-
- public void setPayloadType(int pt) {
- packet[1] = (byte) ((packet[1] & 0x80) | (pt & 0x7F));
- }
-
- public int getSequenceNumber() {
- return (int) get(2, 2);
- }
-
- public void setSequenceNumber(int sn) {
- set((long) sn, 2, 2);
- }
-
- public long getTimestamp() {
- return get(4, 4);
- }
-
- public void setTimestamp(long timestamp) {
- set(timestamp, 4, 4);
- }
-
- void setSscr(long ssrc) {
- set(ssrc, 8, 4);
- }
-
- private long get(int begin, int length) {
- long n = 0;
- for (int i = begin, end = i + length; i < end; i++) {
- n = (n << 8) | ((long) packet[i] & 0xFF);
- }
- return n;
- }
-
- private void set(long n, int begin, int length) {
- for (int i = begin + length - 1; i >= begin; i--) {
- packet[i] = (byte) (n & 0x0FFL);
- n >>= 8;
- }
- }
-}
diff --git a/src/com/android/sip/media/RtpSession.java b/src/com/android/sip/media/RtpSession.java
deleted file mode 100644
index b53afad..0000000
--- a/src/com/android/sip/media/RtpSession.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.sip.media;
-
-import java.io.IOException;
-import java.net.DatagramSocket;
-
-public interface RtpSession {
- int getCodecId();
- String getName();
- int getSampleRate();
- void start(int remoteSampleRate, DatagramSocket connectedSocket)
- throws IOException ;
- void stop();
- void sendDtmf();
-}