summaryrefslogtreecommitdiffstats
path: root/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastPositionTransferTest.java
blob: ff44b17c761026ddcf00f348fb534973278ab6a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.media.remote;

import android.graphics.Rect;
import android.test.suitebuilder.annotation.LargeTest;

import org.chromium.base.test.util.DisabledTest;
import org.chromium.base.test.util.Feature;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.content.browser.test.util.JavaScriptUtils;

import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * Tests related to the transfer of the playback position between the local and
 * the remote player.
 */
public class CastPositionTransferTest extends CastTestBase {

    /** Reference position in the video where we should start casting */
    private static final int CAST_START_TIME_MS = 3000;

    /** Max accepted error for position comparisons. */
    private static final int SEEK_EPSILON_MS = 250;

    /** Used to wait for the UI to properly respond. It is smaller than the default
     * {@link CastTestBase#STABILIZE_TIME_MS} to make sure the video doesn't finish while waiting.*/
    private static final int SMALL_STABILIZE_TIME_MS = 250;


    /** Returns the current time of the video, in milliseconds,  by getting it from JavaScript. */
    private static long getLocalPositionMillis(Tab tab, String videoElementId)
            throws InterruptedException, TimeoutException, NumberFormatException {
        StringBuilder sb = new StringBuilder();
        sb.append("(function() {");
        sb.append("  var node = document.getElementById('" + videoElementId + "');");
        sb.append("  if (node) return node.currentTime;");
        sb.append("  return null");
        sb.append("})();");
        String jsResult = JavaScriptUtils.executeJavaScriptAndWaitForResult(
                tab.getWebContents(), sb.toString());
        return Math.round(Double.parseDouble(jsResult) * 1000);
    }

    private static void seekFromJS(Tab tab, long seekToMs)
            throws InterruptedException, TimeoutException, NumberFormatException {
        final long seekToSec = TimeUnit.MILLISECONDS.toSeconds(seekToMs);
        StringBuilder sb = new StringBuilder();
        sb.append("(function() {");
        sb.append("  var node = document.getElementById('" + VIDEO_ELEMENT + "');");
        sb.append("  if (node) node.currentTime = " + seekToSec + ";");
        sb.append("  return 0;");
        sb.append("})();");
        JavaScriptUtils.executeJavaScriptAndWaitForResult(tab.getWebContents(), sb.toString());
    }

    /** Test for crbug.com/428409 */
    @DisabledTest
//  BUG:http://crbug/517597
//    @Feature({"VideoFling"})
//    @LargeTest
    public void testLocalToRemotePositionTransfer() throws InterruptedException, TimeoutException {
        final Tab tab = getActivity().getActivityTab();
        final Rect videoRect = prepareDefaultVideofromPage(DEFAULT_VIDEO_PAGE, tab);

        // Jump to the position
        seekFromJS(tab, CAST_START_TIME_MS);
        final double localPositionMs = getLocalPositionMillis(tab, VIDEO_ELEMENT);
        assertTrue("Local playback position (" + localPositionMs + ") did not advance past "
                + CAST_START_TIME_MS, localPositionMs >= CAST_START_TIME_MS);

        // Start cast
        final long castStartTimeMs = new Date().getTime();
        castVideoAndWaitUntilPlaying(CAST_TEST_ROUTE, tab, videoRect);

        // Test the position
        final long remotePositionMs = getRemotePositionMs();
        final long castDelayMs = new Date().getTime() - castStartTimeMs;

        assertTrue("The remote playback position (" + remotePositionMs + ") did not advance past "
                + CAST_START_TIME_MS, remotePositionMs >= CAST_START_TIME_MS);
        assertTrue("The remote playback position (" + remotePositionMs + ") went too far.",
                remotePositionMs <= CAST_START_TIME_MS + castDelayMs);
    }

    /** Test for crbug.com/428409 */
    @Feature({"VideoFling"})
    @LargeTest
    public void testRemoteToLocalPositionTransfer() throws InterruptedException, TimeoutException {
        final Tab tab = getActivity().getActivityTab();
        final Rect videoRect = prepareDefaultVideofromPage(DEFAULT_VIDEO_PAGE, tab);

        // Start cast
        castVideoAndWaitUntilPlaying(CAST_TEST_ROUTE, tab, videoRect);

        tapPlayPauseButton(tab, videoRect);
        int pausePosition = getRemotePositionMs();
        for (int time = 0; time < MAX_VIEW_TIME_MS; time += VIEW_RETRY_MS) {
            Thread.sleep(VIEW_RETRY_MS);
            int newPosition = getRemotePositionMs();
            if (newPosition == pausePosition) {
                break;
            }
            pausePosition = newPosition;
        }
        // Jump to the position
        seekFromJS(tab, CAST_START_TIME_MS);
        for (int time = 0; time < MAX_VIEW_TIME_MS
                && getRemotePositionMs() != pausePosition; time += VIEW_RETRY_MS) {
            Thread.sleep(VIEW_RETRY_MS);
        }
        int remotePositionMs = getRemotePositionMs();
        assertEquals("The remote player did not seek",
                CAST_START_TIME_MS, remotePositionMs, SEEK_EPSILON_MS);

        // Stop cast and play locally
        final long castStopTimeMs = new Date().getTime();
        clickDisconnectFromRoute(tab, videoRect);
        tapPlayPauseButton(tab, videoRect);
        sleepNoThrow(SMALL_STABILIZE_TIME_MS);

        // Test the position
        final double localPositionMs = getLocalPositionMillis(tab, VIDEO_ELEMENT);
        final long castDelayMs = new Date().getTime() - castStopTimeMs;
        assertTrue("The local playback position (" + localPositionMs + ") did not advance past "
                + CAST_START_TIME_MS, localPositionMs >= CAST_START_TIME_MS);
        assertTrue("The local playback position (" + localPositionMs + ") went too far.",
                localPositionMs <= CAST_START_TIME_MS + castDelayMs);
    }

    /** Test for crbug.com/425105 */
    @Feature({"VideoFling"})
    @LargeTest
    public void testPositionUpdate() throws InterruptedException, TimeoutException {
        final Tab tab = getActivity().getActivityTab();
        final Rect videoRect = prepareDefaultVideofromPage(DEFAULT_VIDEO_PAGE, tab);
        castVideoAndWaitUntilPlaying(CAST_TEST_ROUTE, tab, videoRect);

        sleepNoThrow(CAST_START_TIME_MS);

        final long remotePositionMs = getRemotePositionMs();
        final long localPositionMs = getLocalPositionMillis(tab, VIDEO_ELEMENT);

        assertEquals("Remote playback position was not properly updated.",
                CAST_START_TIME_MS, remotePositionMs, SEEK_EPSILON_MS);
        assertEquals("The remote playback position was updated, but the local one was not.",
                CAST_START_TIME_MS, localPositionMs, SEEK_EPSILON_MS);
    }
}