[英]How to do good real-time data streaming using Java Android SDK
I have a home-made bluetooth device measuring ECG at 500Hz: every 2 ms the device sends 9 bytes of data (header, ECG measurment, footer). 我有一个自制的蓝牙设备,以500Hz的频率测量ECG:每2毫秒该设备发送9字节的数据(标头,ECG测量,页脚)。 So this is roughly a 9*500=4.5kbytes/s data stream. 因此,这大约是9 * 500 = 4.5kbytes / s的数据流。
I have a C++ Windows program able to connect the device and retrieve the data stream (displaying it with Qt/qwt). 我有一个能够连接设备并检索数据流(使用Qt / qwt显示)的C ++ Windows程序。 In this case, I use Windows control panel to bond the device and I connect it via a virtual COM port using boost serial_port interface. 在这种情况下,我使用Windows控制面板绑定设备,并使用boost serial_port接口通过虚拟COM端口将其连接。 This works perfectly and I'm receiving my data stream in real time: I get a measurment point every 2ms or so. 这非常有效,并且我正在实时接收数据流:每2毫秒左右获得一个测量点。
I ported the whole program on Android via QtCreator 3.0.1 (Qt 5.2.1). 我通过QtCreator 3.0.1(Qt 5.2.1)在Android上移植了整个程序。 It appears that virtual COM ports cannot be accessed by boost (probably SDK permissions won't allow that) so I wrote a piece of Java code to open and manage the Bluetooth connection. 似乎虚拟COM端口无法通过boost访问(可能是SDK权限不允许这样做),所以我写了一段Java代码来打开和管理蓝牙连接。 So my app remains C++/Qt but only the layer connecting and reading data from the device was reworked in Java (opening the connexion with createInsecureRfcommSocketToServiceRecord): 因此,我的应用程序仍然是C ++ / Qt,但是在Java中仅对连接和从设备读取数据的层进行了重新处理(使用createInsecureRfcommSocketToServiceRecord打开连接):
Java code to read the data: Java代码读取数据:
public int readData( byte[] buffer )
{
if( mInputStream == null )
{
traceErrorString("No connection, can't receive data");
}
else
{
try
{
final boolean verbose = false;
int available = mInputStream.available();
if ( verbose )
{
Calendar c = Calendar.getInstance();
Date date = new Date();
c.setTime(date);
c.get(Calendar.MILLISECOND);
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
String currentTime = sdf.format(date);
traceDebugString( currentTime + ":" + c.get(Calendar.MILLISECOND) + " - " + available + " bytes available, requested " + buffer.length );
}
if ( available >= buffer.length )
return mInputStream.read( buffer ); // only call read if we know it's not blocking
else
return 0;
}
catch (IOException e)
{
traceDebugString( "Failed to read data...disconnected?" );
}
}
return -1;
}
Called from C++ like that: 像这样从C ++调用:
bool ReceiveData( JNIEnv* env,
char* data,
size_t length,
bool& haserror )
{
bool result = false;
jbyteArray array = env->NewByteArray(length);
jint res = env->CallIntMethod(j_object, s_patchIfReceiveDataID, array );
if ( static_cast<size_t>(res) == length )
{
env->GetByteArrayRegion(array, 0, length, reinterpret_cast<jbyte*>(data));
result = true;
}
else if ( res == -1 )
{
haserror = true;
}
else
{
// not enough data in the stream buffer
haserror = false;
}
return result;
}
bool readThread( size_t blockSize )
{
BTGETANDCHECKENV // retrieving environment
char* buf = new char[blockSize];
bool haserror = false;
while ( !haserror )
{
if ( !ReceiveData( env, buf, blockSize, haserror ) )
{
// could not read data
if ( haserror )
{
// will stop this thread soon
}
else
{
boost::this_thread::sleep( boost::posix_time::milliseconds( 10 ) );
}
}
}
delete [] buf;
return true;
}
This works pretty well... for the five first seconds I'm gettings values in a sort of real time, then: 这很好用... 在头五个秒中,我实时获取了值,然后:
Here is what the log can look like when verbose is set to true: 将verbose设置为true时,日志如下所示:
14:59:30:756 - 0 bytes available, requested 3
14:59:30:767 - 0 bytes available, requested 3
14:59:30:778 - 0 bytes available, requested 3
14:59:30:789 - 1728 bytes available, requested 3
14:59:30:790 - 1725 bytes available, requested 6
14:59:30:792 - 1719 bytes available, requested 3
My ECG device definitely did not send 1728 bytes in 11ms!! 我的ECG设备绝对没有在11毫秒内发送1728字节!
I know my device sends 9 bytes every 2ms (otherwise, it would not work on my PC application). 我知道我的设备每2ms发送9个字节(否则,它将无法在我的PC应用程序上运行)。 Looks like Java does some unexpected buffering and does not make available 9 bytes every 2ms.... It's also strange things appear to work fine for only 5 seconds at the beginning. 看起来Java进行了一些意外的缓冲,并且每2ms不会提供9个字节。...奇怪的是,开始时仅5秒钟就可以正常工作。
Note that I tried using read() without checking available() (blocking version) but experienced exactly the same behaviour. 请注意,我尝试使用read()而不检查available()(阻止版本),但是体验完全相同。
So I'm wondering what I'm doing wrong... 所以我想知道我在做什么错...
Any help or idea would be welcomed! 任何帮助或想法都将受到欢迎!
Edit: I'm experiencing that on a Nexus 5 phone, Android 4.4.2 I just tested the same apk package on different devices: 编辑:我在Nexus 5手机,Android 4.4.2上遇到了这个问题,我刚刚在不同设备上测试了相同的apk软件包:
Edit: As I got no answer :-( I tried to do the same thing using a pure Java program (no C++, no Qt). Had the same problem: Real-time Bluetooth SPP data streaming on Android only works for 5 seconds 编辑:因为我没有答案:-(我试图使用纯Java程序(没有C ++,没有Qt)做同样的事情。有同样的问题: Android上的实时蓝牙SPP数据流只能工作5秒钟
This problem is apparently similar to the one reported here . 这个问题显然类似于这里报告的问题 。
After 5 seconds, I had either a connection lost, either real-time streaming being dramatically slow down. 5秒后,我要么失去了连接,要么实时流变得非常慢。
As said here Android >4.3 apparently does not like one-way communication exceeding 5 secondes. 如此处所述, Android> 4.3显然不喜欢超过5秒的单向通信。 So I'm now sending a dummy command to the device every 1 seconde (kind of "keep-alive" command) and now Android is happy because it's not a one-way communication anymore...and so data streaming is as good after the fifth second than before! 因此,我现在每隔1秒向设备发送一个虚拟命令(有点“保持活动”命令),现在Android感到很高兴,因为它不再是单向通信了……因此,数据流同样好第五秒比以前!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.