1/*
2 * Copyright 2020 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "modules/skottie/include/Skottie.h"
9
10#include "tests/Test.h"
11
12using namespace skottie;
13using namespace skresources;
14
15DEF_TEST(Skottie_AudioLayer, r) {
16    static constexpr char json[] =
17        R"({
18             "v": "5.2.1",
19             "w": 100,
20             "h": 100,
21             "fr": 10,
22             "ip": 0,
23             "op": 100,
24             "assets": [
25               {
26                 "id": "audio_0",
27                 "p" : "audio.mp3",
28                 "u" : "assets/"
29               }
30             ],
31             "layers": [
32               {
33                 "ty"   : 6,
34                 "ind"  : 0,
35                 "ip"   : 20,
36                 "op"   : 70,
37                 "refId": "audio_0"
38               },
39               {
40                 "ty"   : 6,
41                 "ind"  : 0,
42                 "ip"   : 50,
43                 "op"   : 80,
44                 "refId": "audio_0"
45               },
46               {
47                 "ty": 1,
48                 "ip": 0,
49                 "op": 100,
50                 "sw": 100,
51                 "sh": 100,
52                 "sc": "#ffffff"
53               }
54             ]
55           })";
56
57    class MockTracker final : public ExternalTrackAsset {
58    public:
59        bool isPlaying()    const { return fCurrentTime >= 0; }
60        float currentTime() const { return fCurrentTime; }
61
62    private:
63        void seek(float t) override {
64            fCurrentTime = t;
65        }
66
67        float                     fCurrentTime = 0;
68    };
69
70    class MockResourceProvider final : public ResourceProvider {
71    public:
72        explicit MockResourceProvider(skiatest::Reporter* r) : fReporter(r) {}
73
74        const std::vector<sk_sp<MockTracker>>& tracks() const { return fTracks; }
75
76    private:
77        sk_sp<ExternalTrackAsset> loadAudioAsset(const char path[],
78                                                 const char name[],
79                                                 const char id[]) override {
80            REPORTER_ASSERT(fReporter, !strcmp(path, "assets/"));
81            REPORTER_ASSERT(fReporter, !strcmp(name, "audio.mp3"));
82            REPORTER_ASSERT(fReporter, !strcmp(id  , "audio_0"));
83
84            fTracks.push_back(sk_make_sp<MockTracker>());
85
86            return fTracks.back();
87        }
88
89        skiatest::Reporter*             fReporter;
90        std::vector<sk_sp<MockTracker>> fTracks;
91    };
92
93    SkMemoryStream stream(json, strlen(json));
94    auto rp = sk_make_sp<MockResourceProvider>(r);
95
96    auto skottie = skottie::Animation::Builder()
97            .setResourceProvider(rp)
98            .make(&stream);
99
100    const auto& tracks = rp->tracks();
101
102    REPORTER_ASSERT(r, skottie);
103    REPORTER_ASSERT(r, tracks.size() == 2);
104
105    skottie->seekFrame(0);
106    REPORTER_ASSERT(r, !tracks[0]->isPlaying());
107    REPORTER_ASSERT(r, !tracks[1]->isPlaying());
108
109    skottie->seekFrame(20);
110    REPORTER_ASSERT(r,  tracks[0]->isPlaying());
111    REPORTER_ASSERT(r, !tracks[1]->isPlaying());
112    REPORTER_ASSERT(r,  tracks[0]->currentTime() == 0);
113
114    skottie->seekFrame(50);
115    REPORTER_ASSERT(r, tracks[0]->isPlaying());
116    REPORTER_ASSERT(r, tracks[1]->isPlaying());
117    REPORTER_ASSERT(r, tracks[0]->currentTime() == 3);
118    REPORTER_ASSERT(r, tracks[1]->currentTime() == 0);
119
120    skottie->seekFrame(70);
121    REPORTER_ASSERT(r, tracks[0]->isPlaying());
122    REPORTER_ASSERT(r, tracks[1]->isPlaying());
123    REPORTER_ASSERT(r, tracks[0]->currentTime() == 5);
124    REPORTER_ASSERT(r, tracks[1]->currentTime() == 2);
125
126    skottie->seekFrame(80);
127    REPORTER_ASSERT(r, !tracks[0]->isPlaying());
128    REPORTER_ASSERT(r,  tracks[1]->isPlaying());
129    REPORTER_ASSERT(r,  tracks[1]->currentTime() == 3);
130
131    skottie->seekFrame(100);
132    REPORTER_ASSERT(r, !tracks[0]->isPlaying());
133    REPORTER_ASSERT(r, !tracks[1]->isPlaying());
134}
135