17 #include "../ReaderBase.h"
18 #include "../RendererBase.h"
19 #include "../AudioReaderSource.h"
20 #include "../AudioDevices.h"
21 #include "../Settings.h"
22 #include "../ZmqLogger.h"
28 #include <condition_variable>
36 AudioDeviceManagerSingleton *AudioDeviceManagerSingleton::m_pInstance = NULL;
41 return AudioDeviceManagerSingleton::Instance(44100, 2);
47 static std::mutex mutex;
48 std::lock_guard<std::mutex> lock(mutex);
54 AudioIODevice *foundAudioIODevice = NULL;
55 m_pInstance->initialise_error =
"";
56 m_pInstance->currentAudioDevice.name =
"";
57 m_pInstance->currentAudioDevice.type =
"";
58 m_pInstance->defaultSampleRate = 0.0;
60 std::stringstream constructor_title;
61 constructor_title <<
"AudioDeviceManagerSingleton::Instance (default audio device type: " <<
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);
68 Settings::Instance()->PLAYBACK_AUDIO_DEVICE_NAME};
71 if (requested_device.
type.isEmpty() && !requested_device.
name.isEmpty()) {
72 for (
const auto t : mgr->getAvailableDeviceTypes()) {
74 for (
const auto n : t->getDeviceNames()) {
75 if (requested_device.
name.trim().equalsIgnoreCase(n.trim())) {
76 requested_device.
type = t->getTypeName();
84 std::vector<openshot::AudioDeviceInfo> devices{ { requested_device } };
85 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);
91 for (
const auto n : t->getDeviceNames()) {
93 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);
101 for (
auto attempt_device : devices) {
102 m_pInstance->currentAudioDevice = attempt_device;
105 m_pInstance->audioDeviceManager.initialiseWithDefaultDevices(0, channels);
108 if (!attempt_device.type.isEmpty()) {
109 m_pInstance->audioDeviceManager.setCurrentAudioDeviceType(attempt_device.type,
true);
113 AudioDeviceManager::AudioDeviceSetup deviceSetup = AudioDeviceManager::AudioDeviceSetup();
114 deviceSetup.inputChannels = 0;
115 deviceSetup.outputChannels = channels;
116 deviceSetup.bufferSize = Settings::Instance()->PLAYBACK_AUDIO_BUFFER_SIZE;
121 int possible_rates[] { rate, 48000, 44100, 22050 };
122 for(
int attempt_rate : possible_rates) {
123 std::stringstream title_rate;
124 title_rate <<
"AudioDeviceManagerSingleton::Instance (attempt audio device name: " << attempt_device.name <<
")";
125 ZmqLogger::Instance()->AppendDebugMethod(title_rate.str(),
"rate", attempt_rate,
"channels", channels);
128 m_pInstance->defaultSampleRate = attempt_rate;
129 deviceSetup.sampleRate = attempt_rate;
130 m_pInstance->audioDeviceManager.setAudioDeviceSetup(deviceSetup,
true);
134 juce::String audio_error = m_pInstance->audioDeviceManager.initialise(
144 m_pInstance->initialise_error = audio_error.toStdString();
146 if (!m_pInstance->initialise_error.empty()) {
147 std::stringstream title_error;
148 title_error <<
"AudioDeviceManagerSingleton::Instance (audio device error: " <<
149 m_pInstance->initialise_error <<
")";
150 ZmqLogger::Instance()->AppendDebugMethod(title_error.str(),
"rate", attempt_rate,
"channels", channels);
155 foundAudioIODevice = m_pInstance->audioDeviceManager.getCurrentAudioDevice();
156 if (foundAudioIODevice && foundAudioIODevice->getCurrentSampleRate() == attempt_rate) {
158 std::stringstream title_found;
159 title_found <<
"AudioDeviceManagerSingleton::Instance (successful audio device found: " <<
160 foundAudioIODevice->getTypeName() <<
", name: " << foundAudioIODevice->getName() <<
")";
161 ZmqLogger::Instance()->AppendDebugMethod(title_found.str(),
"rate", attempt_rate,
"channels", channels);
166 if (foundAudioIODevice) {
172 ZmqLogger::Instance()->AppendDebugMethod(
"AudioDeviceManagerSingleton::Instance (audio device initialization completed)");
178 void AudioDeviceManagerSingleton::CloseAudioDevice()
181 audioDeviceManager.closeAudioDevice();
182 audioDeviceManager.removeAllChangeListeners();
183 audioDeviceManager.dispatchPendingMessages();
191 :
juce::Thread(
"audio-playback")
199 , time_thread(
"audio-buffer")
205 AudioPlaybackThread::~AudioPlaybackThread()
215 auto starting_frame = 1;
216 source =
new AudioReaderSource(reader, starting_frame);
233 std::shared_ptr<openshot::Frame> AudioPlaybackThread::getFrame()
235 if (source)
return source->
getFrame();
236 return std::shared_ptr<openshot::Frame>();
240 void AudioPlaybackThread::Seek(int64_t new_position)
243 source->
Seek(new_position);
248 void AudioPlaybackThread::Play() {
250 NotifyTransportStateChanged();
253 void AudioPlaybackThread::Stop() {
255 NotifyTransportStateChanged();
258 void AudioPlaybackThread::NotifyTransportStateChanged()
260 std::lock_guard<std::mutex> lock(transportMutex);
261 transportCondition.notify_all();
265 void AudioPlaybackThread::run()
267 while (!threadShouldExit())
269 if (source && !transport.isPlaying() && is_playing) {
271 AudioDeviceManagerSingleton *audioInstance =
275 audioInstance->audioDeviceManager.addAudioCallback(&player);
278 time_thread.startThread(Priority::high);
287 transport.setPosition(0);
288 transport.setGain(1.0);
291 mixer.addInputSource(&transport,
false);
292 player.setSource(&mixer);
297 while (!threadShouldExit() && transport.isPlaying() && is_playing) {
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;
310 transport.setSource(NULL);
312 player.setSource(NULL);
313 audioInstance->audioDeviceManager.removeAudioCallback(&player);
320 time_thread.stopThread(-1);