[PATCH v2 1/2] sipdroid: redo codec infrastructure to support arbitrary codecs

59 views
Skip to first unread message

James Bottomley

unread,
Feb 14, 2010, 2:31:32 PM2/14/10
to sipdroid-...@googlegroups.com, Pascal Merle
Instead of having the GSM codec as special, this patch uses a plugin
infrastructure to support the adding of arbitrary codecs to Siproid.
It also changes the way users select codecs by adding a new 'Audio
Codecs' preference screen and allowing them to select for each codec
when it will be used (always, edge only or never) and also allowing
them to change the order in which codecs are presented to the other
end.

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

Reply all
Reply to author
Forward
0 new messages