This code also fixes a bug in the original implementation where on an
incoming call, we could be presented with a codec we support that
actually has a different media identifier number in the session
descriptor. On incoming, it is the remote who chooses the media
identifier numbers to use, so we have to do a string comparison to see
if we support it and then globally use the remote's media identifier
number.
I also added the codec being used to the in call screen and a long
delay call disconnect dialog if we find a codec mismatch on either
incoming or outgoing.
Signed-off-by: James Bottomley <James.B...@HansenPartnership.com>
---
AndroidManifest.xml | 6 +-
res/layout/incall.xml | 9 +
res/values/strings.xml | 7 +
res/xml/codec_settings.xml | 5 +
res/xml/preferences.xml | 18 +-
src/org/sipdroid/codecs/Codec.java | 120 ++++++++++++
src/org/sipdroid/codecs/CodecBase.java | 113 +++++++++++
src/org/sipdroid/codecs/Codecs.java | 259 +++++++++++++++++++++++++
src/org/sipdroid/codecs/GSM.java | 75 +++++++
src/org/sipdroid/codecs/alaw.java | 56 ++++++
src/org/sipdroid/codecs/ulaw.java | 56 ++++++
src/org/sipdroid/media/JAudioLauncher.java | 3 +-
src/org/sipdroid/media/RtpStreamReceiver.java | 45 ++---
src/org/sipdroid/media/RtpStreamSender.java | 89 +++------
src/org/sipdroid/sipua/UserAgent.java | 143 ++++++--------
src/org/sipdroid/sipua/UserAgentProfile.java | 2 -
src/org/sipdroid/sipua/phone/CallCard.java | 9 +-
src/org/sipdroid/sipua/ui/InCallScreen.java | 12 +-
src/org/sipdroid/sipua/ui/Receiver.java | 3 +
src/org/sipdroid/sipua/ui/Settings.java | 10 -
20 files changed, 839 insertions(+), 201 deletions(-)
create mode 100644 res/xml/codec_settings.xml
create mode 100644 src/org/sipdroid/codecs/Codec.java
create mode 100644 src/org/sipdroid/codecs/CodecBase.java
create mode 100644 src/org/sipdroid/codecs/Codecs.java
create mode 100644 src/org/sipdroid/codecs/GSM.java
create mode 100644 src/org/sipdroid/codecs/alaw.java
create mode 100644 src/org/sipdroid/codecs/ulaw.java
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 47f3a26..cabbe6f 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -75,6 +75,10 @@
<activity android:name=".ui.Settings" android:label="@string/app_name"
android:excludeFromRecents="true" android:taskAffinity="">
</activity>
+ <activity
+ android:name="org.sipdroid.codecs.Codecs$CodecSettings"
+ android:label="@string/app_name" >
+ </activity>
<activity android:name=".ui.VideoCamera" android:label="@string/menu_video"
android:excludeFromRecents="true" android:taskAffinity=""
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
@@ -118,4 +122,4 @@
<uses-permission android:name="android.permission.VIBRATE" ></uses-permission>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" ></uses-permission>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" ></uses-permission>
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/res/layout/incall.xml b/res/layout/incall.xml
index 5989591..f7bc79e 100644
--- a/res/layout/incall.xml
+++ b/res/layout/incall.xml
@@ -98,6 +98,15 @@ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
+ <TextView
+ android:id="@+id/codec"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center_horizontal"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorSecondary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ />
</LinearLayout>
</RelativeLayout> <!-- End of inCallPanel -->
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 87e2177..b0f5563 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -236,6 +236,7 @@
<string name="card_title_in_progress">Call in progress</string>
<string name="card_title_incoming_call">Incoming call</string>
<string name="card_title_call_ended">Call ended</string>
+<string name="card_title_ended_no_codec">ERROR: Codecs Incompatible</string>
<string name="card_title_on_hold">On hold</string>
<string name="unknown">Unknown</string>
@@ -245,4 +246,10 @@
<string name="ongoing">Current Call</string>
<string name="onHold">On hold</string>
+<string name="codecs">Audio Codecs</string>
+<string name="codecs_summary">Select Audio Codecs to be available for voice calls</string>
+<string name="codecs_move">Move this codec</string>
+<string name="codecs_move_up">Move up one place</string>
+<string name="codecs_move_down">Move down one place</string>
+<string name="cancel">Cancel</string>
</resources>
diff --git a/res/xml/codec_settings.xml b/res/xml/codec_settings.xml
new file mode 100644
index 0000000..17570ea
--- /dev/null
+++ b/res/xml/codec_settings.xml
@@ -0,0 +1,5 @@
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:key="codecs"
+ android:title="@string/codecs">
+</PreferenceScreen>
diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml
index 8cacd79..64dbdab 100644
--- a/res/xml/preferences.xml
+++ b/res/xml/preferences.xml
@@ -1,6 +1,6 @@
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
-
+
<PreferenceScreen android:title="@string/settings_account">
<EditTextPreference
android:key="username"
@@ -58,13 +58,6 @@
android:entryValues="@array/pref_values"
android:summary="@string/settings_pref2"
android:dialogTitle="@string/settings_pref" />
- <ListPreference
- android:key="compression"
- android:title="@string/settings_compression"
- android:entries="@array/compression_display_values"
- android:entryValues="@array/compression_values"
- android:defaultValue="edge"
- android:dialogTitle="@string/settings_compression" />
<CheckBoxPreference
android:key="auto_on"
android:title="@string/settings_auto_on"
@@ -184,4 +177,13 @@
android:hint="Accessno.,PIN#"
android:singleLine="true" />
</PreferenceScreen>
+ <PreferenceScreen
+ android:key="codecs"
+ android:title="@string/codecs" >
+ <intent
+ android:action="android.intent.action.MAIN"
+ android:targetPackage="org.sipdroid.sipua"
+ android:targetClass="org.sipdroid.codecs.Codecs$CodecSettings" />
+
+ </PreferenceScreen>
</PreferenceScreen>
diff --git a/src/org/sipdroid/codecs/Codec.java b/src/org/sipdroid/codecs/Codec.java
new file mode 100644
index 0000000..95c408e
--- /dev/null
+++ b/src/org/sipdroid/codecs/Codec.java
@@ -0,0 +1,120 @@
+package org.sipdroid.codecs;
+
+import android.preference.ListPreference;
+
+/**
+ * Represents the basic interface to the Codec classes All codecs need
+ * to implement basic encode and decode capability Codecs which
+ * inherit from {@link CodecBase} only need to implement encode,
+ * decode and init
+ */
+public interface Codec {
+ /**
+ * Decode a linear pcm audio stream
+ *
+ * @param encoded The encoded audio stream
+ *
+ * @param lin The linear pcm audio frame buffer in which to place the decoded stream
+ *
+ * @param size The size of the encoded frame
+ *
+ * @returns The size of the decoded frame
+ */
+ int decode(byte encoded[], short lin[], int size);
+
+ /**
+ * Encode a linear pcm audio stream
+ *
+ * @param lin The linear stream to encode
+ *
+ * @param offset The offset into the linear stream to begin
+ *
+ * @param encoded The buffer to place the encoded stream
+ *
+ * @param size the size of the linear pcm stream (in words)
+ *
+ * @returns the length (in bytes) of the encoded stream
+ */
+ int encode(short lin[], int offset, byte alaw[], int frames);
+
+ /**
+ * Optionally used to initiallize the codec before any
+ * encoding or decoding
+ */
+ void init();
+
+ /**
+ * Optionally used to free any resources allocated in init
+ * after encoding or decoding is complete
+ */
+ void close();
+
+ /**
+ * (implemented by {@link CodecBase}
+ * <p>
+ * checks to see if the user has enabled the codec.
+ *
+ * @returns true if the codec can be used
+ */
+ boolean isEnabled();
+
+ /**
+ * (implemented by {@link CodecBase}
+ * <p>
+ * Checks to see if the binary library associated with the
+ * codec (if any) loaded OK.
+ *
+ * @returns true if the codec loaded properly
+ */
+ boolean isLoaded();
+
+ /**
+ * (implemented by {@link CodecBase}
+ * <p>
+ * checks to see if the user has enabled the codec for use on
+ * edge only.
+ *
+ * @returns true if the codec can only be used on Edge Networks
+ */
+ boolean edgeOnly();
+
+ /**
+ * (implemented by {@link CodecBase}
+ *
+ * @returns The user friendly string for the codec (should
+ * include both the name and the bandwidth
+ */
+ String getTitle();
+
+
+ /**
+ * (implemented by {@link CodecBase}
+ *
+ * @returns The RTP assigned name string for the codec
+ */
+ String name();
+
+ /**
+ * (implemented by {@link CodecBase}
+ *
+ * @returns The commonly used name for the codec.
+ */
+ String userName();
+
+ /**
+ * (implemented by {@link CodecBase}
+ *
+ * @returns The RTP assigned number for the codec
+ */
+ int number();
+
+ /**
+ * (implemented by {@link CodecBase}
+ *
+ * @param l The list preference controlling this Codec
+ *
+ * Used to add listeners for preference changes and update
+ * the codec parameters accordingly.
+ */
+ void setListPreference(ListPreference l);
+}
diff --git a/src/org/sipdroid/codecs/CodecBase.java b/src/org/sipdroid/codecs/CodecBase.java
new file mode 100644
index 0000000..d5d8c49
--- /dev/null
+++ b/src/org/sipdroid/codecs/CodecBase.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2009 The Sipdroid Open Source Project
+ *
+ * This file is part of Sipdroid (http://www.sipdroid.org)
+ *
+ * Sipdroid is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this source code; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package org.sipdroid.codecs;
+
+import org.sipdroid.sipua.ui.Receiver;
+
+import android.content.SharedPreferences;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.PreferenceManager;
+
+class CodecBase implements Preference.OnPreferenceChangeListener {
+ protected String CODEC_NAME;
+ protected String CODEC_USER_NAME;
+ protected int CODEC_NUMBER;
+ protected String CODEC_DESCRIPTION;
+ protected String CODEC_DEFAULT_SETTING = "never";
+
+ private boolean loaded = false;
+ private boolean enabled = false;
+ private boolean edgeOnly = false;
+ private String value;
+
+ void load() {
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(Receiver.mContext);
+ value = sp.getString(CODEC_NAME, CODEC_DEFAULT_SETTING);
+ updateFlags(value);
+ loaded = true;
+ }
+
+ public boolean isLoaded() {
+ return loaded;
+ }
+
+ public void enable(boolean e) {
+ enabled = e && loaded;
+ }
+
+ public boolean isEnabled() {
+ return loaded && enabled;
+ }
+
+ public boolean edgeOnly() {
+ return loaded && enabled && edgeOnly;
+ }
+
+ public String name() {
+ return CODEC_NAME;
+ }
+
+ public String userName() {
+ return CODEC_USER_NAME;
+ }
+
+ public String getTitle() {
+ return CODEC_USER_NAME + " (" + CODEC_DESCRIPTION + ")";
+ }
+
+ public int number() {
+ return CODEC_NUMBER;
+ }
+
+ public void setListPreference(ListPreference l) {
+ l.setOnPreferenceChangeListener(this);
+ l.setValue(value);
+ }
+
+ public boolean onPreferenceChange(Preference p, Object newValue) {
+ ListPreference l = (ListPreference)p;
+ value = (String)newValue;
+
+ updateFlags(value);
+
+ l.setValue(value);
+ l.setSummary(l.getEntry());
+
+ return true;
+ }
+
+ private void updateFlags(String v) {
+
+ if (v.equals("never")) {
+ enabled = false;
+ } else {
+ enabled = true;
+ if (v.equals("edge"))
+ edgeOnly = true;
+ else
+ edgeOnly = false;
+ }
+ }
+
+ public String toString() {
+ return "CODEC{ " + CODEC_NUMBER + ": " + getTitle() + "}";
+ }
+}
diff --git a/src/org/sipdroid/codecs/Codecs.java b/src/org/sipdroid/codecs/Codecs.java
new file mode 100644
index 0000000..dc9d6df
--- /dev/null
+++ b/src/org/sipdroid/codecs/Codecs.java
@@ -0,0 +1,259 @@
+package org.sipdroid.codecs;
+
+import java.util.HashMap;
+import java.util.Vector;
+
+import org.sipdroid.sipua.R;
+import org.sipdroid.sipua.ui.Receiver;
+import org.zoolu.sdp.SessionDescriptor;
+import org.zoolu.sdp.AttributeField;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+import android.preference.ListPreference;
+import android.preference.PreferenceManager;
+import android.preference.PreferenceScreen;
+import android.telephony.TelephonyManager;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+
+public class Codecs {
+ private static final Vector<Codec> codecs = new Vector<Codec>() {{
+ add(new GSM());
+ add(new alaw());
+ add(new ulaw());
+ }};
+ private static final HashMap<Integer, Codec> codecsNumbers;
+ private static final HashMap<String, Codec> codecsNames;
+
+ static {
+ final int size = codecs.size();
+ codecsNumbers = new HashMap<Integer, Codec>(size);
+ codecsNames = new HashMap<String, Codec>(size);
+
+ for (Codec c : codecs) {
+ codecsNames.put(c.name(), c);
+ codecsNumbers.put(c.number(), c);
+ }
+
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(Receiver.mContext);
+ String prefs = sp.getString("codecs", null);
+ if (prefs == null) {
+ String v = "";
+ SharedPreferences.Editor e = sp.edit();
+
+ for (Codec c : codecs)
+ v = v + c.number() + " ";
+ e.putString("codecs", v);
+ e.commit();
+ } else {
+ String[] vals = prefs.split(" ");
+ for (String v: vals) {
+ try {
+ int i = Integer.parseInt(v);
+ Codec c = codecsNumbers.get(i);
+ /* moves the codec to the end
+ * of the list so we end up
+ * with the new codecs (if
+ * any) at the top and the
+ * remaining ones ordered
+ * according to the user */
+ codecs.remove(c);
+ codecs.add(c);
+ } catch (Exception e) {
+ // do nothing (expecting
+ // NumberFormatException and
+ // indexnot found
+ }
+ }
+ }
+ }
+
+ private static boolean initialised = false;
+
+ public static Codec get(int key) {
+ return codecsNumbers.get(key);
+ }
+
+ public static Codec getName(String name) {
+ return codecsNames.get(name);
+ }
+
+ private static void addPreferences(PreferenceScreen ps) {
+ Context cx = ps.getContext();
+ SharedPreferences sp = ps.getSharedPreferences();
+ Resources r = cx.getResources();
+ ps.setOrderingAsAdded(true);
+
+ for(Codec c : codecs) {
+ ListPreference l = new ListPreference(cx);
+ l.setEntries(r.getStringArray(R.array.compression_display_values));
+ l.setEntryValues(r.getStringArray(R.array.compression_values));
+ l.setKey(c.name());
+ l.setPersistent(true);
+ if (c.isLoaded()) {
+ l.setEnabled(true);
+ c.setListPreference(l);
+ } else {
+ l.setValue("never");
+ l.setEnabled(false);
+ }
+ l.setSummary(l.getEntry());
+ l.setTitle(c.getTitle());
+ ps.addPreference(l);
+ }
+ }
+
+ public static int[] getCodecs() {
+ Vector<Integer> v = new Vector<Integer>(codecs.size());
+ boolean onEdge = onEdge();
+
+ for (Codec c : codecs) {
+ if (!c.isEnabled())
+ continue;
+ if (c.edgeOnly() && !onEdge)
+ continue;
+ v.add(c.number());
+ }
+ int i[] = new int[v.size()];
+ for (int j = 0; j < i.length; j++)
+ i[j] = v.elementAt(j);
+ return i;
+ }
+
+ public static class Map {
+ public final int number;
+ public final Codec codec;
+
+ Map(int n, Codec c) {
+ number = n;
+ codec = c;
+ }
+
+ public String toString() {
+ return "Codecs.Map { " + number + ": " + codec + "}";
+ }
+ };
+
+ public static Map getCodec(SessionDescriptor offers) {
+ boolean onEdge = onEdge();
+ Vector<AttributeField> attrs = offers.getMediaDescriptor("audio").getAttributes("rtpmap");
+ Vector<String> names = new Vector<String>(attrs.size());
+ Vector<Integer> numbers = new Vector<Integer>(attrs.size());
+
+ for (AttributeField a : attrs) {
+ String s = a.getValue();
+ // skip over "rtpmap:"
+ s = s.substring(7, s.indexOf("/"));
+ int i = s.indexOf(" ");
+ try {
+ String name = s.substring(i + 1);
+ int number = Integer.parseInt(s.substring(0, i));
+ names.add(name);
+ numbers.add(number);
+ } catch (NumberFormatException e) {
+ // continue ... remote sent bogus rtp setting
+ }
+ }
+
+ // find the first codec in our list that's also in the offers
+ for (Codec c : codecs) {
+ if (!c.isEnabled())
+ continue;
+ if (c.edgeOnly() && !onEdge)
+ continue;
+ int i = names.indexOf(c.name());
+ if (i == -1)
+ continue;
+
+ return new Map(numbers.elementAt(i), c);
+ }
+ // no codec found ... we can't talk
+ return null;
+ }
+
+ private static boolean onEdge() {
+ TelephonyManager tm = (TelephonyManager) Receiver.mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ return !Receiver.on_wlan && tm.getNetworkType() == TelephonyManager.NETWORK_TYPE_EDGE;
+ }
+
+ public static class CodecSettings extends PreferenceActivity {
+
+ private static final int MENU_UP = 0;
+ private static final int MENU_DOWN = 1;
+ private static final int MENU_CANCEL = 2;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ addPreferencesFromResource(R.xml.codec_settings);
+
+ // for long-press gesture on a profile preference
+ registerForContextMenu(getListView());
+
+ addPreferences(getPreferenceScreen());
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v,
+ ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+
+ menu.setHeaderTitle(R.string.codecs_move);
+ menu.add(Menu.NONE, MENU_UP, 0,
+ R.string.codecs_move_up);
+ menu.add(Menu.NONE, MENU_DOWN, 0,
+ R.string.codecs_move_down);
+ menu.add(Menu.NONE, MENU_CANCEL, 0, R.string.cancel);
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+
+ if (item.getItemId() == MENU_CANCEL)
+ return super.onContextItemSelected(item);
+
+ int posn = (int)((AdapterContextMenuInfo)item.getMenuInfo()).position;
+ Codec c = codecs.elementAt(posn);
+ if (item.getItemId() == MENU_UP) {
+ if (posn == 0)
+ return super.onContextItemSelected(item);
+ Codec tmp = codecs.elementAt(posn - 1);
+ codecs.set(posn - 1, c);
+ codecs.set(posn, tmp);
+ } else if (item.getItemId() == MENU_DOWN) {
+ if (posn == codecs.size() - 1)
+ return super.onContextItemSelected(item);
+ Codec tmp = codecs.elementAt(posn + 1);
+ codecs.set(posn + 1, c);
+ codecs.set(posn, tmp);
+ }
+ PreferenceScreen ps = getPreferenceScreen();
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(Receiver.mContext);
+ String v = "";
+ SharedPreferences.Editor e = sp.edit();
+
+ for (Codec d : codecs)
+ v = v + d.number() + " ";
+ e.putString("codecs", v);
+ e.commit();
+ ps.removeAll();
+ addPreferences(ps);
+ return super.onContextItemSelected(item);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ unregisterForContextMenu(getListView());
+ }
+ }
+}
diff --git a/src/org/sipdroid/codecs/GSM.java b/src/org/sipdroid/codecs/GSM.java
new file mode 100644
index 0000000..44ffb5d
--- /dev/null
+++ b/src/org/sipdroid/codecs/GSM.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2009 The Sipdroid Open Source Project
+ *
+ * This file is part of Sipdroid (http://www.sipdroid.org)
+ *
+ * Sipdroid is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this source code; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package org.sipdroid.codecs;
+
+import java.util.Map;
+
+import org.sipdroid.sipua.ui.Receiver;
+
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+
+class GSM extends CodecBase implements Codec {
+ GSM() {
+ CODEC_NAME = "GSM";
+ CODEC_USER_NAME = "GSM";
+ CODEC_DESCRIPTION = "13kbit";
+ CODEC_NUMBER = 3;
+ CODEC_DEFAULT_SETTING = "edge";
+
+ load();
+ }
+
+ public void init() {
+ org.sipdroid.pjlib.Codec.init();
+ }
+
+ void load() {
+ /* up convert original compression parameter for this codec */
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(Receiver.mContext);
+ String pref = sp.getString("compression", null);
+ if (pref != null) {
+ SharedPreferences.Editor e = sp.edit();
+ e.remove("compression");
+ e.putString(CODEC_NAME, pref);
+ e.commit();
+ }
+ if(org.sipdroid.pjlib.Codec.loaded)
+ super.load();
+ }
+
+ public int decode(byte encoded[], short lin[], int frames) {
+ byte[] buf = new byte[33];
+ int i;
+
+ for (i = 12; i < 15; i++)
+ buf[i] = encoded[i];
+ return org.sipdroid.pjlib.Codec.decode(buf, lin, 0);
+ }
+
+ public int encode(short lin[], int offset, byte encoded[], int frames) {
+ return org.sipdroid.pjlib.Codec.encode(lin, offset, encoded, frames);
+ }
+
+ public void close() {
+ org.sipdroid.pjlib.Codec.close();
+ }
+
+}
diff --git a/src/org/sipdroid/codecs/alaw.java b/src/org/sipdroid/codecs/alaw.java
new file mode 100644
index 0000000..62dfedc
--- /dev/null
+++ b/src/org/sipdroid/codecs/alaw.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2009 The Sipdroid Open Source Project
+ *
+ * This file is part of Sipdroid (http://www.sipdroid.org)
+ *
+ * Sipdroid is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this source code; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package org.sipdroid.codecs;
+
+import java.util.Map;
+
+import org.sipdroid.media.G711;
+import org.sipdroid.sipua.ui.Sipdroid;
+
+class alaw extends CodecBase implements Codec {
+ alaw() {
+ CODEC_NAME = "PCMA";
+ CODEC_USER_NAME = "alaw";
+ CODEC_DESCRIPTION = "64kbit";
+ CODEC_NUMBER = 8;
+ CODEC_DEFAULT_SETTING = "always";
+
+ load();
+ }
+
+ public void init() {
+ G711.init();
+ }
+
+ public int decode(byte enc[], short lin[], int frames) {
+ G711.alaw2linear(enc, lin, frames);
+
+ return frames;
+ }
+
+ public int encode(short lin[], int offset, byte enc[], int frames) {
+ G711.linear2alaw(lin, offset, enc, frames);
+
+ return frames;
+ }
+
+ public void close() {
+ }
+}
diff --git a/src/org/sipdroid/codecs/ulaw.java b/src/org/sipdroid/codecs/ulaw.java
new file mode 100644
index 0000000..c10e498
--- /dev/null
+++ b/src/org/sipdroid/codecs/ulaw.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2009 The Sipdroid Open Source Project
+ *
+ * This file is part of Sipdroid (http://www.sipdroid.org)
+ *
+ * Sipdroid is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this source code; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package org.sipdroid.codecs;
+
+import java.util.Map;
+
+import org.sipdroid.media.G711;
+import org.sipdroid.sipua.ui.Sipdroid;
+
+class ulaw extends CodecBase implements Codec {
+ ulaw() {
+ CODEC_NAME = "PCMU";
+ CODEC_USER_NAME = "ulaw";
+ CODEC_DESCRIPTION = "64kbit";
+ CODEC_NUMBER = 0;
+ CODEC_DEFAULT_SETTING = "always";
+
+ load();
+ }
+
+ public void init() {
+ G711.init();
+ }
+
+ public int decode(byte enc[], short lin[], int frames) {
+ G711.ulaw2linear(enc, lin, frames);
+
+ return frames;
+ }
+
+ public int encode(short lin[], int offset, byte enc[], int frames) {
+ G711.linear2ulaw(lin, offset, enc, frames);
+
+ return frames;
+ }
+
+ public void close() {
+ }
+}
diff --git a/src/org/sipdroid/media/JAudioLauncher.java b/src/org/sipdroid/media/JAudioLauncher.java
index 93797dd..3a2cd0e 100644
--- a/src/org/sipdroid/media/JAudioLauncher.java
+++ b/src/org/sipdroid/media/JAudioLauncher.java
@@ -19,6 +19,7 @@
*/
package org.sipdroid.media;
+import org.sipdroid.codecs.Codecs;
import org.sipdroid.net.SipdroidSocket;
import org.sipdroid.sipua.ui.Sipdroid;
import org.zoolu.sip.provider.SipStack;
@@ -72,7 +73,7 @@ public class JAudioLauncher implements MediaLauncher
}
/** Costructs the audio launcher */
- public JAudioLauncher(int local_port, String remote_addr, int remote_port, int direction, String audiofile_in, String audiofile_out, int sample_rate, int sample_size, int frame_size, Log logger, int payload_type, int dtmf_pt)
+ public JAudioLauncher(int local_port, String remote_addr, int remote_port, int direction, String audiofile_in, String audiofile_out, int sample_rate, int sample_size, int frame_size, Log logger, Codecs.Map payload_type, int dtmf_pt)
{ log=logger;
frame_rate=sample_rate/frame_size;
useDTMF = (dtmf_pt != 0);
diff --git a/src/org/sipdroid/media/RtpStreamReceiver.java b/src/org/sipdroid/media/RtpStreamReceiver.java
index e688d4a..999884e 100644
--- a/src/org/sipdroid/media/RtpStreamReceiver.java
+++ b/src/org/sipdroid/media/RtpStreamReceiver.java
@@ -30,7 +30,7 @@ import org.sipdroid.net.SipdroidSocket;
import org.sipdroid.sipua.UserAgent;
import org.sipdroid.sipua.ui.Receiver;
import org.sipdroid.sipua.ui.Sipdroid;
-import org.sipdroid.pjlib.Codec;
+import org.sipdroid.codecs.Codecs;
import android.content.ContentResolver;
import android.content.Context;
@@ -55,7 +55,9 @@ public class RtpStreamReceiver extends Thread {
public static boolean DEBUG = true;
/** Payload type */
- int p_type;
+ Codecs.Map p_type;
+
+ static String codec = "NONE";
/** Size of the read buffer */
public static final int BUFFER_SIZE = 1024;
@@ -80,9 +82,10 @@ public class RtpStreamReceiver extends Thread {
* @param socket
* the local receiver SipdroidSocket
*/
- public RtpStreamReceiver(SipdroidSocket socket, int payload_type) {
+ public RtpStreamReceiver(SipdroidSocket socket, Codecs.Map payload_type) {
init(socket);
p_type = payload_type;
+ codec = p_type.codec.getTitle();
}
/** Inits the RtpStreamReceiver */
@@ -299,7 +302,6 @@ public class RtpStreamReceiver extends Thread {
}
byte[] buffer = new byte[BUFFER_SIZE+12];
- byte[] buffer_gsm = new byte[33+12];
int i;
rtp_packet = new RtpPacket(buffer, 0);
@@ -330,15 +332,7 @@ public class RtpStreamReceiver extends Thread {
lserver = 0;
luser = -8000;
cnt = 0;
- switch (p_type) {
- case 3:
- Codec.init();
- break;
- case 0:
- case 8:
- G711.init();
- break;
- }
+ p_type.codec.init();
ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_MUSIC,(int)(ToneGenerator.MAX_VOLUME*2*org.sipdroid.sipua.ui.Settings.getEarGain()));
track.play();
empty();
@@ -387,7 +381,6 @@ public class RtpStreamReceiver extends Thread {
m++;
continue;
}
-
server = track.getPlaybackHeadPosition();
headroom = user-server;
@@ -402,21 +395,7 @@ public class RtpStreamReceiver extends Thread {
cnt2 = 0;
if (cnt <= 500 || cnt2 >= 2 || headroom - 875 < len) {
- switch (rtp_packet.getPayloadType()) {
- case 0:
- len = rtp_packet.getPayloadLength();
- G711.ulaw2linear(buffer, lin, len);
- break;
- case 8:
- len = rtp_packet.getPayloadLength();
- G711.alaw2linear(buffer, lin, len);
- break;
- case 3:
- for (i = 12; i < 45; i++)
- buffer_gsm[i] = buffer[i];
- len = Codec.decode(buffer_gsm, lin, 0);
- break;
- }
+ len = p_type.codec.decode(buffer, lin, rtp_packet.getPayloadLength());
if (speakermode == AudioManager.MODE_NORMAL)
calc(lin,0,len);
@@ -494,9 +473,11 @@ public class RtpStreamReceiver extends Thread {
}
tg.stopTone();
tg.release();
-
+
+ p_type.codec.close();
rtp_socket.close();
rtp_socket = null;
+ codec = "NONE";
if (DEBUG)
println("rtp receiver terminated");
@@ -515,4 +496,8 @@ public class RtpStreamReceiver extends Thread {
public static int byte2int(byte b1, byte b2) {
return (((b1 + 0x100) % 0x100) << 8) + (b2 + 0x100) % 0x100;
}
+
+ public static String getCodec() {
+ return codec;
+ }
}
diff --git a/src/org/sipdroid/media/RtpStreamSender.java b/src/org/sipdroid/media/RtpStreamSender.java
index d68fb5c..e57d838 100644
--- a/src/org/sipdroid/media/RtpStreamSender.java
+++ b/src/org/sipdroid/media/RtpStreamSender.java
@@ -34,7 +34,7 @@ import org.sipdroid.sipua.UserAgent;
import org.sipdroid.sipua.ui.Receiver;
import org.sipdroid.sipua.ui.Settings;
import org.sipdroid.sipua.ui.Sipdroid;
-import org.sipdroid.pjlib.Codec;
+import org.sipdroid.codecs.Codecs;
import android.content.Context;
import android.media.AudioFormat;
@@ -56,7 +56,7 @@ public class RtpStreamSender extends Thread {
RtpSocket rtp_socket = null;
/** Payload type */
- int p_type;
+ Codecs.Map p_type;
/** Number of frame per second */
long frame_rate;
@@ -129,22 +129,23 @@ public class RtpStreamSender extends Thread {
* @param dest_port
* the destination port
*/
- public RtpStreamSender(boolean do_sync,
- int payload_type, long frame_rate, int frame_size,
- SipdroidSocket src_socket, String dest_addr, int dest_port) {
+ public RtpStreamSender(boolean do_sync, Codecs.Map payload_type,
+ long frame_rate, int frame_size,
+ SipdroidSocket src_socket, String dest_addr,
+ int dest_port) {
init(do_sync, payload_type, frame_rate, frame_size,
src_socket, dest_addr, dest_port);
}
/** Inits the RtpStreamSender */
- private void init(boolean do_sync,
- int payload_type, long frame_rate, int frame_size,
- SipdroidSocket src_socket, String dest_addr,
- int dest_port) {
+ private void init(boolean do_sync, Codecs.Map payload_type,
+ long frame_rate, int frame_size,
+ SipdroidSocket src_socket, String dest_addr,
+ int dest_port) {
this.p_type = payload_type;
this.frame_rate = frame_rate;
this.frame_size = PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).getString("server","").equals("pbxes.org")?
- (payload_type == 3?960:1024):frame_size; //15
+ (payload_type.codec.number() == 3?960:1024):frame_size; //15
this.do_sync = do_sync;
try {
rtp_socket = new RtpSocket(src_socket, InetAddress
@@ -262,18 +263,17 @@ public class RtpStreamSender extends Thread {
return;
byte[] buffer = new byte[frame_size + 12];
RtpPacket rtp_packet = new RtpPacket(buffer, 0);
- rtp_packet.setPayloadType(p_type);
+ rtp_packet.setPayloadType(p_type.number);
int seqn = 0;
long time = 0;
double p = 0;
TelephonyManager tm = (TelephonyManager) Receiver.mContext.getSystemService(Context.TELEPHONY_SERVICE);
boolean improve = PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).getBoolean("improve",false);
- boolean useGSM = !PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).getString("compression","edge").equals("never");
int micgain = (int)(Settings.getMicGain()*10);
- long frame_period = 1000 / frame_rate;
- long last_tx_time = 0;
- long next_tx_delay;
- long now;
+ long frame_period = 1000 / frame_rate;
+ long last_tx_time = 0;
+ long next_tx_delay;
+ long now;
running = true;
m = 1;
int dtframesize = 4;
@@ -295,15 +295,7 @@ public class RtpStreamSender extends Thread {
} catch (IOException e2) {
if (!Sipdroid.release) e2.printStackTrace();
}
- switch (p_type) {
- case 3:
- Codec.init();
- break;
- case 0:
- case 8:
- G711.init();
- break;
- }
+ p_type.codec.init();
record.startRecording();
while (running) {
if (muted || Receiver.call_state == UserAgent.UA_STATE_HOLD) {
@@ -365,14 +357,14 @@ public class RtpStreamSender extends Thread {
//DTMF change end
if (frame_size == 160) {
- now = System.currentTimeMillis();
- next_tx_delay = frame_period - (now - last_tx_time);
- last_tx_time = now;
- if (next_tx_delay > 0) {
- try {
+ now = System.currentTimeMillis();
+ next_tx_delay = frame_period - (now - last_tx_time);
+ last_tx_time = now;
+ if (next_tx_delay > 0) {
+ try {
sleep(next_tx_delay);
- } catch (InterruptedException e1) {
- }
+ } catch (InterruptedException e1) {
+ }
last_tx_time += next_tx_delay-sync_adj;
}
}
@@ -406,28 +398,12 @@ public class RtpStreamSender extends Thread {
} catch (IOException e) {
if (!Sipdroid.release) e.printStackTrace();
}
- switch (p_type) {// have to add ulaw case?
- case 3:
- G711.alaw2linear(buffer, lin, num);
- num = Codec.encode(lin, 0, buffer, num);
- break;
- case 0:
- G711.alaw2linear(buffer, lin, num);
- G711.linear2ulaw(lin, 0, buffer, num);
- break;
+ if (p_type.codec.number() != 8) {
+ G711.alaw2linear(buffer, lin, num);
+ num = p_type.codec.encode(lin, 0, buffer, num);
}
} else {
- switch (p_type) {
- case 3:
- num = Codec.encode(lin, ring%(frame_size*11), buffer, num);
- break;
- case 0:
- G711.linear2ulaw(lin, ring%(frame_size*11), buffer, num);
- break;
- case 8:
- G711.linear2alaw(lin, ring%(frame_size*11), buffer, num);
- break;
- }
+ num = p_type.codec.encode(lin, ring%(frame_size*11), buffer, num);
}
ring += frame_size;
rtp_packet.setSequenceNumber(seqn++);
@@ -446,13 +422,6 @@ public class RtpStreamSender extends Thread {
m = 2;
else
m = 1;
- if (useGSM && p_type == 8 && !Receiver.on_wlan && tm.getNetworkType() == TelephonyManager.NETWORK_TYPE_EDGE) {
- rtp_packet.setPayloadType(p_type = 3);
- if (frame_size == 1024) {
- frame_size = 960;
- ring = 0;
- }
- }
}
AudioManager am = (AudioManager) Receiver.mContext.getSystemService(Context.AUDIO_SERVICE);
while (am.getMode() == AudioManager.MODE_IN_CALL)
@@ -464,6 +433,7 @@ public class RtpStreamSender extends Thread {
record.release();
m = 0;
+ p_type.codec.close();
rtp_socket.close();
rtp_socket = null;
@@ -476,7 +446,6 @@ public class RtpStreamSender extends Thread {
if (!Sipdroid.release) System.out.println("RtpStreamSender: " + str);
}
- //DTMF change
/** Set RTP payload type of outband DTMF packets. **/
public void setDTMFpayloadType(int payload_type){
dtmf_payload_type = payload_type;
diff --git a/src/org/sipdroid/sipua/UserAgent.java b/src/org/sipdroid/sipua/UserAgent.java
index 1a13b7a..d620a1f 100644
--- a/src/org/sipdroid/sipua/UserAgent.java
+++ b/src/org/sipdroid/sipua/UserAgent.java
@@ -22,9 +22,10 @@
package org.sipdroid.sipua;
import java.util.Enumeration;
-import java.util.HashMap;
import java.util.Vector;
+import org.sipdroid.codecs.Codec;
+import org.sipdroid.codecs.Codecs;
import org.sipdroid.media.JAudioLauncher;
import org.sipdroid.media.MediaLauncher;
import org.sipdroid.media.RtpStreamReceiver;
@@ -51,8 +52,6 @@ import org.zoolu.tools.LogLevel;
import org.zoolu.tools.Parser;
import android.content.Context;
-import android.preference.PreferenceManager;
-import android.telephony.TelephonyManager;
/**
* Simple SIP user agent (UA). It includes audio/video applications.
@@ -91,7 +90,7 @@ public class UserAgent extends CallListenerAdapter {
int call_state = UA_STATE_IDLE;
String remote_media_address;
- int remote_video_port,local_video_port,payload_type;
+ int remote_video_port,local_video_port;
// *************************** Basic methods ***************************
@@ -175,7 +174,7 @@ public class UserAgent extends CallListenerAdapter {
//change start (multi codecs)
/** Inits the local SDP (no media spec) */
- public void initSessionDescriptor(int[] audio_codecs) {
+ public void initSessionDescriptor(Codecs.Map c) {
SessionDescriptor sdp = new SessionDescriptor(
user_profile.from_url,
sip_provider.getViaAddress());
@@ -186,7 +185,7 @@ public class UserAgent extends CallListenerAdapter {
//audio
if (user_profile.audio || !user_profile.video)
{
- addMediaDescriptor("audio", user_profile.audio_port, audio_codecs, user_profile.audio_sample_rate);
+ addMediaDescriptor("audio", user_profile.audio_port, c, user_profile.audio_sample_rate);
}
if (user_profile.video)
@@ -197,9 +196,9 @@ public class UserAgent extends CallListenerAdapter {
}
//change end
- /** Adds a media to the SDP */
- public void addMediaDescriptor(String media, int port, int avp,
- String codec, int rate) {
+ /** Adds a single media to the SDP */
+ private void addMediaDescriptor(String media, int port, int avp,
+ String codec, int rate) {
SessionDescriptor sdp = new SessionDescriptor(local_session);
String attr_param = String.valueOf(avp);
@@ -215,31 +214,29 @@ public class UserAgent extends CallListenerAdapter {
local_session = sdp.toString();
}
- protected static HashMap<Integer,String> avp_map = new HashMap<Integer,String>(){{
- put(0,"PCMU");
- put(3,"GSM");
- put(8,"PCMA");
- }};
-
- /** Adds a media to the SDP */
- public void addMediaDescriptor(String media, int port, int[] avps, int rate) {
+ /** Adds a set of media to the SDP */
+ private void addMediaDescriptor(String media, int port, Codecs.Map c,
+ int rate) {
SessionDescriptor sdp = new SessionDescriptor(local_session);
Vector<String> avpvec = new Vector<String>();
Vector<AttributeField> afvec = new Vector<AttributeField>();
- for (int i=0; i<avps.length ; i++) {
- int avp = avps[i];
- String codec = avp_map.get(avp);
- if (avp==user_profile.dtmf_avp && user_profile.dtmf_avp != 0){
- avpvec.add(String.valueOf(avp));
- afvec.add(new AttributeField("rtpmap", String.format("%d telephone-event/%d", avp, rate)));
- afvec.add(new AttributeField("fmtp", String.format("%d 0-15", avp)));
- }
- else if (codec!=null) {
- avpvec.add(String.valueOf(avp));
- afvec.add(new AttributeField("rtpmap", String.format("%d %s/%d", avp, codec, rate)));
+ if (c == null) {
+ // offer all known codecs
+ for (int i : Codecs.getCodecs()) {
+ Codec codec = Codecs.get(i);
+ avpvec.add(String.valueOf(i));
+ afvec.add(new AttributeField("rtpmap", String.format("%d %s/%d", i, codec.name(), rate)));
}
+ } else {
+ avpvec.add(String.valueOf(c.number));
+ afvec.add(new AttributeField("rtpmap", String.format("%d %s/%d", c.number, c.codec.name(), rate)));
}
+ if (user_profile.dtmf_avp != 0){
+ afvec.add(new AttributeField("rtpmap", String.format("%d telephone-event/%d", user_profile.dtmf_avp, rate)));
+ afvec.add(new AttributeField("fmtp", String.format("%d 0-15", user_profile.dtmf_avp)));
+ }
+
//String attr_param = String.valueOf(avp);
sdp.addMedia(new MediaField(media, port, 0, "RTP/AVP", avpvec), afvec);
@@ -287,7 +284,7 @@ public class UserAgent extends CallListenerAdapter {
}
//change start multi codecs
- createOffer(useAudioCompression());
+ createOffer();
//change end
call = new ExtendedCall(sip_provider, from_url,
user_profile.contact_url, user_profile.username,
@@ -315,19 +312,6 @@ public class UserAgent extends CallListenerAdapter {
return true;
}
- private boolean useAudioCompression() {
- boolean useGSM = false;
- String compression = PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).getString("compression","edge");
- if (compression.equals("always")) {
- useGSM = true;
- } else if (compression.equals("edge")) {
- TelephonyManager tm = (TelephonyManager) Receiver.mContext.getSystemService(Context.TELEPHONY_SERVICE);
- if (!Receiver.on_wlan && tm.getNetworkType() == TelephonyManager.NETWORK_TYPE_EDGE)
- useGSM = true;
- }
- return useGSM;
- }
-
public void info(char c, int duration)
{
boolean use2833 = audio_app != null && audio_app.sendDTMF(c); // send out-band DTMF (rfc2833) if supported
@@ -403,26 +387,23 @@ public class UserAgent extends CallListenerAdapter {
LogLevel.HIGH);
return;
}
- int avp = payload_type; //local_sdp must be set properly
+ Codecs.Map c;
// parse local sdp
SessionDescriptor local_sdp = new SessionDescriptor(call
.getLocalSessionDescriptor());
int local_audio_port = 0;
local_video_port = 0;
int dtmf_pt = 0;
- for (Enumeration<MediaDescriptor> e = local_sdp.getMediaDescriptors()
- .elements(); e.hasMoreElements();) {
- MediaField media = e.nextElement().getMedia();
- if (media.getMedia().equals("audio")) { //change start multi codec
- local_audio_port = media.getPort();
- avp = Integer.valueOf(media.getFormatList().firstElement());
- if (media.getFormatList().contains(String.valueOf(user_profile.dtmf_avp)))
- dtmf_pt = user_profile.dtmf_avp;
- } //change end
- if (media.getMedia().equals("video"))
- local_video_port = media.getPort();
+ c = Codecs.getCodec(local_sdp);
+ MediaDescriptor m = local_sdp.getMediaDescriptor("video");
+ if ( m != null)
+ local_video_port = m.getMedia().getPort();
+ m = local_sdp.getMediaDescriptor("audio");
+ if (m != null) {
+ local_audio_port = m.getMedia().getPort();
+ if (m.getMedia().getFormatList().contains(String.valueOf(user_profile.dtmf_avp)))
+ dtmf_pt = user_profile.dtmf_avp;
}
-
// parse remote sdp
SessionDescriptor remote_sdp = new SessionDescriptor(call
.getRemoteSessionDescriptor());
@@ -466,7 +447,7 @@ public class UserAgent extends CallListenerAdapter {
remote_media_address, remote_audio_port, dir, audio_in,
audio_out, user_profile.audio_sample_rate,
user_profile.audio_sample_size,
- user_profile.audio_frame_size, log, avp, dtmf_pt);
+ user_profile.audio_frame_size, log, c, dtmf_pt);
}
audio_app.startMedia();
}
@@ -492,32 +473,16 @@ public class UserAgent extends CallListenerAdapter {
return 0;
}
- private void createOffer(boolean useGSM) {
- Vector<Integer> avpvec = new Vector<Integer>();
- for (int i=0;i<user_profile.audio_codecs.length;i++){
- int avp = user_profile.audio_codecs[i];
- if (avp == 3 && !useGSM) continue;
- avpvec.add(avp);
- }
- avpvec.add(user_profile.dtmf_avp);
- int[] avps = new int[avpvec.size()];
- for (int i=0;i<avps.length;i++){
- avps[i] = avpvec.elementAt(i);
- }
- initSessionDescriptor(avps);
+ private void createOffer() {
+ initSessionDescriptor(null);
}
- private void createAnswer(SessionDescriptor remote_sdp, boolean useGSM) {
- MediaDescriptor remote_md = remote_sdp.getMediaDescriptor("audio");
- int avp = -1;
- for (int i=0;i<user_profile.audio_codecs.length;i++) {
- avp = user_profile.audio_codecs[i];
- if (avp == 3 && !useGSM) continue;
- if (avp == user_profile.dtmf_avp) continue;
- if (remote_md.hasCodec(avp_map.get(avp))!=null) break;
- }
- if (avp==-1) avp = user_profile.audio_codecs[0]; // no codec was selected
- initSessionDescriptor(new int[]{avp, user_profile.dtmf_avp});
+ private void createAnswer(SessionDescriptor remote_sdp) {
+
+ Codecs.Map c = Codecs.getCodec(remote_sdp);
+ if (c == null)
+ throw new RuntimeException("Failed to get CODEC: AVAILABLE : " + remote_sdp);
+ initSessionDescriptor(c);
sessionProduct(remote_sdp);
}
@@ -557,13 +522,19 @@ public class UserAgent extends CallListenerAdapter {
changeStatus(UA_STATE_INCOMING_CALL,caller.toString());
- boolean useGSM = useAudioCompression();
if (sdp == null) {
- createOffer(useGSM);
+ createOffer();
}
else {
SessionDescriptor remote_sdp = new SessionDescriptor(sdp);
- createAnswer(remote_sdp, useGSM);
+ try {
+ createAnswer(remote_sdp);
+ } catch (Exception e) {
+ // only known exception is no codec
+ Receiver.call_end_reason = R.string.card_title_ended_no_codec;
+ changeStatus(UA_STATE_IDLE);
+ return;
+ }
}
call.ring(local_session);
launchMediaApplication();
@@ -638,7 +609,7 @@ public class UserAgent extends CallListenerAdapter {
SessionDescriptor remote_sdp = new SessionDescriptor(sdp);
if (user_profile.no_offer) {
// answer with the local sdp
- createAnswer(remote_sdp, useAudioCompression());
+ createAnswer(remote_sdp);
call.ackWithAnswer(local_session);
} else {
// Update the local SDP along with offer/answer
@@ -707,6 +678,10 @@ public class UserAgent extends CallListenerAdapter {
return;
}
printLog("REFUSED (" + reason + ")", LogLevel.HIGH);
+ if (reason.equalsIgnoreCase("not acceptable here")) {
+ // bummer we have to string compare, this is sdp 488
+ Receiver.call_end_reason = R.string.card_title_ended_no_codec;
+ }
changeStatus(UA_STATE_IDLE);
if (call == call_transfer)
diff --git a/src/org/sipdroid/sipua/UserAgentProfile.java b/src/org/sipdroid/sipua/UserAgentProfile.java
index e2a235e..47131d2 100644
--- a/src/org/sipdroid/sipua/UserAgentProfile.java
+++ b/src/org/sipdroid/sipua/UserAgentProfile.java
@@ -146,8 +146,6 @@ public class UserAgentProfile extends Configure {
/** Audio port */
public int audio_port = 21000;
-
- /** Supported audio codecs (priority order) */
public int[] audio_codecs = {3, 8, 0};
public int dtmf_avp = 101; // zero means no use of outband DTMF
/** Audio sample rate */
diff --git a/src/org/sipdroid/sipua/phone/CallCard.java b/src/org/sipdroid/sipua/phone/CallCard.java
index 3535052..57d0cdc 100644
--- a/src/org/sipdroid/sipua/phone/CallCard.java
+++ b/src/org/sipdroid/sipua/phone/CallCard.java
@@ -47,6 +47,7 @@ import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import org.sipdroid.sipua.*;
+import org.sipdroid.sipua.ui.Receiver;
/**
* "Call card" UI element: the in-call screen contains a tiled layout of call
@@ -624,10 +625,12 @@ public class CallCard extends FrameLayout
private String getCallFailedString(Call call) {
- int resID;
+ int resID = R.string.card_title_call_ended;
- resID = R.string.card_title_call_ended;
- return getContext().getString(resID);
+ if (Receiver.call_end_reason != -1)
+ resID = Receiver.call_end_reason;
+
+ return getContext().getString(resID);
}
private void showCallConnecting() {
diff --git a/src/org/sipdroid/sipua/ui/InCallScreen.java b/src/org/sipdroid/sipua/ui/InCallScreen.java
index c03d3af..e39746e 100644
--- a/src/org/sipdroid/sipua/ui/InCallScreen.java
+++ b/src/org/sipdroid/sipua/ui/InCallScreen.java
@@ -107,9 +107,13 @@ public class InCallScreen extends CallScreen implements View.OnClickListener {
Receiver.moveTop();
break;
case UserAgent.UA_STATE_IDLE:
+ int delay = 2000;
if (Receiver.ccCall != null)
mCallCard.displayMainCallStatus(ccPhone,Receiver.ccCall);
- mHandler.sendEmptyMessageDelayed(MSG_BACK, 2000);
+ if (Receiver.call_end_reason != -1)
+ // longer delay to see error message
+ delay = 5000;
+ mHandler.sendEmptyMessageDelayed(MSG_BACK, delay);
break;
}
if (socket != null) {
@@ -209,7 +213,8 @@ public class InCallScreen extends CallScreen implements View.OnClickListener {
screenOff(true);
break;
case UserAgent.UA_STATE_IDLE:
- if (!mHandler.hasMessages(MSG_BACK))
+ if (!mHandler.hasMessages(MSG_BACK)
+ && Receiver.call_end_reason == -1)
moveBack();
break;
}
@@ -282,6 +287,7 @@ public class InCallScreen extends CallScreen implements View.OnClickListener {
moveBack();
break;
case MSG_TICK:
+ mCodec.setText(RtpStreamReceiver.getCodec());
if (RtpStreamReceiver.good != 0) {
if (RtpStreamReceiver.timeout != 0)
mStats.setText("no data");
@@ -304,6 +310,7 @@ public class InCallScreen extends CallScreen implements View.OnClickListener {
SlidingDrawer mDialerDrawer;
SlidingCardManager mSlidingCardManager;
TextView mStats;
+ TextView mCodec;
public void initInCallScreen() {
mInCallPanel = (ViewGroup) findViewById(R.id.inCallPanel);
@@ -324,6 +331,7 @@ public class InCallScreen extends CallScreen implements View.OnClickListener {
mMainFrame.addView(wanv, lp);
mStats = (TextView) findViewById(R.id.stats);
+ mCodec = (TextView) findViewById(R.id.codec);
mDialerDrawer = (SlidingDrawer) findViewById(R.id.dialer_container);
mCallCard.displayOnHoldCallStatus(ccPhone,null);
mCallCard.displayOngoingCallStatus(ccPhone,null);
diff --git a/src/org/sipdroid/sipua/ui/Receiver.java b/src/org/sipdroid/sipua/ui/Receiver.java
index 88597cc..18cc685 100644
--- a/src/org/sipdroid/sipua/ui/Receiver.java
+++ b/src/org/sipdroid/sipua/ui/Receiver.java
@@ -90,6 +90,7 @@ import org.sipdroid.sipua.phone.Connection;
public static Call ccCall;
public static Connection ccConn;
public static int call_state;
+ public static int call_end_reason = -1;
public static String pstn_state;
public static long pstn_time;
@@ -128,6 +129,8 @@ import org.sipdroid.sipua.phone.Connection;
ccConn.setCall(ccCall);
}
if (call_state != state) {
+ if (state != UserAgent.UA_STATE_IDLE)
+ call_end_reason = -1;
call_state = state;
android.os.Vibrator v = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
switch(call_state)
diff --git a/src/org/sipdroid/sipua/ui/Settings.java b/src/org/sipdroid/sipua/ui/Settings.java
index 7ca634b..6a14b18 100644
--- a/src/org/sipdroid/sipua/ui/Settings.java
+++ b/src/org/sipdroid/sipua/ui/Settings.java
@@ -20,7 +20,6 @@
package org.sipdroid.sipua.ui;
-import org.sipdroid.pjlib.Codec;
import org.sipdroid.sipua.R;
import org.zoolu.sip.provider.SipStack;
@@ -91,14 +90,6 @@ import android.widget.Toast;
getPreferenceScreen().findPreference("3g").setEnabled(false);
getPreferenceScreen().findPreference("edge").setEnabled(false);
}
- Codec.init();
- if (!Codec.loaded) {
- Editor edit = getPreferenceScreen().getSharedPreferences().edit();
-
- edit.putString("compression", "never");
- edit.commit();
- getPreferenceScreen().findPreference("compression").setEnabled(false);
- }
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
updateSummaries();
}
@@ -222,7 +213,6 @@ import android.widget.Toast;
} else {
getPreferenceScreen().findPreference("par").setEnabled(false);
}
- fill("compression","edge",R.array.compression_values,R.array.compression_display_values);
fill("eargain","0.25",R.array.eargain_values,R.array.eargain_display_values);
fill("micgain","0.25",R.array.eargain_values,R.array.eargain_display_values);
fill("heargain","0.25",R.array.eargain_values,R.array.eargain_display_values);
--
1.6.4.2