MythTV master
audioplayer.cpp
Go to the documentation of this file.
1// C++ headers
2#include <algorithm>
3
8
9#include "audioplayer.h"
10#include "mythplayer.h"
12
13#define LOC QString("AudioPlayer: ")
14
15//static const QString _Location = AudioPlayer::tr("Audio Player");
16
18 : m_parent(parent),
19 m_mutedOnCreation(muted)
20{
21 m_controlsVolume = gCoreContext->GetBoolSetting("MythControlsVolume", true);
22}
23
25{
27 m_visuals.clear();
28}
29
31{
32 if (!m_audioOutput)
33 return;
34
35 QMutexLocker lock(&m_lock);
36#ifdef __cpp_lib_ranges_contains
37 if (!std::ranges::contains(m_visuals, vis))
38#else
39 auto it = std::ranges::find(m_visuals, vis);
40 if (it == m_visuals.end())
41#endif
42 {
43 m_visuals.push_back(vis);
45 }
46}
47
49{
50 if (!m_audioOutput)
51 return;
52
53 QMutexLocker lock(&m_lock);
54 auto it = std::ranges::find(m_visuals, vis);
55 if (it != m_visuals.end())
56 {
57 m_visuals.erase(it);
59 }
60}
61
63{
64 if (!m_audioOutput)
65 return;
66
67 QMutexLocker lock(&m_lock);
68 for (auto & visual : m_visuals)
69 m_audioOutput->addVisual(visual);
70}
71
73{
74 if (!m_audioOutput)
75 return;
76
77 QMutexLocker lock(&m_lock);
78 for (auto & visual : m_visuals)
80}
81
83{
84 if (!m_audioOutput)
85 return;
86
87 QMutexLocker lock(&m_lock);
88 for (auto & visual : m_visuals)
89 visual->prepare();
90}
91
93{
94 if (!m_audioOutput)
95 return;
96
97 QMutexLocker lock(&m_lock);
99}
100
102{
104 QMutexLocker locker(&m_lock);
105 if (m_audioOutput)
106 {
107 delete m_audioOutput;
108 m_audioOutput = nullptr;
109 }
110 m_noAudioOut = true;
111}
112
114{
115 bool want_audio = m_parent->IsAudioNeeded();
116 QString errMsg;
117 QMutexLocker lock(&m_lock);
118
120 m_noAudioIn = m_noAudioOut = true;
121 else
122 m_noAudioIn = false;
123
124 if (want_audio && !m_audioOutput)
125 {
126 // AudioOutput has never been created and we will want audio
132 if (m_noAudioIn)
133 aos.m_init = false;
134
136 if (m_audioOutput == nullptr)
137 {
138 errMsg = tr("Unable to create AudioOutput.");
139 }
140 else if (aos.m_init && !m_audioOutput->isConfigured())
141 {
142 errMsg = tr("AudioOutput has not been successfully configured.");
143 }
144 AddVisuals();
145 }
146 else if (!m_noAudioIn && m_audioOutput)
147 {
151 m_audioOutput->Reconfigure(settings);
153 {
154 errMsg = tr("AudioOutput has not been successfully configured.");
155 }
157 }
158
159 if (!errMsg.isEmpty())
160 {
161 LOG(VB_GENERAL, LOG_NOTICE, LOC + "Disabling Audio" +
162 QString(", reason is: %1").arg(errMsg));
163 ShowNotificationError(tr("Disabling Audio"),
164 AudioPlayer::tr( "Audio Player" ), errMsg);
165 m_noAudioOut = true;
166 }
167 else if (m_noAudioOut && m_audioOutput)
168 {
169 LOG(VB_GENERAL, LOG_NOTICE, LOC + "Enabling Audio");
170 m_noAudioOut = false;
171 }
172
174 {
176 m_mutedOnCreation = false;
177 }
178
179 ResetVisuals();
180
181 return errMsg;
182}
183
185{
187 m_noAudioIn = m_noAudioOut = true;
188}
189
190bool AudioPlayer::Pause(bool pause)
191{
193 return false;
194
195 QMutexLocker lock(&m_lock);
196 m_audioOutput->Pause(pause);
197 return true;
198}
199
201{
203 return false;
204 QMutexLocker lock(&m_lock);
205 return m_audioOutput->IsPaused();
206}
207
209{
211 return;
212 QMutexLocker lock(&m_lock);
214}
215
217{
218 // delete current audio class if any
219 DeleteOutput();
220 m_lock.lock();
221 m_audioOutput = ao;
222 AddVisuals();
223 m_lock.unlock();
224}
225
227{
229 return 0;
230 QMutexLocker lock(&m_lock);
232}
233
238void AudioPlayer::SetAudioInfo(const QString &main_device,
239 const QString &passthru_device,
240 uint samplerate,
241 int codec_profile)
242{
243 m_mainDevice.clear();
244 m_passthruDevice.clear();
245 if (!main_device.isEmpty())
246 m_mainDevice = main_device;
247 if (!passthru_device.isEmpty())
248 m_passthruDevice = passthru_device;
249 m_state.m_sampleRate = static_cast<int>(samplerate);
250 m_state.m_codecProfile = codec_profile;
252}
253
258void AudioPlayer::SetAudioParams(AudioFormat format, int orig_channels,
259 int channels, AVCodecID codec,
260 int samplerate, bool passthru,
261 int codec_profile)
262{
263 m_state.m_format = CanProcess(format) ? format : FORMAT_S16;
264 m_state.m_origChannels = orig_channels;
265 m_state.m_channels = channels;
266 m_state.m_codec = codec;
267 m_state.m_sampleRate = samplerate;
268 m_state.m_passthru = passthru;
269 m_state.m_codecProfile = codec_profile;
270 ResetVisuals();
272}
273
274void AudioPlayer::SetEffDsp(int dsprate)
275{
277 return;
278 QMutexLocker lock(&m_lock);
279 m_audioOutput->SetEffDsp(dsprate);
280}
281
283{
284 bool is_muted = IsMuted();
285 QMutexLocker lock(&m_lock);
286
287 if (m_audioOutput && !m_noAudioOut && !is_muted && mute &&
289 {
290 LOG(VB_AUDIO, LOG_INFO, QString("muting sound %1").arg(IsMuted()));
291 return true;
292 }
293 if (m_audioOutput && !m_noAudioOut && is_muted && !mute &&
295 {
296 LOG(VB_AUDIO, LOG_INFO, QString("unmuting sound %1").arg(IsMuted()));
297 return true;
298 }
299
300 LOG(VB_AUDIO, LOG_ERR,
301 QString("not changing sound mute state %1").arg(IsMuted()));
302
303 return false;
304}
305
307{
309 return kMuteAll;
310 QMutexLocker lock(&m_lock);
311 return m_audioOutput->SetMuteState(mstate);
312}
313
315{
317 return kMuteAll;
319}
320
322{
324 return kMuteAll;
325 QMutexLocker lock(&m_lock);
326 return m_audioOutput->GetMuteState();
327}
328
330{
332 return GetVolume();
333 QMutexLocker lock(&m_lock);
335 return GetVolume();
336}
337
339{
341 return GetVolume();
342 QMutexLocker lock(&m_lock);
344 return GetVolume();
345}
346
347std::chrono::milliseconds AudioPlayer::GetAudioTime(void)
348{
350 return 0ms;
351 QMutexLocker lock(&m_lock);
352 return m_audioOutput->GetAudiotime();
353}
354
356{
357 if (!m_audioOutput)
358 return false;
359 QMutexLocker lock(&m_lock);
360 return m_audioOutput->IsUpmixing();
361}
362
363bool AudioPlayer::EnableUpmix(bool enable, bool toggle)
364{
365 if (!m_audioOutput)
366 return false;
367 QMutexLocker lock(&m_lock);
368 if (toggle || (enable != IsUpmixing()))
369 return m_audioOutput->ToggleUpmix();
370 return enable;
371}
372
374{
375 if (!m_audioOutput)
376 return false;
377 QMutexLocker lock(&m_lock);
378 return m_audioOutput->CanUpmix();
379}
380
382{
383 m_stretchFactor = factor;
384 if (!m_audioOutput)
385 return;
386 QMutexLocker lock(&m_lock);
388}
389
390// The following methods are not locked as this hinders performance.
391// They are however only called from the Decoder and only the decode
392// thread will trigger a deletion/recreation of the AudioOutput device, hence
393// they should be safe.
394
396{
397 if (!ao)
398 return false;
399
400 return ao->GetOutputSettingsUsers(true)->canFeature(feature);
401}
402
404{
406}
407
409{
411}
412
414{
416}
417
419{
421}
422
424{
426}
427
429{
430 if (!m_audioOutput)
431 return 2;
433}
434
436{
437 if (!m_audioOutput)
438 return 0;
440}
441
442bool AudioPlayer::CanPassthrough(int samplerate, int channels,
443 AVCodecID codec, int profile)
444{
445 if (!m_audioOutput)
446 return false;
447 return m_audioOutput->CanPassthrough(samplerate, channels, codec, profile);
448}
449
451{
452 if (!m_audioOutput)
453 return false;
454 return m_audioOutput->CanDownmix();
455}
456
457/*
458 * if frames = -1 : let AudioOuput calculate value
459 * if frames = 0 && len > 0: will calculate according to len
460 */
461void AudioPlayer::AddAudioData(char *buffer, int len,
462 std::chrono::milliseconds timecode, int frames)
463{
465 return;
466
467 if (m_parent->PrepareAudioSample(timecode))
469 int samplesize = m_audioOutput->GetBytesPerFrame();
470
471 if (samplesize <= 0)
472 return;
473
474 if (frames == 0 && len > 0)
475 frames = len / samplesize;
476
477 if (!m_audioOutput->AddData(buffer, len, timecode, frames))
478 LOG(VB_PLAYBACK, LOG_ERR, LOC + "AddAudioData(): "
479 "Audio buffer overflow, audio data lost!");
480}
481
483{
484 if (!m_audioOutput)
485 return true;
487}
488
489std::chrono::milliseconds AudioPlayer::LengthLastData(void)
490{
491 if (!m_audioOutput)
492 return 0ms;
494}
495
497{
498 fill = total = 0;
500 return false;
501 m_audioOutput->GetBufferStatus(fill, total);
502 return true;
503}
504
506{
507 uint ofill = 0;
508 uint ototal = 0;
509 if (GetBufferStatus(ofill, ototal))
510 {
511 uint othresh = ((ototal>>1) + (ototal>>2));
512 if (ofill > othresh)
513 return true;
514 return GetAudioBufferedTime() > 8s;
515 }
516 return false;
517}
518
519std::chrono::milliseconds AudioPlayer::GetAudioBufferedTime(void)
520{
522}
523
524
526{
527 if (!m_audioOutput)
528 return false;
529 return m_audioOutput->CanProcess(fmt);
530}
531
533{
534 if (!m_audioOutput)
535 return 0;
536 return m_audioOutput->CanProcess();
537}
538
549int AudioPlayer::DecodeAudio(AVCodecContext *ctx,
550 uint8_t *buffer, int &data_size,
551 const AVPacket *pkt)
552{
553 if (!m_audioOutput)
554 {
555 data_size = 0;
556 return 0;
557 }
558 return m_audioOutput->DecodeAudio(ctx, buffer, data_size, pkt);
559}
560
561#include "moc_audioplayer.cpp"
static const std::array< featureStruct, 7 > feature
@ FORMAT_NONE
@ FORMAT_S16
DigitalFeature
@ FEATURE_DTS
@ FEATURE_AC3
@ FEATURE_DTSHD
@ FEATURE_EAC3
@ FEATURE_TRUEHD
bool TestDigitalFeature(AudioOutput *ao, DigitalFeature feature)
#define LOC
Definition: audioplayer.cpp:13
@ AUDIOOUTPUT_VIDEO
Definition: audiosettings.h:23
bool canFeature(DigitalFeature arg) const
return DigitalFeature mask.
int GetMaxHDRate() const
return the highest iec958 rate supported.
void addVisual(Visualization *v)
bool isConfigured() const
Definition: audiooutput.h:80
virtual bool AddData(void *buffer, int len, std::chrono::milliseconds timecode, int frames)=0
Add data to the audiobuffer for playback.
virtual bool IsPaused(void) const =0
virtual bool NeedDecodingBeforePassthrough(void) const
Definition: audiooutput.h:131
virtual void Drain(void)=0
void removeVisual(Visualization *v)
static AudioOutput * OpenAudio(const QString &main_device, const QString &passthru_device, AudioFormat format, int channels, AVCodecID codec, int samplerate, AudioOutputSource source, bool set_initial_vol, bool passthru, int upmixer_startup=0, AudioOutputSettings *custom=nullptr)
Definition: audiooutput.cpp:67
virtual std::chrono::milliseconds GetAudioBufferedTime(void)
report amount of audio buffered in milliseconds.
Definition: audiooutput.h:151
virtual bool IsUpmixing(void)
Definition: audiooutput.h:163
virtual void PauseUntilBuffered(void)=0
virtual std::chrono::milliseconds GetAudiotime(void)=0
virtual std::chrono::milliseconds LengthLastData(void) const
Definition: audiooutput.h:138
virtual void SetEffDsp(int dsprate)=0
virtual AudioOutputSettings * GetOutputSettingsUsers(bool digital=true)
virtual bool ToggleUpmix(void)
Definition: audiooutput.h:164
virtual int GetBytesPerFrame(void) const
Definition: audiooutput.h:86
int DecodeAudio(AVCodecContext *ctx, uint8_t *buffer, int &data_size, const AVPacket *pkt)
Utility routine.
virtual bool CanPassthrough(int samplerate, int channels, AVCodecID codec, int profile) const
virtual bool CanDownmix(void) const
Definition: audiooutput.h:92
virtual void Reset(void)=0
virtual bool CanUpmix(void)
Definition: audiooutput.h:165
virtual bool CanProcess(AudioFormat fmt)
Definition: audiooutput.h:173
virtual void Reconfigure(const AudioSettings &settings)=0
virtual void GetBufferStatus(uint &fill, uint &total)
Definition: audiooutput.h:155
virtual void Pause(bool paused)=0
virtual void SetStretchFactor(float factor)
void AudioPlayerStateChanged(MythAudioPlayerState State)
std::chrono::milliseconds GetAudioTime(void)
void ResetVisuals(void)
Definition: audioplayer.cpp:82
MuteState IncrMuteState(void)
bool CanAC3(void)
uint GetVolume(void)
bool m_controlsVolume
Definition: audioplayer.h:118
void PauseAudioUntilBuffered(void)
AudioOutput * m_audioOutput
Definition: audioplayer.h:109
void removeVisual(Visualization *vis)
Definition: audioplayer.cpp:48
bool CanEAC3(void)
bool CanUpmix(void)
bool m_mutedOnCreation
Definition: audioplayer.h:113
uint SetVolume(int newvolume)
float m_stretchFactor
Definition: audioplayer.h:111
void addVisual(Visualization *vis)
Definition: audioplayer.cpp:30
bool IsUpmixing(void)
bool IsPaused(void)
QString ReinitAudio(void)
void RemoveVisuals(void)
Definition: audioplayer.cpp:72
bool CanPassthrough(int samplerate, int channels, AVCodecID codec, int profile)
bool CanTrueHD(void)
AudioPlayer(MythPlayer *parent, bool muted)
Definition: audioplayer.cpp:17
uint GetMaxChannels(void)
bool GetBufferStatus(uint &fill, uint &total)
std::vector< Visualization * > m_visuals
Definition: audioplayer.h:119
bool m_noAudioOut
Definition: audioplayer.h:117
int DecodeAudio(AVCodecContext *ctx, uint8_t *buffer, int &data_size, const AVPacket *pkt)
DecodeAudio Utility routine.
void SetEffDsp(int dsprate)
void AddAudioData(char *buffer, int len, std::chrono::milliseconds timecode, int frames)
void AddVisuals(void)
Definition: audioplayer.cpp:62
MythPlayer * m_parent
Definition: audioplayer.h:108
bool CanDownmix(void)
std::chrono::milliseconds LengthLastData(void)
bool NeedDecodingBeforePassthrough(void)
MythAudioPlayerState m_state
Definition: audioplayer.h:110
void SetAudioParams(AudioFormat format, int orig_channels, int channels, AVCodecID codec, int samplerate, bool passthru, int codec_profile=-1)
Set audio output parameters.
MuteState SetMuteState(MuteState mstate)
void SetAudioOutput(AudioOutput *ao)
QString m_mainDevice
Definition: audioplayer.h:114
bool CanDTSHD(void)
~AudioPlayer() override
Definition: audioplayer.cpp:24
bool IsMuted(void)
Definition: audioplayer.h:84
MuteState GetMuteState(void)
bool Pause(bool pause)
bool m_noAudioIn
Definition: audioplayer.h:116
void CheckFormat(void)
void DeleteOutput(void)
std::chrono::milliseconds GetAudioBufferedTime(void)
QString m_passthruDevice
Definition: audioplayer.h:115
QRecursiveMutex m_lock
Definition: audioplayer.h:112
bool CanDTS(void)
void Reset(void)
Definition: audioplayer.cpp:92
void SetAudioInfo(const QString &main_device, const QString &passthru_device, uint samplerate, int codec_profile=-1)
Set audio output device parameters.
bool IsBufferAlmostFull(void)
bool EnableUpmix(bool enable, bool toggle=false)
void SetStretchFactor(float factor)
bool SetMuted(bool mute)
int GetMaxHDRate(void)
uint32_t CanProcess(void)
uint AdjustVolume(int change)
bool m_init
If set to false, AudioOutput instance will not try to initially open the audio device.
Definition: audiosettings.h:85
bool GetBoolSetting(const QString &key, bool defaultval=false)
bool IsAudioNeeded(void)
Definition: mythplayer.h:133
virtual bool PrepareAudioSample(std::chrono::milliseconds &timecode)
static MuteState NextMuteState(MuteState)
Definition: volumebase.cpp:156
virtual MuteState GetMuteState(void) const
Definition: volumebase.cpp:151
virtual void SetCurrentVolume(int value)
Definition: volumebase.cpp:124
virtual uint GetCurrentVolume(void) const
Definition: volumebase.cpp:119
virtual MuteState SetMuteState(MuteState)
Definition: volumebase.cpp:138
virtual void AdjustCurrentVolume(int change)
Definition: volumebase.cpp:133
unsigned int uint
Definition: compat.h:60
static pid_list_t::iterator find(const PIDInfoMap &map, pid_list_t &list, pid_list_t::iterator begin, pid_list_t::iterator end, bool find_open)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
void ShowNotificationError(const QString &msg, const QString &from, const QString &detail, const VNMask visibility, const MythNotification::Priority priority)
convenience utility to display error message as notification
MuteState
Definition: volumebase.h:8
@ kMuteOff
Definition: volumebase.h:9
@ kMuteAll
Definition: volumebase.h:12