Working with DataChannel in Android WebRTC application - java

Due to the breaking changes in Android WebRTC client's example, I'm looking for the code-example which shows how to add and work with DataChannel in Android. I need to just send "Hello Worlds" via DataChannel between 2 Android devices. Here's the old code:
https://chromium.googlesource.com/external/webrtc/stable/talk/+/master/examples/android/src/org/appspot/apprtc/AppRTCDemoActivity.java#177
It uses some classes and interfaces which don't exist in the new version anymore.
So how can I add support of DataChannel to my Android WebRTC application, send and receive a text through it?

I added DataChannel in a project with an older version of webrtc. I looked at the most up to date classes and it seems the methods and callbacks are still there, so hopefully it will work for you.
Changes to PeerConnectionClient:
Create DataChannel in createPeerConnectionInternal after isInitiator = false;:
DataChannel.Init dcInit = new DataChannel.Init();
dcInit.id = 1;
dataChannel = pc.createDataChannel("1", dcInit);;
dataChannel.registerObserver(new DcObserver());
Changes to onDataChannel:
#Override
public void onDataChannel(final DataChannel dc) {
Log.d(TAG, "onDataChannel");
executor.execute(new Runnable() {
#Override
public void run() {
dataChannel = dc;
String channelName = dataChannel.label();
dataChannel.registerObserver(new DcObserver());
}
});
}
Add the channel observer:
private class DcObserver implements DataChannel.Observer {
#Override
public void onMessage(final DataChannel.Buffer buffer) {
ByteBuffer data = buffer.data;
byte[] bytes = new byte[data.remaining()];
data.get(bytes);
final String command = new String(bytes);
executor.execute(new Runnable() {
public void run() {
events.onReceivedData(command);
}
});
}
#Override
public void onStateChange() {
Log.d(TAG, "DataChannel: onStateChange: " + dataChannel.state());
}
}
I added onReceivedDataevents to PeerConnectionEvents interface and all the events are implemented in the CallActivity so I handle the data received on the channel from there.
To send data, from CallActivity:
public void sendData(final String data) {
ByteBuffer buffer = ByteBuffer.wrap(data.getBytes());
peerConnectionClient.getPCDataChannel().send(new DataChannel.Buffer(buffer, false));
}
I only took a quick look at the new classes and made minor changes to my code, I hope it will work for you with no more changes.
Good luck

I'm sorry that I have a question to the code from Guy S.
In your code, there are two following statements in both createPeerConnectionInternal() and onDataChannel().
dataChannel.registerObserver(new DcObserver());
I think it may cause twice registrations. Is it correct??
I mean, before making a call, it created a dataChannal and registered an Observer. Then.. if there is a call comes in, the onDataChannel called, then the dataChannel point to dc and register again??

Related

How to get every time messages from service to activity using runOnUiThread

I have been stuck with one problem. I need some people which check a part of my code and help me with problem and critize my code (I write code but I haven't people which can say this is wrong or something in this pattern)
Generally.
My service get message from bluetooth (HC-05) and I can see values in Log.d, in service.
A part code of my service which get message.
private class ConnectedThread extends Thread{
private final BluetoothSocket bluetoothSocket;
private final InputStream inputStream;
private final OutputStream outputStream;
public ConnectedThread(BluetoothSocket socket){
Log.d(TAG,"ConnectedThread: Starting");
bluetoothSocket=socket;
InputStream tmpInput = null;
OutputStream tmpOutput = null;
try{
tmpInput = bluetoothSocket.getInputStream();
tmpOutput = bluetoothSocket.getOutputStream();
}catch (IOException e){
e.printStackTrace();
active=false;
}
inputStream=tmpInput;
outputStream=tmpOutput;
}
#Override
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while(active){
try {
bytes = inputStream.read(buffer);
final String comingMsg = new String(buffer,0,bytes);
Log.d(TAG,"InputStream: " + comingMsg);
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Message message = new Message();
message.obj = comingMsg;
message.what = 1; // I need it to prevent NullObjReference
Log.d(TAG,"Handler run(): " + message.obj);
mHandler.sendMessage(message);
}
});
}catch (IOException e){
Log.e(TAG,"Write: Error reading input." + e.getMessage());
active=false;
break;
}
}
}
...some code is hidden because it is diploma thesis
}
The problem is get message every time from this service to another activity where all is happen.
I tried a lot of things (with Threads,Looper,runOnUiThread, handleMessage and callback), checked a lot of posts in stackoverflow and I tried to combine with my project but all time I had nullobjectreference (for that i tried to use msg.what to check) , black screen when tried to move to my home activity (it is main) and update my textView or typical crash app.
Now I want only to get message from service to textview. When everything starts working fine, I want to parse string (for example 3 first chars) and send message to one of six textviews.
A part of codes from onCreate before method runThread() is started:
Log.d(TAG,"Check intent - result");
if(getIntent().getIntExtra("result",0)==RESULT_OK){
mDevice = getIntent().getExtras().getParcelable("bonded device");
startConnection(mDevice,MY_UUID);
Log.d(TAG,"Check is active service ");
checkIfActive();;
}
Log.d(TAG,"Check intent - connect_to_paired");
if(getIntent().getIntExtra("connect_to_paired",0)==RESULT_OK){
mDevice = getIntent().getExtras().getParcelable("bonded_paired_device");
startConnection(mDevice,MY_UUID);
Log.d(TAG,"Check is active service ");
checkIfActive();
}
public void checkIfActive(){
Log.d(TAG,"CheckIfActive: Started");
while(myBluetoothService.active!=true) {
Log.d(TAG,"CheckIfActive() active is "+ myBluetoothService.active);
if (myBluetoothService.active) {
Log.d(TAG, "CheckIfActive: Running method runOnUiThread - myBluetoothService.active is "+myBluetoothService.active);
runThread();
}
}
}
Method runThread() which should work everytime after connected with bluetooth device:
public void runThread(){
//I used there Thread but when connection was fail,
// method created multiply threads when I tried to connect next time
runOnUiThread(new Runnable() {
#Override
public void run() {
handler = new Handler(Looper.getMainLooper()){
#Override
public void handleMessage(Message msg) {
while (true) {
switch (msg.what) {
//when is one, service has messages to send
case 1:
String message = myBluetoothService.mHandler.obtainMessage().toString();
rearLeft.setText(message);
break;
default:
super.handleMessage(msg);
}
}
}
};
}
});
}
UPDATE:
Is it good idea ? Maybe I can put JSON Object to service to send message and in the HomeActivity, I can try get values from JSON. Is it fast ? I send a lot of data, because bluetooth receive data of distance from 4 ultrasound sensors in 4 times in lasts until few milliseconds, everytime.
Here is screen how sees my data in service when I have debug logs.
Next idea, but still nothing:
HomeActivity (my main)
public void runThread(){
runOnUiThread(new Runnable() {
#Override
public void run() {
//Looper.prepare();
new Handler() {
#Override
public void handleMessage(Message msg) {
rearLeft.setText(msg.obj.toString());
}
};
//Looper.loop();
//Log.d(TAG, myBluetoothService.mHandler.getLooper().toString());
//rearLeft.setText(myBluetoothService.mHandler.getLooper().toString());
}
});
}
Service which should send data from bluetooth to UI Thread is the same (Check first code).
Screen from HomeActivity where you can see 6 text views. Now I want put all text to one view which will be refresh by get next message.
Ok this post a bit help me to solve problem:
Sending a simple message from Service to Activity
Maybe this link could help another people.
Thanks for help, now understand why i should use broadcast receiver to do this.

Live Query Couchbase lite peer to peer

I'm making an Android app using Couchbase. There are two devices connected to the same WiFi synchronizing data. I was using Couchbase Sync Gateway but the project needs to be peer to peer, without Sync Gateway in the middle. When I used Sync Gateway every change in one app was updated immediately. But now it's not working. The function I'm using:
private void showAnswers() {
manager = DataManager.getSharedInstance(getApplicationContext());
answersQuery = Answer.getAnswersForQuestion(manager.database, mQuestion.get_id());
liveQuery = answersQuery.toLiveQuery();
liveQuery.addChangeListener(new LiveQuery.ChangeListener() {
#Override
public void changed(LiveQuery.ChangeEvent event) {
QueryEnumerator result = event.getRows();
Map<String, Integer> counts = getAnswerCounts(result);
adapter = (QuestionOptionsAdapter) mQuestionOptions.getAdapter();
adapter.setAnswerCounts(counts);
runOnUiThread(new Runnable() {
#Override
public void run() {
adapter.notifyDataSetChanged();
}
});
}
});
liveQuery.start();
}
I don't know why the Live Query change listener isn't working. It just works once when I start the Activity.
Thank you everybody for your help.

Matlab & Java: Execute matlab asynchronously

so, here is my today problem:
First of all, please note that I do NOT have the Matlab parallel toolbox available.
I am running java code witch interact with Matlab. Sometime Matlab directly call some java functions, sometimes it is the opposite. In this case, we use a notification system which comes from here:
http://undocumentedmatlab.com/blog/matlab-callbacks-for-java-events
We then address the notification in proper callbacks.
Here is a simple use case:
My user select a configuration file using the java interface, loaded into Matlab.
Using an interface listener, we notify Matlab that the configuration file has been selected, it then run a certain number of functions that will analyzes the file
Once the analysis is done, it is pushed into the java runtime, which will populate interface tables with the result. This step involve that matlab will call a java function.
Finally, java request the interface to be switched to an arbitrary decided tab.
This is the order of which things would happen in an ideal world, however, here is the code of the listener actionPerformed method:
#Override
public void actionPerformed(ActionEvent arg0) {
Model wModel = controller.getModel();
Window wWindow = controller.getWindow();
MatlabStructure wStructure = new MatlabStructure();
if(null != wModel) {
wModel.readMatlabData(wStructure);
wModel.notifyMatlab(wStructure, MatlabAction.UpdateCircuit);
}
if(null != wWindow) {
wWindow.getTabContainer().setSelectedComponent(wWindow.getInfosPannel());
}
}
What happen here, is that, when the notifyMatlab method is called, the code does not wait for it to be completed before it continues. So what happen is that the method complete and switch to an empty interface page (setSelectedComponent), and then the component is filled with values.
What I would like to, is for java to wait that my notifyMatlab returns a "I have completed !!" signal, and then pursue. Which involves asynchrounous code since Matlab will code java methods during its execution too ...
So far here is what I tried:
In the MatlabEventObject class, I added an isAcknowledge member, so now the class (which I originaly found in the above link), look like this (I removed all unchanged code from the original class):
public class MatlabEventObject extends java.util.EventObject {
private static final long serialVersionUID = 1L;
private boolean isAcknowledged = false;
public void onNotificationReceived() {
if (source instanceof MatlabEvent) {
System.out.println("Catched a MatlabEvent Pokemon !");
MatlabEvent wSource = (MatlabEvent) source;
wSource.onNotificationReceived();
}
}
public boolean isAcknowledged() {
return isAcknowledged;
}
public void acknowledge() {
isAcknowledged = true;
}
}
In the MatlabEvent class, I have added a future task which goal is to wait for acknowledgement, the methods now look like this:
public class MatlabEvent {
private Vector<IMatlabListener> data = new Vector<IMatlabListener>();
private Vector<MatlabEventObject> matlabEvents = new Vector<MatlabEventObject>();
public void notifyMatlab(final Object obj, final MatlabAction action) {
final Vector<IMatlabListener> dataCopy;
matlabEvents.clear();
synchronized (this) {
dataCopy = new Vector<IMatlabListener>(data);
}
for (int i = 0; i < dataCopy.size(); i++) {
matlabEvents.add(new MatlabEventObject(this, obj, action));
((IMatlabListener) dataCopy.elementAt(i)).testEvent(matlabEvents.get(i));
}
}
public void onNotificationReceived() {
ExecutorService service = Executors.newSingleThreadExecutor();
long timeout = 15;
System.out.println("Executing runnable.");
Runnable r = new Runnable() {
#Override
public void run() {
waitForAcknowledgement(matlabEvents);
}
};
try {
Future<?> task = service.submit(r);
task.get(timeout, TimeUnit.SECONDS);
System.out.println("Notification acknowledged.");
} catch (Exception e) {
e.printStackTrace();
}
}
private void waitForAcknowledgement(final Vector<MatlabEventObject> matlabEvents) {
boolean allEventsAcknowledged = false;
while(!allEventsAcknowledged) {
allEventsAcknowledged = true;
for(MatlabEventObject eventObject : matlabEvents) {
if(!eventObject.isAcknowledged()) {
allEventsAcknowledged = false;
}
break;
}
}
}
}
What happen is that I discover that Matlab actually WAIT for the java code to be completed. So my waitForAcknowledgement method always wait until it timeouts.
In addition, I must say that I have very little knowledge in parallel computing, but I think our java is single thread, so having java waiting for matlab code to complete while matlab is issuing calls to java functions may be an issue. But I can't be sure : ]
If you have any idea on how to solve this issue in a robust way, it will be much much appreciated.

Connecting android device using WiFi Direct

I am developing an application which first discover the peers in range and then connect with all of them one by one my function look like this:
void connectTo(WifiP2pDevice device) {
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
config.groupOwnerIntent=15;
wifiP2pManager.connect(wifiDirectChannel, config, actionListener);
wifiP2pManager.createGroup(wifiDirectChannel, actionListener);
}
But I don't know the difference between the connect and createGroup function of Wifip2pManager class. What's the core difference between them, Please help!
I know I am late to answer but I am sure it would help others. There is no need to createGroup, you simply need to call connect method in this way:
void connectTo(WifiP2pDevice device) {
WifiP2pConfig wifiP2pConfig = new WifiP2pConfig();
wifiP2pConfig.deviceAddress = device.deviceAddress;
wifiP2pConfig.groupOwnerIntent = 0;
wifiP2pConfig.wps.setup = WpsInfo.PBC;
if (wifiP2pManager != null) {
wifiP2pManager.connect(mChannel, wifiP2pConfig,
new ActionListener() {
#Override
public void onSuccess() {
// WiFiDirectBroadcastReceiver will notify us.
// Ignore for now.
Utility.showToast(
WifiP2PConnectionActivity.this,
Constants.CONNECTED);
}
#Override
public void onFailure(int reason) {
Utility.showToast(
WifiP2PConnectionActivity.this,
getErrorMessage(reason));
}
});
}
It will get connected now.
wifiP2pConfig.groupOwnerIntent = 0; is set to zero so that you allow other device to become owner and your own device as client everytime. groupOwnerIntent prioritices our own device priority to be lesser of becoming groupOwner. Rest is upto you how you want your device to behave.

How to extract audio from live video stream on Red5?

I need to extract audio from a live stream on red5 and stream it separately. On nginx with rtmp module I'd just retranslate this stream via ffmpeg without videodata, but I have no idea how to do anything like this (with or without ffmpeg) on Red5.
The first link on google gave me this:
just register IStreamListeners on your IClientStreams, and then separate AudioData from VideoData in the RTMPEvents
But this doesn't help much. To be honest, this doesn't help at all. What are these IStreamListeners and how do I register them on IClientStream?
And, what is more misterious, how do I separate AudioData from VideoData in some RTMPEvents?
This is how your extend RTMPClient and capture the Audio or Video events
private class TestClient extends RTMPClient {
private int audioCounter;
private int videoCounter;
public void connect() {
private IEventDispatcher streamEventDispatcher = new IEventDispatcher() {
public void dispatchEvent(IEvent event) {
System.out.println("ClientStream.dispachEvent()" + event.toString());
String evt = event.toString();
if (evt.indexOf("Audio") >= 0) {
audioCounter++;
} else if (evt.indexOf("Video") >= 0) {
videoCounter++;
}
}
};
}
}
This simply counts the a/v events, but it will get you part of the way there. I suggest looking though the unit tests in red5 and there you can learn a lot.

Categories

Resources