MythTV master
audioplayer.cpp
Go to the documentation of this file.
1
6
7#include "audioplayer.h"
8#include "mythplayer.h"
10
11#define LOC QString("AudioPlayer: ")
12
13//static const QString _Location = AudioPlayer::tr("Audio Player");
14
16 : m_parent(parent),
17 m_mutedOnCreation(muted)
18{
19 m_controlsVolume = gCoreContext->GetBoolSetting("MythControlsVolume", true);
20}
21
23{
25 m_visuals.clear();
26}
27
29{
30 if (!m_audioOutput)
31 return;
32
33 QMutexLocker lock(&m_lock);
34 auto it = std::find(m_visuals.begin(), m_visuals.end(), vis);
35 if (it == m_visuals.end())
36 {
37 m_visuals.push_back(vis);
39 }
40}
41
43{
44 if (!m_audioOutput)
45 return;
46
47 QMutexLocker lock(&m_lock);
48 auto it = std::find(m_visuals.begin(), m_visuals.end(), vis);
49 if (it != m_visuals.end())
50 {
51 m_visuals.erase(it);
53 }
54}
55
57{
58 if (!m_audioOutput)
59 return;
60
61 QMutexLocker lock(&m_lock);
62 for (auto & visual : m_visuals)
63 m_audioOutput->addVisual(visual);
64}
65
67{
68 if (!m_audioOutput)
69 return;
70
71 QMutexLocker lock(&m_lock);
72 for (auto & visual : m_visuals)
74}
75
77{
78 if (!m_audioOutput)
79 return;
80
81 QMutexLocker lock(&m_lock);
82 for (auto & visual : m_visuals)
83 visual->prepare();
84}
85
87{
88 if (!m_audioOutput)
89 return;
90
91 QMutexLocker lock(&m_lock);
93}
94
96{
98 QMutexLocker locker(&m_lock);
99 if (m_audioOutput)
100 {
101 delete m_audioOutput;
102 m_audioOutput = nullptr;
103 }
104 m_noAudioOut = true;
105}
106
108{
109 bool want_audio = m_parent->IsAudioNeeded();
110 QString errMsg;
111 QMutexLocker lock(&m_lock);
112
114 m_noAudioIn = m_noAudioOut = true;
115 else
116 m_noAudioIn = false;
117
118 if (want_audio && !m_audioOutput)
119 {
120 // AudioOutput has never been created and we will want audio
126 if (m_noAudioIn)
127 aos.m_init = false;
128
130 if (m_audioOutput == nullptr)
131 {
132 errMsg = tr("Unable to create AudioOutput.");
133 }
134 else if (aos.m_init && !m_audioOutput->isConfigured())
135 {
136 errMsg = tr("AudioOutput has not been successfully configured.");
137 }
138 AddVisuals();
139 }
140 else if (!m_noAudioIn && m_audioOutput)
141 {
145 m_audioOutput->Reconfigure(settings);
147 {
148 errMsg = tr("AudioOutput has not been successfully configured.");
149 }
151 }
152
153 if (!errMsg.isEmpty())
154 {
155 LOG(VB_GENERAL, LOG_NOTICE, LOC + "Disabling Audio" +
156 QString(", reason is: %1").arg(errMsg));
157 ShowNotificationError(tr("Disabling Audio"),
158 AudioPlayer::tr( "Audio Player" ), errMsg);
159 m_noAudioOut = true;
160 }
161 else if (m_noAudioOut && m_audioOutput)
162 {
163 LOG(VB_GENERAL, LOG_NOTICE, LOC + "Enabling Audio");
164 m_noAudioOut = false;
165 }
166
168 {
170 m_mutedOnCreation = false;
171 }
172
173 ResetVisuals();
174
175 return errMsg;
176}
177
179{
181 m_noAudioIn = m_noAudioOut = true;
182}
183
184bool AudioPlayer::Pause(bool pause)
185{
187 return false;
188
189 QMutexLocker lock(&m_lock);
190 m_audioOutput->Pause(pause);
191 return true;
192}
193
195{
197 return false;
198 QMutexLocker lock(&m_lock);
199 return m_audioOutput->IsPaused();
200}
201
203{
205 return;
206 QMutexLocker lock(&m_lock);
208}
209
211{
212 // delete current audio class if any
213 DeleteOutput();
214 m_lock.lock();
215 m_audioOutput = ao;
216 AddVisuals();
217 m_lock.unlock();
218}
219
221{
223 return 0;
224 QMutexLocker lock(&m_lock);
226}
227
232void AudioPlayer::SetAudioInfo(const QString &main_device,
233 const QString &passthru_device,
234 uint samplerate,
235 int codec_profile)
236{
237 m_mainDevice.clear();
238 m_passthruDevice.clear();
239 if (!main_device.isEmpty())
240 m_mainDevice = main_device;
241 if (!passthru_device.isEmpty())
242 m_passthruDevice = passthru_device;
243 m_state.m_sampleRate = static_cast<int>(samplerate);
244 m_state.m_codecProfile = codec_profile;
246}
247
252void AudioPlayer::SetAudioParams(AudioFormat format, int orig_channels,
253 int channels, AVCodecID codec,
254 int samplerate, bool passthru,
255 int codec_profile)
256{
257 m_state.m_format = CanProcess(format) ? format : FORMAT_S16;
258 m_state.m_origChannels = orig_channels;
259 m_state.m_channels = channels;
260 m_state.m_codec = codec;
261 m_state.m_sampleRate = samplerate;
262 m_state.m_passthru = passthru;
263 m_state.m_codecProfile = codec_profile;
264 ResetVisuals();
266}
267
268void AudioPlayer::SetEffDsp(int dsprate)
269{
271 return;
272 QMutexLocker lock(&m_lock);
273 m_audioOutput->SetEffDsp(dsprate);
274}
275
277{
278 bool is_muted = IsMuted();
279 QMutexLocker lock(&m_lock);
280
281 if (m_audioOutput && !m_noAudioOut && !is_muted && mute &&
283 {
284 LOG(VB_AUDIO, LOG_INFO, QString("muting sound %1").arg(IsMuted()));
285 return true;
286 }
287 if (m_audioOutput && !m_noAudioOut && is_muted && !mute &&
289 {
290 LOG(VB_AUDIO, LOG_INFO, QString("unmuting sound %1").arg(IsMuted()));
291 return true;
292 }
293
294 LOG(VB_AUDIO, LOG_ERR,
295 QString("not changing sound mute state %1").arg(IsMuted()));
296
297 return false;
298}
299
301{
303 return kMuteAll;
304 QMutexLocker lock(&m_lock);
305 return m_audioOutput->SetMuteState(mstate);
306}
307
309{
311 return kMuteAll;
313}
314
316{
318 return kMuteAll;
319 QMutexLocker lock(&m_lock);
320 return m_audioOutput->GetMuteState();
321}
322
324{
326 return GetVolume();
327 QMutexLocker lock(&m_lock);
329 return GetVolume();
330}
331
333{
335 return GetVolume();
336 QMutexLocker lock(&m_lock);
338 return GetVolume();
339}
340
341std::chrono::milliseconds AudioPlayer::GetAudioTime(void)
342{
344 return 0ms;
345 QMutexLocker lock(&m_lock);
346 return m_audioOutput->GetAudiotime();
347}
348
350{
351 if (!m_audioOutput)
352 return false;
353 QMutexLocker lock(&m_lock);
354 return m_audioOutput->IsUpmixing();
355}
356
357bool AudioPlayer::EnableUpmix(bool enable, bool toggle)
358{
359 if (!m_audioOutput)
360 return false;
361 QMutexLocker lock(&m_lock);
362 if (toggle || (enable != IsUpmixing()))
363 return m_audioOutput->ToggleUpmix();
364 return enable;
365}
366
368{
369 if (!m_audioOutput)
370 return false;
371 QMutexLocker lock(&m_lock);
372 return m_audioOutput->CanUpmix();
373}
374
376{
377 m_stretchFactor = factor;
378 if (!m_audioOutput)
379 return;
380 QMutexLocker lock(&m_lock);
382}
383
384// The following methods are not locked as this hinders performance.
385// They are however only called from the Decoder and only the decode
386// thread will trigger a deletion/recreation of the AudioOutput device, hence
387// they should be safe.
388
390{
391 if (!ao)
392 return false;
393
394 return ao->GetOutputSettingsUsers(true)->canFeature(feature);
395}
396
398{
400}
401
403{
405}
406
408{
410}
411
413{
415}
416
418{
420}
421
423{
424 if (!m_audioOutput)
425 return 2;
427}
428
430{
431 if (!m_audioOutput)
432 return 0;
434}
435
436bool AudioPlayer::CanPassthrough(int samplerate, int channels,
437 AVCodecID codec, int profile)
438{
439 if (!m_audioOutput)
440 return false;
441 return m_audioOutput->CanPassthrough(samplerate, channels, codec, profile);
442}
443
445{
446 if (!m_audioOutput)
447 return false;
448 return m_audioOutput->CanDownmix();
449}
450
451/*
452 * if frames = -1 : let AudioOuput calculate value
453 * if frames = 0 && len > 0: will calculate according to len
454 */
455void AudioPlayer::AddAudioData(char *buffer, int len,
456 std::chrono::milliseconds timecode, int frames)
457{
459 return;
460
461 if (m_parent->PrepareAudioSample(timecode))
463 int samplesize = m_audioOutput->GetBytesPerFrame();
464
465 if (samplesize <= 0)
466 return;
467
468 if (frames == 0 && len > 0)
469 frames = len / samplesize;
470
471 if (!m_audioOutput->AddData(buffer, len, timecode, frames))
472 LOG(VB_PLAYBACK, LOG_ERR, LOC + "AddAudioData(): "
473 "Audio buffer overflow, audio data lost!");
474}
475
477{
478 if (!m_audioOutput)
479 return true;
481}
482
483std::chrono::milliseconds AudioPlayer::LengthLastData(void)
484{
485 if (!m_audioOutput)
486 return 0ms;
488}
489
491{
492 fill = total = 0;
494 return false;
495 m_audioOutput->GetBufferStatus(fill, total);
496 return true;
497}
498
500{
501 uint ofill = 0;
502 uint ototal = 0;
503 if (GetBufferStatus(ofill, ototal))
504 {
505 uint othresh = ((ototal>>1) + (ototal>>2));
506 if (ofill > othresh)
507 return true;
508 return GetAudioBufferedTime() > 8s;
509 }
510 return false;
511}
512
513std::chrono::milliseconds AudioPlayer::GetAudioBufferedTime(void)
514{
516}
517
518
520{
521 if (!m_audioOutput)
522 return false;
523 return m_audioOutput->CanProcess(fmt);
524}
525
527{
528 if (!m_audioOutput)
529 return 0;
530 return m_audioOutput->CanProcess();
531}
532
543int AudioPlayer::DecodeAudio(AVCodecContext *ctx,
544 uint8_t *buffer, int &data_size,
545 const AVPacket *pkt)
546{
547 if (!m_audioOutput)
548 {
549 data_size = 0;
550 return 0;
551 }
552 return m_audioOutput->DecodeAudio(ctx, buffer, data_size, pkt);
553}
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:11
@ 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:64
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:76
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:42
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:28
bool IsUpmixing(void)
bool IsPaused(void)
QString ReinitAudio(void)
void RemoveVisuals(void)
Definition: audioplayer.cpp:66
bool CanPassthrough(int samplerate, int channels, AVCodecID codec, int profile)
bool CanTrueHD(void)
AudioPlayer(MythPlayer *parent, bool muted)
Definition: audioplayer.cpp:15
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:56
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:22
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)
Definition: audioplayer.cpp:95
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:86
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:155
virtual MuteState GetMuteState(void) const
Definition: volumebase.cpp:150
virtual void SetCurrentVolume(int value)
Definition: volumebase.cpp:123
virtual uint GetCurrentVolume(void) const
Definition: volumebase.cpp:118
virtual MuteState SetMuteState(MuteState)
Definition: volumebase.cpp:137
virtual void AdjustCurrentVolume(int change)
Definition: volumebase.cpp:132
unsigned int uint
Definition: compat.h:68
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