如何使用Java Android SDK中做好实时数据流 [英] How to do good real-time data streaming using Java Android SDK

查看:235
本文介绍了如何使用Java Android SDK中做好实时数据流的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个自制的蓝牙设备测量心电图在500Hz的:每2毫秒设备发送9个字节的数据(头,心电measurment,页脚)。因此,这是一个大致9 * 500 = 4.5kbytes / s的数据流。

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). So this is roughly a 9*500=4.5kbytes/s data stream.

我有一个C ++ Windows程序能够连接设备和检索数据流(使用Qt / QWT显示它)。在这种情况下,我使用的是Windows控制面板粘合装置,我使用boost serial_port接口,通过虚拟COM端口连接。这完美的作品,我收到我的数据流进行实时:我得到一个measurment点每2ms左右

I have a C++ Windows program able to connect the device and retrieve the data stream (displaying it with Qt/qwt). 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. This works perfectly and I'm receiving my data stream in real time: I get a measurment point every 2ms or so.

我通过QtCreator 3.0.1(Qt的5.2.1)移植整个程序在Android上。看来,虚拟COM端口不能被提升访问(可能SDK权限将不会允许),所以我写了一篇Java的code打开和管理蓝牙连接。所以,我的应用程序仍然是C ++ / Qt的,但只有在连接并读取设备数据的层返工的Java(开放与createInsecureRfcommSocketToServiceRecord了连接):

I ported the whole program on Android via QtCreator 3.0.1 (Qt 5.2.1). 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. 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):

Java的code读取数据:

Java code to read the data:

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 ++调用这样的:

Called from C++ like that:

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;
}

这适用于五个第一秒我gettings值排序的实时,那么pretty的好...

This works pretty well...for the five first seconds I'm gettings values in a sort of real time, then:

  • 有时冻结,直到永远,这意味着mInputStream.available()值仍低于要求。
  • 有时冻结只为一秒钟左右,然后将其继续,但数据由1〜第二块被接收。含义mInputStream.available()可以从0移动到超过3000两个呼叫(由10毫秒后)之间。事实上,我看到相同的过程中5首创秒,但缓冲可用性决不会超过150个字节,5秒钟后,它可以达到3000个字节。

下面是日志可以查看哪些详细当设置为true,如:

Here is what the log can look like when verbose is set to 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

我的心电图设备绝对没有在11毫秒发送1728个字节!

My ECG device definitely did not send 1728 bytes in 11ms!!

我知道我的设备发送9个字节每2ms(否则,它不会对我的PC应用程序的工作)。看起来像Java做一些意想不到的缓冲,不会使现有9个字节每2ms .... 这也是奇怪的事情出现在开头做工精细的只有5秒。

I know my device sends 9 bytes every 2ms (otherwise, it would not work on my PC application). 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.

请注意,我试图使用的read()不检查可用()(堵版),但经历了完全一样的行为。

Note that I tried using read() without checking available() (blocking version) but experienced exactly the same behaviour.

所以,我不知道我在做什么错了......

So I'm wondering what I'm doing wrong...

  • 有没有办法强制Java输入流进行自我更新?
  • 有没有办法问Java来进行它的未完成的事件(像我们的QApplication :: processEvents)?
  • 有没有全局设置,以指定缓冲区大小溪流(我没有发现任何在BluetoothDevice类/的BluetoothSocket级)
  • 在PC上,打开虚拟COM端口的时候,我必须指定波特率,停止位,握手之类的东西。在Android上我刚打开RFCOMM插座没办法,难道这是问题(当时的心电图设备和智能手机将不会同步...)?

任何帮助或想法将受到欢迎!

Any help or idea would be welcomed!

编辑:我遇到的一台Nexus 5的手机,安卓4.4.2我只是测试相同的APK包在不同设备上:

I'm experiencing that on a Nexus 5 phone, Android 4.4.2 I just tested the same apk package on different devices:

  • 银河S4采用Android 4.4.2:同样的问题
  • 银河S3自定义的CyanogenMod 11的Andr​​oid 4.4.2:数据流似乎完美,5秒和数据到达的实时后....不结冰使看起来像整个系统能够达到我想要的,但看起来像Android的默认设置使事情变得太慢....说不上来,如果有可能是一个设置在操作系统层面来解决这个问题而改变。

编辑:由于我没有答案:-(我试图用纯Java程序(没有C ++,没有Qt的)做同样的事情有同样的问题:<一href="http://stackoverflow.com/questions/27229813/real-time-bluetooth-spp-data-streaming-on-android-only-works-for-5-seconds">Real-time蓝牙SPP数据流在Android上只能持续5秒

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

推荐答案

这个问题显然是一个类似报道这里

This problem is apparently similar to the one reported here.

5秒后,我无论是连接丢失,无论是实时流是显着放缓。

After 5 seconds, I had either a connection lost, either real-time streaming being dramatically slow down.

正如所说这里的Andr​​oid> 4.3显然不喜欢单向通信超过5 secondes。所以,我现在发送假命令,设备每隔1 Seconde系列(一种保持活跃命令),现在Android是幸福的,因为它不是一个单向通信了......等等的数据流是经过好第五第二比以前!

As said here Android >4.3 apparently does not like one-way communication exceeding 5 secondes. 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!

这篇关于如何使用Java Android SDK中做好实时数据流的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆