OpenShot Library | libopenshot  0.2.4
AudioPlaybackThread.cpp
Go to the documentation of this file.
1 /**
2  * @file
3  * @brief Source file for AudioPlaybackThread class
4  * @author Duzy Chan <code@duzy.info>
5  * @author Jonathan Thomas <jonathan@openshot.org> *
6  *
7  * @ref License
8  */
9 
10 /* LICENSE
11  *
12  * Copyright (c) 2008-2019 OpenShot Studios, LLC
13  * <http://www.openshotstudios.com/>. This file is part of
14  * OpenShot Library (libopenshot), an open-source project dedicated to
15  * delivering high quality video editing and animation solutions to the
16  * world. For more information visit <http://www.openshot.org/>.
17  *
18  * OpenShot Library (libopenshot) is free software: you can redistribute it
19  * and/or modify it under the terms of the GNU Lesser General Public License
20  * as published by the Free Software Foundation, either version 3 of the
21  * License, or (at your option) any later version.
22  *
23  * OpenShot Library (libopenshot) is distributed in the hope that it will be
24  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26  * GNU Lesser General Public License for more details.
27  *
28  * You should have received a copy of the GNU Lesser General Public License
29  * along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
30  */
31 
32 #include "../../include/Qt/AudioPlaybackThread.h"
33 
34 namespace openshot
35 {
36 
37  // Global reference to device manager
38  AudioDeviceManagerSingleton *AudioDeviceManagerSingleton::m_pInstance = NULL;
39 
40  // Create or Get an instance of the device manager singleton
42  {
43  if (!m_pInstance) {
44  // Create the actual instance of device manager only once
45  m_pInstance = new AudioDeviceManagerSingleton;
46 
47  // Get preferred audio device name (if any)
48  juce::String preferred_audio_device = juce::String(Settings::Instance()->PLAYBACK_AUDIO_DEVICE_NAME.c_str());
49 
50  // Initialize audio device only 1 time
51  juce::String audio_error = m_pInstance->audioDeviceManager.initialise (
52  0, /* number of input channels */
53  2, /* number of output channels */
54  0, /* no XML settings.. */
55  true, /* select default device on failure */
56  preferred_audio_device /* preferredDefaultDeviceName */);
57 
58  // Persist any errors detected
59  if (audio_error.isNotEmpty()) {
60  m_pInstance->initialise_error = audio_error.toRawUTF8();
61  } else {
62  m_pInstance->initialise_error = "";
63  }
64 
65  // Get all audio device names
66  for (int i = 0; i < m_pInstance->audioDeviceManager.getAvailableDeviceTypes().size(); ++i)
67  {
68  const AudioIODeviceType* t = m_pInstance->audioDeviceManager.getAvailableDeviceTypes()[i];
69  const juce::StringArray deviceNames = t->getDeviceNames ();
70 
71  for (int j = 0; j < deviceNames.size (); ++j )
72  {
73  juce::String deviceName = deviceNames[j];
74  juce::String typeName = t->getTypeName();
75  openshot::AudioDeviceInfo deviceInfo = {deviceName.toRawUTF8(), typeName.toRawUTF8()};
76  m_pInstance->audio_device_names.push_back(deviceInfo);
77  }
78  }
79  }
80 
81  return m_pInstance;
82  }
83 
84  // Close audio device
86  {
87  // Close Audio Device
88  audioDeviceManager.closeAudioDevice();
89  audioDeviceManager.removeAllChangeListeners();
90  audioDeviceManager.dispatchPendingMessages();
91  }
92 
93  // Constructor
94  AudioPlaybackThread::AudioPlaybackThread()
95  : juce::Thread("audio-playback")
96  , player()
97  , transport()
98  , mixer()
99  , source(NULL)
100  , sampleRate(0.0)
101  , numChannels(0)
102  , buffer_size(12000)
103  , is_playing(false)
104  , time_thread("audio-buffer")
105  {
106  }
107 
108  // Destructor
109  AudioPlaybackThread::~AudioPlaybackThread()
110  {
111  }
112 
113  // Set the reader object
114  void AudioPlaybackThread::Reader(openshot::ReaderBase *reader) {
115  if (source)
116  source->Reader(reader);
117  else {
118  // Create new audio source reader
119  source = new AudioReaderSource(reader, 1, buffer_size);
120  source->setLooping(true); // prevent this source from terminating when it reaches the end
121  }
122 
123  // Set local vars
124  sampleRate = reader->info.sample_rate;
125  numChannels = reader->info.channels;
126 
127  // TODO: Update transport or audio source's sample rate, incase the sample rate
128  // is different than the original Reader
129 
130  // Mark as 'playing'
131  Play();
132  }
133 
134  // Get the current frame object (which is filling the buffer)
135  std::shared_ptr<openshot::Frame> AudioPlaybackThread::getFrame()
136  {
137  if (source) return source->getFrame();
138  return std::shared_ptr<openshot::Frame>();
139  }
140 
141  // Get the currently playing frame number
142  int64_t AudioPlaybackThread::getCurrentFramePosition()
143  {
144  return source ? source->getEstimatedFrame() : 0;
145  }
146 
147  // Seek the audio thread
148  void AudioPlaybackThread::Seek(int64_t new_position)
149  {
150  source->Seek(new_position);
151  }
152 
153  // Play the audio
154  void AudioPlaybackThread::Play() {
155  // Start playing
156  is_playing = true;
157  }
158 
159  // Stop the audio
160  void AudioPlaybackThread::Stop() {
161  // Stop playing
162  is_playing = false;
163  }
164 
165  // Start audio thread
166  void AudioPlaybackThread::run()
167  {
168  while (!threadShouldExit())
169  {
170  if (source && !transport.isPlaying() && is_playing) {
171 
172  // Start new audio device (or get existing one)
173  // Add callback
174  AudioDeviceManagerSingleton::Instance()->audioDeviceManager.addAudioCallback(&player);
175 
176  // Create TimeSliceThread for audio buffering
177  time_thread.startThread();
178 
179  // Connect source to transport
180  transport.setSource(
181  source,
182  buffer_size, // tells it to buffer this many samples ahead
183  &time_thread,
184  sampleRate,
185  numChannels);
186  transport.setPosition(0);
187  transport.setGain(1.0);
188 
189  // Connect transport to mixer and player
190  mixer.addInputSource(&transport, false);
191  player.setSource(&mixer);
192 
193  // Start the transport
194  transport.start();
195 
196  while (!threadShouldExit() && transport.isPlaying() && is_playing)
197  usleep(2500);
198 
199  // Stop audio and shutdown transport
200  Stop();
201  transport.stop();
202 
203  // Kill previous audio
204  transport.setSource(NULL);
205 
206  player.setSource(NULL);
207  AudioDeviceManagerSingleton::Instance()->audioDeviceManager.removeAudioCallback(&player);
208 
209  // Remove source
210  delete source;
211  source = NULL;
212 
213  // Stop time slice thread
214  time_thread.stopThread(-1);
215  }
216  }
217 
218  }
219 }
static AudioDeviceManagerSingleton * Instance()
Override with no channels and no preferred audio device.
void CloseAudioDevice()
Close audio device.
AudioDeviceManager audioDeviceManager
Public device manager property.
This abstract class is the base class, used by all readers in libopenshot.
Definition: ReaderBase.h:97
std::string initialise_error
Error found during JUCE initialise method.
std::vector< openshot::AudioDeviceInfo > audio_device_names
List of valid audio device names.
openshot::ReaderInfo info
Information about the current media file.
Definition: ReaderBase.h:111
This class is used to expose any ReaderBase derived class as an AudioSource in JUCE.
This namespace is the default namespace for all code in the openshot library.
Singleton wrapper for AudioDeviceManager (to prevent multiple instances).
static Settings * Instance()
Create or get an instance of this logger singleton (invoke the class with this method) ...
Definition: Settings.cpp:41
int channels
The number of audio channels used in the audio stream.
Definition: ReaderBase.h:83
int sample_rate
The number of audio samples per second (44100 is a common sample rate)
Definition: ReaderBase.h:82