【问题标题】:How can I sync the system clocks of two or more android phones?如何同步两部或多部安卓手机的系统时钟?
【发布时间】:2017-03-13 08:14:45
【问题描述】:

我正在尝试开发一个应用程序,它允许其他安卓手机充当扬声器,从而创建一个类似派对的东西。该应用程序将类似于三星提供的群组游戏功能。

为了实现这个功能,我决定执行以下步骤 -

  1. 主机创建热点并在热点上发布党名并等待连接。
  2. 客户端现在可以在列表视图中查看可用的参与方名称并选择要连接的参与方。
  3. 一旦主机和客户端之间的连接建立,主机将被定向到出现歌曲列表的活动。主持人选择其中一首歌曲。
  4. 使用套接字编程将所选歌曲传输到客户端并保存在文件夹中。
  5. 之后,主机获取当前系统时间并将其增加 5 秒,并将此秒数发送给客户端。例如 - 10:35 - 当前时间。嗯,我们会在 10:40 玩
  6. 主机发送完时间并且客户端收到时间后,它们都会创建一个警报,触发它们开始使用媒体播放器播放 MP3 文件。

**面临的问题 - ** 实现此功能后,我注意到两个 Android 设备的系统时间不同,因此我使用 ClockSync 应用程序同步系统时间,该应用程序使用 NTP 同步时间。 我不希望我的用户使用需要 root 访问权限的第三方应用程序。那么如何同步两部安卓手机的时钟呢? 我该如何解决这个问题?

编辑 - 我使用AsyncTask下面的类来计算NTP时钟和本地时钟之间的差异。

public class offSetAsyncTask extends AsyncTask<Void,Void,Double> {

private String serverName;
private double localClockOffset;
private double destinationTimestamp;
private double roundTripDelay;
double total = 0;
Context context;
double avg;

@Override
protected Double doInBackground(Void... params) {


    getAllForMe();
    getAllForMe();
    getAllForMe();
    getAllForMe();
    getAllForMe();

    System.out.println("!!!!!!!" + total);
    avg = total/5;
    System.out.println("~~~avg. Lag: " +  avg);

    response.processFinish(avg);

    return avg;
}

public interface AsyncResponse{
    void processFinish(double offSet);
}

public AsyncResponse response = null;


public offSetAsyncTask(AsyncResponse res, String name, Context c){
    response = res;
    serverName = name;
    context = c;
}

private void getAllForMe(){

    try{
        DatagramSocket socket = new DatagramSocket();
        InetAddress address = InetAddress.getByName(serverName);
        byte[] buf = new NtpMessage().toByteArray();
        DatagramPacket packet =
                new DatagramPacket(buf, buf.length, address, 123);

        // Set the transmit timestamp *just* before sending the packet
        // ToDo: Does this actually improve performance or not?
        NtpMessage.encodeTimestamp(packet.getData(), 40,
                (System.currentTimeMillis()/1000.0) + 2208988800.0);

        socket.send(packet);


        // Get response
        System.out.println("NTP request sent, waiting for response...\n");
        packet = new DatagramPacket(buf, buf.length);
        socket.receive(packet);

        // Immediately record the incoming timestamp
        destinationTimestamp =
                (System.currentTimeMillis()/1000.0) + 2208988800.0;


        // Process response
        NtpMessage msg = new NtpMessage(packet.getData());

        // Corrected, according to RFC2030 errata
        roundTripDelay = (destinationTimestamp-msg.originateTimestamp) -
                (msg.transmitTimestamp-msg.receiveTimestamp);

        localClockOffset =
                ((msg.receiveTimestamp - msg.originateTimestamp) +
                        (msg.transmitTimestamp - destinationTimestamp)) / 2;

        total+=localClockOffset;

        // Display response
        System.out.println("NTP server: " + serverName);
        System.out.println(msg.toString());

        System.out.println("Dest. timestamp:     " +
                NtpMessage.timestampToString(destinationTimestamp));

        System.out.println("Round-trip delay: " +
                new DecimalFormat("0.00").format(roundTripDelay*1000) + " ms");

        System.out.println("Local clock offset: " +
                new DecimalFormat("0.00").format(localClockOffset*1000) + " ms");

        socket.close();
    } catch (Exception e){
        e.printStackTrace();
    }
    }

}

【问题讨论】:

  • 我认为你最初关于音频播放同步的问题实际上更好的是不是XY problem。从您的问题中仍然不清楚您当前在代码中的方法到底有什么问题。您似乎在每台设备上都有localClockOffset
  • 是的。我们在每个设备上都有本地偏移量。但我们仍然会延迟 0.3-0.5 秒。
  • @SergGr 你有更好的方法来同步两部手机之间的播放吗?
  • 对不起,我还是不明白。您在什么和什么之间“仍然有 0.3-0.5 秒的延迟”?你到底是怎么使用localClockOffset的?
  • @SergGr 我们正在使用警报管理器来触发媒体播放器开始在每台设备上播放歌曲。由于每个设备都有不同的系统时间,我们使用偏移量和它们的系统时间让设备等待某个时间,例如晚上 10:45,然后当闹钟响起时,媒体播放开始。

标签: android networking android-mediaplayer ntp


【解决方案1】:

那么如何同步两部安卓手机的时钟呢?我该如何解决这个问题?

从概念上讲,您可以跳过同步系统时钟,而只需确定相对偏移和漂移。在论文Tiny-Sync: Tight Time Synchronization for Wireless Sensor Networks中,作者首先将节点i的时间描述为

ti (t) = ai t + bi

根据 UTCt

其中ai和bi是节点i时钟的漂移和偏移量。

由此,您可以将节点 1 的时间 t1 表示为节点 2 的时间 t2,为

t1 (t) = a12 t2 (t) + b12

为了估计这些系数,发送消息,如下所示:

每个消息发送者都会添加一个时间戳。只需两个数据点,就可以估计两个节点的偏移和漂移,并使用基于树的方法来同步节点网络。

截至发稿,

算法提供了很好的 精度(如果精心制作,则为微秒)并限制使用时的精度 资源非常有限,[强调我的]

【讨论】:

    【解决方案2】:

    如果可以接受,我认为我们应该换个角度——我们可以让每个设备与外部源同步,而不是针对A == B(并且必须手动考虑偏移和延迟)来相互同步设备(服务器)因为如果A == CB == C 然后A == B

    您的用例将类似于:

    1. 主机创建热点并发布 (...)
    2. 客户端现在可以看到可用方 (...)
    3. 一旦主机和客户端之间的连接建立(...)
    4. 所选歌曲被传输到客户端 (...)
    5. 每个客户端/主机都与服务器联系以获取“正确”时间
    6. 存储接收时间与设备时间之间的偏移量
    7. 客户端向主机广播时间已对齐
    8. 当所有客户端都标记时间对齐后,主机广播所需的开始时间
    9. 当客户端收到请求的开始时间时,他们使用他们存储的偏移量来根据他们的设备系统时间计算开始时间
    10. 在计算出的时间开始播放

    如果您只需要精确到一分钟内,public api 已经存在。否则服务器将是您自己创建的私有端点。

    注意:由于您的目标似乎是同步播放,并且不同的设备会有不同的性能,因此您需要在播放开始之前完全准备(加载/缓冲)媒体播放器。可能在收到歌曲后立即同步时间之前

    【讨论】:

    • 这是鸟瞰的答案,我更详细地详细介绍了步骤 5 到 8。
    猜你喜欢
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 2017-08-06
    • 1970-01-01
    • 1970-01-01
    • 2015-12-24
    • 2015-06-03
    • 1970-01-01
    相关资源
    最近更新 更多