Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Comminos <andrewcomminos@gmail.com>2013-12-07 07:08:31 +0400
committerAndrew Comminos <andrewcomminos@gmail.com>2013-12-07 07:08:31 +0400
commiteae58cca15df72ee7b3cc2d0a0311b38ed739f23 (patch)
treea037be9b0834fd54e1ead71ce34eab28a43524e7 /src/main/java
parent2d851e3951caada8a6e5375760fd9c7849777eaf (diff)
Added bluetooth support, audio input and output resource management.
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/com/morlunk/jumble/JumbleService.java73
-rw-r--r--src/main/java/com/morlunk/jumble/audio/AudioInput.java16
-rw-r--r--src/main/java/com/morlunk/jumble/audio/AudioOutput.java36
3 files changed, 108 insertions, 17 deletions
diff --git a/src/main/java/com/morlunk/jumble/JumbleService.java b/src/main/java/com/morlunk/jumble/JumbleService.java
index d73d71d..279fe61 100644
--- a/src/main/java/com/morlunk/jumble/JumbleService.java
+++ b/src/main/java/com/morlunk/jumble/JumbleService.java
@@ -17,14 +17,19 @@
package com.morlunk.jumble;
import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.SharedPreferences;
+import android.media.AudioManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
+import android.widget.Toast;
import com.morlunk.jumble.audio.AudioInput;
import com.morlunk.jumble.audio.AudioOutput;
@@ -94,6 +99,43 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
private AudioOutput mAudioOutput;
private AudioInput mAudioInput;
+ private AudioManager.OnAudioFocusChangeListener mAudioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() {
+ @Override
+ public void onAudioFocusChange(int focusChange) {
+ switch (focusChange) {
+ case AudioManager.AUDIOFOCUS_GAIN:
+ mAudioOutput.startPlaying(false);
+ break;
+ case AudioManager.AUDIOFOCUS_LOSS:
+ mAudioOutput.stopPlaying();
+ break;
+ }
+ }
+ };
+
+ private BroadcastReceiver mBluetoothReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int audioState = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, AudioManager.SCO_AUDIO_STATE_ERROR);
+ switch (audioState) {
+ case AudioManager.SCO_AUDIO_STATE_CONNECTED:
+ Toast.makeText(JumbleService.this, R.string.bluetooth_connected, Toast.LENGTH_LONG).show();
+ mAudioOutput.stopPlaying();
+ if(isConnected())
+ mAudioOutput.startPlaying(true);
+ break;
+ case AudioManager.SCO_AUDIO_STATE_DISCONNECTED:
+ case AudioManager.SCO_AUDIO_STATE_ERROR:
+ if(mAudioOutput.isPlaying())
+ Toast.makeText(JumbleService.this, R.string.bluetooth_disconnected, Toast.LENGTH_LONG).show();
+ mAudioOutput.stopPlaying();
+ if(isConnected())
+ mAudioOutput.startPlaying(false);
+ break;
+ }
+ }
+ };
+
private AudioInput.AudioInputListener mAudioInputListener = new AudioInput.AudioInputListener() {
@Override
public void onFrameEncoded(byte[] data, int length, JumbleUDPMessageType messageType) {
@@ -266,20 +308,21 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
@Override
public void setTalkingState(boolean talking) throws RemoteException {
- if(talking)
- mAudioInput.startRecording();
- else
- mAudioInput.stopRecording();
+ if(talking) mAudioInput.startRecording();
+ else mAudioInput.stopRecording();
}
@Override
public boolean isBluetoothAvailable() throws RemoteException {
- return false;
+ AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
+ return audioManager.isBluetoothScoOn();
}
@Override
public void setBluetoothEnabled(boolean enabled) throws RemoteException {
-
+ AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
+ if(enabled) audioManager.startBluetoothSco();
+ else audioManager.stopBluetoothSco();
}
@Override
@@ -520,7 +563,14 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
ab.addAllTokens(mAccessTokens);
mConnection.sendTCPMessage(ab.build(), JumbleTCPMessageType.Authenticate);
- mAudioOutput.startPlaying();
+ // Configure audio manager
+ AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
+ int result = audioManager.requestAudioFocus(mAudioFocusChangeListener,
+ AudioManager.STREAM_MUSIC,
+ AudioManager.AUDIOFOCUS_GAIN);
+ // TODO handle result
+ // This sticky broadcast will initialize the audio output.
+ registerReceiver(mBluetoothReceiver, new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED));
if(mTransmitMode == Constants.TRANSMIT_CONTINUOUS || mTransmitMode == Constants.TRANSMIT_VOICE_ACTIVITY)
mAudioInput.startRecording();
@@ -535,9 +585,16 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
@Override
public void onConnectionDisconnected() {
Log.v(Constants.TAG, "Disconnected");
+ unregisterReceiver(mBluetoothReceiver);
mAudioOutput.stopPlaying();
- mAudioInput.stopRecording();
+ mAudioInput.stopRecordingAndWait();
+ mAudioInput.destroy();
+
+ // Restore audio manager mode
+ AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
+ audioManager.abandonAudioFocus(mAudioFocusChangeListener);
+ audioManager.stopBluetoothSco();
notifyObservers(new ObserverRunnable() {
@Override
diff --git a/src/main/java/com/morlunk/jumble/audio/AudioInput.java b/src/main/java/com/morlunk/jumble/audio/AudioInput.java
index 9eebe64..cdc3e35 100644
--- a/src/main/java/com/morlunk/jumble/audio/AudioInput.java
+++ b/src/main/java/com/morlunk/jumble/audio/AudioInput.java
@@ -231,6 +231,8 @@ public class AudioInput extends ProtocolHandler implements Runnable {
* Stops the record loop after the current iteration.
*/
public void stopRecording() {
+ if(!mRecording) return;
+
synchronized (mRecordLock) {
mRecording = false;
mRecordThread = null;
@@ -241,10 +243,17 @@ public class AudioInput extends ProtocolHandler implements Runnable {
* Stops the record loop and waits on it to finish.
* @throws InterruptedException
*/
- public void stopRecordingAndWait() throws InterruptedException {
- stopRecording();
+ public void stopRecordingAndWait() {
+ if(!mRecording) return;
+
synchronized (mRecordLock) {
- mRecordLock.wait();
+ mRecording = false;
+ try {
+ mRecordThread.join();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ mRecordThread = null;
}
}
@@ -418,6 +427,7 @@ public class AudioInput extends ProtocolHandler implements Runnable {
mPreprocessState.destroy();
if(mResampler != null)
mResampler.destroy();
+ mAudioRecord.release();
}
@Override
diff --git a/src/main/java/com/morlunk/jumble/audio/AudioOutput.java b/src/main/java/com/morlunk/jumble/audio/AudioOutput.java
index 8db90cd..32104c4 100644
--- a/src/main/java/com/morlunk/jumble/audio/AudioOutput.java
+++ b/src/main/java/com/morlunk/jumble/audio/AudioOutput.java
@@ -16,6 +16,10 @@
package com.morlunk.jumble.audio;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
@@ -59,29 +63,49 @@ public class AudioOutput extends ProtocolHandler implements Runnable, AudioOutpu
public AudioOutput(JumbleService service) {
super(service);
+ }
+
+ public void startPlaying(boolean scoEnabled) {
+ if(mRunning)
+ return;
+
int bufferSize = AudioTrack.getMinBufferSize(Audio.SAMPLE_RATE, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT) * 2;
- mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
+ mAudioTrack = new AudioTrack(scoEnabled ? AudioManager.STREAM_VOICE_CALL : AudioManager.STREAM_MUSIC,
Audio.SAMPLE_RATE,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT,
bufferSize,
AudioTrack.MODE_STREAM);
- }
-
- public void startPlaying() {
- if(mRunning)
- return;
mThread = new Thread(this);
mThread.start();
}
public void stopPlaying() {
+ if(!mRunning)
+ return;
+
mRunning = false;
+ synchronized (mInactiveLock) {
+ mInactiveLock.notify(); // Wake inactive lock if active
+ }
+ try {
+ mThread.join();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
mThread = null;
for(AudioOutputSpeech s : mAudioOutputs.values())
s.destroy();
+
+ mAudioOutputs.clear();
+ mAudioTrack.release();
+ mAudioTrack = null;
+ }
+
+ public boolean isPlaying() {
+ return mRunning;
}
@Override