Skip to content

Commit a0dfb68

Browse files
authored
Fix tape realtime play (#265)
1 parent 203dcc7 commit a0dfb68

File tree

4 files changed

+36
-15
lines changed

4 files changed

+36
-15
lines changed

src/api/apiCore.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1258,7 +1258,7 @@ RGL_API rgl_status_t rgl_tape_play(const char* path)
12581258
throw RecordError("rgl_tape_play: recording active");
12591259
} else {
12601260
TapePlayer player(path);
1261-
player.playRealtime();
1261+
player.playApproximatelyRealtime();
12621262
}
12631263
});
12641264
#endif //_WIN32

src/tape/TapePlayer.cpp

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <filesystem>
1616
#include <fstream>
1717
#include <cassert>
18+
#include <thread>
1819

1920
#include <tape/TapePlayer.hpp>
2021
#include <tape/tapeDefinitions.hpp>
@@ -23,14 +24,11 @@
2324

2425
namespace fs = std::filesystem;
2526

26-
TapePlayer::TapePlayer(const char* path)
27+
TapePlayer::TapePlayer(const char* path) : path(path)
2728
{
28-
std::string pathYaml = fs::path(path).concat(YAML_EXTENSION).string();
29-
std::string pathBin = fs::path(path).concat(BIN_EXTENSION).string();
30-
31-
playbackState = std::make_unique<PlaybackState>(pathBin.c_str());
29+
playbackState = std::make_unique<PlaybackState>(getBinPath().c_str());
3230

33-
yamlRoot = YAML::LoadFile(pathYaml);
31+
yamlRoot = YAML::LoadFile(getYamlPath());
3432
if (yamlRoot.IsNull()) {
3533
throw RecordError("Invalid Tape: Empty YAML file detected");
3634
}
@@ -43,6 +41,10 @@ TapePlayer::TapePlayer(const char* path)
4341
nextCallIdx = 0;
4442
}
4543

44+
std::string TapePlayer::getBinPath() const { return fs::path(path).concat(BIN_EXTENSION).string(); }
45+
46+
std::string TapePlayer::getYamlPath() const { return fs::path(path).concat(YAML_EXTENSION).string(); }
47+
4648
void TapePlayer::checkTapeVersion()
4749
{
4850
auto versionCallIdx = findFirst({RGL_VERSION});
@@ -110,8 +112,6 @@ void TapePlayer::playUntil(std::optional<APICallIdx> breakpoint)
110112
}
111113
}
112114

113-
void TapePlayer::rewindTo(APICallIdx nextCall) { this->nextCallIdx = nextCall; }
114-
115115
void TapePlayer::playThis(APICallIdx idx)
116116
{
117117
const TapeCall& call = getTapeCall(idx);
@@ -121,15 +121,30 @@ void TapePlayer::playThis(APICallIdx idx)
121121
tapeFunctions[call.getFnName()](call.getArgsNode(), *playbackState);
122122
}
123123

124-
#include <thread>
125-
void TapePlayer::playRealtime()
124+
125+
void TapePlayer::playApproximatelyRealtime()
126126
{
127+
// Approximation comes from the fact that we don't account for the time it takes to execute the function
128+
// This could be fixed by moving TAPE_HOOK to the beginning of the API call
129+
// It might be a good idea to do so, because it would record failed calls.
127130
auto beginTimestamp = std::chrono::steady_clock::now();
128-
TapeCall nextCall = getTapeCall(nextCallIdx);
129131
for (; nextCallIdx < yamlRoot.size(); ++nextCallIdx) {
132+
TapeCall nextCall = getTapeCall(nextCallIdx);
130133
auto nextCallNs = std::chrono::nanoseconds(nextCall.getTimestamp().asNanoseconds());
131134
auto elapsed = std::chrono::steady_clock::now() - beginTimestamp;
132135
std::this_thread::sleep_for(nextCallNs - elapsed);
133136
playThis(nextCallIdx);
134137
}
135138
}
139+
140+
void TapePlayer::reset()
141+
{
142+
auto status = rgl_cleanup();
143+
if (status != RGL_SUCCESS) {
144+
const char* error = nullptr;
145+
rgl_get_last_error_string(&error);
146+
throw RecordError(fmt::format("Failed to reset playback state: {}", error));
147+
}
148+
nextCallIdx = 0;
149+
playbackState = std::make_unique<PlaybackState>(getBinPath().c_str());
150+
}

src/tape/TapePlayer.hpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,18 @@ struct TapePlayer
4646
void playThis(APICallIdx idx);
4747
void playThrough(APICallIdx last);
4848
void playUntil(std::optional<APICallIdx> breakpoint = std::nullopt);
49-
void playRealtime();
50-
void rewindTo(APICallIdx nextCall = 0);
49+
void playApproximatelyRealtime();
50+
void reset();
5151

5252
rgl_node_t getNodeHandle(TapeAPIObjectID key) { return playbackState->nodes.at(key); }
5353

5454
private:
5555
YAML::Node yamlRoot{};
5656
APICallIdx nextCallIdx{};
5757
std::unique_ptr<PlaybackState> playbackState;
58+
std::string path;
5859

5960
static inline std::map<std::string, TapeFunction> tapeFunctions = {};
61+
std::string getBinPath() const;
62+
std::string getYamlPath() const;
6063
};

tools/tapePlayer.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ int main(int argc, char** argv)
2222
return 1;
2323
}
2424
TapePlayer player{argv[1]};
25-
player.playUntil();
25+
while (true) {
26+
player.playApproximatelyRealtime();
27+
player.reset();
28+
}
2629
return 0;
2730
}

0 commit comments

Comments
 (0)