From e98f26aa80760d3eb3b3bced656cd6a07b7f2431 Mon Sep 17 00:00:00 2001 From: Benjamin Jemlich Date: Fri, 8 Oct 2010 03:38:30 +0200 Subject: [PATCH] Reformat everything... --- AndroidManifest.xml | 4 +- res/layout/channel_list.xml | 58 ++- res/layout/chat_view.xml | 41 +- res/layout/main.xml | 14 +- res/layout/server_add.xml | 80 ++-- res/layout/server_list_row.xml | 17 +- src/org/pcgod/mumbleclient/Globals.java | 1 - .../pcgod/mumbleclient/app/ChannelList.java | 355 ++++++++-------- .../pcgod/mumbleclient/app/ChatActivity.java | 45 ++- .../mumbleclient/app/ConnectedActivity.java | 18 +- .../app/ConnectedListActivity.java | 18 +- src/org/pcgod/mumbleclient/app/DbAdapter.java | 25 +- .../pcgod/mumbleclient/app/RecordThread.java | 19 +- .../pcgod/mumbleclient/app/ServerInfo.java | 26 +- .../pcgod/mumbleclient/app/ServerList.java | 87 ++-- .../mumbleclient/service/AudioOutput.java | 72 ++-- .../pcgod/mumbleclient/service/AudioUser.java | 158 ++++---- .../mumbleclient/service/JitterBuffer.java | 65 +-- .../service/MumbleConnection.java | 134 ++++--- .../service/MumbleConnectionHost.java | 17 +- .../mumbleclient/service/MumbleService.java | 378 ++++++++++-------- .../service/MumbleServiceConnection.java | 12 +- .../service/PacketDataStream.java | 38 +- .../mumbleclient/service/model/Channel.java | 5 +- .../mumbleclient/service/model/Message.java | 5 +- .../mumbleclient/service/model/User.java | 38 +- 26 files changed, 927 insertions(+), 803 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 8666fa37..b98e54e3 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -12,8 +12,8 @@ - - + + diff --git a/res/layout/channel_list.xml b/res/layout/channel_list.xml index 42b50809..a9ea60e6 100644 --- a/res/layout/channel_list.xml +++ b/res/layout/channel_list.xml @@ -1,66 +1,82 @@ - + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> - - + - diff --git a/res/layout/main.xml b/res/layout/main.xml index e6c2d646..f0d2955b 100644 --- a/res/layout/main.xml +++ b/res/layout/main.xml @@ -1,16 +1,16 @@ - + + android:layout_width="fill_parent" /> + android:id="@+id/android:empty" /> diff --git a/res/layout/server_add.xml b/res/layout/server_add.xml index 642af324..52765427 100644 --- a/res/layout/server_add.xml +++ b/res/layout/server_add.xml @@ -1,38 +1,66 @@ - - - + + - - - + - - - - - - - diff --git a/res/layout/server_list_row.xml b/res/layout/server_list_row.xml index 294e2313..081cabaa 100644 --- a/res/layout/server_list_row.xml +++ b/res/layout/server_list_row.xml @@ -1,7 +1,16 @@ - - + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_height="wrap_content" + android:layout_width="fill_parent" + android:orientation="vertical"> + + diff --git a/src/org/pcgod/mumbleclient/Globals.java b/src/org/pcgod/mumbleclient/Globals.java index 9cb47b30..020206a9 100644 --- a/src/org/pcgod/mumbleclient/Globals.java +++ b/src/org/pcgod/mumbleclient/Globals.java @@ -4,7 +4,6 @@ * Constant global values * * @author Rantanen - * */ public class Globals { diff --git a/src/org/pcgod/mumbleclient/app/ChannelList.java b/src/org/pcgod/mumbleclient/app/ChannelList.java index 713fa6b1..f98c8e00 100644 --- a/src/org/pcgod/mumbleclient/app/ChannelList.java +++ b/src/org/pcgod/mumbleclient/app/ChannelList.java @@ -20,7 +20,6 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; -import android.content.res.Resources; import android.media.AudioManager; import android.os.Bundle; import android.util.Log; @@ -94,37 +93,13 @@ * */ public class ChannelList extends ConnectedActivity { - - public static final String JOIN_CHANNEL = "join_channel"; - - public static final String SAVED_STATE_VISIBLE_CHANNEL = "visible_channel"; - - private class UserAdapter extends ArrayAdapter { - public UserAdapter(final Context context, final List users) { - super(context, android.R.layout.simple_list_item_1, users); - } - - @Override - public final View getView(final int position, View v, - final ViewGroup parent) { - if (v == null) { - final LayoutInflater inflater = (LayoutInflater) ChannelList.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - v = inflater.inflate(android.R.layout.simple_list_item_1, null); - } - final User u = getItem(position); - final TextView tv = (TextView) v.findViewById(android.R.id.text1); - tv.setText(u.name); - return tv; - } - } - /** * Handles broadcasts from MumbleService */ private class ChannelBroadcastReceiver extends BroadcastReceiver { @Override public final void onReceive(final Context ctx, final Intent i) { - String action = i.getAction(); + final String action = i.getAction(); if (action.equals(MumbleService.INTENT_CONNECTION_STATE_CHANGED)) { onConnectionStateChanged(); @@ -148,11 +123,12 @@ public final void onReceive(final Context ctx, final Intent i) { if (action.equals(MumbleService.INTENT_CHANNEL_LIST_UPDATE)) { // Channel list update doesn't matter if the visible channel // isn't valid from the beginning. - if (visibleChannel == null) + if (visibleChannel == null) { return; + } boolean visibleChannelValid = false; - for (Channel c : mService.getChannelList()) { + for (final Channel c : mService.getChannelList()) { if (visibleChannel.id == c.id) { visibleChannelValid = true; break; @@ -177,8 +153,8 @@ private final void onConnectionStateChanged() { switch (mService.getConnectionState()) { case Connecting: Log.i(Globals.LOG_TAG, "ChannelList: Connecting"); - mProgressDialog = ProgressDialog.show(ChannelList.this, "Connecting", - "Connecting to Mumble server", true); + mProgressDialog = ProgressDialog.show(ChannelList.this, + "Connecting", "Connecting to Mumble server", true); break; case Connected: Log.i(Globals.LOG_TAG, "ChannelList: Connected"); @@ -199,11 +175,35 @@ private final void onConnectionStateChanged() { } } + private class UserAdapter extends ArrayAdapter { + public UserAdapter(final Context context, final List users) { + super(context, android.R.layout.simple_list_item_1, users); + } + + @Override + public final View getView(final int position, View v, + final ViewGroup parent) { + if (v == null) { + final LayoutInflater inflater = (LayoutInflater) ChannelList.this + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + v = inflater.inflate(android.R.layout.simple_list_item_1, null); + } + final User u = getItem(position); + final TextView tv = (TextView) v.findViewById(android.R.id.text1); + tv.setText(u.name); + return tv; + } + } + + public static final String JOIN_CHANNEL = "join_channel"; + + public static final String SAVED_STATE_VISIBLE_CHANNEL = "visible_channel"; + private static final int MENU_CHAT = Menu.FIRST; private boolean isConnected = false; private Channel visibleChannel; - private List channelUsers = new ArrayList(); + private final List channelUsers = new ArrayList(); private TextView channelNameText; private Button browseButton; @@ -220,42 +220,43 @@ private final void onConnectionStateChanged() { private AlertDialog mDisconnectDialog; public final OnClickListener browseButtonClickEvent = new OnClickListener() { - @Override - public void onClick(View v) { + public void onClick(final View v) { // Save the current channels so we can match them by index even if // the real // channels change. - List currentChannels = mService.getChannelList(); + final List currentChannels = mService.getChannelList(); selectableChannels = new ArrayList(currentChannels); - Channel currentChannel = mService.getCurrentChannel(); + final Channel currentChannel = mService.getCurrentChannel(); int currentChannelId = -1; if (currentChannel != null) { currentChannelId = currentChannel.id; } - Iterator i = selectableChannels.iterator(); + final Iterator i = selectableChannels.iterator(); int step = 0; - String[] channelNames = new String[selectableChannels.size()]; + final String[] channelNames = new String[selectableChannels.size()]; while (i.hasNext()) { - Channel c = i.next(); + final Channel c = i.next(); if (c.id == currentChannelId) { - channelNames[step] = String.format("%s (C, %d)", c.name, c.userCount); + channelNames[step] = String.format("%s (C, %d)", c.name, + c.userCount); } else { - channelNames[step] = String.format("%s (%d)", c.name, c.userCount); + channelNames[step] = String.format("%s (%d)", c.name, + c.userCount); } step++; } - new AlertDialog.Builder(ChannelList.this).setCancelable(true).setItems(channelNames, - channelListClickEvent).show(); + new AlertDialog.Builder(ChannelList.this).setCancelable(true) + .setItems(channelNames, channelListClickEvent).show(); } }; public final DialogInterface.OnClickListener channelListClickEvent = new DialogInterface.OnClickListener() { @Override - public void onClick(DialogInterface dialog, int which) { + public void onClick(final DialogInterface dialog, final int which) { setChannel(selectableChannels.get(which)); } }; @@ -274,111 +275,38 @@ public void onClick(final View v) { public final DialogInterface.OnClickListener onDisconnectConfirm = new DialogInterface.OnClickListener() { @Override - public void onClick(DialogInterface dialog, int which) { + public void onClick(final DialogInterface dialog, final int which) { mService.disconnect(); } }; @Override - protected final void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.channel_list); - setVolumeControlStream(AudioManager.STREAM_VOICE_CALL); - - if (savedInstanceState != null) { - visibleChannel = (Channel) savedInstanceState.getSerializable(SAVED_STATE_VISIBLE_CHANNEL); - } - - // Get the UI views - channelNameText = (TextView) findViewById(R.id.channelName); - browseButton = (Button) findViewById(R.id.browseButton); - channelUsersList = (ListView) findViewById(R.id.channelUsers); - noUsersText = (TextView) findViewById(R.id.noUsersText); - speakButton = (ToggleButton) findViewById(R.id.speakButton); - joinButton = (Button) findViewById(R.id.joinButton); - speakerCheckBox = (CheckBox) findViewById(R.id.speakerCheckBox); - - // Set event handlers. - browseButton.setOnClickListener(browseButtonClickEvent); - joinButton.setOnClickListener(joinButtonClickEvent); - speakButton.setOnClickListener(speakButtonClickEvent); - - channelUsersList.setAdapter(new UserAdapter(this, channelUsers)); - - // Disable speaker check box for now since switching between audio - // inputs isn't supported. - speakerCheckBox.setEnabled(false); - speakerCheckBox.setVisibility(View.GONE); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putSerializable(SAVED_STATE_VISIBLE_CHANNEL, visibleChannel); - } - - @Override - protected final void onPause() { - super.onPause(); - - if (bcReceiver != null) { - unregisterReceiver(bcReceiver); - bcReceiver = null; - } - - cleanDialogs(); - } - - @Override - protected final void onResume() { - super.onResume(); - - final IntentFilter ifilter = new IntentFilter(); - ifilter.addAction(MumbleService.INTENT_CHANNEL_LIST_UPDATE); - ifilter.addAction(MumbleService.INTENT_USER_LIST_UPDATE); - ifilter.addAction(MumbleService.INTENT_CONNECTION_STATE_CHANGED); - ifilter.addAction(MumbleService.INTENT_CURRENT_CHANNEL_CHANGED); - bcReceiver = new ChannelBroadcastReceiver(); - registerReceiver(bcReceiver, ifilter); - - synchronizeControls(); + public final boolean onCreateOptionsMenu(final Menu menu) { + menu.add(0, MENU_CHAT, 0, "Chat").setIcon( + android.R.drawable.ic_btn_speak_now); + return true; } - /** - * Signals that the service has been bound and is available for use. - */ @Override - protected final void onServiceBound() { + public boolean onKeyDown(final int keyCode, final KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) { + final AlertDialog.Builder b = new AlertDialog.Builder(this); + b.setIcon(android.R.drawable.ic_dialog_alert); + b.setTitle("Disconnect"); + b.setMessage("Are you sure you want to disconnect from Mumble?"); + b.setPositiveButton(android.R.string.yes, onDisconnectConfirm); + b.setNegativeButton(android.R.string.no, null); + mDisconnectDialog = b.show(); - switch (mService.getConnectionState()) { - case Connecting: - mProgressDialog = ProgressDialog.show(this, - getString(R.string.connectionProgressTitle), - getString(R.string.connectionProgressConnectingMessage), true); - break; - case Connected: - // We might have resumed right after the connection was established - // in which case the connection is incomplete. Try setting up the - // connection anyway as onConnected takes care of the proper checks. - onConnected(); - break; - case Disconnected: - case Disconnecting: - onDisconnected(); - break; - default: - Assert.fail("Unknown connection state"); + return true; } - } - @Override - public final boolean onCreateOptionsMenu(final Menu menu) { - menu.add(0, MENU_CHAT, 0, "Chat").setIcon(android.R.drawable.ic_btn_speak_now); - return true; + return super.onKeyDown(keyCode, event); } @Override - public final boolean onMenuItemSelected(final int featureId, final MenuItem item) { + public final boolean onMenuItemSelected(final int featureId, + final MenuItem item) { switch (item.getItemId()) { case MENU_CHAT: final Intent i = new Intent(this, ChatActivity.class); @@ -389,35 +317,29 @@ public final boolean onMenuItemSelected(final int featureId, final MenuItem item } } - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) { - AlertDialog.Builder b = new AlertDialog.Builder(this); - b.setIcon(android.R.drawable.ic_dialog_alert); - b.setTitle("Disconnect"); - b.setMessage("Are you sure you want to disconnect from Mumble?"); - b.setPositiveButton(android.R.string.yes, onDisconnectConfirm); - b.setNegativeButton(android.R.string.no, null); - mDisconnectDialog = b.show(); - - return true; + private void cleanDialogs() { + if (mChannelSelectDialog != null) { + mChannelSelectDialog.dismiss(); + mChannelSelectDialog = null; } - return super.onKeyDown(keyCode, event); - } - - private void setChannel(Channel channel) { - visibleChannel = channel; + if (mProgressDialog != null) { + mProgressDialog.dismiss(); + mProgressDialog = null; + } - synchronizeControls(); - updateUserList(); + if (mDisconnectDialog != null) { + mDisconnectDialog.dismiss(); + mDisconnectDialog = null; + } } private void onConnected() { if (isConnected || mService.getCurrentChannel() == null) { if (mProgressDialog != null && mService.getConnectionState() == ConnectionState.Connected) { - mProgressDialog.setMessage(getString(R.string.connectionProgressSynchronizingMessage)); + mProgressDialog + .setMessage(getString(R.string.connectionProgressSynchronizingMessage)); } return; } @@ -426,8 +348,9 @@ private void onConnected() { // If we don't have visible channel selected, default to the // current channel. - if (visibleChannel == null) + if (visibleChannel == null) { visibleChannel = mService.getCurrentChannel(); + } // We are now connected! \o/ if (mProgressDialog != null) { @@ -439,7 +362,7 @@ private void onConnected() { speakButton.setEnabled(true); joinButton.setEnabled(true); - String channelName = mService.getCurrentChannel().name; + final String channelName = mService.getCurrentChannel().name; channelNameText.setText(channelName); } @@ -448,21 +371,11 @@ private void onDisconnected() { finish(); } - private void cleanDialogs() { - if (mChannelSelectDialog != null) { - mChannelSelectDialog.dismiss(); - mChannelSelectDialog = null; - } - - if (mProgressDialog != null) { - mProgressDialog.dismiss(); - mProgressDialog = null; - } + private void setChannel(final Channel channel) { + visibleChannel = channel; - if (mDisconnectDialog != null) { - mDisconnectDialog.dismiss(); - mDisconnectDialog = null; - } + synchronizeControls(); + updateUserList(); } private void synchronizeControls() { @@ -486,21 +399,115 @@ private void synchronizeControls() { } private void updateUserList() { - List allUsers = mService.getUserList(); + final List allUsers = mService.getUserList(); channelUsers.clear(); if (isConnected) { - for (User u : allUsers) { + for (final User u : allUsers) { if (u.getChannel().id == visibleChannel.id) { channelUsers.add(u); } } - ((UserAdapter) channelUsersList.getAdapter()).notifyDataSetChanged(); + ((UserAdapter) channelUsersList.getAdapter()) + .notifyDataSetChanged(); } - boolean showList = (channelUsers.size() > 0); + final boolean showList = (channelUsers.size() > 0); channelUsersList.setVisibility(showList ? View.VISIBLE : View.GONE); noUsersText.setVisibility(showList ? View.GONE : View.VISIBLE); } + + @Override + protected final void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.channel_list); + setVolumeControlStream(AudioManager.STREAM_VOICE_CALL); + + if (savedInstanceState != null) { + visibleChannel = (Channel) savedInstanceState + .getSerializable(SAVED_STATE_VISIBLE_CHANNEL); + } + + // Get the UI views + channelNameText = (TextView) findViewById(R.id.channelName); + browseButton = (Button) findViewById(R.id.browseButton); + channelUsersList = (ListView) findViewById(R.id.channelUsers); + noUsersText = (TextView) findViewById(R.id.noUsersText); + speakButton = (ToggleButton) findViewById(R.id.speakButton); + joinButton = (Button) findViewById(R.id.joinButton); + speakerCheckBox = (CheckBox) findViewById(R.id.speakerCheckBox); + + // Set event handlers. + browseButton.setOnClickListener(browseButtonClickEvent); + joinButton.setOnClickListener(joinButtonClickEvent); + speakButton.setOnClickListener(speakButtonClickEvent); + + channelUsersList.setAdapter(new UserAdapter(this, channelUsers)); + + // Disable speaker check box for now since switching between audio + // inputs isn't supported. + speakerCheckBox.setEnabled(false); + speakerCheckBox.setVisibility(View.GONE); + } + + @Override + protected final void onPause() { + super.onPause(); + + if (bcReceiver != null) { + unregisterReceiver(bcReceiver); + bcReceiver = null; + } + + cleanDialogs(); + } + + @Override + protected final void onResume() { + super.onResume(); + + final IntentFilter ifilter = new IntentFilter(); + ifilter.addAction(MumbleService.INTENT_CHANNEL_LIST_UPDATE); + ifilter.addAction(MumbleService.INTENT_USER_LIST_UPDATE); + ifilter.addAction(MumbleService.INTENT_CONNECTION_STATE_CHANGED); + ifilter.addAction(MumbleService.INTENT_CURRENT_CHANNEL_CHANGED); + bcReceiver = new ChannelBroadcastReceiver(); + registerReceiver(bcReceiver, ifilter); + + synchronizeControls(); + } + + @Override + protected void onSaveInstanceState(final Bundle outState) { + super.onSaveInstanceState(outState); + outState.putSerializable(SAVED_STATE_VISIBLE_CHANNEL, visibleChannel); + } + + /** + * Signals that the service has been bound and is available for use. + */ + @Override + protected final void onServiceBound() { + switch (mService.getConnectionState()) { + case Connecting: + mProgressDialog = ProgressDialog.show(this, + getString(R.string.connectionProgressTitle), + getString(R.string.connectionProgressConnectingMessage), + true); + break; + case Connected: + // We might have resumed right after the connection was established + // in which case the connection is incomplete. Try setting up the + // connection anyway as onConnected takes care of the proper checks. + onConnected(); + break; + case Disconnected: + case Disconnecting: + onDisconnected(); + break; + default: + Assert.fail("Unknown connection state"); + } + } } diff --git a/src/org/pcgod/mumbleclient/app/ChatActivity.java b/src/org/pcgod/mumbleclient/app/ChatActivity.java index 4d791532..7f905c48 100644 --- a/src/org/pcgod/mumbleclient/app/ChatActivity.java +++ b/src/org/pcgod/mumbleclient/app/ChatActivity.java @@ -28,7 +28,8 @@ public class ChatActivity extends ConnectedActivity { private class ChatBroadcastReceiver extends BroadcastReceiver { @Override public final void onReceive(final Context ctx, final Intent i) { - Message msg = (Message)i.getSerializableExtra(MumbleService.EXTRA_MESSAGE); + final Message msg = (Message) i + .getSerializableExtra(MumbleService.EXTRA_MESSAGE); addMessage(msg); } } @@ -38,11 +39,12 @@ public final void onReceive(final Context ctx, final Intent i) { private static final int MENU_CLEAR = Menu.FIRST; - private OnEditorActionListener chatTextEditActionEvent = new OnEditorActionListener() { + private final OnEditorActionListener chatTextEditActionEvent = new OnEditorActionListener() { @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + public boolean onEditorAction(final TextView v, final int actionId, + final KeyEvent event) { if (event != null && !event.isShiftPressed() && v != null) { - View focus = v.focusSearch(View.FOCUS_RIGHT); + final View focus = v.focusSearch(View.FOCUS_RIGHT); if (focus != null) { focus.requestFocus(); return true; @@ -60,7 +62,7 @@ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { } }; - private OnClickListener sendOnClickEvent = new OnClickListener() { + private final OnClickListener sendOnClickEvent = new OnClickListener() { @Override public void onClick(final View v) { sendMessage(chatTextEdit); @@ -121,8 +123,8 @@ protected final void onResume() { protected void onServiceBound() { super.onServiceBound(); - List messages = mService.getMessageList(); - for (Message m : messages) { + final List messages = mService.getMessageList(); + for (final Message m : messages) { addMessage(m); } @@ -132,13 +134,8 @@ protected void onServiceBound() { registerReceiver(bcReceiver, ifilter); } - void sendMessage(TextView v) { - mService.sendChannelTextMessage(v.getText().toString()); - v.setText(""); - } - - void addMessage(Message msg) { - StringBuilder sb = new StringBuilder(); + void addMessage(final Message msg) { + final StringBuilder sb = new StringBuilder(); sb.append("["); sb.append(DateUtils.formatDateTime(this, msg.timestamp, DateUtils.FORMAT_SHOW_TIME)); @@ -148,11 +145,18 @@ void addMessage(Message msg) { sb.append("To "); sb.append(msg.channel.name); } else { - if (msg.channelIds > 0) { sb.append("(C) "); } - if (msg.treeIds > 0) { sb.append("(T) "); } + if (msg.channelIds > 0) { + sb.append("(C) "); + } + if (msg.treeIds > 0) { + sb.append("(T) "); + } - if (msg.actor != null) { sb.append(msg.actor.name); } - else { sb.append("Server"); } + if (msg.actor != null) { + sb.append(msg.actor.name); + } else { + sb.append("Server"); + } } sb.append(": "); sb.append(msg.message); @@ -160,6 +164,11 @@ void addMessage(Message msg) { chatText.append(sb.toString()); } + void sendMessage(final TextView v) { + mService.sendChannelTextMessage(v.getText().toString()); + v.setText(""); + } + void updateText() { chatText.beginBatchEdit(); chatText.setText(""); diff --git a/src/org/pcgod/mumbleclient/app/ConnectedActivity.java b/src/org/pcgod/mumbleclient/app/ConnectedActivity.java index 2cbb1d06..ce358037 100644 --- a/src/org/pcgod/mumbleclient/app/ConnectedActivity.java +++ b/src/org/pcgod/mumbleclient/app/ConnectedActivity.java @@ -19,15 +19,16 @@ */ public class ConnectedActivity extends Activity { ServiceConnection mServiceConn = new ServiceConnection() { - public void onServiceDisconnected(ComponentName arg0) { - mService = null; - } - - public void onServiceConnected(ComponentName className, IBinder binder) { - mService = ((MumbleService.LocalBinder)binder).getService(); + public void onServiceConnected(final ComponentName className, + final IBinder binder) { + mService = ((MumbleService.LocalBinder) binder).getService(); Log.i("Mumble", "mService set"); onServiceBound(); } + + public void onServiceDisconnected(final ComponentName arg0) { + mService = null; + } }; protected MumbleService mService; @@ -40,9 +41,10 @@ protected void onPause() { @Override protected void onResume() { super.onResume(); - Intent intent = new Intent(this, MumbleService.class); + final Intent intent = new Intent(this, MumbleService.class); bindService(intent, mServiceConn, BIND_AUTO_CREATE); } - protected void onServiceBound() { } + protected void onServiceBound() { + } } diff --git a/src/org/pcgod/mumbleclient/app/ConnectedListActivity.java b/src/org/pcgod/mumbleclient/app/ConnectedListActivity.java index 5ba2e380..eb1bff65 100644 --- a/src/org/pcgod/mumbleclient/app/ConnectedListActivity.java +++ b/src/org/pcgod/mumbleclient/app/ConnectedListActivity.java @@ -19,15 +19,16 @@ */ public class ConnectedListActivity extends ListActivity { ServiceConnection mServiceConn = new ServiceConnection() { - public void onServiceDisconnected(ComponentName arg0) { - mService = null; - } - - public void onServiceConnected(ComponentName className, IBinder binder) { - mService = ((MumbleService.LocalBinder)binder).getService(); + public void onServiceConnected(final ComponentName className, + final IBinder binder) { + mService = ((MumbleService.LocalBinder) binder).getService(); Log.i("Mumble", "mService set"); onServiceBound(); } + + public void onServiceDisconnected(final ComponentName arg0) { + mService = null; + } }; protected MumbleService mService; @@ -40,9 +41,10 @@ protected void onPause() { @Override protected void onResume() { super.onResume(); - Intent intent = new Intent(this, MumbleService.class); + final Intent intent = new Intent(this, MumbleService.class); bindService(intent, mServiceConn, BIND_AUTO_CREATE); } - protected void onServiceBound() { } + protected void onServiceBound() { + } } diff --git a/src/org/pcgod/mumbleclient/app/DbAdapter.java b/src/org/pcgod/mumbleclient/app/DbAdapter.java index bc66a43f..7895aa5e 100644 --- a/src/org/pcgod/mumbleclient/app/DbAdapter.java +++ b/src/org/pcgod/mumbleclient/app/DbAdapter.java @@ -73,18 +73,6 @@ public final long createServer(final String name, final String host, return db.insert(SERVER_TABLE, null, values); } - public final void updateServer(final long id, final String name, final String host, - final int port, final String username, final String password) { - final ContentValues values = new ContentValues(); - values.put(SERVER_COL_NAME, name); - values.put(SERVER_COL_HOST, host); - values.put(SERVER_COL_PORT, port); - values.put(SERVER_COL_USERNAME, username); - values.put(SERVER_COL_PASSWORD, password); - db.update(SERVER_TABLE, values, - SERVER_COL_ID + "=?", new String[] { Long.toString(id) }); - } - public final boolean deleteServer(final long serverId) { return db.delete(SERVER_TABLE, SERVER_COL_ID + " = " + serverId, null) > 0; } @@ -115,4 +103,17 @@ public final DbAdapter open() { db = dbHelper.getWritableDatabase(); return this; } + + public final void updateServer(final long id, final String name, + final String host, final int port, final String username, + final String password) { + final ContentValues values = new ContentValues(); + values.put(SERVER_COL_NAME, name); + values.put(SERVER_COL_HOST, host); + values.put(SERVER_COL_PORT, port); + values.put(SERVER_COL_USERNAME, username); + values.put(SERVER_COL_PASSWORD, password); + db.update(SERVER_TABLE, values, SERVER_COL_ID + "=?", + new String[] { Long.toString(id) }); + } } diff --git a/src/org/pcgod/mumbleclient/app/RecordThread.java b/src/org/pcgod/mumbleclient/app/RecordThread.java index b1e6c350..64be717e 100644 --- a/src/org/pcgod/mumbleclient/app/RecordThread.java +++ b/src/org/pcgod/mumbleclient/app/RecordThread.java @@ -38,7 +38,7 @@ public class RecordThread implements Runnable { private final long speexResamplerState; private final MumbleService mService; - public RecordThread(MumbleService service) { + public RecordThread(final MumbleService service) { mService = service; for (final int s : new int[] { 48000, 44100, 22050, 11025, 8000 }) { @@ -68,12 +68,14 @@ public RecordThread(MumbleService service) { celtMode = Native.celt_mode_create(MumbleConnection.SAMPLE_RATE, MumbleConnection.FRAME_SIZE); celtEncoder = Native.celt_encoder_create(celtMode, 1); - Native.celt_encoder_ctl(celtEncoder, celtConstants.CELT_SET_PREDICTION_REQUEST, 0); - Native.celt_encoder_ctl(celtEncoder, celtConstants.CELT_SET_VBR_RATE_REQUEST, AUDIO_QUALITY); + Native.celt_encoder_ctl(celtEncoder, + celtConstants.CELT_SET_PREDICTION_REQUEST, 0); + Native.celt_encoder_ctl(celtEncoder, + celtConstants.CELT_SET_VBR_RATE_REQUEST, AUDIO_QUALITY); if (recordingSampleRate != TARGET_SAMPLE_RATE) { - speexResamplerState = Native.speex_resampler_init(1, recordingSampleRate, - TARGET_SAMPLE_RATE, 3); + speexResamplerState = Native.speex_resampler_init(1, + recordingSampleRate, TARGET_SAMPLE_RATE, 3); } else { speexResamplerState = 0; } @@ -107,8 +109,8 @@ public final void run() { out = resampleBuffer; final int[] in_len = new int[] { buffer.length }; final int[] out_len = new int[] { out.length }; - Native.speex_resampler_process_int(speexResamplerState, 0, buffer, in_len, out, - out_len); + Native.speex_resampler_process_int(speexResamplerState, 0, + buffer, in_len, out, out_len); } else { out = buffer; } @@ -119,7 +121,8 @@ public final void run() { final byte[] comp = compressed.array(); int len; synchronized (Native.class) { - len = Native.celt_encode(celtEncoder, out, comp, compressedSize); + len = Native + .celt_encode(celtEncoder, out, comp, compressedSize); } compressed.limit(len); outputQueue.add(compressed); diff --git a/src/org/pcgod/mumbleclient/app/ServerInfo.java b/src/org/pcgod/mumbleclient/app/ServerInfo.java index 8e207f10..b42b4576 100644 --- a/src/org/pcgod/mumbleclient/app/ServerInfo.java +++ b/src/org/pcgod/mumbleclient/app/ServerInfo.java @@ -11,7 +11,6 @@ import android.widget.EditText; public class ServerInfo extends Activity { - private final OnClickListener addButtonListener = new OnClickListener() { public void onClick(final View v) { final EditText nameEdit = (EditText) findViewById(R.id.serverNameEdit); @@ -26,7 +25,7 @@ public void onClick(final View v) { int port; try { port = Integer.parseInt((portEdit).getText().toString()); - } catch (NumberFormatException ex) { + } catch (final NumberFormatException ex) { port = 64738; } @@ -36,7 +35,8 @@ public void onClick(final View v) { final DbAdapter db = new DbAdapter(v.getContext()); db.open(); - long serverId = ServerInfo.this.getIntent().getLongExtra("serverId", -1); + final long serverId = ServerInfo.this.getIntent().getLongExtra( + "serverId", -1); if (serverId != -1) { db.updateServer(serverId, name, host, port, username, password); } else { @@ -53,7 +53,7 @@ protected final void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.server_add); - long serverId = this.getIntent().getLongExtra("serverId", -1); + final long serverId = this.getIntent().getLongExtra("serverId", -1); if (serverId != -1) { final EditText nameEdit = (EditText) findViewById(R.id.serverNameEdit); final EditText hostEdit = (EditText) findViewById(R.id.serverHostEdit); @@ -63,13 +63,17 @@ protected final void onCreate(final Bundle savedInstanceState) { final DbAdapter db = new DbAdapter(this); db.open(); - Cursor c = db.fetchServer(serverId); - nameEdit.setText(c.getString(c.getColumnIndexOrThrow(DbAdapter.SERVER_COL_NAME))); - hostEdit.setText(c.getString(c.getColumnIndexOrThrow(DbAdapter.SERVER_COL_HOST))); - portEdit.setText(Integer.toString( - c.getInt(c.getColumnIndexOrThrow(DbAdapter.SERVER_COL_PORT)))); - usernameEdit.setText(c.getString(c.getColumnIndexOrThrow(DbAdapter.SERVER_COL_USERNAME))); - passwordEdit.setText(c.getString(c.getColumnIndexOrThrow(DbAdapter.SERVER_COL_PASSWORD))); + final Cursor c = db.fetchServer(serverId); + nameEdit.setText(c.getString(c + .getColumnIndexOrThrow(DbAdapter.SERVER_COL_NAME))); + hostEdit.setText(c.getString(c + .getColumnIndexOrThrow(DbAdapter.SERVER_COL_HOST))); + portEdit.setText(Integer.toString(c.getInt(c + .getColumnIndexOrThrow(DbAdapter.SERVER_COL_PORT)))); + usernameEdit.setText(c.getString(c + .getColumnIndexOrThrow(DbAdapter.SERVER_COL_USERNAME))); + passwordEdit.setText(c.getString(c + .getColumnIndexOrThrow(DbAdapter.SERVER_COL_PASSWORD))); db.close(); } diff --git a/src/org/pcgod/mumbleclient/app/ServerList.java b/src/org/pcgod/mumbleclient/app/ServerList.java index d537bee8..b8b481af 100644 --- a/src/org/pcgod/mumbleclient/app/ServerList.java +++ b/src/org/pcgod/mumbleclient/app/ServerList.java @@ -35,7 +35,6 @@ * */ public class ServerList extends ConnectedListActivity { - private class ServerAdapter extends BaseAdapter { private final Context context; private final Cursor cursor; @@ -92,8 +91,8 @@ public final View getView(final int position, final View v, userText.setText(serverUsername); } else { nameText.setText(serverName); - userText.setText(serverUsername + "@" + serverHost + ":" - + serverPort); + userText.setText(serverUsername + "@" + serverHost + ":" + + serverPort); } return row; @@ -119,7 +118,8 @@ public final boolean onContextItemSelected(final MenuItem item) { .getMenuInfo(); switch (item.getItemId()) { case MENU_CONNECT_SERVER: - onListItemClick(getListView(), getCurrentFocus(), info.position, getListAdapter().getItemId(info.position)); + onListItemClick(getListView(), getCurrentFocus(), info.position, + getListAdapter().getItemId(info.position)); return true; case MENU_EDIT_SERVER: editServer(getListAdapter().getItemId(info.position)); @@ -139,7 +139,8 @@ public final void onCreateContextMenu(final ContextMenu menu, final View v, super.onCreateContextMenu(menu, v, menuInfo); final int menuPosition = ((AdapterView.AdapterContextMenuInfo) menuInfo).position; - final int serverId = (int) getListView().getItemIdAtPosition(menuPosition); + final int serverId = (int) getListView().getItemIdAtPosition( + menuPosition); final Cursor c = dbAdapter.fetchServer(serverId); final String name = getServerName(c); c.close(); @@ -184,12 +185,6 @@ private void addServer() { startActivityForResult(i, ACTIVITY_ADD_SERVER); } - private void editServer(long id) { - final Intent i = new Intent(this, ServerInfo.class); - i.putExtra("serverId", id); - startActivityForResult(i, ACTIVITY_ADD_SERVER); - } - private Dialog createDeleteServerDialog() { final AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage("Are you sure you want to delete this server?") @@ -201,7 +196,9 @@ public void onClick(final DialogInterface dialog, dbAdapter.deleteServer(serverToDeleteId); serverToDeleteId = -1; fillList(); - Toast.makeText(ServerList.this, R.string.server_deleted, Toast.LENGTH_SHORT).show(); + Toast.makeText(ServerList.this, + R.string.server_deleted, + Toast.LENGTH_SHORT).show(); } } }).setNegativeButton("No", @@ -215,6 +212,12 @@ public void onClick(final DialogInterface dialog, return builder.create(); } + private void editServer(final long id) { + final Intent i = new Intent(this, ServerInfo.class); + i.putExtra("serverId", id); + startActivityForResult(i, ACTIVITY_ADD_SERVER); + } + private String getServerName(final Cursor c) { String name = c.getString(c .getColumnIndexOrThrow(DbAdapter.SERVER_COL_NAME)); @@ -228,6 +231,36 @@ private String getServerName(final Cursor c) { return name; } + /** + * Starts connecting to a server. + * + * @param id + */ + protected final void connectServer(final long id) { + final Cursor c = dbAdapter.fetchServer(id); + final String host = c.getString(c + .getColumnIndexOrThrow(DbAdapter.SERVER_COL_HOST)); + final int port = c.getInt(c + .getColumnIndexOrThrow(DbAdapter.SERVER_COL_PORT)); + final String username = c.getString(c + .getColumnIndexOrThrow(DbAdapter.SERVER_COL_USERNAME)); + final String password = c.getString(c + .getColumnIndexOrThrow(DbAdapter.SERVER_COL_PASSWORD)); + c.close(); + + final Intent connectionIntent = new Intent(this, MumbleService.class); + connectionIntent.setAction(MumbleService.ACTION_CONNECT); + connectionIntent.putExtra(MumbleService.EXTRA_HOST, host); + connectionIntent.putExtra(MumbleService.EXTRA_PORT, port); + connectionIntent.putExtra(MumbleService.EXTRA_USERNAME, username); + connectionIntent.putExtra(MumbleService.EXTRA_PASSWORD, password); + startService(connectionIntent); + //mService.setServer(host, port, username, password); + + final Intent i = new Intent(this, ChannelList.class); + startActivityForResult(i, ACTIVITY_CHANNEL_LIST); + } + @Override protected final void onActivityResult(final int requestCode, final int resultCode, final Intent data) { @@ -276,36 +309,6 @@ protected final void onListItemClick(final ListView l, final View v, connectServer(id); } - /** - * Starts connecting to a server. - * - * @param id - */ - protected final void connectServer(final long id) { - final Cursor c = dbAdapter.fetchServer(id); - final String host = c.getString(c - .getColumnIndexOrThrow(DbAdapter.SERVER_COL_HOST)); - final int port = c.getInt(c - .getColumnIndexOrThrow(DbAdapter.SERVER_COL_PORT)); - final String username = c.getString(c - .getColumnIndexOrThrow(DbAdapter.SERVER_COL_USERNAME)); - final String password = c.getString(c - .getColumnIndexOrThrow(DbAdapter.SERVER_COL_PASSWORD)); - c.close(); - - Intent connectionIntent = new Intent(this, MumbleService.class); - connectionIntent.setAction(MumbleService.ACTION_CONNECT); - connectionIntent.putExtra(MumbleService.EXTRA_HOST, host); - connectionIntent.putExtra(MumbleService.EXTRA_PORT, port); - connectionIntent.putExtra(MumbleService.EXTRA_USERNAME, username); - connectionIntent.putExtra(MumbleService.EXTRA_PASSWORD, password); - startService(connectionIntent); - //mService.setServer(host, port, username, password); - - final Intent i = new Intent(this, ChannelList.class); - startActivityForResult(i, ACTIVITY_CHANNEL_LIST); - } - void fillList() { setListAdapter(new ServerAdapter(this, dbAdapter)); } diff --git a/src/org/pcgod/mumbleclient/service/AudioOutput.java b/src/org/pcgod/mumbleclient/service/AudioOutput.java index c613faed..0bda7493 100644 --- a/src/org/pcgod/mumbleclient/service/AudioOutput.java +++ b/src/org/pcgod/mumbleclient/service/AudioOutput.java @@ -13,8 +13,8 @@ class AudioOutput implements Runnable { static long celtDecoder; private final ConcurrentHashMap outputMap = new ConcurrentHashMap(); - private short[] out; - private short[] tmpOut; + private final short[] out; + private final short[] tmpOut; private boolean running; //private final AudioTrack at; private final long celtMode; @@ -25,21 +25,19 @@ class AudioOutput implements Runnable { private static int bufferSize = MumbleConnection.FRAME_SIZE; AudioOutput() { -/* double minbuffer = Math.max(AudioTrack - .getMinBufferSize(MumbleConnection.SAMPLE_RATE, - AudioFormat.CHANNEL_CONFIGURATION_MONO, - AudioFormat.ENCODING_PCM_16BIT), bufferSize); - Log.i("mumbleclient", "buffer size: " + minbuffer); - bufferSize = (int) (Math.ceil(minbuffer / MumbleConnection.FRAME_SIZE) * MumbleConnection.FRAME_SIZE); - Log.i("mumbleclient", "new buffer size: " + bufferSize); -*/ -/* - at = new AudioTrack(AudioManager.STREAM_MUSIC, - MumbleConnection.SAMPLE_RATE, - AudioFormat.CHANNEL_CONFIGURATION_MONO, - AudioFormat.ENCODING_PCM_16BIT, bufferSize * 20, - AudioTrack.MODE_STREAM); -*/ +// double minbuffer = Math.max(AudioTrack +// .getMinBufferSize(MumbleConnection.SAMPLE_RATE, +// AudioFormat.CHANNEL_CONFIGURATION_MONO, +// AudioFormat.ENCODING_PCM_16BIT), bufferSize); +// Log.i("mumbleclient", "buffer size: " + minbuffer); +// bufferSize = (int) (Math.ceil(minbuffer / MumbleConnection.FRAME_SIZE) * MumbleConnection.FRAME_SIZE); +// Log.i("mumbleclient", "new buffer size: " + bufferSize); + +// at = new AudioTrack(AudioManager.STREAM_MUSIC, +// MumbleConnection.SAMPLE_RATE, +// AudioFormat.CHANNEL_CONFIGURATION_MONO, +// AudioFormat.ENCODING_PCM_16BIT, bufferSize * 20, +// AudioTrack.MODE_STREAM); out = new short[bufferSize]; tmpOut = new short[bufferSize]; celtMode = Native.celt_mode_create(MumbleConnection.SAMPLE_RATE, @@ -48,7 +46,7 @@ class AudioOutput implements Runnable { } public void addFrameToBuffer(final User u, final PacketDataStream pds, - int flags) { + final int flags) { AudioUser au = outputMap.get(u); if (au == null) { au = new AudioUser(u); @@ -56,11 +54,9 @@ public void addFrameToBuffer(final User u, final PacketDataStream pds, } au.addFrameToBuffer(pds, flags); -/* - lock.lock(); - notEmpty.signal(); - lock.unlock(); -*/ +// lock.lock(); +// notEmpty.signal(); +// lock.unlock(); } @Override @@ -74,26 +70,26 @@ public void run() { // final boolean mixed = mix(bufferSize); // if (mixed) { // at.write(out, 0, bufferSize); - //at.flush(); + //at.flush(); // } else { - try { - lock.lock(); - if (outputMap.isEmpty()) { + try { + lock.lock(); + if (outputMap.isEmpty()) { // at.stop(); - notEmpty.await(); - } - } catch (final InterruptedException e) { - e.printStackTrace(); - running = false; - } finally { - lock.unlock(); -// at.play(); + notEmpty.await(); } + } catch (final InterruptedException e) { + e.printStackTrace(); + running = false; + } finally { + lock.unlock(); +// at.play(); + } // } lock.lock(); try { notEmpty.await(); - } catch (InterruptedException e) { + } catch (final InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } @@ -117,8 +113,8 @@ private boolean mix(final int nsamp) { } } - Arrays.fill(tmpOut, (short)0); - Arrays.fill(out, (short)0); + Arrays.fill(tmpOut, (short) 0); + Arrays.fill(out, (short) 0); if (!mix.isEmpty()) { for (final AudioUser au : mix) { final short[] pfBuffer = au.pfBuffer; diff --git a/src/org/pcgod/mumbleclient/service/AudioUser.java b/src/org/pcgod/mumbleclient/service/AudioUser.java index db974a47..06c8b7f5 100644 --- a/src/org/pcgod/mumbleclient/service/AudioUser.java +++ b/src/org/pcgod/mumbleclient/service/AudioUser.java @@ -21,10 +21,10 @@ class AudioUser { private int missCount; private int ucFlags = 0xFF; private boolean hasTerminator; - private short[] pOut = new short[MumbleConnection.FRAME_SIZE]; - private AudioTrack at; - private short[] out; - private int bufferSize = MumbleConnection.FRAME_SIZE; + private final short[] pOut = new short[MumbleConnection.FRAME_SIZE]; + private final AudioTrack at; + private final short[] out; + private final int bufferSize = MumbleConnection.FRAME_SIZE; private static double[] fadeIn; private static double[] fadeOut; long jitterBuffer; @@ -35,21 +35,20 @@ class AudioUser { fadeOut = new double[MumbleConnection.FRAME_SIZE]; final double mul = Math.PI / (2.0 * MumbleConnection.FRAME_SIZE); for (int i = 0; i < MumbleConnection.FRAME_SIZE; ++i) { - fadeIn[i] = fadeOut[MumbleConnection.FRAME_SIZE - i - 1] = Math.sin(i - * mul); + fadeIn[i] = fadeOut[MumbleConnection.FRAME_SIZE - i - 1] = Math + .sin(i * mul); } } AudioUser(final User u_) { u = u_; - /* - jb = new JitterBuffer(MumbleConnection.FRAME_SIZE); - jb.setMargin(50 * MumbleConnection.FRAME_SIZE); - */ +// jb = new JitterBuffer(MumbleConnection.FRAME_SIZE); +// jb.setMargin(50 * MumbleConnection.FRAME_SIZE); jitterBuffer = Native.jitter_buffer_init(MumbleConnection.FRAME_SIZE); // 0 = JITTER_BUFFER_SET_MARGIN - Native.jitter_buffer_ctl(jitterBuffer, 0, new int[] { 50 * MumbleConnection.FRAME_SIZE }); + Native.jitter_buffer_ctl(jitterBuffer, 0, + new int[] { 50 * MumbleConnection.FRAME_SIZE }); at = new AudioTrack(AudioManager.STREAM_MUSIC, MumbleConnection.SAMPLE_RATE, @@ -62,7 +61,12 @@ class AudioUser { Log.i("mc", "Create audio user for " + u_.name); } - void addFrameToBuffer(final PacketDataStream pds, int flags) { + @Override + protected final void finalize() { + Native.jitter_buffer_destroy(jitterBuffer); + } + + void addFrameToBuffer(final PacketDataStream pds, final int flags) { // skip iSeq pds.readLong(); @@ -79,36 +83,31 @@ void addFrameToBuffer(final PacketDataStream pds, int flags) { pds.skip(1); // skip uiSession pds.readLong(); - /*final long iSeq =*/ pds.readLong(); - - /* - final JitterBufferPacket jbp = new JitterBufferPacket(); - jbp.flags = flags; - jbp.data = packet; - jbp.span = MumbleConnection.FRAME_SIZE * frames; - jbp.timestamp = MumbleConnection.FRAME_SIZE * iSeq; - */ - - /* - final Native.JitterBufferPacket njbp = new Native.JitterBufferPacket(); - njbp.user_data = flags; - byte tmp[] = new byte[packet.remaining()]; - packet.get(tmp); - njbp.data = tmp; - njbp.len = tmp.length; - njbp.span = MumbleConnection.FRAME_SIZE * frames; - njbp.timestamp = MumbleConnection.FRAME_SIZE * iSeq; - */ - - byte[] tmp = new byte[256]; + /* final long iSeq = */pds.readLong(); + +// final JitterBufferPacket jbp = new JitterBufferPacket(); +// jbp.flags = flags; +// jbp.data = packet; +// jbp.span = MumbleConnection.FRAME_SIZE * frames; +// jbp.timestamp = MumbleConnection.FRAME_SIZE * iSeq; + +// final Native.JitterBufferPacket njbp = new Native.JitterBufferPacket(); +// njbp.user_data = flags; +// byte tmp[] = new byte[packet.remaining()]; +// packet.get(tmp); +// njbp.data = tmp; +// njbp.len = tmp.length; +// njbp.span = MumbleConnection.FRAME_SIZE * frames; +// njbp.timestamp = MumbleConnection.FRAME_SIZE * iSeq; + + final byte[] tmp = new byte[256]; header = 0; do { header = pds.next(); if (header > 0) { final int len = header & 0x7f; pds.dataBlock(tmp, len); - Native.celt_decode(AudioOutput.celtDecoder, tmp, - len, pOut); + Native.celt_decode(AudioOutput.celtDecoder, tmp, len, pOut); at.write(pOut, 0, MumbleConnection.FRAME_SIZE); } else { @@ -120,11 +119,9 @@ void addFrameToBuffer(final PacketDataStream pds, int flags) { // jb.put(jbp); // } - /* - synchronized (jbLock) { - Native.jitter_buffer_put(jitterBuffer, njbp); - } - */ +// synchronized (jbLock) { +// Native.jitter_buffer_put(jitterBuffer, njbp); +// } } } @@ -138,19 +135,21 @@ boolean needSamples(final int snum) { while (bufferFilled < snum) { if (!lastAlive) { - Arrays.fill(pfBuffer, bufferFilled, bufferFilled + MumbleConnection.FRAME_SIZE, (short) 0); + Arrays.fill(pfBuffer, bufferFilled, bufferFilled + + MumbleConnection.FRAME_SIZE, (short) 0); } else { final int timestamp; final int available; -/* synchronized (jb) { - timestamp = jb.getTimestamp(); - available = jb.getAvailable(); - } -*/ +// synchronized (jb) { +// timestamp = jb.getTimestamp(); +// available = jb.getAvailable(); +// } + synchronized (jbLock) { - timestamp = Native.jitter_buffer_get_pointer_timestamp(jitterBuffer); + timestamp = Native + .jitter_buffer_get_pointer_timestamp(jitterBuffer); // 3 = JITTER_BUFFER_GET_AVAILABLE_COUNT - int[] tmp = new int[1]; + final int[] tmp = new int[1]; Native.jitter_buffer_ctl(jitterBuffer, 3, tmp); available = tmp[0]; } @@ -160,7 +159,8 @@ boolean needSamples(final int snum) { if (available < want) { ++missCount; if (missCount < 20) { - Arrays.fill(pfBuffer, bufferFilled, bufferFilled + MumbleConnection.FRAME_SIZE, (short) 0); + Arrays.fill(pfBuffer, bufferFilled, bufferFilled + + MumbleConnection.FRAME_SIZE, (short) 0); bufferFilled += MumbleConnection.FRAME_SIZE; continue; } @@ -168,19 +168,18 @@ boolean needSamples(final int snum) { } if (frameList.isEmpty()) { - /* - final JitterBufferPacket jbp; - synchronized (jb) { - jbp = jb.get(MumbleConnection.FRAME_SIZE); - } - */ +// final JitterBufferPacket jbp; +// synchronized (jb) { +// jbp = jb.get(MumbleConnection.FRAME_SIZE); +// } final Native.JitterBufferPacket jbp = new Native.JitterBufferPacket(); jbp.data = new byte[1024]; jbp.len = 1024; synchronized (jbLock) { - int current_timestamp[] = new int[1]; - Native.jitter_buffer_get(jitterBuffer, jbp, MumbleConnection.FRAME_SIZE, current_timestamp); - byte[] tmp = new byte[jbp.len]; + final int current_timestamp[] = new int[1]; + Native.jitter_buffer_get(jitterBuffer, jbp, + MumbleConnection.FRAME_SIZE, current_timestamp); + final byte[] tmp = new byte[jbp.len]; System.arraycopy(jbp.data, 0, tmp, 0, tmp.length); jbp.data = tmp; } @@ -198,7 +197,7 @@ boolean needSamples(final int snum) { header = pds.next(); if (header > 0) { final int len = header & 0x7f; - byte[] tmp = new byte[len]; + final byte[] tmp = new byte[len]; pds.dataBlock(tmp, len); frameList.add(tmp); } else { @@ -229,13 +228,12 @@ boolean needSamples(final int snum) { } } } else { - /* - synchronized (jb) { - jb.updateDelay(); - } - */ +// synchronized (jb) { +// jb.updateDelay(); +// } synchronized (jbLock) { - Native.jitter_buffer_update_delay(jitterBuffer, jbp, null); + Native.jitter_buffer_update_delay(jitterBuffer, + jbp, null); } ++missCount; @@ -249,8 +247,8 @@ boolean needSamples(final int snum) { final byte[] frame = frameList.poll(); //synchronized (Native.class) { - Native.celt_decode(AudioOutput.celtDecoder, frame, - frame.length, pOut); + Native.celt_decode(AudioOutput.celtDecoder, frame, + frame.length, pOut); //} at.write(pOut, 0, MumbleConnection.FRAME_SIZE); @@ -280,13 +278,12 @@ boolean needSamples(final int snum) { // update = (pow < (fPowerMin + 0.01f * (fPowerMax - fPowerMin))); // } if (frameList.isEmpty() && update) { - /* - synchronized (jb) { - jb.updateDelay(); - } - */ +// synchronized (jb) { +// jb.updateDelay(); +// } synchronized (jbLock) { - Native.jitter_buffer_update_delay(jitterBuffer, null, null); + Native.jitter_buffer_update_delay(jitterBuffer, + null, null); } } @@ -305,11 +302,9 @@ boolean needSamples(final int snum) { // } // } - /* - synchronized (jb) { - jb.tick(); - } - */ +// synchronized (jb) { +// jb.tick(); +// } synchronized (jbLock) { Native.jitter_buffer_tick(jitterBuffer); } @@ -341,9 +336,4 @@ boolean needSamples(final int snum) { lastAlive = nextAlive; return tmp; } - - @Override - protected final void finalize() { - Native.jitter_buffer_destroy(jitterBuffer); - } } diff --git a/src/org/pcgod/mumbleclient/service/JitterBuffer.java b/src/org/pcgod/mumbleclient/service/JitterBuffer.java index eb32ad5d..7793266e 100644 --- a/src/org/pcgod/mumbleclient/service/JitterBuffer.java +++ b/src/org/pcgod/mumbleclient/service/JitterBuffer.java @@ -6,7 +6,7 @@ private class TimingBuffer { int curr_count; int[] timing = new int[MAX_TIMINGS]; short[] counts = new short[MAX_TIMINGS]; - + public void add(final short timing_) { if (filled >= MAX_TIMINGS && timing_ >= timing[filled - 1]) { curr_count++; @@ -51,17 +51,17 @@ public void add(final short timing_) { private int buffered; /** Packets stored in the buffer */ - private JitterBufferPacket[] packets = new JitterBufferPacket[JITTER_MAX_BUFFER_SIZE]; + private final JitterBufferPacket[] packets = new JitterBufferPacket[JITTER_MAX_BUFFER_SIZE]; /** * Packet arrival time (0 means it was late, even though it's a valid * timestamp) */ - private int[] arrival = new int[JITTER_MAX_BUFFER_SIZE]; + private final int[] arrival = new int[JITTER_MAX_BUFFER_SIZE]; /** Size of the steps when adjusting buffering (timestamp units) */ - private int delay_step; + private final int delay_step; /** Size of the packet loss concealment "units" */ - private int concealment_size; + private final int concealment_size; /** True if state was just reset */ private boolean reset_state; /** How many frames we want to keep in the buffer (lower bound) */ @@ -100,8 +100,8 @@ public JitterBufferPacket get(final int desired_span) { boolean found = false; int oldest = 0; for (int i = 0; i < JITTER_MAX_BUFFER_SIZE; ++i) { - if (packets[i] != null - && (!found || packets[i].timestamp < oldest)) { + if (packets[i] != null && + (!found || packets[i].timestamp < oldest)) { oldest = packets[i].timestamp; found = true; } @@ -128,20 +128,20 @@ public JitterBufferPacket get(final int desired_span) { int i; for (i = 0; i < JITTER_MAX_BUFFER_SIZE; ++i) { - if (packets[i] != null - && packets[i].timestamp == timestamp - && packets[i].timestamp + packets[i].span >= timestamp - + desired_span) { + if (packets[i] != null && + packets[i].timestamp == timestamp && + packets[i].timestamp + packets[i].span >= timestamp + + desired_span) { break; } } if (i == JITTER_MAX_BUFFER_SIZE) { for (i = 0; i < JITTER_MAX_BUFFER_SIZE; ++i) { - if (packets[i] != null - && packets[i].timestamp <= timestamp - && packets[i].timestamp + packets[i].span >= timestamp - + desired_span) { + if (packets[i] != null && + packets[i].timestamp <= timestamp && + packets[i].timestamp + packets[i].span >= timestamp + + desired_span) { break; } } @@ -149,8 +149,8 @@ public JitterBufferPacket get(final int desired_span) { if (i == JITTER_MAX_BUFFER_SIZE) { for (i = 0; i < JITTER_MAX_BUFFER_SIZE; ++i) { - if (packets[i] != null && packets[i].timestamp <= timestamp - && packets[i].timestamp + packets[i].span > timestamp) { + if (packets[i] != null && packets[i].timestamp <= timestamp && + packets[i].timestamp + packets[i].span > timestamp) { break; } } @@ -162,12 +162,12 @@ public JitterBufferPacket get(final int desired_span) { int best_span = 0; int besti = 0; for (i = 0; i < JITTER_MAX_BUFFER_SIZE; ++i) { - if (packets[i] != null - && packets[i].timestamp < timestamp + desired_span - && packets[i].timestamp >= timestamp) { - if (!found - || packets[i].timestamp < best_time - || (packets[i].timestamp == best_time && packets[i].span > best_span)) { + if (packets[i] != null && + packets[i].timestamp < timestamp + desired_span && + packets[i].timestamp >= timestamp) { + if (!found || + packets[i].timestamp < best_time || + (packets[i].timestamp == best_time && packets[i].span > best_span)) { best_time = packets[i].timestamp; best_span = packets[i].span; besti = i; @@ -206,7 +206,8 @@ public JitterBufferPacket get(final int desired_span) { // Log.i("mumble.jb", // "JITTER_BUFFER_INSERTION - Forced to interpolate"); } else { - final int tmp_desired_span = Math.min(desired_span, concealment_size); + final int tmp_desired_span = Math.min(desired_span, + concealment_size); timestamp += tmp_desired_span; buffered = tmp_desired_span - tmp_desired_span; // Log.i("mumble.jb", "JITTER_BUFFER_MISSING - Normal loss"); @@ -233,8 +234,8 @@ public void put(final JitterBufferPacket packet) { if (!reset_state) { for (int i = 0; i < JITTER_MAX_BUFFER_SIZE; ++i) { - if (packets[i] != null - && packets[i].timestamp + packets[i].span <= timestamp) { + if (packets[i] != null && + packets[i].timestamp + packets[i].span <= timestamp) { packets[i] = null; } } @@ -249,8 +250,8 @@ public void put(final JitterBufferPacket packet) { reset(); } - if (reset_state - || packet.timestamp + packet.span + delay_step >= timestamp) { + if (reset_state || + packet.timestamp + packet.span + delay_step >= timestamp) { int i; for (i = 0; i < JITTER_MAX_BUFFER_SIZE; ++i) { if (packets[i] == null) { @@ -296,8 +297,8 @@ public void reset() { timeBuffers[i] = new TimingBuffer(); } } - - public void setMargin(int margin) { + + public void setMargin(final int margin) { buffer_margin = margin; } @@ -370,8 +371,8 @@ private short computeOptimalDelay() { int next = -1; int latest = 32767; for (int j = 0; j < MAX_BUFFERS; ++j) { - if (pos[j] < timeBuffers[j].filled - && timeBuffers[j].timing[pos[j]] < latest) { + if (pos[j] < timeBuffers[j].filled && + timeBuffers[j].timing[pos[j]] < latest) { next = j; latest = timeBuffers[j].timing[pos[j]]; } diff --git a/src/org/pcgod/mumbleclient/service/MumbleConnection.java b/src/org/pcgod/mumbleclient/service/MumbleConnection.java index 462baa03..d59dd228 100644 --- a/src/org/pcgod/mumbleclient/service/MumbleConnection.java +++ b/src/org/pcgod/mumbleclient/service/MumbleConnection.java @@ -43,7 +43,6 @@ * communication protocol * * @author pcgod - * */ public class MumbleConnection implements Runnable { public enum MessageType { @@ -62,13 +61,14 @@ public enum MessageType { public static final int SAMPLE_RATE = 48000; public static final int FRAME_SIZE = SAMPLE_RATE / 100; - private static final MessageType[] MT_CONSTANTS = MessageType.class.getEnumConstants(); + private static final MessageType[] MT_CONSTANTS = MessageType.class + .getEnumConstants(); - private static final int protocolVersion = (1 << 16) | (2 << 8) - | (3 & 0xFF); + private static final int protocolVersion = (1 << 16) | (2 << 8) | + (3 & 0xFF); private static final int supportedCodec = 0x8000000b; - + public Map channels = new HashMap(); public Map users = new HashMap(); public Channel currentChannel = null; @@ -90,11 +90,11 @@ public enum MessageType { private AudioOutput ao; private Thread audioOutputThread; private Thread readingThread; - private Object stateLock = new Object(); + private final Object stateLock = new Object(); public MumbleConnection(final MumbleConnectionHost connectionHost_, - final String host_, final int port_, - final String username_, final String password_) { + final String host_, final int port_, final String username_, + final String password_) { connectionHost = connectionHost_; host = host_; port = port_; @@ -104,10 +104,27 @@ public MumbleConnection(final MumbleConnectionHost connectionHost_, connectionHost.setConnectionState(ConnectionState.Disconnected); } + public final void disconnect() { + synchronized (stateLock) { + if (readingThread != null) { + readingThread.interrupt(); + readingThread = null; + } + + disconnecting = true; + connectionHost.setConnectionState(ConnectionState.Disconnecting); + stateLock.notifyAll(); + } + } + + public final boolean isConnectionAlive() { + return !disconnecting; + } + public final boolean isSameServer(final String host_, final int port_, final String username_, final String password_) { - return host.equals(host_) && port == port_ - && username.equals(username_) && password.equals(password_); + return host.equals(host_) && port == port_ && + username.equals(username_) && password.equals(password_); } public final void joinChannel(final int channelId) { @@ -128,13 +145,15 @@ public final void run() { try { SSLSocket socket_; - synchronized(stateLock) { + synchronized (stateLock) { final SSLContext ctx_ = SSLContext.getInstance("TLS"); - ctx_.init(null, new TrustManager[] { new LocalSSLTrustManager() }, - null); + ctx_ + .init( + null, + new TrustManager[] { new LocalSSLTrustManager() }, + null); final SSLSocketFactory factory = ctx_.getSocketFactory(); - socket_ = (SSLSocket) factory.createSocket(host, - port); + socket_ = (SSLSocket) factory.createSocket(host, port); socket_.setUseClientMode(true); socket_.setEnabledProtocols(new String[] { "TLSv1" }); socket_.startHandshake(); @@ -153,11 +172,11 @@ public final void run() { e.printStackTrace(); } catch (final IOException e) { e.printStackTrace(); - } catch (InterruptedException e) { + } catch (final InterruptedException e) { e.printStackTrace(); } - synchronized(stateLock) { + synchronized (stateLock) { connectionHost.setConnectionState(ConnectionState.Disconnected); } } @@ -172,7 +191,7 @@ public final void sendChannelTextMessage(final String message) { e.printStackTrace(); } - Message msg = new Message(); + final Message msg = new Message(); msg.timestamp = System.currentTimeMillis(); msg.message = message; msg.channel = currentChannel; @@ -209,23 +228,6 @@ public final void sendUdpTunnelMessage(final byte[] buffer) } } - public final void disconnect() { - synchronized (stateLock) { - if (readingThread != null) { - readingThread.interrupt(); - readingThread = null; - } - - disconnecting = true; - connectionHost.setConnectionState(ConnectionState.Disconnecting); - stateLock.notifyAll(); - } - } - - public final boolean isConnectionAlive() { - return !disconnecting; - } - private Channel findChannel(final int id) { return channels.get(id); } @@ -234,10 +236,12 @@ private User findUser(final int session_) { return users.get(session_); } - private void handleProtocol(final Socket socket_) throws IOException, InterruptedException { + private void handleProtocol(final Socket socket_) throws IOException, + InterruptedException { synchronized (stateLock) { - if (disconnecting) + if (disconnecting) { return; + } out = new DataOutputStream(socket_.getOutputStream()); in = new DataInputStream(socket_.getInputStream()); @@ -278,15 +282,16 @@ public void run() { // Message processing can be done inside stateLock as it shouldn't involve // slow network operations. - synchronized(stateLock) { + synchronized (stateLock) { processMsg(MT_CONSTANTS[type], msg); } } - } catch (IOException ex) { + } catch (final IOException ex) { Log.e(Globals.LOG_TAG, ex.toString()); } finally { - synchronized(stateLock) { - connectionHost.setConnectionState(ConnectionState.Disconnecting); + synchronized (stateLock) { + connectionHost + .setConnectionState(ConnectionState.Disconnecting); disconnecting = true; // The thread is dying so null it. This prevents the waiting loop from @@ -314,7 +319,7 @@ private void handleTextMessage(final TextMessage ts) { u = findUser(ts.getActor()); } - Message msg = new Message(); + final Message msg = new Message(); msg.timestamp = System.currentTimeMillis(); msg.message = ts.getMessage(); msg.actor = u; @@ -347,7 +352,7 @@ private void processMsg(final MessageType t, final byte[] buffer) Channel channel; User user; - + switch (t) { case UDPTunnel: processVoicePacket(buffer); @@ -358,9 +363,11 @@ private void processMsg(final MessageType t, final byte[] buffer) case CodecVersion: final CodecVersion codecVersion = CodecVersion.parseFrom(buffer); codec = CODEC_NOCODEC; - if (codecVersion.hasAlpha() && codecVersion.getAlpha() == supportedCodec) { + if (codecVersion.hasAlpha() && + codecVersion.getAlpha() == supportedCodec) { codec = CODEC_ALPHA; - } else if (codecVersion.hasBeta() && codecVersion.getBeta() == supportedCodec) { + } else if (codecVersion.hasBeta() && + codecVersion.getBeta() == supportedCodec) { codec = CODEC_BETA; } canSpeak = canSpeak && (codec != CODEC_NOCODEC); @@ -415,25 +422,27 @@ private void processMsg(final MessageType t, final byte[] buffer) break; case UserState: final UserState us = UserState.parseFrom(buffer); - User u = findUser(us.getSession()); - if (u != null) { + user = findUser(us.getSession()); + if (user != null) { if (us.hasChannelId()) { - Channel c = channels.get(us.getChannelId()); - u.setChannel(c); + channel = channels.get(us.getChannelId()); + user.setChannel(channel); if (us.getSession() == session) { - currentChannel = c; + currentChannel = channel; connectionHost.currentChannelChanged(); } - connectionHost.channelUpdated(c); + connectionHost.channelUpdated(channel); } if (us.getSession() == session) { if (us.hasMute() || us.hasSuppress()) { if (us.hasMute()) { - canSpeak = (codec != CODEC_NOCODEC) && !us.getMute(); + canSpeak = (codec != CODEC_NOCODEC) && + !us.getMute(); } if (us.hasSuppress()) { - canSpeak = (codec != CODEC_NOCODEC) && !us.getSuppress(); + canSpeak = (codec != CODEC_NOCODEC) && + !us.getSuppress(); } } } @@ -442,14 +451,14 @@ private void processMsg(final MessageType t, final byte[] buffer) break; } // New user - u = new User(); - u.session = us.getSession(); - u.name = us.getName(); - u.setChannel(channels.get(us.getChannelId())); - users.put(u.session, u); - - connectionHost.userAdded(u); - connectionHost.channelUpdated(u.getChannel()); + user = new User(); + user.session = us.getSession(); + user.name = us.getName(); + user.setChannel(channels.get(us.getChannelId())); + users.put(user.session, user); + + connectionHost.userAdded(user); + connectionHost.channelUpdated(user.getChannel()); break; case UserRemove: final UserRemove ur = UserRemove.parseFrom(buffer); @@ -478,7 +487,8 @@ private void processVoicePacket(final byte[] buffer) { final int flags = buffer[0] & 0x1f; // There is no speex support... - if (type != UDPMESSAGETYPE_UDPVOICECELTALPHA && type != UDPMESSAGETYPE_UDPVOICECELTBETA) { + if (type != UDPMESSAGETYPE_UDPVOICECELTALPHA && + type != UDPMESSAGETYPE_UDPVOICECELTBETA) { return; } diff --git a/src/org/pcgod/mumbleclient/service/MumbleConnectionHost.java b/src/org/pcgod/mumbleclient/service/MumbleConnectionHost.java index c4854dbb..d25fb1d6 100644 --- a/src/org/pcgod/mumbleclient/service/MumbleConnectionHost.java +++ b/src/org/pcgod/mumbleclient/service/MumbleConnectionHost.java @@ -9,18 +9,23 @@ public enum ConnectionState { Disconnected, Connecting, Connected, Disconnecting } - public void setConnectionState(ConnectionState state); + public void channelAdded(Channel channel); + + public void channelRemoved(int channelId); + + public void channelUpdated(Channel channel); + + public void currentChannelChanged(); public void messageReceived(Message msg); + public void messageSent(Message msg); - public void channelAdded(Channel channel); - public void channelUpdated(Channel channel); - public void channelRemoved(int channelId); + public void setConnectionState(ConnectionState state); public void userAdded(User user); - public void userUpdated(User user); + public void userRemoved(int userId); - public void currentChannelChanged(); + public void userUpdated(User user); } diff --git a/src/org/pcgod/mumbleclient/service/MumbleService.java b/src/org/pcgod/mumbleclient/service/MumbleService.java index 982b43cc..5489575d 100644 --- a/src/org/pcgod/mumbleclient/service/MumbleService.java +++ b/src/org/pcgod/mumbleclient/service/MumbleService.java @@ -35,31 +35,29 @@ * it for binding activities. * * @author wace - * */ public class MumbleService extends Service { + public class LocalBinder extends Binder { + public MumbleService getService() { + return MumbleService.this; + } + } public static final String ACTION_CONNECT = "mumbleclient.action.CONNECT"; - public static final String INTENT_CHANNEL_LIST_UPDATE = "mumbleclient.intent.CHANNEL_LIST_UPDATE"; public static final String INTENT_CURRENT_CHANNEL_CHANGED = "mumbleclient.intent.CURRENT_CHANNEL_CHANGED"; public static final String INTENT_USER_LIST_UPDATE = "mumbleclient.intent.USER_LIST_UPDATE"; public static final String INTENT_CHAT_TEXT_UPDATE = "mumbleclient.intent.CHAT_TEXT_UPDATE"; - public static final String INTENT_CONNECTION_STATE_CHANGED = "mumbleclient.intent.CONNECTION_STATE_CHANGED"; + public static final String INTENT_CONNECTION_STATE_CHANGED = "mumbleclient.intent.CONNECTION_STATE_CHANGED"; public static final String EXTRA_MESSAGE = "mumbleclient.extra.MESSAGE"; - public static final String EXTRA_CONNECTION_STATE = "mumbleclient.extra.CONNECTION_STATE"; + public static final String EXTRA_CONNECTION_STATE = "mumbleclient.extra.CONNECTION_STATE"; public static final String EXTRA_HOST = "mumbleclient.extra.HOST"; public static final String EXTRA_PORT = "mumbleclient.extra.PORT"; public static final String EXTRA_USERNAME = "mumbleclient.extra.USERNAME"; - public static final String EXTRA_PASSWORD = "mumbleclient.extra.PASSWORD"; - public class LocalBinder extends Binder { - public MumbleService getService() { - return MumbleService.this; - } - } + public static final String EXTRA_PASSWORD = "mumbleclient.extra.PASSWORD"; private MumbleConnection mClient; private Thread mClientThread; @@ -68,64 +66,7 @@ public MumbleService getService() { private Notification mNotification; private boolean mHasConnections; - private MumbleConnectionHost connectionHost = new MumbleConnectionHost() { - - public void currentChannelChanged() { - sendBroadcast(INTENT_CURRENT_CHANNEL_CHANGED); - } - - public void messageReceived(Message msg) { - messages.add(msg); - Bundle b = new Bundle(); - b.putSerializable(EXTRA_MESSAGE, msg); - sendBroadcast(INTENT_CHAT_TEXT_UPDATE, b); - } - - public void messageSent(Message msg) { - messages.add(msg); - Bundle b = new Bundle(); - b.putSerializable(EXTRA_MESSAGE, msg); - sendBroadcast(INTENT_CHAT_TEXT_UPDATE, b); - } - - public void setConnectionState(ConnectionState state) { - if (MumbleService.this.state == state) - return; - - MumbleService.this.state = state; - Bundle b = new Bundle(); - b.putSerializable(EXTRA_CONNECTION_STATE, state); - sendBroadcast(INTENT_CONNECTION_STATE_CHANGED); - - Log.i(Globals.LOG_TAG, "MumbleService: Connection state changed to " + state.toString()); - - // Handle foreground stuff - if (state == ConnectionState.Connected) { - mNotification = new Notification(R.drawable.icon, "Mumble connected", System.currentTimeMillis()); - - Intent channelListIntent = new Intent(MumbleService.this, ChannelList.class ); - channelListIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mNotification.setLatestEventInfo(MumbleService.this, "Mumble", "Mumble is connected to a server", - PendingIntent.getActivity(MumbleService.this, 0, channelListIntent, 0)); - startForegroundCompat(1, mNotification); - } else if (state == ConnectionState.Disconnected) { - if (mNotification != null) { - stopForegroundCompat(1); - mNotification = null; - } - - // Clear the user and channel collections. - users.clear(); - channels.clear(); - } - - // If the connection was disconnected and there are no bound - // connections to this service, finish it. - if (state == ConnectionState.Disconnected && !mHasConnections) { - Log.i(Globals.LOG_TAG, "MumbleService: Service disconnected while there are no connections up."); - stopSelf(); - } - } + private final MumbleConnectionHost connectionHost = new MumbleConnectionHost() { @Override public void channelAdded(final Channel channel) { @@ -170,6 +111,73 @@ public void run() { }); } + public void currentChannelChanged() { + sendBroadcast(INTENT_CURRENT_CHANNEL_CHANGED); + } + + public void messageReceived(final Message msg) { + messages.add(msg); + final Bundle b = new Bundle(); + b.putSerializable(EXTRA_MESSAGE, msg); + sendBroadcast(INTENT_CHAT_TEXT_UPDATE, b); + } + + public void messageSent(final Message msg) { + messages.add(msg); + final Bundle b = new Bundle(); + b.putSerializable(EXTRA_MESSAGE, msg); + sendBroadcast(INTENT_CHAT_TEXT_UPDATE, b); + } + + public void setConnectionState(final ConnectionState state) { + if (MumbleService.this.state == state) { + return; + } + + MumbleService.this.state = state; + final Bundle b = new Bundle(); + b.putSerializable(EXTRA_CONNECTION_STATE, state); + sendBroadcast(INTENT_CONNECTION_STATE_CHANGED); + + Log.i(Globals.LOG_TAG, + "MumbleService: Connection state changed to " + + state.toString()); + + // Handle foreground stuff + if (state == ConnectionState.Connected) { + mNotification = new Notification(R.drawable.icon, + "Mumble connected", System.currentTimeMillis()); + + final Intent channelListIntent = new Intent(MumbleService.this, + ChannelList.class); + channelListIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mNotification.setLatestEventInfo(MumbleService.this, "Mumble", + "Mumble is connected to a server", PendingIntent + .getActivity(MumbleService.this, 0, + channelListIntent, 0)); + startForegroundCompat(1, mNotification); + } else if (state == ConnectionState.Disconnected) { + if (mNotification != null) { + stopForegroundCompat(1); + mNotification = null; + } + + // Clear the user and channel collections. + users.clear(); + channels.clear(); + } + + // If the connection was disconnected and there are no bound + // connections to this service, finish it. + if (state == ConnectionState.Disconnected && !mHasConnections) { + Log + .i(Globals.LOG_TAG, + "MumbleService: Service disconnected while there are no connections up."); + stopSelf(); + } + } + @Override public void userAdded(final User user) { handler.post(new Runnable() { @@ -222,57 +230,65 @@ public void run() { private final List channels = new ArrayList(); private final List users = new ArrayList(); - @Override - public void onCreate() { - super.onCreate(); + private static final Class[] mStartForegroundSignature = new Class[] { + int.class, Notification.class }; - try { - mStartForeground = getClass().getMethod("startForeground", - mStartForegroundSignature); - mStopForeground = getClass().getMethod("stopForeground", - mStopForegroundSignature); - } catch (NoSuchMethodException e) { - // Running on an older platform. - mStartForeground = mStopForeground = null; - } + private static final Class[] mStopForegroundSignature = new Class[] { boolean.class }; - Log.i(Globals.LOG_TAG, "MumbleService: Created"); - state = ConnectionState.Disconnected; - } + private Method mStartForeground; - @Override - public void onDestroy() { - super.onDestroy(); + private Method mStopForeground; - // Make sure our notification is gone. - stopForegroundCompat(1); + private final Object[] mStartForegroundArgs = new Object[2]; - Log.i(Globals.LOG_TAG, "MumbleService: Destroyed"); + private final Object[] mStopForegroundArgs = new Object[1]; + + public boolean canSpeak() { + return mClient.canSpeak; } - @Override - public IBinder onBind(Intent intent) { - mHasConnections = true; + public void disconnect() { + assertConnected(); - Log.i(Globals.LOG_TAG, "MumbleService: Bound"); - return mBinder; + mClient.disconnect(); } - @Override - public boolean onUnbind(Intent intent) { - mHasConnections = false; + public List getChannelList() { + assertConnected(); - Log.i(Globals.LOG_TAG, "MumbleService: Unbound"); + return Collections.unmodifiableList(channels); + } - if (state == ConnectionState.Disconnected) { - stopSelf(); - Log.i(Globals.LOG_TAG, "MumbleService: No clients bound and connection is not alive -> Stopping"); + public int getCodec() { + if (mClient.codec == MumbleConnection.CODEC_NOCODEC) { + throw new IllegalStateException( + "Called getCodec on a connection with unsupported codec"); } - return false; + return mClient.codec; + } + + public ConnectionState getConnectionState() { + return state; + } + + public Channel getCurrentChannel() { + assertConnected(); + + return mClient.currentChannel; + } + + public List getMessageList() { + return Collections.unmodifiableList(messages); + } + + public List getUserList() { + assertConnected(); + + return Collections.unmodifiableList(users); } - public int handleCommand(Intent intent) { + public int handleCommand(final Intent intent) { // When using START_STICKY the onStartCommand can be called with // null intent after the whole service process has been killed. // Such scenario doesn't make sense for the service process so @@ -281,13 +297,14 @@ public int handleCommand(Intent intent) { // Leaving the null check in though just in case. // // TODO: Figure out the correct start type. - if (intent == null) + if (intent == null) { return START_NOT_STICKY; + } - String host = intent.getStringExtra(EXTRA_HOST); - int port = intent.getIntExtra(EXTRA_PORT, -1); - String username = intent.getStringExtra(EXTRA_USERNAME); - String password = intent.getStringExtra(EXTRA_PASSWORD); + final String host = intent.getStringExtra(EXTRA_HOST); + final int port = intent.getIntExtra(EXTRA_PORT, -1); + final String username = intent.getStringExtra(EXTRA_USERNAME); + final String password = intent.getStringExtra(EXTRA_PASSWORD); if (mClient != null && mClient.isSameServer(host, port, username, password) && @@ -295,95 +312,110 @@ public int handleCommand(Intent intent) { return START_NOT_STICKY; } - if (mClientThread != null) + if (mClientThread != null) { mClientThread.interrupt(); + } - mClient = new MumbleConnection(connectionHost, host, port, username, password); + mClient = new MumbleConnection(connectionHost, host, port, username, + password); mClientThread = new Thread(mClient, "net"); mClientThread.start(); return START_NOT_STICKY; } - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - return handleCommand(intent); - } - - @Override - public void onStart(Intent intent, int startId) { - handleCommand(intent); - } - public boolean isConnected() { return state == ConnectionState.Connected; } - public ConnectionState getConnectionState() { - return state; + public boolean isRecording() { + return (mRecordThread != null); } - public void disconnect() { + public void joinChannel(final int channelId) { assertConnected(); - mClient.disconnect(); + mClient.joinChannel(channelId); } - public Channel getCurrentChannel() { - assertConnected(); + @Override + public IBinder onBind(final Intent intent) { + mHasConnections = true; - return mClient.currentChannel; + Log.i(Globals.LOG_TAG, "MumbleService: Bound"); + return mBinder; } - public void joinChannel(int channelId) { - assertConnected(); + @Override + public void onCreate() { + super.onCreate(); - mClient.joinChannel(channelId); - } + try { + mStartForeground = getClass().getMethod("startForeground", + mStartForegroundSignature); + mStopForeground = getClass().getMethod("stopForeground", + mStopForegroundSignature); + } catch (final NoSuchMethodException e) { + // Running on an older platform. + mStartForeground = mStopForeground = null; + } - public boolean canSpeak() { - return mClient.canSpeak; + Log.i(Globals.LOG_TAG, "MumbleService: Created"); + state = ConnectionState.Disconnected; } - public List getUserList() { - assertConnected(); + @Override + public void onDestroy() { + super.onDestroy(); - return Collections.unmodifiableList(users); - } + // Make sure our notification is gone. + stopForegroundCompat(1); - public List getChannelList() { - assertConnected(); + Log.i(Globals.LOG_TAG, "MumbleService: Destroyed"); + } - return Collections.unmodifiableList(channels); + @Override + public void onStart(final Intent intent, final int startId) { + handleCommand(intent); } - public List getMessageList() { - return Collections.unmodifiableList(messages); + @Override + public int onStartCommand(final Intent intent, final int flags, + final int startId) { + return handleCommand(intent); } - public int getCodec() { - if (mClient.codec == MumbleConnection.CODEC_NOCODEC) - throw new IllegalStateException("Called getCodec on a connection with unsupported codec"); + @Override + public boolean onUnbind(final Intent intent) { + mHasConnections = false; - return mClient.codec; - } + Log.i(Globals.LOG_TAG, "MumbleService: Unbound"); - public void sendUdpTunnelMessage(byte[] buffer) throws IOException { - assertConnected(); + if (state == ConnectionState.Disconnected) { + stopSelf(); + Log + .i(Globals.LOG_TAG, + "MumbleService: No clients bound and connection is not alive -> Stopping"); + } - mClient.sendUdpTunnelMessage(buffer); + return false; } - public void sendChannelTextMessage(String message) { + // ----------------------------------------------------------------------- + // StartForeground API Wrapper + + public void sendChannelTextMessage(final String message) { assertConnected(); mClient.sendChannelTextMessage(message); } - public boolean isRecording() { - return (mRecordThread != null); + public void sendUdpTunnelMessage(final byte[] buffer) throws IOException { + assertConnected(); + + mClient.sendUdpTunnelMessage(buffer); } - public void setRecording(boolean state) { + public void setRecording(final boolean state) { assertConnected(); if (mRecordThread == null && state) { @@ -399,50 +431,40 @@ public void setRecording(boolean state) { } private void assertConnected() { - if (!isConnected()) + if (!isConnected()) { throw new IllegalStateException("Service is not connected"); + } } private void sendBroadcast(final String action) { sendBroadcast(action, null); } - private void sendBroadcast(final String action, Bundle extras) { + private void sendBroadcast(final String action, final Bundle extras) { final Intent i = new Intent(action); - if (extras != null) + if (extras != null) { i.putExtras(extras); + } sendBroadcast(i); } - // ----------------------------------------------------------------------- - // StartForeground API Wrapper - - private static final Class[] mStartForegroundSignature = new Class[] { - int.class, Notification.class }; - private static final Class[] mStopForegroundSignature = new Class[] { boolean.class }; - - private Method mStartForeground; - private Method mStopForeground; - private Object[] mStartForegroundArgs = new Object[2]; - private Object[] mStopForegroundArgs = new Object[1]; - /** * This is a wrapper around the new startForeground method, using the older * APIs if it is not available. */ - void startForegroundCompat(int id, Notification notification) { + void startForegroundCompat(final int id, final Notification notification) { // If we have the new startForeground API, then use it. if (mStartForeground != null) { mStartForegroundArgs[0] = Integer.valueOf(id); mStartForegroundArgs[1] = notification; try { mStartForeground.invoke(this, mStartForegroundArgs); - } catch (InvocationTargetException e) { + } catch (final InvocationTargetException e) { // Should not happen. Log.w(Globals.LOG_TAG, "Unable to invoke startForeground", e); - } catch (IllegalAccessException e) { + } catch (final IllegalAccessException e) { // Should not happen. Log.w(Globals.LOG_TAG, "Unable to invoke startForeground", e); } @@ -451,23 +473,24 @@ void startForegroundCompat(int id, Notification notification) { // Fall back on the old API. setForeground(true); - ((NotificationManager)getSystemService(NOTIFICATION_SERVICE)).notify(id, notification); + ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).notify( + id, notification); } /** * This is a wrapper around the new stopForeground method, using the older * APIs if it is not available. */ - void stopForegroundCompat(int id) { + void stopForegroundCompat(final int id) { // If we have the new stopForeground API, then use it. if (mStopForeground != null) { mStopForegroundArgs[0] = Boolean.TRUE; try { mStopForeground.invoke(this, mStopForegroundArgs); - } catch (InvocationTargetException e) { + } catch (final InvocationTargetException e) { // Should not happen. Log.w(Globals.LOG_TAG, "Unable to invoke stopForeground", e); - } catch (IllegalAccessException e) { + } catch (final IllegalAccessException e) { // Should not happen. Log.w(Globals.LOG_TAG, "Unable to invoke stopForeground", e); } @@ -476,7 +499,8 @@ void stopForegroundCompat(int id) { // Fall back on the old API. Note to cancel BEFORE changing the // foreground state, since we could be killed at that point. - ((NotificationManager)getSystemService(NOTIFICATION_SERVICE)).cancel(id); + ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)) + .cancel(id); setForeground(false); } } diff --git a/src/org/pcgod/mumbleclient/service/MumbleServiceConnection.java b/src/org/pcgod/mumbleclient/service/MumbleServiceConnection.java index cb249864..85b7f355 100644 --- a/src/org/pcgod/mumbleclient/service/MumbleServiceConnection.java +++ b/src/org/pcgod/mumbleclient/service/MumbleServiceConnection.java @@ -8,14 +8,14 @@ import android.os.IBinder; public class MumbleServiceConnection { - ServiceConnection mServiceConn = new ServiceConnection() { - public void onServiceDisconnected(ComponentName arg0) { - mService = null; + public void onServiceConnected(final ComponentName className, + final IBinder binder) { + mService = ((MumbleService.LocalBinder) binder).getService(); } - public void onServiceConnected(ComponentName className, IBinder binder) { - mService = ((MumbleService.LocalBinder)binder).getService(); + public void onServiceDisconnected(final ComponentName arg0) { + mService = null; } }; protected MumbleService mService; @@ -28,7 +28,7 @@ public MumbleServiceConnection(final Context ctx) { public void bind() { Assert.assertNull(mService); - Intent intent = new Intent(ctx, MumbleService.class); + final Intent intent = new Intent(ctx, MumbleService.class); ctx.bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE); } diff --git a/src/org/pcgod/mumbleclient/service/PacketDataStream.java b/src/org/pcgod/mumbleclient/service/PacketDataStream.java index ec026136..eac691b5 100644 --- a/src/org/pcgod/mumbleclient/service/PacketDataStream.java +++ b/src/org/pcgod/mumbleclient/service/PacketDataStream.java @@ -30,6 +30,20 @@ public final void append(final byte[] d) { } } + public void append(final ByteBuffer tmp) { + final int len = tmp.limit(); + if (left() >= len) { + for (int i = 0; i < len; ++i) { + data.put(tmp.get(i)); + } + } else { + final int l = left(); + data.put(null, 0, l); + overshoot += len - l; + ok = false; + } + } + public final void append(final long v) { if (data.position() < data.capacity()) { data.put((byte) v); @@ -67,20 +81,6 @@ public void append(final ShortBuffer tmp) { } } - public void append(final ByteBuffer tmp) { - final int len = tmp.limit(); - if (left() >= len) { - for (int i = 0; i < len; ++i) { - data.put(tmp.get(i)); - } - } else { - final int l = left(); - data.put(null, 0, l); - overshoot += len - l; - ok = false; - } - } - public final int capacity() { return data.capacity(); } @@ -94,7 +94,7 @@ public final boolean dataBlock(final byte[] buffer, final int len) { return false; } } - + public final boolean isValid() { return ok; } @@ -124,8 +124,8 @@ public final double readDouble() { return 0; } - final long i = next() | next() << 8 | next() << 16 | next() << 24 - | next() << 32 | next() << 40 | next() << 48 | next() << 56; + final long i = next() | next() << 8 | next() << 16 | next() << 24 | + next() << 32 | next() << 40 | next() << 48 | next() << 56; return i; } @@ -154,8 +154,8 @@ public final long readLong() { i = next() << 24 | next() << 16 | next() << 8 | next(); break; case 0xF4: - i = next() << 56 | next() << 48 | next() << 40 | next() << 32 - | next() << 24 | next() << 16 | next() << 8 | next(); + i = next() << 56 | next() << 48 | next() << 40 | next() << 32 | + next() << 24 | next() << 16 | next() << 8 | next(); break; case 0xF8: i = readLong(); diff --git a/src/org/pcgod/mumbleclient/service/model/Channel.java b/src/org/pcgod/mumbleclient/service/model/Channel.java index 75637a25..0129991a 100644 --- a/src/org/pcgod/mumbleclient/service/model/Channel.java +++ b/src/org/pcgod/mumbleclient/service/model/Channel.java @@ -11,7 +11,6 @@ public class Channel implements Serializable { /** * Value signaling whether this channel has just been removed. - * * Once this value is set the connection signals one last update for the * channel which should result in the channel being removed from all the * caches where it might be stored. @@ -33,7 +32,7 @@ public final int hashCode() { @Override public final String toString() { - return "Channel [id=" + id + ", name=" + name + ", userCount=" - + userCount + "]"; + return "Channel [id=" + id + ", name=" + name + ", userCount=" + + userCount + "]"; } } diff --git a/src/org/pcgod/mumbleclient/service/model/Message.java b/src/org/pcgod/mumbleclient/service/model/Message.java index 8a3e9e6f..d5dde72c 100644 --- a/src/org/pcgod/mumbleclient/service/model/Message.java +++ b/src/org/pcgod/mumbleclient/service/model/Message.java @@ -3,11 +3,12 @@ import java.io.Serializable; public class Message implements Serializable { + public enum Direction { + Sent, Received + } private static final long serialVersionUID = 1L; - public enum Direction { Sent, Received } - public String message; public String sender; public User actor; diff --git a/src/org/pcgod/mumbleclient/service/model/User.java b/src/org/pcgod/mumbleclient/service/model/User.java index 2921f864..8367b432 100644 --- a/src/org/pcgod/mumbleclient/service/model/User.java +++ b/src/org/pcgod/mumbleclient/service/model/User.java @@ -19,6 +19,23 @@ public class User implements Serializable { private Channel channel; + @Override + public final boolean equals(final Object o) { + if (!(o instanceof User)) { + return false; + } + return session == ((User) o).session; + } + + public final Channel getChannel() { + return this.channel; + } + + @Override + public final int hashCode() { + return session; + } + public void setChannel(final Channel newChannel) { // Moving user to another channel? // If so, remove the user from the original first. @@ -33,26 +50,9 @@ public void setChannel(final Channel newChannel) { this.channel.userCount++; } - public final Channel getChannel() { - return this.channel; - } - - @Override - public final boolean equals(final Object o) { - if (!(o instanceof User)) { - return false; - } - return session == ((User) o).session; - } - - @Override - public final int hashCode() { - return session; - } - @Override public final String toString() { - return "User [session=" + session + ", name=" + name + ", channel=" - + channel + "]"; + return "User [session=" + session + ", name=" + name + ", channel=" + + channel + "]"; } }