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

31 views
Skip to first unread message

James Bottomley

unread,
Jan 29, 2010, 1:48:51 PM1/29/10
to sipdroid-...@googlegroups.com
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.

Oh, and the old compression settings are also migrated

Signed-off-by: James Bottomley <James.B...@HansenPartnership.com>
---
AndroidManifest.xml | 6 +-
res/layout/incall.xml | 9 +
res/values/strings.xml | 6 +
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 | 98 ++++------
src/org/sipdroid/sipua/UserAgent.java | 117 ++++-------
src/org/sipdroid/sipua/UserAgentProfile.java | 3 -
src/org/sipdroid/sipua/ui/InCallScreen.java | 3 +
src/org/sipdroid/sipua/ui/Settings.java | 10 -
18 files changed, 809 insertions(+), 193 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 2bdc541..aaeeee2 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 c837c95..3263f28 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -242,4 +242,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 d62d6f8..a001335 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"
@@ -173,4 +166,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 daa835c..f6ebb3e 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;
@@ -69,7 +70,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)
+ 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)
{ log=logger;
frame_rate=sample_rate/frame_size;
try
diff --git a/src/org/sipdroid/media/RtpStreamReceiver.java b/src/org/sipdroid/media/RtpStreamReceiver.java
index 6cae0b3..2a31a32 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;
@@ -53,7 +53,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;
@@ -78,9 +80,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 */
@@ -287,7 +290,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);

@@ -318,15 +320,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();
System.gc();
@@ -373,7 +367,6 @@ public class RtpStreamReceiver extends Thread {
m++;
continue;
}
-
server = track.getPlaybackHeadPosition();
headroom = user-server;

@@ -388,21 +381,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);
@@ -478,9 +457,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");
@@ -499,4 +480,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 d969932..a93fcdf 100644
--- a/src/org/sipdroid/media/RtpStreamSender.java
+++ b/src/org/sipdroid/media/RtpStreamSender.java
@@ -33,7 +33,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;
@@ -55,7 +55,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;
@@ -104,22 +104,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
@@ -237,18 +238,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;

@@ -269,15 +269,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) {
@@ -291,20 +283,20 @@ public class RtpStreamSender extends Thread {
record.startRecording();
}
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-1;
- }
- }
+ }
+ }
num = record.read(lin,(ring+delay)%(frame_size*11),frame_size);
- if (num <= 0)
- continue;
+ if (num <= 0)
+ continue;

if (RtpStreamReceiver.speakermode == AudioManager.MODE_NORMAL) {
calc(lin,(ring+delay)%(frame_size*11),num);
@@ -331,28 +323,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++);
@@ -371,13 +347,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)
@@ -388,6 +357,7 @@ public class RtpStreamSender extends Thread {
record.stop();
record.release();

+ p_type.codec.close();
rtp_socket.close();
rtp_socket = null;

@@ -400,4 +370,4 @@ public class RtpStreamSender extends Thread {
if (!Sipdroid.release) System.out.println("RtpStreamSender: " + str);
}

-}
+}
diff --git a/src/org/sipdroid/sipua/UserAgent.java b/src/org/sipdroid/sipua/UserAgent.java
index d8447e6..7c765ff 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,26 +214,23 @@ public class UserAgent extends CallListenerAdapter {
local_session = sdp.toString();
}

- protected static HashMap<Integer,String> codecs = new HashMap<Integer,String>(){{
- put(0,"PCMU");
- put(3,"GSM");
- put(8,"PCMA");
- put(103,"h263-1998");
- }};
-
- /** 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 = codecs.get(avp);
- 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)));
}
//String attr_param = String.valueOf(avp);

@@ -283,7 +279,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,
@@ -311,19 +307,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)
{
if (call != null)
@@ -397,22 +380,19 @@ 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;
- 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());
- } //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();

// parse remote sdp
SessionDescriptor remote_sdp = new SessionDescriptor(call
@@ -457,7 +437,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);
+ user_profile.audio_frame_size, log, c);
}
audio_app.startMedia();
}
@@ -483,30 +463,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.codecs.length;i++){
- int avp = user_profile.codecs[i];
- if (avp == 3 && !useGSM) continue;
- avpvec.add(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) {
- Vector<String> remote_formats = remote_sdp.getMediaDescriptor("audio").getMedia().getFormatList();
-
- int avp = -1;
- for (int i=0;i<user_profile.codecs.length;i++) {
- avp = user_profile.codecs[i];
- if (avp == 3 && !useGSM) continue;
- if (remote_formats.contains(String.valueOf(avp))) break;
- }
- initSessionDescriptor(new int[]{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);
}

@@ -545,13 +511,12 @@ 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);
+ createAnswer(remote_sdp);
}
call.ring(local_session);
launchMediaApplication();
@@ -613,7 +578,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
diff --git a/src/org/sipdroid/sipua/UserAgentProfile.java b/src/org/sipdroid/sipua/UserAgentProfile.java
index b9da20a..d4a49df 100644
--- a/src/org/sipdroid/sipua/UserAgentProfile.java
+++ b/src/org/sipdroid/sipua/UserAgentProfile.java
@@ -146,9 +146,6 @@ public class UserAgentProfile extends Configure {

/** Audio port */
public int audio_port = 21000;
-
- /** Supported codecs (priority order) */
- public int[] codecs = {3, 8, 0}; //change multi codecs
/** Audio sample rate */
public int audio_sample_rate = 8000;
/** Audio sample size */
diff --git a/src/org/sipdroid/sipua/ui/InCallScreen.java b/src/org/sipdroid/sipua/ui/InCallScreen.java
index 7363fcf..78e876b 100644
--- a/src/org/sipdroid/sipua/ui/InCallScreen.java
+++ b/src/org/sipdroid/sipua/ui/InCallScreen.java
@@ -275,6 +275,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");
@@ -297,6 +298,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);
@@ -317,6 +319,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/Settings.java b/src/org/sipdroid/sipua/ui/Settings.java
index 9a15232..f1db3b3 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;

@@ -83,14 +82,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();
}
@@ -207,7 +198,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

James Bottomley

unread,
Jan 30, 2010, 9:45:28 AM1/30/10
to sipdroid-...@googlegroups.com
On Fri, 2010-01-29 at 12:48 -0600, James Bottomley wrote:
> 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.
>
> Oh, and the old compression settings are also migrated

Actually, there's a slight bug in this (also present in the original):
The codecs are actually opened and closed for each stream (both sender
and receiver). This leads to two inits per codec and two closes.
Codecs are really only expecting one of each, so move the init and close
code to the JAudioLauncher to facilitate this.

I'll just roll this into the original patch if it looks OK.

James

---

diff --git a/src/org/sipdroid/media/JAudioLauncher.java b/src/org/sipdroid/media/JAudioLauncher.java
index f6ebb3e..f16557c 100644
--- a/src/org/sipdroid/media/JAudioLauncher.java
+++ b/src/org/sipdroid/media/JAudioLauncher.java
@@ -42,6 +42,7 @@ public class JAudioLauncher implements MediaLauncher
int frame_rate=50; //=sample_rate/(frame_size/sample_size);
boolean signed=false;
boolean big_endian=false;
+ Codecs.Map codec;

//String filename="audio.wav";

@@ -73,6 +74,7 @@ public class JAudioLauncher implements MediaLauncher


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)
{ log=logger;
frame_rate=sample_rate/frame_size;

+ codec = payload_type;
try
{ socket=new SipdroidSocket(local_port);
dir=direction;
@@ -97,6 +99,8 @@ public class JAudioLauncher implements MediaLauncher
public boolean startMedia()
{ printLog("starting java audio..",LogLevel.HIGH);

+ codec.codec.init();
+
if (sender!=null)
{ printLog("start sending",LogLevel.LOW);
sender.start();
@@ -119,7 +123,8 @@ public class JAudioLauncher implements MediaLauncher
if (receiver!=null)
{ receiver.halt(); receiver=null;
printLog("receiver halted",LogLevel.LOW);
- }
+ }
+ codec.codec.close();
socket.close();
return true;
}
diff --git a/src/org/sipdroid/media/RtpStreamReceiver.java b/src/org/sipdroid/media/RtpStreamReceiver.java
index 2a31a32..c678df4 100644
--- a/src/org/sipdroid/media/RtpStreamReceiver.java
+++ b/src/org/sipdroid/media/RtpStreamReceiver.java
@@ -320,7 +320,6 @@ public class RtpStreamReceiver extends Thread {


lserver = 0;
luser = -8000;
cnt = 0;

- p_type.codec.init();


ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_MUSIC,(int)(ToneGenerator.MAX_VOLUME*2*org.sipdroid.sipua.ui.Settings.getEarGain()));
track.play();
System.gc();

@@ -458,7 +457,6 @@ public class RtpStreamReceiver extends Thread {
tg.stopTone();
tg.release();

- p_type.codec.close();
rtp_socket.close();
rtp_socket = null;
codec = "NONE";
diff --git a/src/org/sipdroid/media/RtpStreamSender.java b/src/org/sipdroid/media/RtpStreamSender.java
index a93fcdf..fe1a187 100644
--- a/src/org/sipdroid/media/RtpStreamSender.java
+++ b/src/org/sipdroid/media/RtpStreamSender.java
@@ -269,7 +269,6 @@ public class RtpStreamSender extends Thread {


} catch (IOException e2) {
if (!Sipdroid.release) e2.printStackTrace();
}

- p_type.codec.init();


record.startRecording();
while (running) {
if (muted || Receiver.call_state == UserAgent.UA_STATE_HOLD) {

@@ -357,7 +356,6 @@ public class RtpStreamSender extends Thread {
record.stop();
record.release();

- p_type.codec.close();
rtp_socket.close();
rtp_socket = null;


Reply all
Reply to author
Forward
0 new messages