Skip to content

Commit 1107e9f

Browse files
authored
Merge pull request #983 from OpenShot/recovery-menu
Fix for Windows 11 Audio Lag
2 parents 09ca2ce + db73d22 commit 1107e9f

File tree

11 files changed

+57
-30
lines changed

11 files changed

+57
-30
lines changed

.gitlab-ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ mac-builder:
5252
- unzip artifacts.zip
5353
- export LIBOPENSHOT_AUDIO_DIR=$CI_PROJECT_DIR/build/install-x64
5454
- mkdir -p build; cd build;
55-
- cmake -DCMAKE_EXE_LINKER_FLAGS="-stdlib=libc++" -DCMAKE_SHARED_LINKER_FLAGS="-stdlib=libc++" -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR/build/install-x64" -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -D"CMAKE_BUILD_TYPE:STRING=Release" -D"CMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk" -D"CMAKE_OSX_DEPLOYMENT_TARGET=10.9" -DCMAKE_PREFIX_PATH=/usr/local/qt5.15.X/qt5.15/5.15.0/clang_64/ -D"CMAKE_INSTALL_RPATH_USE_LINK_PATH=1" -D"ENABLE_RUBY=0" ../
55+
- cmake -DCMAKE_EXE_LINKER_FLAGS="-stdlib=libc++" -DCMAKE_SHARED_LINKER_FLAGS="-stdlib=libc++" -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -D"CMAKE_INSTALL_PREFIX:PATH=$CI_PROJECT_DIR/build/install-x64" -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -D"CMAKE_BUILD_TYPE:STRING=Release" -D"CMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk" -D"CMAKE_OSX_DEPLOYMENT_TARGET=10.12" -DCMAKE_PREFIX_PATH=/usr/local/qt5.15.X/qt5.15/5.15.0/clang_64/ -D"CMAKE_INSTALL_RPATH_USE_LINK_PATH=1" -D"ENABLE_RUBY=0" ../
5656
- make -j 9
5757
- make install
5858
- PROJECT_VERSION=$(grep -E '^set\(PROJECT_VERSION_FULL "(.*)' ../CMakeLists.txt | awk '{print $2}' | tr -d '")')
@@ -122,7 +122,7 @@ trigger-pipeline:
122122
stage: trigger-openshot-qt
123123
script:
124124
- "curl -X POST -F token=$OPENSHOT_QT_PIPELINE_TOKEN -F ref=$CI_COMMIT_REF_NAME http://gitlab.openshot.org/api/v4/projects/3/trigger/pipeline"
125-
when: always
125+
when: on_success
126126
dependencies: []
127127
except:
128128
- tags

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ if ((${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") AND
9797
endif()
9898

9999
#### Set C++ standard level
100-
set(CMAKE_CXX_STANDARD 14)
100+
set(CMAKE_CXX_STANDARD 17)
101101
set(CMAKE_CXX_STANDARD_REQUIRED ON)
102102
set(CMAKE_CXX_EXTENSIONS OFF)
103103

src/AudioReaderSource.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include "Exceptions.h"
1515
#include "Frame.h"
1616

17-
1817
using namespace std;
1918
using namespace openshot;
2019

@@ -43,7 +42,6 @@ void AudioReaderSource::getNextAudioBlock(const juce::AudioSourceChannelInfo& in
4342
}
4443

4544
while (remaining_samples > 0) {
46-
4745
try {
4846
// Get current frame object
4947
if (reader) {

src/Qt/AudioPlaybackThread.cpp

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include <thread> // for std::this_thread::sleep_for
2626
#include <chrono> // for std::chrono::milliseconds
2727
#include <sstream>
28+
#include <condition_variable>
29+
#include <mutex>
2830

2931
using namespace juce;
3032

@@ -57,9 +59,9 @@ namespace openshot
5759

5860
std::stringstream constructor_title;
5961
constructor_title << "AudioDeviceManagerSingleton::Instance (default audio device type: " <<
60-
Settings::Instance()->PLAYBACK_AUDIO_DEVICE_TYPE << ", default audio device name: " <<
61-
Settings::Instance()->PLAYBACK_AUDIO_DEVICE_NAME << ")";
62-
ZmqLogger::Instance()->AppendDebugMethod(constructor_title.str(), "channels", channels);
62+
Settings::Instance()->PLAYBACK_AUDIO_DEVICE_TYPE << ", default audio device name: " <<
63+
Settings::Instance()->PLAYBACK_AUDIO_DEVICE_NAME << ")";
64+
ZmqLogger::Instance()->AppendDebugMethod(constructor_title.str(), "channels", channels, "buffer", Settings::Instance()->PLAYBACK_AUDIO_BUFFER_SIZE);
6365

6466
// Get preferred audio device type and name (if any - these can be blank)
6567
openshot::AudioDeviceInfo requested_device = {Settings::Instance()->PLAYBACK_AUDIO_DEVICE_TYPE,
@@ -81,10 +83,17 @@ namespace openshot
8183
// Populate all possible device types and device names (starting with the user's requested settings)
8284
std::vector<openshot::AudioDeviceInfo> devices{ { requested_device } };
8385
for (const auto t : mgr->getAvailableDeviceTypes()) {
86+
std::stringstream type_debug;
87+
type_debug << "AudioDeviceManagerSingleton::Instance (iterate audio device type: " << t->getTypeName() << ")";
88+
ZmqLogger::Instance()->AppendDebugMethod(type_debug.str(), "rate", rate, "channels", channels);
89+
8490
t->scanForDevices();
8591
for (const auto n : t->getDeviceNames()) {
8692
AudioDeviceInfo device = { t->getTypeName(), n.trim() };
8793
devices.push_back(device);
94+
std::stringstream device_debug;
95+
device_debug << "AudioDeviceManagerSingleton::Instance (iterate audio device name: " << device.name << ", type: " << t->getTypeName() << ")";
96+
ZmqLogger::Instance()->AppendDebugMethod(device_debug.str(), "rate", rate, "channels", channels);
8897
}
8998
}
9099

@@ -104,6 +113,7 @@ namespace openshot
104113
AudioDeviceManager::AudioDeviceSetup deviceSetup = AudioDeviceManager::AudioDeviceSetup();
105114
deviceSetup.inputChannels = 0;
106115
deviceSetup.outputChannels = channels;
116+
deviceSetup.bufferSize = Settings::Instance()->PLAYBACK_AUDIO_BUFFER_SIZE;
107117

108118
// Loop through common sample rates, starting with the user's requested rate
109119
// Not all sample rates are supported by audio devices, for example, many VMs
@@ -234,16 +244,21 @@ namespace openshot
234244
}
235245
}
236246

237-
// Play the audio
247+
// Override Play and Stop to notify of state changes
238248
void AudioPlaybackThread::Play() {
239-
// Start playing
240249
is_playing = true;
250+
NotifyTransportStateChanged();
241251
}
242252

243-
// Stop the audio
244253
void AudioPlaybackThread::Stop() {
245-
// Stop playing
246254
is_playing = false;
255+
NotifyTransportStateChanged();
256+
}
257+
258+
void AudioPlaybackThread::NotifyTransportStateChanged()
259+
{
260+
std::lock_guard<std::mutex> lock(transportMutex);
261+
transportCondition.notify_all();
247262
}
248263

249264
// Start audio thread
@@ -260,7 +275,7 @@ namespace openshot
260275
audioInstance->audioDeviceManager.addAudioCallback(&player);
261276

262277
// Create TimeSliceThread for audio buffering
263-
time_thread.startThread();
278+
time_thread.startThread(Priority::high);
264279

265280
// Connect source to transport
266281
transport.setSource(
@@ -279,8 +294,13 @@ namespace openshot
279294
// Start the transport
280295
transport.start();
281296

282-
while (!threadShouldExit() && transport.isPlaying() && is_playing)
283-
std::this_thread::sleep_for(std::chrono::milliseconds(2));
297+
while (!threadShouldExit() && transport.isPlaying() && is_playing) {
298+
// Wait until transport state changes or thread should exit
299+
std::unique_lock<std::mutex> lock(transportMutex);
300+
transportCondition.wait_for(lock, std::chrono::milliseconds(10), [this]() {
301+
return threadShouldExit() || !transport.isPlaying() || !is_playing;
302+
});
303+
}
284304

285305
// Stop audio and shutdown transport
286306
Stop();

src/Qt/AudioPlaybackThread.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,17 @@ class AudioDeviceManagerSingleton {
8686
bool is_playing;
8787
juce::TimeSliceThread time_thread;
8888
openshot::VideoCacheThread *videoCache; /// The cache thread (for pre-roll checking)
89+
std::mutex transportMutex;
90+
std::condition_variable transportCondition;
8991

9092
/// Constructor
9193
AudioPlaybackThread(openshot::VideoCacheThread* cache);
9294
/// Destructor
9395
~AudioPlaybackThread();
9496

97+
/// Notify all
98+
void NotifyTransportStateChanged();
99+
95100
/// Set the current thread's reader
96101
void Reader(openshot::ReaderBase *reader);
97102

src/Qt/PlayerPrivate.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ namespace openshot
4949

5050
// Start the threads
5151
if (reader->info.has_audio)
52-
audioPlayback->startThread(8);
52+
audioPlayback->startThread(Priority::high);
5353
if (reader->info.has_video) {
54-
videoCache->startThread(2);
55-
videoPlayback->startThread(4);
54+
videoCache->startThread(Priority::high);
55+
videoPlayback->startThread(Priority::high);
5656
}
5757

5858
using std::chrono::duration_cast;
@@ -179,7 +179,7 @@ namespace openshot
179179
if (video_position < 0) return false;
180180

181181
stopPlayback();
182-
startThread(1);
182+
startThread(Priority::high);
183183
return true;
184184
}
185185

src/Settings.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ namespace openshot {
103103
/// The device type for the playback audio devices
104104
std::string PLAYBACK_AUDIO_DEVICE_TYPE = "";
105105

106+
/// Size of playback buffer before audio playback starts
107+
int PLAYBACK_AUDIO_BUFFER_SIZE = 512;
108+
106109
/// The current install path of OpenShot (needs to be set when using Timeline(path), since certain
107110
/// paths depend on the location of OpenShot transitions and files)
108111
std::string PATH_OPENSHOT_INSTALL = "";

src/Timeline.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ double Timeline::GetMinTime() {
482482
int64_t Timeline::GetMinFrame() {
483483
double fps = info.fps.ToDouble();
484484
auto min_time = GetMinTime();
485-
return std::round(min_time * fps);
485+
return std::round(min_time * fps) + 1;
486486
}
487487

488488
// Apply a FrameMapper to a clip which matches the settings of this timeline

src/Timeline.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ namespace openshot {
289289

290290
/// Look up the position/start time of the first timeline element
291291
double GetMinTime();
292-
/// Look up the start frame number of the first element on the timeline
292+
/// Look up the start frame number of the first element on the timeline (first frame is 1)
293293
int64_t GetMinFrame();
294294

295295
/// Close the timeline reader (and any resources it was consuming)

src/effects/ObjectDetection.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,8 @@ void ObjectDetection::SetJsonValue(const Json::Value root) {
411411
QString qClassFilter = QString::fromStdString(root["class_filter"].asString());
412412

413413
// Split the QString by commas and automatically trim each resulting string
414-
QStringList classList = qClassFilter.split(',', QString::SkipEmptyParts);
414+
QStringList classList = qClassFilter.split(',');
415+
classList.removeAll(""); // Skip empty parts
415416
display_classes.clear();
416417

417418
// Iterate over the QStringList and add each trimmed, non-empty string

0 commit comments

Comments
 (0)