diff --git a/app/build.gradle b/app/build.gradle index 34e72448..546e7429 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,7 +6,7 @@ android { defaultConfig { applicationId = 'com.tutpro.baresip' minSdkVersion 21 - targetSdkVersion 23 + targetSdkVersion 25 versionCode = 1 versionName = '1.0' ndk { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 30576d9c..05aa1799 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -36,7 +36,7 @@ - - - - - + # # -;auth_user=foo;auth_pass=xxx;outbound="sip:192.168.43.98:5060;transport=tcp";ptime=20;audio_codecs=OPUS/48000/2,speex/16000,speex/8000;video_codecs="";regint=600;pubint=0;sipnat=outbound +;auth_user=foo;auth_pass=xxx;outbound="sip:192.168.43.98:5060;transport=tcp";ptime=20;audio_codecs=OPUS/48000/2,speex/16000,speex/8000,PCMU,PCMA;video_codecs="";regint=600;pubint=0;sipnat=outbound diff --git a/app/src/main/assets/config b/app/src/main/assets/config index f501c607..fddee23c 100644 --- a/app/src/main/assets/config +++ b/app/src/main/assets/config @@ -19,27 +19,27 @@ call_max_calls 4 # Audio audio_player opensles,nil audio_source opensles,nil -audio_alert opensles,nil -audio_srate 8000-48000 +audio_alert opensles,nil +audio_srate 8000-48000 audio_channels 1-2 #ausrc_srate 48000 #auplay_srate 48000 #ausrc_channels 0 #auplay_channels 0 -audio_level no +audio_level no # Video #video_source v4l2,/dev/video0 #video_display x11,nil -video_size 352x288 +video_size 352x288 video_bitrate 500000 -video_fps 25 +video_fps 25 video_fullscreen yes # AVT - Audio/Video Transport rtp_tos 184 #rtp_ports 10000-20000 -#rtp_bandwidth 512-1024 # [kbit/s] +#rtp_bandwidth 512-1024 # [kbit/s] rtcp_enable yes rtcp_mux no jitter_buffer_delay 5-10 # frames @@ -176,13 +176,13 @@ speex_complexity 7 # 0-10 speex_enhancement 0 # 0-1 speex_mode_nb 3 # 1-6 speex_mode_wb 6 # 1-6 -speex_vbr 0 # Variable Bit Rate 0-1 -speex_vad 0 # Voice Activity Detection 0-1 +speex_vbr 0 # Variable Bit Rate 0-1 +speex_vad 0 # Voice Activity Detection 0-1 speex_agc_level 8000 # Opus codec parameters opus_bitrate 28000 # 6000-510000 -opus_cbr no +opus_cbr no opus_inbandfec yes # Selfview @@ -192,7 +192,7 @@ opus_inbandfec yes # ICE ice_turn no ice_debug no -ice_nomination regular # {regular,aggressive} +ice_nomination regular # {regular,aggressive} ice_mode full # {full,lite} # Menu diff --git a/app/src/main/assets/contacts b/app/src/main/assets/contacts index d884f5f1..00ff0e92 100644 --- a/app/src/main/assets/contacts +++ b/app/src/main/assets/contacts @@ -1,17 +1,20 @@ # # SIP contacts # -# Displayname ;addr-params +# "display-name" ;addr-params +# +# display-name: +# needs to be at least two characters long # # addr-params: # ;presence={none,p2p} # ;access={allow,block} # +# Peer contacts "Echo Server" #"user" ;presence=p2p - # Access rules #"Catch All" ;access=block #"Good Friend" ;access=allow diff --git a/app/src/main/cpp/baresip.c b/app/src/main/cpp/baresip.c index fae31b7b..797aaa4f 100644 --- a/app/src/main/cpp/baresip.c +++ b/app/src/main/cpp/baresip.c @@ -456,3 +456,31 @@ Java_com_tutpro_baresip_MainActivity_ua_1hangup(JNIEnv *env, jobject thiz, (*env)->ReleaseStringUTFChars(env, reason, native_reason); return; } + +JNIEXPORT void JNICALL +Java_com_tutpro_baresip_MainActivity_contacts_1remove(JNIEnv *env, jobject thiz) { + struct le *le; + le = list_head(contact_list(baresip_contacts())); + while ((le = list_head(contact_list(baresip_contacts())))) { + struct contact *c = le->data; + contact_remove(baresip_contacts(), c); + } + return; +} + +JNIEXPORT void JNICALL +Java_com_tutpro_baresip_MainActivity_contact_1add(JNIEnv *env, jobject thiz, + jstring javaContact) { + struct pl pl_addr; + const struct list *lst; + struct le *le; + const char *native_contact = (*env)->GetStringUTFChars(env, javaContact, 0); + pl_set_str(&pl_addr, native_contact); + if (contact_add(baresip_contacts(), NULL, &pl_addr) != 0) { + LOGE("failed to add contact %s\n", native_contact); + } else { + LOGD("added contact %s\n", native_contact); + } + return; +} + diff --git a/app/src/main/java/com/tutpro/baresip/AccountSpinnerAdapter.java b/app/src/main/java/com/tutpro/baresip/AccountSpinnerAdapter.java index 7a5d8436..c5cf72bc 100644 --- a/app/src/main/java/com/tutpro/baresip/AccountSpinnerAdapter.java +++ b/app/src/main/java/com/tutpro/baresip/AccountSpinnerAdapter.java @@ -38,6 +38,7 @@ public class AccountSpinnerAdapter extends ArrayAdapter { View row = inflater.inflate(R.layout.account_spinner, parent, false); TextView textView = (TextView) row.findViewById(R.id.spinnerText); textView.setText(aors.get(position)); + textView.setTextSize(17); ImageView imageView = (ImageView) row.findViewById(R.id.spinnerImage); imageView.setImageResource(images.get(position)); return row; diff --git a/app/src/main/java/com/tutpro/baresip/Contact.java b/app/src/main/java/com/tutpro/baresip/Contact.java new file mode 100644 index 00000000..c42d11b6 --- /dev/null +++ b/app/src/main/java/com/tutpro/baresip/Contact.java @@ -0,0 +1,20 @@ +package com.tutpro.baresip; + +public class Contact { + + private String name, uri; + + public Contact(String name, String uri) { + this.name = name; + this.uri = uri; + } + + public String getName() { + return name; + } + + public String getURI() { + return uri; + } + +} diff --git a/app/src/main/java/com/tutpro/baresip/EditContactsActivity.java b/app/src/main/java/com/tutpro/baresip/EditContactsActivity.java index f9868e91..d27d12a4 100644 --- a/app/src/main/java/com/tutpro/baresip/EditContactsActivity.java +++ b/app/src/main/java/com/tutpro/baresip/EditContactsActivity.java @@ -8,53 +8,28 @@ import android.util.TypedValue; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; +import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.TextView; + import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.OutputStreamWriter; +import java.util.ArrayList; public class EditContactsActivity extends AppCompatActivity { private EditText editText; - private String path; - private File file; + static public ArrayList Contacts = new java.util.ArrayList<>(); + static public ArrayList Names = new java.util.ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_edit_contacts); - editText = (EditText)findViewById(R.id.editText); - path = getApplicationContext().getFilesDir().getAbsolutePath() + - "/contacts"; - file = new File(path); - String content; - - if (!file.exists()) { - Log.e("Baresip", "Failed to find contacts file"); - content = "No contacts"; - } else { - Log.e("Baresip", "Found contacts file"); - int length = (int)file.length(); - byte[] bytes = new byte[length]; - try { - FileInputStream in = new FileInputStream(file); - try { - in.read(bytes); - } finally { - in.close(); - } - content = new String(bytes); - } catch (java.io.IOException e) { - Log.e("Baresip", "Failed to read contacts file: " + e.toString()); - content = "Failed to read account file"; - } - } - - Log.d("Baresip", "Content length is: " + content.length()); - + String path = getApplicationContext().getFilesDir().getAbsolutePath() + "/contacts"; + File file = new File(path); + String content = Utils.getFileContents(file); + Log.d("Baresip", "Contacts length is: " + content.length()); editText.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimension(R.dimen.textsize)); editText.setText(content, TextView.BufferType.EDITABLE); @@ -71,34 +46,71 @@ public class EditContactsActivity extends AppCompatActivity { Intent i = new Intent(this, MainActivity.class); switch (item.getItemId()) { case R.id.save: - try { - FileOutputStream fOut = - new FileOutputStream(file.getAbsoluteFile(), false); - OutputStreamWriter fWriter = new OutputStreamWriter(fOut); - String res = editText.getText().toString(); - try { - fWriter.write(res); - fWriter.close(); - fOut.close(); - } catch (java.io.IOException e) { - Log.e("Baresip", "Failed to write contacts file: " + - e.toString()); - } - } catch (java.io.FileNotFoundException e) { - Log.e("Baresip", "Failed to find contacts file: " + - e.toString()); - } + String path = getApplicationContext().getFilesDir().getAbsolutePath() + "/contacts"; + File file = new File(path); + Utils.putFileContents(file, editText.getText().toString()); Log.d("Baresip", "Updated contacts file"); + MainActivity.contacts_remove(); + updateContactsAndNames(); + // MainActivity.CalleeAdapter.notifyDataSetChanged(); + MainActivity.CalleeAdapter = new ArrayAdapter + (this,android.R.layout.select_dialog_item, Names); + MainActivity.callee.setThreshold(2); + MainActivity.callee.setAdapter(MainActivity.CalleeAdapter); i.putExtra("action", "save"); - startActivity(i); + setResult(RESULT_OK, i); + finish(); return true; case R.id.cancel: i.putExtra("action", "cancel"); - startActivity(i); + setResult(RESULT_OK, i); + finish(); return true; default: return super.onOptionsItemSelected(item); } } + + static public void updateContactsAndNames() { + String path = MainActivity.mainActivityContext.getFilesDir().getAbsolutePath() + "/contacts"; + File file = new File(path); + String[] lines = Utils.getFileContents(file).split("\n"); + String name, uri; + Contacts.clear(); + Names.clear(); + for (String line : lines) { + line.trim(); + if (line.startsWith("#") || line.length() == 0) continue; + String[] parts = line.split("\""); + if (parts.length != 3) { + Log.e("Baresip", "Invalid contacts line: " + line); + continue; + } + name = parts[1]; + if (name.length() < 2) { + Log.e("Baresip", "Too short contact display name: " + name); + continue; + } + uri = parts[2].trim(); + if (!uri.startsWith("<") || !uri.contains(">")) { + Log.e("Baresip", "Invalid contact uri: " + uri); + continue; + } + MainActivity.contact_add("\"" + name + "\" " + uri); + if (uri.indexOf(";access") > 0) continue; + uri = uri.substring(1, uri.indexOf(">")); + Log.d("Baresip", "Adding contact name/uri: " + name + "/" + uri); + Contacts.add(new Contact(name, uri)); + Names.add(name); + } + } + + static public String findContactURI(String name) { + for (Contact c : Contacts) { + if (c.getName().equals(name)) return c.getURI(); + } + return name; + } + } diff --git a/app/src/main/java/com/tutpro/baresip/MainActivity.java b/app/src/main/java/com/tutpro/baresip/MainActivity.java index 9a6948bb..f3812740 100644 --- a/app/src/main/java/com/tutpro/baresip/MainActivity.java +++ b/app/src/main/java/com/tutpro/baresip/MainActivity.java @@ -1,13 +1,18 @@ package com.tutpro.baresip; +import android.Manifest; import android.content.Intent; +import android.content.pm.PackageManager; import android.content.res.AssetManager; import android.content.res.Configuration; import android.graphics.Color; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.*; import android.widget.RelativeLayout.LayoutParams; +import android.widget.AutoCompleteTextView; import android.view.*; import android.util.Log; import java.util.*; @@ -18,17 +23,19 @@ public class MainActivity extends AppCompatActivity { static Context mainActivityContext; static Boolean running = false; - static List accountList = new ArrayList<>(); - static EditText callee; + static AutoCompleteTextView callee; static RelativeLayout layout; static Button callButton; static ArrayList Accounts = new ArrayList<>(); static ArrayList AoRs = new ArrayList<>(); static ArrayList Images = new ArrayList<>(); static AccountSpinnerAdapter AccountAdapter = null; + static ArrayAdapter CalleeAdapter = null; static ArrayList In = new ArrayList<>(); static ArrayList Out = new ArrayList<>(); + private static final int RECORD_AUDIO_PERMISSION = 1; + @Override protected void onCreate(Bundle savedInstanceState) { @@ -73,8 +80,8 @@ public class MainActivity extends AppCompatActivity { } }); - String[] assets = {"config", "accounts", "busy.wav", "callwaiting.wav", "error.wav", - "message.wav", "notfound.wav", "ring.wav", "ringback.wav"}; + String[] assets = {"accounts", "contacts", "config", "busy.wav", "callwaiting.wav", + "error.wav", "message.wav", "notfound.wav", "ring.wav", "ringback.wav"}; final String path = mainActivityContext.getFilesDir().getPath(); Log.d("Baresip", "path is: " + path); File file; @@ -93,9 +100,18 @@ public class MainActivity extends AppCompatActivity { if (!file.exists()) { Log.d("Baresip", "Copying asset " + a); copyAsset(a, path + "/" + a); + } else { + Log.d("Baresip", "Asset " + a + " already copied"); } } + if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) + != PackageManager.PERMISSION_GRANTED) { + Log.d("Baresip", "Baresip does not have RECORD_AUDIO permission"); + ActivityCompat.requestPermissions(this, + new String[]{Manifest.permission.RECORD_AUDIO}, RECORD_AUDIO_PERMISSION); + } + if (!running) { Log.i("Baresip", "Starting Baresip with path " + path); new Thread(new Runnable() { @@ -108,7 +124,12 @@ public class MainActivity extends AppCompatActivity { layout = (RelativeLayout) findViewById(R.id.mainActivityLayout); - callee = (EditText)findViewById(R.id.callee); + callee = (AutoCompleteTextView)findViewById(R.id.callee); + EditContactsActivity.updateContactsAndNames(); + CalleeAdapter = new ArrayAdapter + (this,android.R.layout.select_dialog_item, EditContactsActivity.Names); + callee.setThreshold(2); + callee.setAdapter(CalleeAdapter); callButton = (Button)findViewById(R.id.callButton); callButton.setText("Call"); @@ -117,7 +138,8 @@ public class MainActivity extends AppCompatActivity { public void onClick(View v) { String ua = ua_current(); if (callButton.getText().toString().equals("Call")) { - String uri = ((EditText) findViewById(R.id.callee)).getText().toString(); + String callee = ((EditText) findViewById(R.id.callee)).getText().toString(); + String uri = EditContactsActivity.findContactURI(callee); if (!uri.startsWith("sip:")) uri = "sip:" + uri; if (!uri.contains("@")) { String aor = ua_aor(ua); @@ -152,6 +174,24 @@ public class MainActivity extends AppCompatActivity { } } + @Override + public void onRequestPermissionsResult(int requestCode, + String permissions[], int[] grantResults) { + switch (requestCode) { + case RECORD_AUDIO_PERMISSION: { + if (grantResults.length > 0 + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + Log.d("Baresip", "RECORD_AUDIO permission granted"); + } else { + Log.d("Baresip", "RECORD_AUDIO permission NOT granted"); + } + return; + } + default: + Log.e("Baresip", "Unknown permissions request code: " + requestCode); + } + } + public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); MenuInflater inflater = getMenuInflater(); @@ -166,14 +206,15 @@ public class MainActivity extends AppCompatActivity { startActivity(new Intent(MainActivity.this, EditAccountsActivity.class)); return true; + case R.id.contacts: + startActivity(new Intent(MainActivity.this, + EditContactsActivity.class)); + + return true; case R.id.config: startActivity(new Intent(MainActivity.this, EditConfigActivity.class)); return true; - //case R.id.contacts: - // startActivity(new Intent(MainActivity.this, - // EditContactsActivity.class)); - //return true; case R.id.about: startActivity(new Intent(MainActivity.this, AboutActivity.class)); @@ -414,6 +455,7 @@ public class MainActivity extends AppCompatActivity { final String peer_uri = call_peeruri(call); Log.d("Baresip", "Incoming call " + ua + "/" + call + "/" + peer_uri); + final Call new_call = new Call(ua, call, peer_uri, "Answer"); In.add(new_call); Log.d("Baresip", "Current UA is " + ua_current()); @@ -485,13 +527,14 @@ public class MainActivity extends AppCompatActivity { public native String ua_aor(String ua); public native Boolean ua_isregistered(long ua_ptr); public native String ua_call(String ua); - public native String ua_prev_call(String ua); public native String call_peeruri(String call); public native String ua_current(); public static native void ua_current_set(String s); public native String ua_connect(String s); public native void ua_answer(String ua, String call); public native void ua_hangup(String ua, String call, int code, String reason); + static public native void contacts_remove(); + static public native void contact_add(String contact); static { System.loadLibrary("baresip"); diff --git a/app/src/main/java/com/tutpro/baresip/Utils.java b/app/src/main/java/com/tutpro/baresip/Utils.java new file mode 100644 index 00000000..e78505fc --- /dev/null +++ b/app/src/main/java/com/tutpro/baresip/Utils.java @@ -0,0 +1,55 @@ +package com.tutpro.baresip; + +import android.util.Log; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; + +public class Utils { + + static public String getFileContents(File file) { + if (!file.exists()) { + Log.e("Baresip", "Failed to find file: " + file.getPath()); + return ""; + } else { + Log.e("Baresip", "Found file: " + file.getPath()); + int length = (int) file.length(); + byte[] bytes = new byte[length]; + try { + FileInputStream in = new FileInputStream(file); + try { + in.read(bytes); + } finally { + in.close(); + } + return new String(bytes); + } catch (java.io.IOException e) { + Log.e("Baresip", "Failed to read file: " + file.getPath() + ": " + + e.toString()); + return ""; + } + } + } + + static public void putFileContents(File file, String contents) { + try { + FileOutputStream fOut = + new FileOutputStream(file.getAbsoluteFile(), false); + OutputStreamWriter fWriter = new OutputStreamWriter(fOut); + try { + fWriter.write(contents); + fWriter.close(); + fOut.close(); + } catch (java.io.IOException e) { + Log.e("Baresip", "Failed to put contents to file: " + + e.toString()); + } + } catch (java.io.FileNotFoundException e) { + Log.e("Baresip", "Failed to find contents file: " + + e.toString()); + } + } + +} diff --git a/app/src/main/res/layout/activity_edit_contacts.xml b/app/src/main/res/layout/activity_edit_contacts.xml index a556e598..7efb1bc1 100644 --- a/app/src/main/res/layout/activity_edit_contacts.xml +++ b/app/src/main/res/layout/activity_edit_contacts.xml @@ -12,7 +12,7 @@ diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 6eb0b84c..85665a4b 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,7 +1,7 @@ - - - + +