Skip to content

Commit ca63c5a

Browse files
Gustl22SNNafi
andauthored
refactor(windows): simplify position and duration processing (#1553)
# Description Use `double` for `position` and `duration` on windows implementation ## Related Issues Closes #1547 Co-authored-by: SNNAFI <shahriarnasim.nafi@gmail.com>
1 parent 125ed96 commit ca63c5a

10 files changed

Lines changed: 116 additions & 66 deletions

File tree

packages/audioplayers/example/integration_test/lib_test.dart

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,18 @@ void main() {
2828
source: UrlSource(wavUrl1),
2929
duration: const Duration(milliseconds: 451),
3030
);
31+
final mp3Url1TestData = LibSourceTestData(
32+
source: UrlSource(mp3Url1),
33+
duration: const Duration(minutes: 3, seconds: 30, milliseconds: 77),
34+
);
3135
final audioTestDataList = [
3236
if (features.hasUrlSource) wavUrl1TestData,
3337
if (features.hasUrlSource)
3438
LibSourceTestData(
3539
source: UrlSource(wavUrl2),
3640
duration: const Duration(seconds: 1, milliseconds: 068),
3741
),
38-
if (features.hasUrlSource)
39-
LibSourceTestData(
40-
source: UrlSource(mp3Url1),
41-
duration: const Duration(minutes: 3, seconds: 30, milliseconds: 77),
42-
),
42+
if (features.hasUrlSource) mp3Url1TestData,
4343
if (features.hasUrlSource)
4444
LibSourceTestData(
4545
source: UrlSource(mp3Url2),
@@ -393,6 +393,56 @@ void main() {
393393
}
394394
});
395395

396+
testWidgets('#seek with millisecond precision', (tester) async {
397+
final platform = AudioplayersPlatformInterface.instance;
398+
399+
final playerId = 'somePlayerId${isLinux ? linuxPlayerCount++ : ''}';
400+
await platform.create(playerId);
401+
402+
final preparedCompleter = Completer<void>();
403+
final eventStream = platform.getEventStream(playerId);
404+
final onPreparedSub = eventStream
405+
.where((event) => event.eventType == AudioEventType.prepared)
406+
.map((event) => event.isPrepared!)
407+
.listen(
408+
(isPrepared) {
409+
if (isPrepared) {
410+
preparedCompleter.complete();
411+
}
412+
},
413+
onError: preparedCompleter.completeError,
414+
);
415+
if (isLinux) {
416+
// FIXME(gustl22): Linux needs additional pump (#1507)
417+
await tester.pump();
418+
}
419+
await platform.setSourceUrl(
420+
playerId,
421+
(mp3Url1TestData.source as UrlSource).url,
422+
);
423+
await preparedCompleter.future.timeout(const Duration(seconds: 30));
424+
425+
final seekCompleter = Completer<void>();
426+
final onSeekSub = eventStream
427+
.where((event) => event.eventType == AudioEventType.seekComplete)
428+
.listen(
429+
(_) {
430+
seekCompleter.complete();
431+
},
432+
onError: seekCompleter.completeError,
433+
);
434+
await platform.seek(playerId, const Duration(milliseconds: 21));
435+
await seekCompleter.future.timeout(const Duration(seconds: 30));
436+
await onSeekSub.cancel();
437+
expect(await platform.getCurrentPosition(playerId), 21);
438+
439+
await onPreparedSub.cancel();
440+
if (!isLinux) {
441+
// FIXME(gustl22): Linux not disposing properly (#1507)
442+
await platform.dispose(playerId);
443+
}
444+
});
445+
396446
testWidgets('Set same source twice (#1520)', (tester) async {
397447
final platform = AudioplayersPlatformInterface.instance;
398448

packages/audioplayers/example/windows/runner/Runner.rc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,14 @@ IDI_APP_ICON ICON "resources\\app_icon.ico"
6060
// Version
6161
//
6262

63-
#ifdef FLUTTER_BUILD_NUMBER
64-
#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER
63+
#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD)
64+
#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD
6565
#else
66-
#define VERSION_AS_NUMBER 1,0,0
66+
#define VERSION_AS_NUMBER 1,0,0,0
6767
#endif
6868

69-
#ifdef FLUTTER_BUILD_NAME
70-
#define VERSION_AS_STRING #FLUTTER_BUILD_NAME
69+
#if defined(FLUTTER_VERSION)
70+
#define VERSION_AS_STRING FLUTTER_VERSION
7171
#else
7272
#define VERSION_AS_STRING "1.0.0"
7373
#endif

packages/audioplayers_windows/windows/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ add_library(${PLUGIN_NAME} SHARED
3333
"audioplayers_windows_plugin.cpp"
3434
"audio_player.h"
3535
"audio_player.cpp"
36+
"audioplayers_helpers.h"
3637
"event_stream_handler.h"
3738
"MediaEngineExtension.h"
3839
"MediaEngineExtension.cpp"

packages/audioplayers_windows/windows/MediaEngineWrapper.cpp

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "MediaEngineWrapper.h"
2020
#include "MediaFoundationHelpers.h"
21+
#include "audioplayers_helpers.h"
2122
#include <Audioclient.h>
2223

2324
using namespace Microsoft::WRL;
@@ -143,15 +144,14 @@ void MediaEngineWrapper::Shutdown()
143144
});
144145
}
145146

146-
void MediaEngineWrapper::StartPlayingFrom(uint64_t timeStamp)
147+
void MediaEngineWrapper::StartPlayingFrom(double timestampInSeconds)
147148
{
148149
RunSyncInMTA([&]()
149150
{
150151
auto lock = m_lock.lock();
151152
if (m_mediaEngine == nullptr) {
152153
return;
153154
}
154-
const double timestampInSeconds = ConvertHnsToSeconds(timeStamp);
155155
THROW_IF_FAILED(m_mediaEngine->SetCurrentTime(timestampInSeconds));
156156
THROW_IF_FAILED(m_mediaEngine->Play());
157157
});
@@ -233,52 +233,52 @@ bool MediaEngineWrapper::GetLooping()
233233
return looping;
234234
}
235235

236-
void MediaEngineWrapper::SeekTo(uint64_t timeStamp)
236+
void MediaEngineWrapper::SeekTo(double timestampInSeconds)
237237
{
238238
RunSyncInMTA([&]()
239239
{
240240
auto lock = m_lock.lock();
241241
if (m_mediaEngine == nullptr) {
242242
return;
243243
}
244-
const double timestampInSeconds = ConvertHnsToSeconds(timeStamp);
245244
THROW_IF_FAILED(m_mediaEngine->SetCurrentTime(timestampInSeconds));
246245
});
247246
}
248247

249-
uint64_t MediaEngineWrapper::GetMediaTime()
248+
// Get media time in seconds
249+
double MediaEngineWrapper::GetMediaTime()
250250
{
251-
uint64_t currentTimeInHns = 0;
251+
double currentTimeInSeconds = 0;
252252
RunSyncInMTA([&]()
253253
{
254254
auto lock = m_lock.lock();
255255
if (m_mediaEngine == nullptr) {
256256
return;
257257
}
258-
double currentTimeInSeconds = m_mediaEngine->GetCurrentTime();
259-
currentTimeInHns = ConvertSecondsToHns(currentTimeInSeconds);
258+
currentTimeInSeconds = m_mediaEngine->GetCurrentTime();
260259
});
261-
return currentTimeInHns;
260+
return currentTimeInSeconds;
262261
}
263262

264-
uint64_t MediaEngineWrapper::GetDuration()
263+
// Get duration in seconds
264+
double MediaEngineWrapper::GetDuration()
265265
{
266-
uint64_t durationInHns = 0;
266+
double durationInSeconds = 0;
267267
RunSyncInMTA([&]()
268268
{
269269
auto lock = m_lock.lock();
270270
if (m_mediaEngine == nullptr) {
271271
return;
272272
}
273-
double durationInSeconds = m_mediaEngine->GetDuration();
274-
durationInHns = ConvertSecondsToHns(durationInSeconds);
273+
durationInSeconds = m_mediaEngine->GetDuration();
275274
});
276-
return durationInHns;
275+
return durationInSeconds;
277276
}
278277

279-
std::vector<std::tuple<uint64_t, uint64_t>> MediaEngineWrapper::GetBufferedRanges()
278+
// Get buffered ranges in milliseconds
279+
std::vector<std::tuple<int64_t, int64_t>> MediaEngineWrapper::GetBufferedRanges()
280280
{
281-
std::vector<std::tuple<uint64_t, uint64_t>> result;
281+
std::vector<std::tuple<int64_t, int64_t>> result;
282282
RunSyncInMTA([&]()
283283
{
284284
auto lock = m_lock.lock();
@@ -296,7 +296,7 @@ std::vector<std::tuple<uint64_t, uint64_t>> MediaEngineWrapper::GetBufferedRange
296296
{
297297
mediaTimeRange->GetStart(i, &start);
298298
mediaTimeRange->GetEnd(i, &end);
299-
result.push_back(std::make_tuple(ConvertSecondsToHns(start), ConvertSecondsToHns(end)));
299+
result.push_back(std::make_tuple(ConvertSecondsToMs(start), ConvertSecondsToMs(end)));
300300
}
301301
});
302302
return result;

packages/audioplayers_windows/windows/MediaEngineWrapper.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,21 +43,21 @@ class MediaEngineWrapper : public winrt::implements<MediaEngineWrapper, IUnknown
4343
void Shutdown();
4444

4545
// Control various aspects of playback
46-
void StartPlayingFrom(uint64_t timeStamp);
46+
void StartPlayingFrom(double timestampInSeconds);
4747
void Resume();
4848
void SetPlaybackRate(double playbackRate);
4949
void SetVolume(float volume);
5050
void SetBalance(double balance);
5151
void SetLooping(bool isLooping);
52-
void SeekTo(uint64_t timeStamp);
52+
void SeekTo(double timeStamp);
5353

5454
// Query the current playback position
55-
uint64_t GetMediaTime();
56-
uint64_t GetDuration();
55+
double GetMediaTime();
56+
double GetDuration();
5757

5858
bool GetLooping();
5959

60-
std::vector<std::tuple<uint64_t, uint64_t>> GetBufferedRanges();
60+
std::vector<std::tuple<int64_t, int64_t>> GetBufferedRanges();
6161

6262
private:
6363
wil::critical_section m_lock;
@@ -80,4 +80,4 @@ class MediaEngineWrapper : public winrt::implements<MediaEngineWrapper, IUnknown
8080
void OnSeekCompleted();
8181
};
8282

83-
} // namespace media
83+
} // namespace media

packages/audioplayers_windows/windows/MediaFoundationHelpers.h

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -143,21 +143,4 @@ inline void RunSyncInMTA(std::function<void()> callback)
143143
}
144144
}
145145

146-
constexpr uint64_t c_hnsPerSecond = 10000000;
147-
148-
template<typename SecondsT>
149-
inline uint64_t ConvertSecondsToHns(SecondsT seconds)
150-
{
151-
if (isinf(seconds))
152-
return 0;
153-
return static_cast<uint64_t>(seconds * c_hnsPerSecond);
154-
}
155-
156-
template<typename HnsT>
157-
inline double ConvertHnsToSeconds(HnsT hns)
158-
{
159-
return static_cast<double>(hns) / c_hnsPerSecond;
160-
}
161-
162-
163-
} // namespace media
146+
} // namespace media

packages/audioplayers_windows/windows/audio_player.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include <shobjidl.h>
1010
#include <windows.h>
1111

12+
#include "audioplayers_helpers.h"
13+
1214
#undef GetCurrentTime
1315

1416
using namespace winrt;
@@ -145,8 +147,7 @@ void AudioPlayer::OnTimeUpdate() {
145147
flutter::EncodableValue("audio.onCurrentPosition")},
146148
{flutter::EncodableValue("value"),
147149
flutter::EncodableValue(
148-
(int64_t)m_mediaEngineWrapper->GetMediaTime() /
149-
10000)}})));
150+
ConvertSecondsToMs(m_mediaEngineWrapper->GetMediaTime()))}})));
150151
}
151152
}
152153

@@ -158,8 +159,7 @@ void AudioPlayer::OnDurationUpdate() {
158159
flutter::EncodableValue("audio.onDuration")},
159160
{flutter::EncodableValue("value"),
160161
flutter::EncodableValue(
161-
(int64_t)m_mediaEngineWrapper->GetDuration() /
162-
10000)}})));
162+
ConvertSecondsToMs(m_mediaEngineWrapper->GetDuration()))}})));
163163
}
164164
}
165165

@@ -236,12 +236,12 @@ void AudioPlayer::Resume() {
236236
OnDurationUpdate();
237237
}
238238

239-
int64_t AudioPlayer::GetPosition() {
239+
double AudioPlayer::GetPosition() {
240240
return m_mediaEngineWrapper->GetMediaTime();
241241
}
242242

243-
int64_t AudioPlayer::GetDuration() {
243+
double AudioPlayer::GetDuration() {
244244
return m_mediaEngineWrapper->GetDuration();
245245
}
246246

247-
void AudioPlayer::SeekTo(int64_t seek) { m_mediaEngineWrapper->SeekTo(seek); }
247+
void AudioPlayer::SeekTo(double seek) { m_mediaEngineWrapper->SeekTo(seek); }

packages/audioplayers_windows/windows/audio_player.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ class AudioPlayer {
6969

7070
bool GetLooping();
7171

72-
int64_t GetPosition();
72+
double GetPosition();
7373

74-
int64_t GetDuration();
74+
double GetDuration();
7575

76-
void SeekTo(int64_t seek);
76+
void SeekTo(double seek);
7777

7878
void SetSourceUrl(std::string url);
7979

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
constexpr int64_t c_msPerSecond = 1000;
2+
3+
template<typename SecondsT>
4+
inline int64_t ConvertSecondsToMs(SecondsT seconds)
5+
{
6+
if (isinf(seconds))
7+
return 0;
8+
return static_cast<int64_t>(seconds * c_msPerSecond);
9+
}
10+
11+
template<typename MsT>
12+
inline double ConvertMsToSeconds(MsT ms)
13+
{
14+
return static_cast<double>(ms) / c_msPerSecond;
15+
}

packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <sstream>
1717

1818
#include "audio_player.h"
19+
#include "audioplayers_helpers.h"
1920

2021
namespace {
2122

@@ -170,9 +171,9 @@ void AudioplayersWindowsPlugin::HandleMethodCall(
170171
player->SeekTo(0);
171172
result->Success(EncodableValue(1));
172173
} else if (method_call.method_name().compare("seek") == 0) {
173-
auto position = GetArgument<int>("position", args,
174-
(int)(player->GetPosition() / 10000));
175-
player->SeekTo(static_cast<int64_t>(position * 10000.0));
174+
auto positionInMs = GetArgument<int>("position", args,
175+
(int)ConvertSecondsToMs(player->GetPosition()));
176+
player->SeekTo(ConvertMsToSeconds(positionInMs));
176177
result->Success(EncodableValue(1));
177178
} else if (method_call.method_name().compare("setSourceUrl") == 0) {
178179
auto url = GetArgument<std::string>("url", args, std::string());
@@ -185,13 +186,13 @@ void AudioplayersWindowsPlugin::HandleMethodCall(
185186
std::thread(&AudioPlayer::SetSourceUrl, player, url).detach();
186187
result->Success(EncodableValue(1));
187188
} else if (method_call.method_name().compare("getDuration") == 0) {
188-
result->Success(EncodableValue(player->GetDuration() / 10000));
189+
result->Success(EncodableValue(ConvertSecondsToMs(player->GetDuration())));
189190
} else if (method_call.method_name().compare("setVolume") == 0) {
190191
auto volume = GetArgument<double>("volume", args, 1.0);
191192
player->SetVolume(volume);
192193
result->Success(EncodableValue(1));
193194
} else if (method_call.method_name().compare("getCurrentPosition") == 0) {
194-
result->Success(EncodableValue(player->GetPosition() / 10000));
195+
result->Success(EncodableValue(ConvertSecondsToMs(player->GetPosition())));
195196
} else if (method_call.method_name().compare("setPlaybackRate") == 0) {
196197
auto playbackRate = GetArgument<double>("playbackRate", args, 1.0);
197198
player->SetPlaybackSpeed(playbackRate);

0 commit comments

Comments
 (0)