如何使用Java Android SDK做好的实时数据流
How to do good real-time data streaming using Java Android SDK
我有一个自制的蓝牙设备在500Hz测量心电图:每2毫秒设备发送9字节的数据(头部,ECG测量,页脚)。所以这大概是一个9*500=4.5kbytes/s的数据流。
我有一个c++ Windows程序能够连接设备和检索数据流(显示它与Qt/qwt)。在这种情况下,我使用Windows控制面板绑定设备,并使用boost serial_port接口通过虚拟COM端口连接它。这工作得很完美,我正在实时接收我的数据流:我每隔2毫秒左右得到一个测量点。
我通过QtCreator 3.0.1 (Qt 5.2.1)将整个程序移植到Android上。看起来虚拟COM端口不能被boost访问(可能SDK权限不允许),所以我写了一段Java代码来打开和管理蓝牙连接。所以我的应用程序仍然是c++/Qt,但只有从设备连接和读取数据的层在Java中重新设计(使用createInsecureRfcommSocketToServiceRecord打开连接):
读取数据的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;
}
从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;
}
这个工作得很好…的前五秒我得到的值在一种实时的,然后:
- 有时它永远冻结,这意味着mInputStream.available()的值仍然低于请求。
- 有时它只冻结一秒钟左右,然后继续,但数据被接收到~1秒的块。这意味着mInputStream.available()可以在两次调用之间从0移动到3000以上(耗时10ms)。实际上,我在前5秒看到了相同的情况,但缓冲区可用性从未超过150字节,5秒后,它可以达到3000字节。
下面是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
我的ECG设备肯定没有在11ms内发送1728字节!!
我知道我的设备每2ms发送9字节(否则,它将无法在我的PC应用程序上工作)。看起来Java做了一些意想不到的缓冲,并且没有每2ms提供9字节可用....而且奇怪的是,一开始只有5秒的时间可以正常工作。
请注意,我尝试使用read()而不检查available()(阻塞版本),但经历了完全相同的行为。
所以我想知道我做错了什么…
- 是否有一种方法来强制Java输入流更新自己?
- 是否有一种方法来要求Java继续它的未决事件(像我们有QApplication::processEvents)?
- 是否有任何全局设置来指定流的缓冲区大小(我没有在BluetoothDevice/BluetoothSocket级别找到任何) 在PC上,当打开虚拟COM端口时,我必须指定波特率,停止位,握手和类似的东西。在Android上,我只是打开Rfcomm套接字,没有选项,这可能是问题(然后ECG设备和智能手机将无法同步…)?
欢迎任何帮助或想法!
编辑:我在Nexus 5手机,Android 4.4.2上遇到了这个问题,我刚刚在不同的设备上测试了相同的apk包:
- 安装Android 4.4.2的Galaxy S4:同样的问题。
- 一个Galaxy S3与自定义CyanogenMod 11 Android 4.4.2:数据流似乎完美,没有冻结后5秒和数据实时到达....所以看起来整个系统能够实现我想要的,但看起来Android的默认设置使事情太慢....不知道是否可以在操作系统级别更改设置来解决这个问题。
编辑:因为我没有得到答案:-(我试图用一个纯Java程序做同样的事情(没有c++,没有Qt)。有同样的问题:Android上的实时蓝牙SPP数据流只能工作5秒
这个问题显然与这里报告的问题相似。
5秒后,我要么失去了连接,要么实时流急剧减慢。
正如这里所说的,Android>4.3显然不喜欢超过5秒的单向通信。所以我现在每隔1秒向设备发送一个虚拟命令(类似于"keep-alive"命令),现在Android很高兴,因为它不再是单向通信了……所以数据流在第五秒之后还是和之前一样好!
- 线程之间的实时数据共享
- 使来自线程的数据流对所有其他线程都可读
- 什么是 DirectX 9 中的数据流?
- 将数据流到字节数组中
- 如何将 Matlab 与 Visual Studio 连接以进行实时数据交换?
- C .exe在C#实时相机流应用程序中
- 使用 Python 连接到数据流
- 使用 N-API 将数据流式传输到 Node.js C++ 插件中
- 是否存在与将数据流式传输到 c++ 异常类相关的任何危险
- C++从 CSV 读取的实时数据
- 跨平台实时媒体流客户端
- 如何将数据流添加到具有FFmpeg和C / C++的MXF(使用mpeg2video)文件中
- C 中的数据流
- QTCharts,当实时数据进入时,我如何使图表遵循x轴
- 从QTcpSocket上的数据流中连续运行复杂算法的最佳Qt线程解决方案是什么
- 如何使用 c++ 实时数据增加 gnuplot 的绘图频率
- 将数据流式传输到 protobuf 解析器 c++
- 使用来自不同线程的实时数据更新QTableView的最佳策略
- 实时地理数据流分析
- 如何使用Java Android SDK做好的实时数据流