Make two way communication over ip addresses
parent
a0cea8b8da
commit
aab2cbd3a4
|
@ -60,7 +60,7 @@
|
||||||
<ConfirmationsSetting value="0" id="Add" />
|
<ConfirmationsSetting value="0" id="Add" />
|
||||||
<ConfirmationsSetting value="0" id="Remove" />
|
<ConfirmationsSetting value="0" id="Remove" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
|
|
@ -1,17 +1,27 @@
|
||||||
package com.smarthomies.realtimetalk;
|
package com.smarthomies.realtimetalk;
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.utils.MediaRecorderThread;
|
||||||
|
import com.smarthomies.realtimetalk.utils.MediaStreamServer;
|
||||||
|
import com.smarthomies.realtimetalk.utils.MediaStreamerThread;
|
||||||
import com.smarthomies.realtimetalk.utils.RTTAppHelper;
|
import com.smarthomies.realtimetalk.utils.RTTAppHelper;
|
||||||
|
import com.smarthomies.realtimetalk.utils.SocketAudioPlayer;
|
||||||
|
import com.smarthomies.realtimetalk.utils.SocketAudioRecorder;
|
||||||
|
|
||||||
|
import java.net.Socket;
|
||||||
|
|
||||||
import io.realm.Realm;
|
import io.realm.Realm;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by ensar on 31/10/16.
|
* Created by ensar on 31/10/16.
|
||||||
*/
|
*/
|
||||||
public class RTTApp extends Application {
|
public class RTTApp extends Application implements MediaStreamServer.CallCallbacks {
|
||||||
public static final String TAG = RTTApp.class.getSimpleName();
|
public static final String TAG = RTTApp.class.getSimpleName();
|
||||||
|
|
||||||
|
private SocketAudioRecorder socketAudioRecorder;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
@ -19,5 +29,46 @@ public class RTTApp extends Application {
|
||||||
RTTAppHelper.getInstance().initWithContext(getApplicationContext());
|
RTTAppHelper.getInstance().initWithContext(getApplicationContext());
|
||||||
|
|
||||||
Realm.init(this);
|
Realm.init(this);
|
||||||
|
|
||||||
|
MediaStreamServer.initWithContext(this);
|
||||||
|
|
||||||
|
MediaStreamServer.getInstance().setCallListener(this);
|
||||||
|
MediaStreamServer.getInstance().startListeningToPort();
|
||||||
|
|
||||||
|
MediaStreamerThread.initWithContext(this);
|
||||||
|
MediaStreamerThread.getInstance().start();
|
||||||
|
|
||||||
|
MediaRecorderThread.initWithContext(this);
|
||||||
|
MediaRecorderThread.getInstance().start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(int errorCode) {
|
||||||
|
Log.d(TAG, "onError: " + errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConnectionRequested(Socket sourceSocket) {
|
||||||
|
Log.d(TAG, "onConnectionRequested: ");
|
||||||
|
if(socketAudioRecorder != null) {
|
||||||
|
socketAudioRecorder.stop();
|
||||||
|
}
|
||||||
|
socketAudioRecorder = MediaRecorderThread.getInstance().startStreamingAudio(sourceSocket.getInetAddress().toString().substring(1), 8087);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConnectionFinished() {
|
||||||
|
Log.d(TAG, "onConnectionFinished: ");
|
||||||
|
if(socketAudioRecorder != null) {
|
||||||
|
socketAudioRecorder.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTerminate() {
|
||||||
|
super.onTerminate();
|
||||||
|
MediaStreamServer.getInstance().stop();
|
||||||
|
MediaStreamerThread.getInstance().interrupt();
|
||||||
|
MediaRecorderThread.getInstance().interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
package com.smarthomies.realtimetalk.utils;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.HandlerThread;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.R;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
|
public class MediaRecorderThread extends HandlerThread {
|
||||||
|
private static final String TAG = MediaRecorderThread.class.getSimpleName();
|
||||||
|
|
||||||
|
private int frequency;
|
||||||
|
private int channelConfiguration;
|
||||||
|
private int audioEncoding;
|
||||||
|
|
||||||
|
private static MediaRecorderThread instance;
|
||||||
|
|
||||||
|
public static void initWithContext(Context context) {
|
||||||
|
instance = new MediaRecorderThread(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Handler mHandler;
|
||||||
|
|
||||||
|
public static MediaRecorderThread getInstance() {
|
||||||
|
if(instance == null) {
|
||||||
|
throw new RuntimeException("Initialize server first with initWithContext");
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MediaRecorderThread(Context ctx) {
|
||||||
|
super(TAG);
|
||||||
|
Properties prop = new Properties();
|
||||||
|
try {
|
||||||
|
InputStream inputStream = ctx.getResources().openRawResource(R.raw.config);
|
||||||
|
prop.load(inputStream);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
Log.d(TAG, "Can't find config");
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(TAG, "Can't load config");
|
||||||
|
}
|
||||||
|
|
||||||
|
frequency = Integer.parseInt(prop.getProperty("frequency"));
|
||||||
|
channelConfiguration = Integer.parseInt(prop.getProperty("client_channel"));
|
||||||
|
audioEncoding = Integer.parseInt(prop.getProperty("audio_encoding"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLooperPrepared() {
|
||||||
|
super.onLooperPrepared();
|
||||||
|
mHandler = new Handler(getLooper());
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketAudioRecorder startStreamingAudio(String ip, int port) {
|
||||||
|
SocketAudioRecorder recorder = new SocketAudioRecorder(ip, port, frequency, channelConfiguration, audioEncoding);
|
||||||
|
mHandler.post(recorder);
|
||||||
|
return recorder;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import android.content.Context;
|
||||||
import android.media.AudioFormat;
|
import android.media.AudioFormat;
|
||||||
import android.media.AudioRecord;
|
import android.media.AudioRecord;
|
||||||
import android.media.MediaRecorder;
|
import android.media.MediaRecorder;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import com.smarthomies.realtimetalk.R;
|
import com.smarthomies.realtimetalk.R;
|
||||||
import com.smarthomies.realtimetalk.views.activities.CallActivity;
|
import com.smarthomies.realtimetalk.views.activities.CallActivity;
|
||||||
|
@ -31,17 +32,19 @@ public class MediaStreamClient {
|
||||||
InputStream inputStream = ctx.getResources().openRawResource(R.raw.config);
|
InputStream inputStream = ctx.getResources().openRawResource(R.raw.config);
|
||||||
prop.load(inputStream);
|
prop.load(inputStream);
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
System.out.println("Can't finde config");
|
System.out.println("Can't find config");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.out.println("Can't load config");
|
System.out.println("Can't load config");
|
||||||
}
|
}
|
||||||
|
|
||||||
final int frequency = Integer.parseInt(prop.getProperty("frequency"));
|
final int frequency = Integer.parseInt(prop.getProperty("frequency"));
|
||||||
final int channelConfiguration = Integer.parseInt(prop.getProperty("channal_server"));
|
final int channelConfiguration = Integer.parseInt(prop.getProperty("client_channel"));
|
||||||
final int audioEncoding = Integer.parseInt(prop.getProperty("audio_encoding"));
|
final int audioEncoding = Integer.parseInt(prop.getProperty("audio_encoding"));
|
||||||
final int SERVERPORT = Integer.parseInt(prop.getProperty("serverport_server"));
|
final int SERVERPORT = Integer.parseInt(prop.getProperty("port_server"));
|
||||||
|
|
||||||
|
|
||||||
recBufSize = AudioRecord.getMinBufferSize(frequency, channelConfiguration, audioEncoding);
|
recBufSize = AudioRecord.getMinBufferSize(frequency, channelConfiguration, audioEncoding);
|
||||||
|
Log.d(TAG, "MediaStreamClient buffer size: " + recBufSize);
|
||||||
//Log.v(TAG,String.valueOf(AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_CONFIGURATION_MONO , AudioFormat.ENCODING_PCM_16BIT)));
|
//Log.v(TAG,String.valueOf(AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_CONFIGURATION_MONO , AudioFormat.ENCODING_PCM_16BIT)));
|
||||||
audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, frequency, channelConfiguration, audioEncoding, recBufSize);
|
audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, frequency, channelConfiguration, audioEncoding, recBufSize);
|
||||||
|
|
||||||
|
@ -70,7 +73,7 @@ public class MediaStreamClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
audioRecord.stop();
|
audioRecord.stop();
|
||||||
//audioRecord.release();
|
audioRecord.release();
|
||||||
try { connfd.close(); }
|
try { connfd.close(); }
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|
|
@ -1,108 +1,172 @@
|
||||||
package com.smarthomies.realtimetalk.utils;
|
package com.smarthomies.realtimetalk.utils;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.media.AudioFormat;
|
|
||||||
import android.media.AudioManager;
|
|
||||||
import android.media.AudioTrack;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.smarthomies.realtimetalk.R;
|
import com.smarthomies.realtimetalk.R;
|
||||||
import com.smarthomies.realtimetalk.views.activities.CallActivity;
|
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
public class MediaStreamServer implements Runnable {
|
public class MediaStreamServer implements Runnable {
|
||||||
|
private static final String TAG = MediaStreamServer.class.getSimpleName();
|
||||||
|
|
||||||
boolean isPlaying;
|
private boolean isListening;
|
||||||
int playBufSize;
|
private Socket socketConnection;
|
||||||
Socket connfd;
|
private ServerSocket serverSocket;
|
||||||
ServerSocket sockfd;
|
private final int SERVERPORT;
|
||||||
AudioTrack audioTrack;
|
|
||||||
private static final String TAG = "MyActivity";
|
|
||||||
final int SERVERPORT;
|
|
||||||
Context ctx;
|
|
||||||
|
|
||||||
public MediaStreamServer(final Context ctx) {
|
private Thread serverThread;
|
||||||
|
|
||||||
|
private CallCallbacks callListener;
|
||||||
|
|
||||||
|
private static MediaStreamServer instance;
|
||||||
|
|
||||||
|
public static void initWithContext(Context context) {
|
||||||
|
instance = new MediaStreamServer(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MediaStreamServer getInstance() {
|
||||||
|
if(instance == null) {
|
||||||
|
throw new RuntimeException("Initialize server first with initWithContext");
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCallListener(CallCallbacks callListener) {
|
||||||
|
this.callListener = callListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeCallListener() {
|
||||||
|
this.callListener = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MediaStreamServer(Context ctx) {
|
||||||
|
|
||||||
Properties prop = new Properties();
|
Properties prop = new Properties();
|
||||||
try {
|
try {
|
||||||
InputStream inputStream = ctx.getResources().openRawResource(R.raw.config);
|
InputStream inputStream = ctx.getResources().openRawResource(R.raw.config);
|
||||||
prop.load(inputStream);
|
prop.load(inputStream);
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
System.out.println("Can't finde config");
|
Log.d(TAG, "Can't find config");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.out.println("Can't load config");
|
Log.d(TAG, "Can't load config");
|
||||||
}
|
}
|
||||||
|
|
||||||
final int frequency = Integer.parseInt(prop.getProperty("frequency"));
|
SERVERPORT = Integer.parseInt(prop.getProperty("port_client"));
|
||||||
final int channelConfiguration = Integer.parseInt(prop.getProperty("channal_client"));
|
|
||||||
final int audioEncoding = Integer.parseInt(prop.getProperty("audio_encoding"));
|
|
||||||
SERVERPORT = Integer.parseInt(prop.getProperty("serverport_client"));
|
|
||||||
|
|
||||||
|
|
||||||
playBufSize=AudioTrack.getMinBufferSize(frequency, channelConfiguration, audioEncoding);
|
|
||||||
audioTrack = new AudioTrack(AudioManager.STREAM_VOICE_CALL, frequency, channelConfiguration, audioEncoding, playBufSize, AudioTrack.MODE_STREAM);
|
|
||||||
audioTrack.setStereoVolume(1f, 1f);
|
|
||||||
this.ctx=ctx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
isPlaying = false;
|
isListening = false;
|
||||||
|
serverThread.interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void startListeningToPort() {
|
||||||
|
if(serverThread == null) {
|
||||||
|
serverThread = new Thread(this);
|
||||||
|
}
|
||||||
|
serverThread.start();
|
||||||
|
}
|
||||||
|
|
||||||
public void setVolume(float lvol, float rvol) {
|
public void stopListeningToPort() {
|
||||||
audioTrack.setStereoVolume(lvol, rvol);
|
isListening = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
byte[] buffer = new byte[playBufSize];
|
isListening = true;
|
||||||
try { sockfd = new ServerSocket(SERVERPORT); }
|
try {
|
||||||
catch (Exception e) {
|
serverSocket = new ServerSocket(SERVERPORT);
|
||||||
|
Log.d(TAG, "Server socket open on port: " + SERVERPORT);
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
CallActivity.toast("Port unavailable",ctx);
|
notifyError(ERROR_PORT_UNAVAILABLE);
|
||||||
|
isListening = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while(true) {
|
|
||||||
|
while(isListening) {
|
||||||
try {
|
try {
|
||||||
connfd = sockfd.accept();
|
socketConnection = serverSocket.accept();
|
||||||
} catch (Exception e) {
|
Log.d(TAG, "Accepted socket connection!");
|
||||||
|
Log.d(TAG, "Socket connection info: " + socketConnection);
|
||||||
|
notifyConnectionRequested(socketConnection);
|
||||||
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
CallActivity.toast("Connection not accepted",ctx);
|
notifyError(ERROR_WHILE_ACCEPTING);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
CallActivity.toast("Connected",ctx);
|
|
||||||
audioTrack.play();
|
final CountDownLatch callTerminationLock = new CountDownLatch(1);
|
||||||
isPlaying = true;
|
|
||||||
while (isPlaying) {
|
Log.d(TAG, "Playing audio!");
|
||||||
int readSize = 0;
|
MediaStreamerThread.getInstance().playAudioFromSocket(socketConnection, callTerminationLock);
|
||||||
try {
|
|
||||||
readSize = connfd.getInputStream().read(buffer);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.v(TAG, "palo");
|
|
||||||
e.printStackTrace();
|
|
||||||
CallActivity.toast("Closed stream by sender",ctx);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
audioTrack.write(buffer, 0, readSize);
|
|
||||||
}
|
|
||||||
audioTrack.stop();
|
|
||||||
audioTrack.flush();
|
|
||||||
try {
|
try {
|
||||||
connfd.close();
|
callTerminationLock.await();
|
||||||
|
Log.d(TAG, "Done playing!");
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
notifyError(ERROR_CALL_INTERRUPTED);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
socketConnection.close();
|
||||||
|
notifyConnectionFinished();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
CallActivity.toast("Can't close connection!",ctx);
|
notifyError(ERROR_WHILE_CLOSING_CONNECTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
serverSocket.close();
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
notifyError(ERROR_WHILE_CLOSING);
|
||||||
|
isListening = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyError(int errorCode) {
|
||||||
|
if(callListener != null) {
|
||||||
|
callListener.onError(errorCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void notifyConnectionRequested(Socket sourceSocket) {
|
||||||
|
if(callListener != null) {
|
||||||
|
callListener.onConnectionRequested(sourceSocket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyConnectionFinished() {
|
||||||
|
if(callListener != null) {
|
||||||
|
callListener.onConnectionFinished();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final int ERROR_PORT_UNAVAILABLE = 0;
|
||||||
|
public static final int ERROR_WHILE_CLOSING = 1;
|
||||||
|
public static final int ERROR_WHILE_ACCEPTING = 2;
|
||||||
|
public static final int ERROR_WHILE_PLAYING = 3;
|
||||||
|
public static final int ERROR_WHILE_CLOSING_CONNECTION = 4;
|
||||||
|
public static final int ERROR_CALL_INTERRUPTED = 5;
|
||||||
|
|
||||||
|
|
||||||
|
public interface CallCallbacks {
|
||||||
|
void onError(int errorCode);
|
||||||
|
void onConnectionRequested(Socket sourceSocket);
|
||||||
|
void onConnectionFinished();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
package com.smarthomies.realtimetalk.utils;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.databinding.repacked.org.antlr.v4.codegen.model.Loop;
|
||||||
|
import android.media.AudioManager;
|
||||||
|
import android.media.AudioTrack;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.HandlerThread;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.R;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
|
public class MediaStreamerThread extends HandlerThread {
|
||||||
|
private static final String TAG = MediaStreamerThread.class.getSimpleName();
|
||||||
|
|
||||||
|
private int frequency;
|
||||||
|
private int channelConfiguration;
|
||||||
|
private int audioEncoding;
|
||||||
|
|
||||||
|
private static MediaStreamerThread instance;
|
||||||
|
|
||||||
|
public static void initWithContext(Context context) {
|
||||||
|
instance = new MediaStreamerThread(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Handler mHandler;
|
||||||
|
|
||||||
|
public static MediaStreamerThread getInstance() {
|
||||||
|
if(instance == null) {
|
||||||
|
throw new RuntimeException("Initialize server first with initWithContext");
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MediaStreamerThread(Context ctx) {
|
||||||
|
super(TAG);
|
||||||
|
Properties prop = new Properties();
|
||||||
|
try {
|
||||||
|
InputStream inputStream = ctx.getResources().openRawResource(R.raw.config);
|
||||||
|
prop.load(inputStream);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
Log.d(TAG, "Can't find config");
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(TAG, "Can't load config");
|
||||||
|
}
|
||||||
|
|
||||||
|
frequency = Integer.parseInt(prop.getProperty("frequency"));
|
||||||
|
channelConfiguration = Integer.parseInt(prop.getProperty("server_channel"));
|
||||||
|
audioEncoding = Integer.parseInt(prop.getProperty("audio_encoding"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLooperPrepared() {
|
||||||
|
super.onLooperPrepared();
|
||||||
|
mHandler = new Handler(getLooper());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void playAudioFromSocket(Socket socket, final CountDownLatch finishedLock) {
|
||||||
|
mHandler.post(new SocketAudioPlayer(socket, frequency, channelConfiguration, audioEncoding, finishedLock));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package com.smarthomies.realtimetalk.utils;
|
||||||
|
|
||||||
|
import android.media.AudioManager;
|
||||||
|
import android.media.AudioTrack;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
|
public class SocketAudioPlayer implements Runnable {
|
||||||
|
private static final String TAG = SocketAudioPlayer.class.getSimpleName();
|
||||||
|
|
||||||
|
private int playBufSize;
|
||||||
|
private AudioTrack audioTrack;
|
||||||
|
|
||||||
|
private boolean isPlaying;
|
||||||
|
|
||||||
|
private Socket socket;
|
||||||
|
|
||||||
|
private CountDownLatch completionLock;
|
||||||
|
|
||||||
|
private int noDataCounter = 0;
|
||||||
|
|
||||||
|
|
||||||
|
public SocketAudioPlayer(Socket socket, int frequency, int channelConfiguration, int audioEncoding, final CountDownLatch countDownLatch) {
|
||||||
|
this.socket = socket;
|
||||||
|
playBufSize=AudioTrack.getMinBufferSize(frequency, channelConfiguration, audioEncoding);
|
||||||
|
audioTrack = new AudioTrack(AudioManager.STREAM_VOICE_CALL, frequency, channelConfiguration, audioEncoding, playBufSize, AudioTrack.MODE_STREAM);
|
||||||
|
audioTrack.setStereoVolume(1f, 1f);
|
||||||
|
this.completionLock = countDownLatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
Log.d(TAG, "Start!");
|
||||||
|
byte[] buffer = new byte[playBufSize];
|
||||||
|
audioTrack.play();
|
||||||
|
isPlaying = true;
|
||||||
|
while (isPlaying) {
|
||||||
|
int readSize = 0;
|
||||||
|
try {
|
||||||
|
readSize = socket.getInputStream().read(buffer);
|
||||||
|
|
||||||
|
Log.d(TAG, "Received " + readSize + " bytes");
|
||||||
|
|
||||||
|
if(readSize <= 0) {
|
||||||
|
noDataCounter++;
|
||||||
|
} else {
|
||||||
|
noDataCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(noDataCounter == 10) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
isPlaying = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
audioTrack.write(buffer, 0, readSize);
|
||||||
|
}
|
||||||
|
audioTrack.stop();
|
||||||
|
audioTrack.flush();
|
||||||
|
} finally {
|
||||||
|
Log.d(TAG, "Done!");
|
||||||
|
completionLock.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
package com.smarthomies.realtimetalk.utils;
|
||||||
|
|
||||||
|
import android.media.AudioRecord;
|
||||||
|
import android.media.MediaRecorder;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.views.activities.CallActivity;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
|
public class SocketAudioRecorder implements Runnable {
|
||||||
|
private static final String TAG = SocketAudioRecorder.class.getSimpleName();
|
||||||
|
|
||||||
|
private static int recBufSize;
|
||||||
|
private static AudioRecord audioRecord;
|
||||||
|
|
||||||
|
private boolean isRecording;
|
||||||
|
|
||||||
|
private Socket socket;
|
||||||
|
|
||||||
|
private String ip;
|
||||||
|
private int port;
|
||||||
|
|
||||||
|
public SocketAudioRecorder(String ip, int port, int frequency, int channelConfiguration, int audioEncoding) {
|
||||||
|
this.ip = ip;
|
||||||
|
this.port = port;
|
||||||
|
if(audioRecord == null || audioRecord.getState() == AudioRecord.STATE_UNINITIALIZED) {
|
||||||
|
recBufSize = AudioRecord.getMinBufferSize(frequency, channelConfiguration, audioEncoding);
|
||||||
|
Log.d(TAG, "MediaStreamClient buffer size: " + recBufSize);
|
||||||
|
//Log.v(TAG,String.valueOf(AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_CONFIGURATION_MONO , AudioFormat.ENCODING_PCM_16BIT)));
|
||||||
|
audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, frequency, channelConfiguration, audioEncoding, recBufSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
byte[] buffer = new byte[recBufSize];
|
||||||
|
try {
|
||||||
|
socket = new Socket(ip, port);
|
||||||
|
Log.d(TAG, "Socket open!");
|
||||||
|
Log.d(TAG, "Socket info: " + socket);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
audioRecord.startRecording();
|
||||||
|
|
||||||
|
Log.d(TAG, "Started recording");
|
||||||
|
isRecording = true;
|
||||||
|
while (isRecording) {
|
||||||
|
|
||||||
|
int readSize = audioRecord.read(buffer, 0, recBufSize);
|
||||||
|
|
||||||
|
Log.d(TAG, "Recorded " + readSize + " bytes");
|
||||||
|
|
||||||
|
try {
|
||||||
|
socket.getOutputStream().write(buffer, 0, readSize);
|
||||||
|
Log.d(TAG, "Sent " + readSize + " bytes");
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
audioRecord.stop();
|
||||||
|
Log.d(TAG, "Stopped recording!");
|
||||||
|
try {
|
||||||
|
socket.close();
|
||||||
|
Log.d(TAG, "Socket closed!");
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
isRecording = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -12,20 +12,21 @@ import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.smarthomies.realtimetalk.R;
|
import com.smarthomies.realtimetalk.R;
|
||||||
|
import com.smarthomies.realtimetalk.utils.MediaRecorderThread;
|
||||||
import com.smarthomies.realtimetalk.utils.MediaStreamClient;
|
import com.smarthomies.realtimetalk.utils.MediaStreamClient;
|
||||||
import com.smarthomies.realtimetalk.utils.MediaStreamServer;
|
import com.smarthomies.realtimetalk.utils.MediaStreamServer;
|
||||||
|
import com.smarthomies.realtimetalk.utils.SocketAudioRecorder;
|
||||||
|
|
||||||
public class CallActivity extends AppCompatActivity {
|
public class CallActivity extends AppCompatActivity {
|
||||||
|
|
||||||
private TextView serverStatus;
|
private TextView serverStatus;
|
||||||
private EditText serverIp;
|
private EditText serverIp;
|
||||||
private Button nazovi;
|
private Button nazovi;
|
||||||
private MediaStreamClient mss;
|
|
||||||
private MediaStreamServer msc;
|
|
||||||
// DESIGNATE A PORT
|
// DESIGNATE A PORT
|
||||||
boolean isRecording;
|
boolean isRecording;
|
||||||
private static Handler handler = new Handler();
|
private static Handler handler = new Handler();
|
||||||
Thread t=null;
|
|
||||||
|
private SocketAudioRecorder socketAudioRecorder;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
@ -37,9 +38,6 @@ public class CallActivity extends AppCompatActivity {
|
||||||
serverStatus=(TextView) findViewById(R.id.labela);
|
serverStatus=(TextView) findViewById(R.id.labela);
|
||||||
nazovi.setOnTouchListener(nazoviL);
|
nazovi.setOnTouchListener(nazoviL);
|
||||||
isRecording=false;
|
isRecording=false;
|
||||||
msc=new MediaStreamServer(CallActivity.this);
|
|
||||||
t=new Thread(msc);
|
|
||||||
t.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,11 +48,15 @@ public class CallActivity extends AppCompatActivity {
|
||||||
String ip=serverIp.getText().toString();
|
String ip=serverIp.getText().toString();
|
||||||
switch (event.getAction()) {
|
switch (event.getAction()) {
|
||||||
case MotionEvent.ACTION_DOWN:
|
case MotionEvent.ACTION_DOWN:
|
||||||
msc.stop();
|
if(socketAudioRecorder != null) {
|
||||||
mss=new MediaStreamClient(CallActivity.this,ip);
|
socketAudioRecorder.stop();
|
||||||
|
}
|
||||||
|
socketAudioRecorder=MediaRecorderThread.getInstance().startStreamingAudio(ip, 8087);
|
||||||
break;
|
break;
|
||||||
case MotionEvent.ACTION_UP:
|
case MotionEvent.ACTION_UP:
|
||||||
mss.stop(CallActivity.this);
|
if(socketAudioRecorder != null) {
|
||||||
|
socketAudioRecorder.stop();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
frequency = 44100
|
frequency = 44100
|
||||||
serverport_client = 8087
|
port_client = 8087
|
||||||
serverport_server = 8083
|
port_server = 8083
|
||||||
audio_encoding=2
|
audio_encoding=2
|
||||||
channal_client=4
|
client_channel=2
|
||||||
channal_server=2
|
server_channel=2
|
||||||
|
|
Loading…
Reference in New Issue