adb shell setprop debug.checkjni 1
adb shell setprop debug.mono.env MONO_LOG_LEVEL=info
adb shell setprop debug.mono.log gref,gc
And if none of the above helps:
adb shell setprop debug.mono.trace N:Your.App.Namespace
Undoing
adb shell setprop debug.checkjni 0
adb shell setprop debug.mono.env ''
adb shell setprop debug.mono.log ''
adb shell setprop debug.mono.trace ''
Showing posts with label Mono. Show all posts
Showing posts with label Mono. Show all posts
Wednesday, January 22, 2014
Monday, January 20, 2014
Goal: Cross platform (Android / iOS) WebRTC app using MVVMCross
I am attempting to port 2 Java apps that are part of the WebRTC code to Mono/C#.
The code is available on GitHub, it is still a fairly early version but it builds (there are some problems during run-time).
Project goals
- make an opensource viable implementation of WebRTC for use in Mono / Xamarin / .NET on Android and iOS
- make an implementation of a WebRTC UIView/Activity that can be re-used across Android and iOS with as little as possible modifications
- be able to share as much code as possible between the different platforms by utilizing PCL (portable class libraries) and MVVMCross
- all possible UI logic moved to a shared portable class library using MVVMCross ViewModels
- move the WebRTC signaling behind to an interface located in a portable class library with an reference implementation, allowing people to reuse signaling code across platforms, while still implementing their own.
- in time write a new similar native interface as the JNI for Java but without JNI and directly targeting being invoked using P/Invoke / Mono / .NET allowing C#/Mono to directly interact with the C/C++ WebRTC library (see related question at Mono-JNI-Performance)
At least one of these goals are outside my comfort zone (#6), and all of them are currently pending, I believe #1 is well in progress.
Currently I am still in the progress of getting the actual WebRTC meeting working. I believe I have a problem in the converted signaling code, which I am trying to track down.
GitHub repositories
appspotdemo-mono (this is the repository that I am focusing my immediate attention on - but I have been short on time lately)
Background for the webrtc-app-mono repository:
When I built the native .so (http://kenneththorman. blogspot.dk/2014/01/webrtc- app-c-xamarin-part-1-building. html) it also build a full android apk that you can install and test. That was the app I already tried on my devices which worked the same way as apprtc.appspot.com. That that was the code I was actually looking for, and as embarrassing it is to admit it - the repo https://github.com/ kenneththorman/webrtc-app-mono was me porting the "wrong" Java app code. When I found out and figured out how to work with JNI (mainly through using the Java Binding Library) I went looking in the official WebRTC code again to find the app that I tested in the Java version. This is the repo at https://github.com/ kenneththorman/appspotdemo- mono. So basically having 2 repositories are proof of me not being familiar with the official WebRTC code base and not really knowing what code is which.
Any help or suggestions are welcome, please feel free to fork, create issues or communicate here and I will do my best to answer.
References
Blog postings describing my finding while porting webrtc-app-mono can be found at
- WebRTC app - C# / Xamarin - Part #1 - Building platform native webrtc library
- WebRTC app - C# / Xamarin - Part #2 - Attempt #1 - failure to using a JNI .so file directly from C# / Mono
- WebRTC app - C# / Xamarin - Part #2 - Attempt #2 - success using a JNI .so file from C# / Mono
- WebRTC app - C# / Xamarin - (C# - JNI - C/C++) - Summary and GitHub repository
Monday, June 03, 2013
Xamarin Mono.Droid Receiving different bluetooth devices data records
When you are working with several different Bluetooth devices (from different manufacturers) you will have to be able to handle different types of data records. The official Android Bluetooth sample ported for Xamarin/Mono.Droid can be found at BluetoothChatService.cs. This was the code I used for inspiration when I built this app.
I could however not really get the code to work as I wanted and the problem was located in the following method Run().
What I discovered while testing was that for some devices it was working out of the box with the default code in the Run method above. However on some more complex devices which were sending larger data records back, it never seemed to work.
After spending some time analyzing the problem - being new to the bluetooth scene and Mono.Droid development - I found that data records got chopped into pieces in the while(true) loop in the above Run() method. Assuming that a full data record was 65 bytes, sometimes the code would pass 13 bytes to the SendToTarget() method. The next iteration might yield 31 bytes and the last 21 bytes was yielded on the 3rd pass.
The number of bytes returned on each iteration was never the same and there was no specific pattern to this. To be able to handle this for different devices sending data in different ways I needed some kind of smart buffering. I came up with the following.
In the handler that handles the read bytes I changed the implementation from what can be found here BluetoothChat.cs.
. The interface IDeviceResponseParser looks like the following
I could however not really get the code to work as I wanted and the problem was located in the following method Run().
public override void Run ()
{
Log.Info (TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.Read (buffer, 0, buffer.Length);
// Send the obtained bytes to the UI Activity
_handler.ObtainMessage (BluetoothChat.MESSAGE_READ, bytes, -1, buffer)
.SendToTarget ();
} catch (Java.IO.IOException e) {
Log.Error (TAG, "disconnected", e);
_service.ConnectionLost ();
break;
}
}
}
The problem is the following call
// Send the obtained bytes to the UI Activity _handler.ObtainMessage (BluetoothChat.MESSAGE_READ, bytes, -1, buffer).SendToTarget ();which might not always send back the entire device record to the handler. This is caused by the various devices implementation of how to send the data record back as a byte stream to the mobile device/phone might not finish, before the while loop is starting another iteration, as well as the multithreading and the context switches that occurs in the BluetoothChatService.
What I discovered while testing was that for some devices it was working out of the box with the default code in the Run method above. However on some more complex devices which were sending larger data records back, it never seemed to work.
After spending some time analyzing the problem - being new to the bluetooth scene and Mono.Droid development - I found that data records got chopped into pieces in the while(true) loop in the above Run() method. Assuming that a full data record was 65 bytes, sometimes the code would pass 13 bytes to the SendToTarget() method. The next iteration might yield 31 bytes and the last 21 bytes was yielded on the 3rd pass.
The number of bytes returned on each iteration was never the same and there was no specific pattern to this. To be able to handle this for different devices sending data in different ways I needed some kind of smart buffering. I came up with the following.
public override void Run ()
{
Log.Info (TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.Read(buffer, 0, buffer.Length);
var messagePart = new byte[bytes];
Array.Copy(buffer,messagePart, bytes);
// Send the obtained bytes to the UI Activity
_handler.ObtainMessage(MESSAGE_READ, bytes, -1, messagePart)
.SendToTarget();
} catch (Java.IO.IOException e) {
Log.Error (TAG, "disconnected", e);
_service.ConnectionLost ();
break;
}
}
}
The new code is only a little bit different in that I am no longer sending back the buffer but instead only the partial message (messagePart).In the handler that handles the read bytes I changed the implementation from what can be found here BluetoothChat.cs.
case MESSAGE_READ: byte[] readBuf = (byte[])msg.Obj; // construct a string from the valid bytes in the buffer var readMessage = new Java.Lang.String (readBuf, 0, msg.Arg1); bluetoothChat.conversationArrayAdapter.Add (bluetoothChat.connectedDeviceName + ": " + readMessage); break;to the following code
case BluetoothService.MESSAGE_READ: byte[] readBuf = (byte[])msg.Obj; ParseBluetoothDeviceReading(readBuf); break;and the ParseBluetoothDeviceReading() method looking like this
public void ParseBluetoothDeviceReading (byte[] readBuffer)
{
if (readBuffer == null || readBuffer.Length <= 0)
return;
var deviceRecord = _zephyrResponseParser.ParseDeviceResponse(readBuffer);
_data.LungFunction= deviceRecord.LungFunction;
lblValue.Text = deviceRecord.LungFunction.ToString("0.00");
}
the data record buffer is implemented in the _zephyrResponseParser which is of type IDeviceResponseParserpublic interface IDeviceResponseParser<TDataRecord>
{
TDataRecord ParseDeviceResponse(byte[] response);
}
and finally the actual device specific data record parser for the zephyr device.using System.Collections.Generic;
namespace Droid.Devices.Zephyr
{
public class ZephyrResponseParser : IDeviceResponseParser<ZephyrRecord>
{
public const int DeviceMessageLength = 65;
private List<byte> _messageBuffer = new List<byte>();
public ZephyrRecord ParseDeviceResponse(byte[] response)
{
// Since the data (byte[]) that we are getting is retreived from a BluetoothNetworkStream there are no guarantees that we will get the full message in one go.
// For that reason we need to buffer it our selves until whe have a full message
_messageBuffer.AddRange(response);
if (_messageBuffer.Count < DeviceMessageLength)
{
// Not full message return
return new ZephyrRecord();
}
// Full message, pass on to temp so we can reset the local messageBuffer for the next
// device message
var temp = _messageBuffer.ToArray();
// Reset buffer
_messageBuffer.Clear();
// Now process the full message
response = temp;
if (response.Length >= DeviceMessageLength)
{
var deviceRecord = ExtractDataFromRawByteStream();
return new ZephyrRecord { LungFunction = deviceRecord.LungFunction };
}
return new ZephyrRecord();
}
}
...
public class ZephyrRecord
{
public float LungFunction { get; set; }
}
}
This has proven to work so far, without any known problems, for several different devices that are working very differently, has different manufacturers and are measuring different medical parameters.
Subscribe to:
Posts (Atom)