2 * Copyright (C) 2010-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
23 using namespace ActiveAE;
24 #include "ActiveAESound.h"
25 #include "ActiveAEStream.h"
26 #include "cores/AudioEngine/Utils/AEUtil.h"
27 #include "cores/AudioEngine/Encoders/AEEncoderFFmpeg.h"
29 #include "settings/Settings.h"
30 #include "settings/AdvancedSettings.h"
31 #include "windowing/WindowingFactory.h"
33 #define MAX_CACHE_LEVEL 0.5 // total cache time of stream in seconds
34 #define MAX_WATER_LEVEL 0.25 // buffered time after stream stages in seconds
36 void CEngineStats::Reset(unsigned int sampleRate)
38 CSingleLock lock(m_lock);
39 m_sinkUpdate = XbmcThreads::SystemClockMillis();
41 m_sinkSampleRate = sampleRate;
42 m_bufferedSamples = 0;
46 void CEngineStats::UpdateSinkDelay(double delay, int samples)
48 CSingleLock lock(m_lock);
49 m_sinkUpdate = XbmcThreads::SystemClockMillis();
51 if (samples > m_bufferedSamples)
53 CLog::Log(LOGERROR, "CEngineStats::UpdateSinkDelay - inconsistency in buffer time");
56 m_bufferedSamples -= samples;
59 void CEngineStats::AddSamples(int samples, std::list<CActiveAEStream*> &streams)
61 CSingleLock lock(m_lock);
62 m_bufferedSamples += samples;
64 //update buffered time of streams
65 std::list<CActiveAEStream*>::iterator it;
66 for(it=streams.begin(); it!=streams.end(); ++it)
69 std::deque<CSampleBuffer*>::iterator itBuf;
70 for(itBuf=(*it)->m_processingSamples.begin(); itBuf!=(*it)->m_processingSamples.end(); ++itBuf)
72 delay += (float)(*itBuf)->pkt->nb_samples / (*itBuf)->pkt->config.sample_rate;
74 delay += (*it)->m_resampleBuffers->GetDelay();
75 (*it)->m_bufferedTime = delay;
79 float CEngineStats::GetDelay()
81 CSingleLock lock(m_lock);
82 unsigned int now = XbmcThreads::SystemClockMillis();
83 float delay = m_sinkDelay - (double)(now-m_sinkUpdate) / 1000;
84 delay += (float)m_bufferedSamples / m_sinkSampleRate;
92 // this is used to sync a/v so we need to add sink latency here
93 float CEngineStats::GetDelay(CActiveAEStream *stream)
95 CSingleLock lock(m_lock);
96 unsigned int now = XbmcThreads::SystemClockMillis();
97 float delay = m_sinkDelay - (double)(now-m_sinkUpdate) / 1000;
98 delay += m_sinkLatency;
99 delay += (float)m_bufferedSamples / m_sinkSampleRate;
104 delay += stream->m_bufferedTime;
108 float CEngineStats::GetCacheTime(CActiveAEStream *stream)
110 CSingleLock lock(m_lock);
111 float delay = (float)m_bufferedSamples / m_sinkSampleRate;
113 delay += stream->m_bufferedTime;
117 float CEngineStats::GetCacheTotal(CActiveAEStream *stream)
119 return MAX_CACHE_LEVEL + m_sinkCacheTotal;
122 float CEngineStats::GetWaterLevel()
124 return (float)m_bufferedSamples / m_sinkSampleRate;
127 void CEngineStats::SetSuspended(bool state)
129 CSingleLock lock(m_lock);
133 bool CEngineStats::IsSuspended()
135 CSingleLock lock(m_lock);
139 CActiveAE::CActiveAE() :
141 m_controlPort("OutputControlPort", &m_inMsgEvent, &m_outMsgEvent),
142 m_dataPort("OutputDataPort", &m_inMsgEvent, &m_outMsgEvent),
143 m_sink(&m_outMsgEvent)
145 m_sinkBuffers = NULL;
146 m_silenceBuffers = NULL;
147 m_encoderBuffers = NULL;
149 m_vizBuffersInput = NULL;
156 m_audioCallback = NULL;
157 m_vizInitialized = false;
158 m_sinkHasVolume = false;
161 CActiveAE::~CActiveAE()
166 void CActiveAE::Dispose()
168 #if defined(HAS_GLX) || defined(TARGET_DARWIN_OSX)
169 g_Windowing.Unregister(this);
175 m_controlPort.Purge();
179 m_dllAvFormat.Unload();
180 m_dllAvCodec.Unload();
181 m_dllAvUtil.Unload();
184 //-----------------------------------------------------------------------------
186 //-----------------------------------------------------------------------------
192 AE_TOP_UNCONFIGURED, // 2
193 AE_TOP_RECONFIGURING, // 3
194 AE_TOP_CONFIGURED, // 4
195 AE_TOP_CONFIGURED_SUSPEND, // 5
196 AE_TOP_CONFIGURED_IDLE, // 6
197 AE_TOP_CONFIGURED_PLAY, // 7
200 int AE_parentStates[] = {
203 0, //TOP_UNCONFIGURED
205 0, //TOP_RECONFIGURING
206 4, //TOP_CONFIGURED_SUSPEND
207 4, //TOP_CONFIGURED_IDLE
208 4, //TOP_CONFIGURED_PLAY
211 void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg)
213 for (int state = m_state; ; state = AE_parentStates[state])
218 if (port == &m_controlPort)
222 case CActiveAEControlProtocol::GETSTATE:
223 msg->Reply(CActiveAEControlProtocol::ACC, &m_state, sizeof(m_state));
225 case CActiveAEControlProtocol::VOLUME:
226 m_volume = *(float*)msg->data;
228 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::VOLUME, &m_volume, sizeof(float));
230 case CActiveAEControlProtocol::MUTE:
231 m_muted = *(bool*)msg->data;
233 case CActiveAEControlProtocol::KEEPCONFIG:
234 m_extKeepConfig = *(unsigned int*)msg->data;
236 case CActiveAEControlProtocol::DISPLAYRESET:
242 else if (port == &m_dataPort)
246 case CActiveAEDataProtocol::NEWSOUND:
247 CActiveAESound *sound;
248 sound = *(CActiveAESound**)msg->data;
251 m_sounds.push_back(sound);
255 case CActiveAEDataProtocol::FREESTREAM:
256 CActiveAEStream *stream;
257 stream = *(CActiveAEStream**)msg->data;
258 DiscardStream(stream);
260 case CActiveAEDataProtocol::FREESOUND:
261 sound = *(CActiveAESound**)msg->data;
264 case CActiveAEDataProtocol::DRAINSTREAM:
265 stream = *(CActiveAEStream**)msg->data;
266 stream->m_drain = true;
267 stream->m_resampleBuffers->m_drain = true;
268 msg->Reply(CActiveAEDataProtocol::ACC);
269 stream->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMDRAINED);
275 else if (port == &m_sink.m_dataPort)
279 case CSinkDataProtocol::RETURNSAMPLE:
280 CSampleBuffer **buffer;
281 buffer = (CSampleBuffer**)msg->data;
292 std::string portName = port == NULL ? "timer" : port->portName;
293 CLog::Log(LOGWARNING, "CActiveAE::%s - signal: %d from port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
298 if (port == NULL) // timeout
302 case CActiveAEControlProtocol::TIMEOUT:
308 m_state = AE_TOP_CONFIGURED_IDLE;
313 m_state = AE_TOP_ERROR;
323 case AE_TOP_UNCONFIGURED:
324 if (port == &m_controlPort)
328 case CActiveAEControlProtocol::INIT:
330 m_sink.EnumerateSinkList(false);
333 msg->Reply(CActiveAEControlProtocol::ACC);
336 m_state = AE_TOP_CONFIGURED_IDLE;
341 m_state = AE_TOP_ERROR;
352 case AE_TOP_RECONFIGURING:
353 if (port == NULL) // timeout
357 case CActiveAEControlProtocol::TIMEOUT:
364 if (!m_sinkBuffers->m_inputSamples.empty() || !m_sinkBuffers->m_outputSamples.empty())
369 if (NeedReconfigureSink())
376 m_state = AE_TOP_CONFIGURED_PLAY;
381 m_state = AE_TOP_ERROR;
384 m_extDeferData = false;
392 case AE_TOP_CONFIGURED:
393 if (port == &m_controlPort)
397 case CActiveAEControlProtocol::RECONFIGURE:
398 if (m_streams.empty())
400 bool silence = false;
401 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::SILENCEMODE, &silence, sizeof(bool));
405 if (!NeedReconfigureBuffers() && !NeedReconfigureSink())
407 m_state = AE_TOP_RECONFIGURING;
409 // don't accept any data until we are reconfigured
410 m_extDeferData = true;
412 case CActiveAEControlProtocol::SUSPEND:
414 m_stats.SetSuspended(true);
415 m_state = AE_TOP_CONFIGURED_SUSPEND;
416 m_extDeferData = true;
418 case CActiveAEControlProtocol::DISPLAYLOST:
419 if (m_sink.GetDeviceType(m_mode == MODE_PCM ? m_settings.device : m_settings.passthoughdevice) == AE_DEVTYPE_HDMI)
422 m_stats.SetSuspended(true);
423 m_state = AE_TOP_CONFIGURED_SUSPEND;
424 m_extDeferData = true;
426 msg->Reply(CActiveAEControlProtocol::ACC);
428 case CActiveAEControlProtocol::PAUSESTREAM:
429 CActiveAEStream *stream;
430 stream = *(CActiveAEStream**)msg->data;
431 if (stream->m_paused != true && m_streams.size() == 1)
433 stream->m_paused = true;
435 case CActiveAEControlProtocol::RESUMESTREAM:
436 stream = *(CActiveAEStream**)msg->data;
437 stream->m_paused = false;
440 case CActiveAEControlProtocol::FLUSHSTREAM:
441 stream = *(CActiveAEStream**)msg->data;
442 SFlushStream(stream);
443 msg->Reply(CActiveAEControlProtocol::ACC);
446 case CActiveAEControlProtocol::STREAMAMP:
447 MsgStreamParameter *par;
448 par = (MsgStreamParameter*)msg->data;
449 par->stream->m_limiter.SetAmplification(par->parameter.float_par);
450 par->stream->m_amplify = par->parameter.float_par;
452 case CActiveAEControlProtocol::STREAMVOLUME:
453 par = (MsgStreamParameter*)msg->data;
454 par->stream->m_volume = par->parameter.float_par;
456 case CActiveAEControlProtocol::STREAMRGAIN:
457 par = (MsgStreamParameter*)msg->data;
458 par->stream->m_rgain = par->parameter.float_par;
460 case CActiveAEControlProtocol::STREAMRESAMPLERATIO:
461 par = (MsgStreamParameter*)msg->data;
462 if (par->stream->m_resampleBuffers)
464 par->stream->m_resampleBuffers->m_resampleRatio = par->parameter.double_par;
467 case CActiveAEControlProtocol::STREAMFADE:
469 fade = (MsgStreamFade*)msg->data;
470 fade->stream->m_fadingBase = fade->from;
471 fade->stream->m_fadingTarget = fade->target;
472 fade->stream->m_fadingTime = fade->millis;
473 fade->stream->m_fadingSamples = -1;
475 case CActiveAEControlProtocol::STOPSOUND:
476 CActiveAESound *sound;
477 sound = *(CActiveAESound**)msg->data;
484 else if (port == &m_dataPort)
488 case CActiveAEDataProtocol::PLAYSOUND:
489 CActiveAESound *sound;
490 sound = *(CActiveAESound**)msg->data;
491 if (m_settings.guisoundmode == AE_SOUND_OFF ||
492 (m_settings.guisoundmode == AE_SOUND_IDLE && !m_streams.empty()))
496 SoundState st = {sound, 0};
497 m_sounds_playing.push_back(st);
499 m_state = AE_TOP_CONFIGURED_PLAY;
502 case CActiveAEDataProtocol::NEWSTREAM:
503 MsgStreamNew *streamMsg;
504 CActiveAEStream *stream;
505 streamMsg = (MsgStreamNew*)msg->data;
506 stream = CreateStream(streamMsg);
509 msg->Reply(CActiveAEDataProtocol::ACC, &stream, sizeof(CActiveAEStream*));
514 m_state = AE_TOP_CONFIGURED_PLAY;
519 m_state = AE_TOP_ERROR;
524 msg->Reply(CActiveAEDataProtocol::ERR);
526 case CActiveAEDataProtocol::STREAMSAMPLE:
527 MsgStreamSample *msgData;
528 CSampleBuffer *samples;
529 msgData = (MsgStreamSample*)msg->data;
530 samples = msgData->stream->m_processingSamples.front();
531 msgData->stream->m_processingSamples.pop_front();
532 if (samples != msgData->buffer)
533 CLog::Log(LOGERROR, "CActiveAE - inconsistency in stream sample message");
534 if (msgData->buffer->pkt->nb_samples == 0)
535 msgData->buffer->Return();
537 msgData->stream->m_resampleBuffers->m_inputSamples.push_back(msgData->buffer);
539 m_state = AE_TOP_CONFIGURED_PLAY;
541 case CActiveAEDataProtocol::FREESTREAM:
542 stream = *(CActiveAEStream**)msg->data;
543 DiscardStream(stream);
544 if (m_streams.empty())
547 m_extDrainTimer.Set(m_extKeepConfig);
549 m_extDrainTimer.Set(m_stats.GetDelay() * 1000);
553 m_state = AE_TOP_CONFIGURED_PLAY;
555 case CActiveAEDataProtocol::DRAINSTREAM:
556 stream = *(CActiveAEStream**)msg->data;
557 stream->m_drain = true;
558 stream->m_resampleBuffers->m_drain = true;
560 m_state = AE_TOP_CONFIGURED_PLAY;
561 msg->Reply(CActiveAEDataProtocol::ACC);
567 else if (port == &m_sink.m_dataPort)
571 case CSinkDataProtocol::RETURNSAMPLE:
572 CSampleBuffer **buffer;
573 buffer = (CSampleBuffer**)msg->data;
579 m_state = AE_TOP_CONFIGURED_PLAY;
587 case AE_TOP_CONFIGURED_SUSPEND:
588 if (port == &m_controlPort)
590 bool displayReset = false;
593 case CActiveAEControlProtocol::DISPLAYRESET:
595 case CActiveAEControlProtocol::INIT:
599 m_sink.EnumerateSinkList(true);
604 msg->Reply(CActiveAEControlProtocol::ACC);
607 m_state = AE_TOP_CONFIGURED_PLAY;
612 m_state = AE_TOP_ERROR;
615 m_stats.SetSuspended(false);
616 m_extDeferData = false;
622 else if (port == &m_sink.m_dataPort)
626 case CSinkDataProtocol::RETURNSAMPLE:
627 CSampleBuffer **buffer;
628 buffer = (CSampleBuffer**)msg->data;
638 else if (port == NULL) // timeout
642 case CActiveAEControlProtocol::TIMEOUT:
651 case AE_TOP_CONFIGURED_IDLE:
652 if (port == &m_controlPort)
656 case CActiveAEControlProtocol::RESUMESTREAM:
657 CActiveAEStream *stream;
658 stream = *(CActiveAEStream**)msg->data;
659 stream->m_paused = false;
660 m_state = AE_TOP_CONFIGURED_PLAY;
663 case CActiveAEControlProtocol::FLUSHSTREAM:
664 stream = *(CActiveAEStream**)msg->data;
665 SFlushStream(stream);
666 msg->Reply(CActiveAEControlProtocol::ACC);
667 m_state = AE_TOP_CONFIGURED_PLAY;
674 else if (port == NULL) // timeout
678 case CActiveAEControlProtocol::TIMEOUT:
680 ClearDiscardedBuffers();
683 if (m_extDrainTimer.IsTimePast())
688 m_state = AE_TOP_CONFIGURED_PLAY;
693 m_state = AE_TOP_ERROR;
698 m_extTimeout = m_extDrainTimer.MillisLeft();
709 case AE_TOP_CONFIGURED_PLAY:
710 if (port == NULL) // timeout
714 case CActiveAEControlProtocol::TIMEOUT:
717 m_state = AE_TOP_ERROR;
726 if (!m_extDrain && HasWork())
728 ClearDiscardedBuffers();
733 m_state = AE_TOP_CONFIGURED_IDLE;
741 default: // we are in no state, should not happen
742 CLog::Log(LOGERROR, "CActiveAE::%s - no valid state: %d", __FUNCTION__, m_state);
748 void CActiveAE::Process()
751 Protocol *port = NULL;
753 XbmcThreads::EndTime timer;
755 m_state = AE_TOP_UNCONFIGURED;
757 m_bStateMachineSelfTrigger = false;
759 m_extDeferData = false;
768 timer.Set(m_extTimeout);
770 if (m_bStateMachineSelfTrigger)
772 m_bStateMachineSelfTrigger = false;
773 // self trigger state machine
774 StateMachine(msg->signal, port, msg);
775 if (!m_bStateMachineSelfTrigger)
782 // check control port
783 else if (m_controlPort.ReceiveOutMessage(&msg))
786 port = &m_controlPort;
788 // check sink data port
789 else if (m_sink.m_dataPort.ReceiveInMessage(&msg))
792 port = &m_sink.m_dataPort;
794 else if (!m_extDeferData)
797 if (m_dataPort.ReceiveOutMessage(&msg))
805 std::list<CActiveAEStream*>::iterator it;
806 for(it=m_streams.begin(); it!=m_streams.end(); ++it)
808 if((*it)->m_streamPort->ReceiveOutMessage(&msg))
820 StateMachine(msg->signal, port, msg);
821 if (!m_bStateMachineSelfTrigger)
830 else if (m_outMsgEvent.WaitMSec(m_extTimeout))
832 m_extTimeout = timer.MillisLeft();
838 msg = m_controlPort.GetMessage();
839 msg->signal = CActiveAEControlProtocol::TIMEOUT;
841 // signal timeout to state machine
842 StateMachine(msg->signal, port, msg);
843 if (!m_bStateMachineSelfTrigger)
852 AEAudioFormat CActiveAE::GetInputFormat(AEAudioFormat *desiredFmt)
854 AEAudioFormat inputFormat;
856 if (m_streams.empty())
858 inputFormat.m_dataFormat = AE_FMT_FLOAT;
859 inputFormat.m_sampleRate = 44100;
860 inputFormat.m_encodedRate = 0;
861 inputFormat.m_channelLayout = AE_CH_LAYOUT_2_0;
862 inputFormat.m_frames = 0;
863 inputFormat.m_frameSamples = 0;
864 inputFormat.m_frameSize = 0;
866 // force input format after unpausing slave
867 else if (desiredFmt != NULL)
869 inputFormat = *desiredFmt;
871 // keep format when having multiple streams
872 else if (m_streams.size() > 1 && m_silenceBuffers == NULL)
874 inputFormat = m_inputFormat;
878 inputFormat = m_streams.front()->m_format;
879 m_inputFormat = inputFormat;
885 void CActiveAE::Configure(AEAudioFormat *desiredFmt)
887 bool initSink = false;
889 AEAudioFormat sinkInputFormat, inputFormat;
890 AEAudioFormat oldInternalFormat = m_internalFormat;
891 AEAudioFormat oldSinkRequestFormat = m_sinkRequestFormat;
893 inputFormat = GetInputFormat(desiredFmt);
895 m_sinkRequestFormat = inputFormat;
896 ApplySettingsToFormat(m_sinkRequestFormat, m_settings, (int*)&m_mode);
899 std::string device = AE_IS_RAW(m_sinkRequestFormat.m_dataFormat) ? m_settings.passthoughdevice : m_settings.device;
901 CAESinkFactory::ParseDevice(device, driver);
902 if ((!CompareFormat(m_sinkRequestFormat, m_sinkFormat) && !CompareFormat(m_sinkRequestFormat, oldSinkRequestFormat)) ||
903 m_currDevice.compare(device) != 0 ||
904 m_settings.driver.compare(driver) != 0)
908 m_settings.driver = driver;
909 m_currDevice = device;
911 m_stats.Reset(m_sinkFormat.m_sampleRate);
912 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::VOLUME, &m_volume, sizeof(float));
914 // limit buffer size in case of sink returns large buffer
915 unsigned int buffertime = (m_sinkFormat.m_frames*1000) / m_sinkFormat.m_sampleRate;
918 CLog::Log(LOGWARNING, "ActiveAE::%s - sink returned large buffer of %d ms, reducing to 80 ms", __FUNCTION__, buffertime);
919 m_sinkFormat.m_frames = 80 * m_sinkFormat.m_sampleRate / 1000;
923 if (m_silenceBuffers)
925 m_discardBufferPools.push_back(m_silenceBuffers);
926 m_silenceBuffers = NULL;
929 // buffers for driving gui sounds if no streams are active
930 if (m_streams.empty())
932 inputFormat = m_sinkFormat;
933 if (m_sinkFormat.m_channelLayout.Count() > m_sinkRequestFormat.m_channelLayout.Count())
935 inputFormat.m_channelLayout = m_sinkRequestFormat.m_channelLayout;
936 inputFormat.m_channelLayout.ResolveChannels(m_sinkFormat.m_channelLayout);
938 inputFormat.m_dataFormat = AE_FMT_FLOAT;
939 inputFormat.m_frameSize = inputFormat.m_channelLayout.Count() *
940 (CAEUtil::DataFormatToBits(inputFormat.m_dataFormat) >> 3);
941 m_silenceBuffers = new CActiveAEBufferPool(inputFormat);
942 m_silenceBuffers->Create(MAX_WATER_LEVEL*1000);
943 sinkInputFormat = inputFormat;
944 m_internalFormat = inputFormat;
946 bool silence = false;
947 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::SILENCEMODE, &silence, sizeof(bool));
952 if (m_encoderBuffers)
954 m_discardBufferPools.push_back(m_encoderBuffers);
955 m_encoderBuffers = NULL;
959 m_discardBufferPools.push_back(m_vizBuffers);
962 if (m_vizBuffersInput)
964 m_discardBufferPools.push_back(m_vizBuffersInput);
965 m_vizBuffersInput = NULL;
968 // resample buffers for streams
972 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::SILENCEMODE, &silence, sizeof(bool));
974 AEAudioFormat outputFormat;
975 if (m_mode == MODE_RAW)
977 inputFormat.m_frames = m_sinkFormat.m_frames;
978 outputFormat = inputFormat;
979 sinkInputFormat = m_sinkFormat;
981 // transcode everything with more than 2 channels
982 else if (m_mode == MODE_TRANSCODE)
984 outputFormat = inputFormat;
985 outputFormat.m_dataFormat = AE_FMT_FLOATP;
986 outputFormat.m_sampleRate = 48000;
991 m_encoder = new CAEEncoderFFmpeg();
992 m_encoder->Initialize(outputFormat, true);
993 m_encoderFormat = outputFormat;
996 outputFormat = m_encoderFormat;
998 outputFormat.m_channelLayout = m_encoderFormat.m_channelLayout;
999 outputFormat.m_frames = m_encoderFormat.m_frames;
1002 if (m_encoder->GetCodecID() == AV_CODEC_ID_AC3)
1004 AEAudioFormat format;
1005 format.m_channelLayout = AE_CH_LAYOUT_2_0;
1006 format.m_dataFormat = AE_FMT_S16NE;
1007 format.m_frameSize = 2* (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);
1008 format.m_frames = AC3_FRAME_SIZE;
1009 format.m_sampleRate = 48000;
1010 format.m_encodedRate = m_encoderFormat.m_sampleRate;
1011 if (m_encoderBuffers && initSink)
1013 m_discardBufferPools.push_back(m_encoderBuffers);
1014 m_encoderBuffers = NULL;
1016 if (!m_encoderBuffers)
1018 m_encoderBuffers = new CActiveAEBufferPool(format);
1019 m_encoderBuffers->Create(MAX_WATER_LEVEL*1000);
1023 sinkInputFormat = m_sinkFormat;
1027 outputFormat = m_sinkFormat;
1028 outputFormat.m_dataFormat = AE_FMT_FLOAT;
1029 outputFormat.m_frameSize = outputFormat.m_channelLayout.Count() *
1030 (CAEUtil::DataFormatToBits(outputFormat.m_dataFormat) >> 3);
1032 // due to channel ordering of the driver, a sink may return more channels than
1033 // requested, i.e. 2.1 request returns FL,FR,BL,BR,FC,LFE for ALSA
1034 // in this case we need to downmix to requested format
1035 if (m_sinkFormat.m_channelLayout.Count() > m_sinkRequestFormat.m_channelLayout.Count())
1037 outputFormat.m_channelLayout = m_sinkRequestFormat.m_channelLayout;
1038 outputFormat.m_channelLayout.ResolveChannels(m_sinkFormat.m_channelLayout);
1041 // TODO: adjust to decoder
1042 sinkInputFormat = outputFormat;
1044 m_internalFormat = outputFormat;
1046 std::list<CActiveAEStream*>::iterator it;
1047 for(it=m_streams.begin(); it!=m_streams.end(); ++it)
1049 // check if we support input format of stream
1050 if (!AE_IS_RAW((*it)->m_format.m_dataFormat) &&
1051 CActiveAEResample::GetAVSampleFormat((*it)->m_format.m_dataFormat) == AV_SAMPLE_FMT_FLT &&
1052 (*it)->m_format.m_dataFormat != AE_FMT_FLOAT)
1054 (*it)->m_convertFn = CAEConvert::ToFloat((*it)->m_format.m_dataFormat);
1055 (*it)->m_format.m_dataFormat = AE_FMT_FLOAT;
1058 if (!(*it)->m_inputBuffers)
1060 // align input buffers with period of sink or encoder
1061 (*it)->m_format.m_frames = m_internalFormat.m_frames * ((float)(*it)->m_format.m_sampleRate / m_internalFormat.m_sampleRate);
1063 // create buffer pool
1064 (*it)->m_inputBuffers = new CActiveAEBufferPool((*it)->m_format);
1065 (*it)->m_inputBuffers->Create(MAX_CACHE_LEVEL*1000);
1066 (*it)->m_streamSpace = (*it)->m_format.m_frameSize * (*it)->m_format.m_frames;
1068 // if input format does not follow ffmpeg channel mask, we may need to remap channels
1069 (*it)->InitRemapper();
1071 if (initSink && (*it)->m_resampleBuffers)
1073 m_discardBufferPools.push_back((*it)->m_resampleBuffers);
1074 (*it)->m_resampleBuffers = NULL;
1076 if (!(*it)->m_resampleBuffers)
1078 (*it)->m_resampleBuffers = new CActiveAEBufferPoolResample((*it)->m_inputBuffers->m_format, outputFormat, m_settings.resampleQuality);
1079 (*it)->m_resampleBuffers->m_changeResampler = (*it)->m_forceResampler;
1080 (*it)->m_resampleBuffers->Create(MAX_CACHE_LEVEL*1000, false, m_settings.stereoupmix, m_settings.normalizelevels);
1082 if (m_mode == MODE_TRANSCODE || m_streams.size() > 1)
1083 (*it)->m_resampleBuffers->m_fillPackets = true;
1086 (*it)->m_limiter.SetSamplerate(outputFormat.m_sampleRate);
1089 // update buffered time of streams
1090 m_stats.AddSamples(0, m_streams);
1093 if (!AE_IS_RAW(inputFormat.m_dataFormat))
1095 if (initSink && m_vizBuffers)
1097 m_discardBufferPools.push_back(m_vizBuffers);
1098 m_vizBuffers = NULL;
1099 m_discardBufferPools.push_back(m_vizBuffersInput);
1100 m_vizBuffersInput = NULL;
1104 AEAudioFormat vizFormat = m_internalFormat;
1105 vizFormat.m_channelLayout = AE_CH_LAYOUT_2_0;
1106 vizFormat.m_dataFormat = AE_FMT_FLOAT;
1109 m_vizBuffersInput = new CActiveAEBufferPool(m_internalFormat);
1110 m_vizBuffersInput->Create(2000);
1113 m_vizBuffers = new CActiveAEBufferPoolResample(m_internalFormat, vizFormat, m_settings.resampleQuality);
1114 // TODO use cache of sync + water level
1115 m_vizBuffers->Create(2000, false, false);
1116 m_vizInitialized = false;
1121 // resample buffers for sink
1122 if (m_sinkBuffers &&
1123 (!CompareFormat(m_sinkBuffers->m_format,m_sinkFormat) || !CompareFormat(m_sinkBuffers->m_inputFormat, sinkInputFormat)))
1125 m_discardBufferPools.push_back(m_sinkBuffers);
1126 m_sinkBuffers = NULL;
1130 m_sinkBuffers = new CActiveAEBufferPoolResample(sinkInputFormat, m_sinkFormat, m_settings.resampleQuality);
1131 m_sinkBuffers->Create(MAX_WATER_LEVEL*1000, true, false);
1135 if (!CompareFormat(oldInternalFormat, m_internalFormat))
1137 if (m_settings.guisoundmode == AE_SOUND_ALWAYS ||
1138 (m_settings.guisoundmode == AE_SOUND_IDLE && m_streams.empty()))
1140 std::vector<CActiveAESound*>::iterator it;
1141 for (it = m_sounds.begin(); it != m_sounds.end(); ++it)
1143 (*it)->SetConverted(false);
1146 m_sounds_playing.clear();
1149 ClearDiscardedBuffers();
1153 CActiveAEStream* CActiveAE::CreateStream(MsgStreamNew *streamMsg)
1155 // we only can handle a single pass through stream
1156 bool hasRawStream = false;
1157 bool hasStream = false;
1158 std::list<CActiveAEStream*>::iterator it;
1159 for(it = m_streams.begin(); it != m_streams.end(); ++it)
1161 if((*it)->IsDrained())
1163 if(AE_IS_RAW((*it)->m_format.m_dataFormat))
1164 hasRawStream = true;
1167 if (hasRawStream || (hasStream && AE_IS_RAW(streamMsg->format.m_dataFormat)))
1172 // create the stream
1173 CActiveAEStream *stream;
1174 stream = new CActiveAEStream(&streamMsg->format);
1175 stream->m_streamPort = new CActiveAEDataProtocol("stream",
1176 &stream->m_inMsgEvent, &m_outMsgEvent);
1178 // create buffer pool
1179 stream->m_inputBuffers = NULL; // create in Configure when we know the sink format
1180 stream->m_resampleBuffers = NULL; // create in Configure when we know the sink format
1181 stream->m_statsLock = m_stats.GetLock();
1182 stream->m_fadingSamples = 0;
1183 stream->m_started = false;
1185 if (streamMsg->options & AESTREAM_PAUSED)
1186 stream->m_paused = true;
1188 if (streamMsg->options & AESTREAM_FORCE_RESAMPLE)
1189 stream->m_forceResampler = true;
1191 m_streams.push_back(stream);
1196 void CActiveAE::DiscardStream(CActiveAEStream *stream)
1198 std::list<CActiveAEStream*>::iterator it;
1199 for (it=m_streams.begin(); it!=m_streams.end(); )
1201 if (stream == (*it))
1203 while (!(*it)->m_processingSamples.empty())
1205 (*it)->m_processingSamples.front()->Return();
1206 (*it)->m_processingSamples.pop_front();
1208 m_discardBufferPools.push_back((*it)->m_inputBuffers);
1209 m_discardBufferPools.push_back((*it)->m_resampleBuffers);
1210 CLog::Log(LOGDEBUG, "CActiveAE::DiscardStream - audio stream deleted");
1211 delete (*it)->m_streamPort;
1213 it = m_streams.erase(it);
1219 ClearDiscardedBuffers();
1222 void CActiveAE::SFlushStream(CActiveAEStream *stream)
1224 while (!stream->m_processingSamples.empty())
1226 stream->m_processingSamples.front()->Return();
1227 stream->m_processingSamples.pop_front();
1229 stream->m_resampleBuffers->Flush();
1230 stream->m_streamPort->Purge();
1231 stream->m_bufferedTime = 0.0;
1232 stream->m_paused = false;
1234 // flush the engine if we only have a single stream
1235 if (m_streams.size() == 1)
1241 void CActiveAE::FlushEngine()
1244 m_sinkBuffers->Flush();
1246 m_vizBuffers->Flush();
1248 // send message to sink
1250 if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::FLUSH,
1253 bool success = reply->signal == CSinkControlProtocol::ACC;
1256 CLog::Log(LOGERROR, "ActiveAE::%s - returned error on flush", __FUNCTION__);
1263 CLog::Log(LOGERROR, "ActiveAE::%s - failed to flush", __FUNCTION__);
1266 m_stats.Reset(m_sinkFormat.m_sampleRate);
1269 void CActiveAE::ClearDiscardedBuffers()
1271 std::list<CActiveAEBufferPool*>::iterator it;
1272 for (it=m_discardBufferPools.begin(); it!=m_discardBufferPools.end(); ++it)
1274 CActiveAEBufferPoolResample *rbuf = dynamic_cast<CActiveAEBufferPoolResample*>(*it);
1279 // if all buffers have returned, we can delete the buffer pool
1280 if ((*it)->m_allSamples.size() == (*it)->m_freeSamples.size())
1283 CLog::Log(LOGDEBUG, "CActiveAE::ClearDiscardedBuffers - buffer pool deleted");
1284 m_discardBufferPools.erase(it);
1290 void CActiveAE::SStopSound(CActiveAESound *sound)
1292 std::list<SoundState>::iterator it;
1293 for (it=m_sounds_playing.begin(); it!=m_sounds_playing.end(); ++it)
1295 if (it->sound == sound)
1297 m_sounds_playing.erase(it);
1303 void CActiveAE::DiscardSound(CActiveAESound *sound)
1307 std::vector<CActiveAESound*>::iterator it;
1308 for (it=m_sounds.begin(); it!=m_sounds.end(); ++it)
1318 void CActiveAE::ChangeResamplers()
1320 std::list<CActiveAEStream*>::iterator it;
1321 for(it=m_streams.begin(); it!=m_streams.end(); ++it)
1323 bool normalize = true;
1324 if (((*it)->m_resampleBuffers->m_format.m_channelLayout.Count() <
1325 (*it)->m_resampleBuffers->m_inputFormat.m_channelLayout.Count()) &&
1326 !m_settings.normalizelevels)
1329 if ((*it)->m_resampleBuffers && (*it)->m_resampleBuffers->m_resampler &&
1330 (((*it)->m_resampleBuffers->m_resampleQuality != m_settings.resampleQuality) ||
1331 (((*it)->m_resampleBuffers->m_stereoUpmix != m_settings.stereoupmix)) ||
1332 ((*it)->m_resampleBuffers->m_normalize != normalize)))
1334 (*it)->m_resampleBuffers->m_changeResampler = true;
1336 (*it)->m_resampleBuffers->m_resampleQuality = m_settings.resampleQuality;
1337 (*it)->m_resampleBuffers->m_stereoUpmix = m_settings.stereoupmix;
1338 (*it)->m_resampleBuffers->m_normalize = normalize;
1342 void CActiveAE::ApplySettingsToFormat(AEAudioFormat &format, AudioSettings &settings, int *mode)
1344 int oldMode = m_mode;
1349 if (AE_IS_RAW(format.m_dataFormat))
1351 if ((format.m_dataFormat == AE_FMT_AC3 && !settings.ac3passthrough) ||
1352 (format.m_dataFormat == AE_FMT_EAC3 && !settings.eac3passthrough) ||
1353 (format.m_dataFormat == AE_FMT_TRUEHD && !settings.truehdpassthrough) ||
1354 (format.m_dataFormat == AE_FMT_DTS && !settings.dtspassthrough) ||
1355 (format.m_dataFormat == AE_FMT_DTSHD && !settings.dtshdpassthrough))
1357 CLog::Log(LOGERROR, "CActiveAE::ApplySettingsToFormat - input audio format is wrong");
1363 else if (settings.channels <= AE_CH_LAYOUT_2_0 && // no multichannel pcm
1364 settings.passthrough &&
1365 settings.ac3passthrough &&
1366 settings.ac3transcode &&
1367 !m_streams.empty() &&
1368 (format.m_channelLayout.Count() > 2 || settings.stereoupmix))
1370 format.m_dataFormat = AE_FMT_AC3;
1371 format.m_sampleRate = 48000;
1372 format.m_channelLayout = AE_CH_LAYOUT_2_0;
1374 *mode = MODE_TRANSCODE;
1378 format.m_dataFormat = AE_FMT_FLOAT;
1379 // consider user channel layout for those cases
1380 // 1. input stream is multichannel
1381 // 2. stereo upmix is selected
1383 if ((format.m_channelLayout.Count() > 2) ||
1384 settings.stereoupmix ||
1385 (settings.config == AE_CONFIG_FIXED))
1387 CAEChannelInfo stdLayout;
1388 switch (settings.channels)
1391 case 0: stdLayout = AE_CH_LAYOUT_2_0; break;
1392 case 1: stdLayout = AE_CH_LAYOUT_2_0; break;
1393 case 2: stdLayout = AE_CH_LAYOUT_2_1; break;
1394 case 3: stdLayout = AE_CH_LAYOUT_3_0; break;
1395 case 4: stdLayout = AE_CH_LAYOUT_3_1; break;
1396 case 5: stdLayout = AE_CH_LAYOUT_4_0; break;
1397 case 6: stdLayout = AE_CH_LAYOUT_4_1; break;
1398 case 7: stdLayout = AE_CH_LAYOUT_5_0; break;
1399 case 8: stdLayout = AE_CH_LAYOUT_5_1; break;
1400 case 9: stdLayout = AE_CH_LAYOUT_7_0; break;
1401 case 10: stdLayout = AE_CH_LAYOUT_7_1; break;
1404 if (m_settings.config == AE_CONFIG_FIXED || (settings.stereoupmix && format.m_channelLayout.Count() <= 2))
1405 format.m_channelLayout = stdLayout;
1406 else if (m_extKeepConfig && (settings.config == AE_CONFIG_AUTO) && (oldMode != MODE_RAW))
1407 format.m_channelLayout = m_internalFormat.m_channelLayout;
1409 format.m_channelLayout.ResolveChannels(stdLayout);
1411 // don't change from multi to stereo in AUTO mode
1412 else if ((settings.config == AE_CONFIG_AUTO) &&
1413 m_stats.GetWaterLevel() > 0 && m_internalFormat.m_channelLayout.Count() > 2)
1415 format.m_channelLayout = m_internalFormat.m_channelLayout;
1418 if (m_sink.GetDeviceType(m_settings.device) == AE_DEVTYPE_IEC958)
1420 if (format.m_sampleRate > m_settings.samplerate)
1422 format.m_sampleRate = m_settings.samplerate;
1423 CLog::Log(LOGINFO, "CActiveAE::ApplySettings - limit samplerate for SPDIF to %d", format.m_sampleRate);
1425 format.m_channelLayout = AE_CH_LAYOUT_2_0;
1428 if (m_settings.config == AE_CONFIG_FIXED)
1430 format.m_sampleRate = m_settings.samplerate;
1431 CLog::Log(LOGINFO, "CActiveAE::ApplySettings - Forcing samplerate to %d", format.m_sampleRate);
1434 // sinks may not support mono
1435 if (format.m_channelLayout.Count() == 1)
1437 format.m_channelLayout = AE_CH_LAYOUT_2_0;
1442 bool CActiveAE::NeedReconfigureBuffers()
1444 AEAudioFormat newFormat = GetInputFormat();
1445 ApplySettingsToFormat(newFormat, m_settings);
1447 if (newFormat.m_dataFormat != m_sinkRequestFormat.m_dataFormat ||
1448 newFormat.m_channelLayout != m_sinkRequestFormat.m_channelLayout ||
1449 newFormat.m_sampleRate != m_sinkRequestFormat.m_sampleRate)
1455 bool CActiveAE::NeedReconfigureSink()
1457 AEAudioFormat newFormat = GetInputFormat();
1458 ApplySettingsToFormat(newFormat, m_settings);
1460 std::string device = AE_IS_RAW(newFormat.m_dataFormat) ? m_settings.passthoughdevice : m_settings.device;
1462 CAESinkFactory::ParseDevice(device, driver);
1464 if (!CompareFormat(newFormat, m_sinkFormat) ||
1465 m_currDevice.compare(device) != 0 ||
1466 m_settings.driver.compare(driver) != 0)
1472 bool CActiveAE::InitSink()
1475 config.format = m_sinkRequestFormat;
1476 config.stats = &m_stats;
1477 config.device = AE_IS_RAW(m_sinkRequestFormat.m_dataFormat) ? &m_settings.passthoughdevice :
1480 // send message to sink
1482 if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::CONFIGURE,
1485 &config, sizeof(config)))
1487 bool success = reply->signal == CSinkControlProtocol::ACC;
1491 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
1496 data = (SinkReply*)reply->data;
1499 m_sinkFormat = data->format;
1500 m_sinkHasVolume = data->hasVolume;
1501 m_stats.SetSinkCacheTotal(data->cacheTotal);
1502 m_stats.SetSinkLatency(data->latency);
1508 CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__);
1509 m_stats.SetSinkCacheTotal(0);
1510 m_stats.SetSinkLatency(0);
1515 m_inMsgEvent.Reset();
1519 void CActiveAE::DrainSink()
1521 // send message to sink
1523 if (m_sink.m_dataPort.SendOutMessageSync(CSinkDataProtocol::DRAIN,
1527 bool success = reply->signal == CSinkDataProtocol::ACC;
1531 CLog::Log(LOGERROR, "ActiveAE::%s - returned error on drain", __FUNCTION__);
1539 CLog::Log(LOGERROR, "ActiveAE::%s - failed to drain", __FUNCTION__);
1545 void CActiveAE::UnconfigureSink()
1547 // send message to sink
1549 if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::UNCONFIGURE,
1553 bool success = reply->signal == CSinkControlProtocol::ACC;
1556 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
1563 CLog::Log(LOGERROR, "ActiveAE::%s - failed to unconfigure", __FUNCTION__);
1567 // make sure we open sink on next configure
1570 m_inMsgEvent.Reset();
1574 bool CActiveAE::RunStages()
1578 // serve input streams
1579 std::list<CActiveAEStream*>::iterator it;
1580 for (it = m_streams.begin(); it != m_streams.end(); ++it)
1582 if ((*it)->m_resampleBuffers && !(*it)->m_paused)
1583 busy = (*it)->m_resampleBuffers->ResampleBuffers();
1584 else if ((*it)->m_resampleBuffers &&
1585 ((*it)->m_resampleBuffers->m_inputSamples.size() > (*it)->m_resampleBuffers->m_allSamples.size() * 0.5))
1587 CSingleLock lock((*it)->m_streamLock);
1588 (*it)->m_streamIsBuffering = false;
1591 // provide buffers to stream
1592 float time = m_stats.GetCacheTime((*it));
1593 CSampleBuffer *buffer;
1594 if (!(*it)->m_drain)
1596 while (time < MAX_CACHE_LEVEL && !(*it)->m_inputBuffers->m_freeSamples.empty())
1598 buffer = (*it)->m_inputBuffers->GetFreeBuffer();
1599 (*it)->m_processingSamples.push_back(buffer);
1600 (*it)->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMBUFFER, &buffer, sizeof(CSampleBuffer*));
1601 (*it)->IncFreeBuffers();
1602 time += (float)buffer->pkt->max_nb_samples / buffer->pkt->config.sample_rate;
1607 if ((*it)->m_resampleBuffers->m_inputSamples.empty() &&
1608 (*it)->m_resampleBuffers->m_outputSamples.empty() &&
1609 (*it)->m_processingSamples.empty())
1611 (*it)->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMDRAINED);
1612 (*it)->m_drain = false;
1613 (*it)->m_resampleBuffers->m_drain = false;
1614 (*it)->m_started = false;
1616 // set variables being polled via stream interface
1617 CSingleLock lock((*it)->m_streamLock);
1618 if ((*it)->m_streamSlave)
1620 CActiveAEStream *slave = (CActiveAEStream*)((*it)->m_streamSlave);
1621 slave->m_paused = false;
1623 // TODO: find better solution for this
1624 // gapless bites audiophile
1625 if (m_settings.config == AE_CONFIG_MATCH)
1626 Configure(&slave->m_format);
1628 (*it)->m_streamSlave = NULL;
1630 (*it)->m_streamDrained = true;
1631 (*it)->m_streamDraining = false;
1632 (*it)->m_streamFading = false;
1637 if (m_stats.GetWaterLevel() < MAX_WATER_LEVEL &&
1638 (m_mode != MODE_TRANSCODE || (m_encoderBuffers && !m_encoderBuffers->m_freeSamples.empty())))
1640 // mix streams and sounds sounds
1641 if (m_mode != MODE_RAW)
1643 CSampleBuffer *out = NULL;
1644 if (!m_sounds_playing.empty() && m_streams.empty())
1646 if (m_silenceBuffers && !m_silenceBuffers->m_freeSamples.empty())
1648 out = m_silenceBuffers->GetFreeBuffer();
1649 for (int i=0; i<out->pkt->planes; i++)
1651 memset(out->pkt->data[i], 0, out->pkt->linesize);
1653 out->pkt->nb_samples = out->pkt->max_nb_samples;
1658 std::list<CActiveAEStream*>::iterator it;
1660 // if we deal with more than a single stream, all streams
1661 // must provide samples for mixing
1662 bool allStreamsReady = true;
1663 for (it = m_streams.begin(); it != m_streams.end(); ++it)
1665 if ((*it)->m_paused || !(*it)->m_started || !(*it)->m_resampleBuffers)
1668 if ((*it)->m_resampleBuffers->m_outputSamples.empty())
1669 allStreamsReady = false;
1672 bool needClamp = false;
1673 for (it = m_streams.begin(); it != m_streams.end() && allStreamsReady; ++it)
1675 if ((*it)->m_paused || !(*it)->m_resampleBuffers)
1678 if (!(*it)->m_resampleBuffers->m_outputSamples.empty())
1680 (*it)->m_started = true;
1684 out = (*it)->m_resampleBuffers->m_outputSamples.front();
1685 (*it)->m_resampleBuffers->m_outputSamples.pop_front();
1687 int nb_floats = out->pkt->nb_samples * out->pkt->config.channels / out->pkt->planes;
1689 float fadingStep = 0.0f;
1692 if ((*it)->m_fadingSamples == -1)
1694 (*it)->m_fadingSamples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1695 (*it)->m_volume = (*it)->m_fadingBase;
1697 if ((*it)->m_fadingSamples > 0)
1699 nb_floats = out->pkt->config.channels / out->pkt->planes;
1700 nb_loops = out->pkt->nb_samples;
1701 float delta = (*it)->m_fadingTarget - (*it)->m_fadingBase;
1702 int samples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1703 fadingStep = delta / samples;
1706 // for stream amplification,
1707 // turned off downmix normalization,
1708 // or if sink format is float (in order to prevent from clipping)
1709 // we need to run on a per sample basis
1710 if ((*it)->m_amplify != 1.0 || !(*it)->m_resampleBuffers->m_normalize || (m_sinkFormat.m_dataFormat == AE_FMT_FLOAT))
1712 nb_floats = out->pkt->config.channels / out->pkt->planes;
1713 nb_loops = out->pkt->nb_samples;
1716 for(int i=0; i<nb_loops; i++)
1718 if ((*it)->m_fadingSamples > 0)
1720 (*it)->m_volume += fadingStep;
1721 (*it)->m_fadingSamples--;
1723 if ((*it)->m_fadingSamples == 0)
1725 // set variables being polled via stream interface
1726 CSingleLock lock((*it)->m_streamLock);
1727 (*it)->m_streamFading = false;
1731 // volume for stream
1732 float volume = (*it)->m_volume * (*it)->m_rgain;
1734 volume *= (*it)->m_limiter.Run((float**)out->pkt->data, out->pkt->config.channels, i*nb_floats, out->pkt->planes > 1);
1736 for(int j=0; j<out->pkt->planes; j++)
1739 CAEUtil::SSEMulArray((float*)out->pkt->data[j]+i*nb_floats, volume, nb_floats);
1741 float* fbuffer = (float*) out->pkt->data[j]+i*nb_floats;
1742 for (int k = 0; k < nb_floats; ++k)
1744 fbuffer[k] *= volume;
1752 CSampleBuffer *mix = NULL;
1753 mix = (*it)->m_resampleBuffers->m_outputSamples.front();
1754 (*it)->m_resampleBuffers->m_outputSamples.pop_front();
1756 int nb_floats = mix->pkt->nb_samples * mix->pkt->config.channels / mix->pkt->planes;
1758 float fadingStep = 0.0f;
1761 if ((*it)->m_fadingSamples == -1)
1763 (*it)->m_fadingSamples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1764 (*it)->m_volume = (*it)->m_fadingBase;
1766 if ((*it)->m_fadingSamples > 0)
1768 nb_floats = mix->pkt->config.channels / mix->pkt->planes;
1769 nb_loops = mix->pkt->nb_samples;
1770 float delta = (*it)->m_fadingTarget - (*it)->m_fadingBase;
1771 int samples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1772 fadingStep = delta / samples;
1775 // for streams amplification of turned off downmix normalization
1776 // we need to run on a per sample basis
1777 if ((*it)->m_amplify != 1.0 || !(*it)->m_resampleBuffers->m_normalize)
1779 nb_floats = out->pkt->config.channels / out->pkt->planes;
1780 nb_loops = out->pkt->nb_samples;
1783 for(int i=0; i<nb_loops; i++)
1785 if ((*it)->m_fadingSamples > 0)
1787 (*it)->m_volume += fadingStep;
1788 (*it)->m_fadingSamples--;
1790 if ((*it)->m_fadingSamples == 0)
1792 // set variables being polled via stream interface
1793 CSingleLock lock((*it)->m_streamLock);
1794 (*it)->m_streamFading = false;
1798 // volume for stream
1799 float volume = (*it)->m_volume * (*it)->m_rgain;
1801 volume *= (*it)->m_limiter.Run((float**)mix->pkt->data, mix->pkt->config.channels, i*nb_floats, mix->pkt->planes > 1);
1803 for(int j=0; j<out->pkt->planes && j<mix->pkt->planes; j++)
1805 float *dst = (float*)out->pkt->data[j]+i*nb_floats;
1806 float *src = (float*)mix->pkt->data[j]+i*nb_floats;
1808 CAEUtil::SSEMulAddArray(dst, src, volume, nb_floats);
1809 for (int k = 0; k < nb_floats; ++k)
1811 if (fabs(dst[k]) > 1.0f)
1818 for (int k = 0; k < nb_floats; ++k)
1820 dst[k] += src[k] * volume;
1821 if (fabs(dst[k]) > 1.0f)
1833 // finally clamp samples
1834 if(out && needClamp)
1836 int nb_floats = out->pkt->nb_samples * out->pkt->config.channels / out->pkt->planes;
1837 for(int i=0; i<out->pkt->planes; i++)
1839 CAEUtil::ClampArray((float*)out->pkt->data[i], nb_floats);
1843 // process output buffer, gui sounds, encode, viz
1848 CSingleLock lock(m_vizLock);
1849 if (m_audioCallback && m_vizBuffers && !m_streams.empty())
1851 if (!m_vizInitialized)
1853 m_audioCallback->OnInitialize(2, m_vizBuffers->m_format.m_sampleRate, 32);
1854 m_vizInitialized = true;
1857 if (!m_vizBuffersInput->m_freeSamples.empty())
1859 // copy the samples into the viz input buffer
1860 CSampleBuffer *viz = m_vizBuffersInput->GetFreeBuffer();
1861 int samples = std::min(512, out->pkt->nb_samples);
1862 int bytes = samples * out->pkt->config.channels / out->pkt->planes * out->pkt->bytes_per_sample;
1863 for(int i= 0; i < out->pkt->planes; i++)
1865 memcpy(viz->pkt->data[i], out->pkt->data[i], bytes);
1867 viz->pkt->nb_samples = samples;
1868 m_vizBuffers->m_inputSamples.push_back(viz);
1871 CLog::Log(LOGWARNING,"ActiveAE::%s - viz ran out of free buffers", __FUNCTION__);
1872 unsigned int now = XbmcThreads::SystemClockMillis();
1873 unsigned int timestamp = now + m_stats.GetDelay() * 1000;
1874 busy |= m_vizBuffers->ResampleBuffers(timestamp);
1875 while(!m_vizBuffers->m_outputSamples.empty())
1877 CSampleBuffer *buf = m_vizBuffers->m_outputSamples.front();
1878 if ((now - buf->timestamp) & 0x80000000)
1883 samples = std::min(512, buf->pkt->nb_samples);
1884 m_audioCallback->OnAudioData((float*)(buf->pkt->data[0]), samples);
1886 m_vizBuffers->m_outputSamples.pop_front();
1890 else if (m_vizBuffers)
1891 m_vizBuffers->Flush();
1895 MixSounds(*(out->pkt));
1896 if (!m_sinkHasVolume || m_muted)
1897 Deamplify(*(out->pkt));
1899 if (m_mode == MODE_TRANSCODE && m_encoder)
1901 CSampleBuffer *buf = m_encoderBuffers->GetFreeBuffer();
1902 m_encoder->Encode(out->pkt->data[0], out->pkt->planes*out->pkt->linesize,
1903 buf->pkt->data[0], buf->pkt->planes*buf->pkt->linesize);
1904 buf->pkt->nb_samples = buf->pkt->max_nb_samples;
1914 m_stats.AddSamples(out->pkt->nb_samples, m_streams);
1915 m_sinkBuffers->m_inputSamples.push_back(out);
1921 std::list<CActiveAEStream*>::iterator it;
1922 CSampleBuffer *buffer;
1923 for (it = m_streams.begin(); it != m_streams.end(); ++it)
1925 if (!(*it)->m_resampleBuffers->m_outputSamples.empty())
1927 buffer = (*it)->m_resampleBuffers->m_outputSamples.front();
1928 (*it)->m_resampleBuffers->m_outputSamples.pop_front();
1929 m_stats.AddSamples(buffer->pkt->nb_samples, m_streams);
1930 m_sinkBuffers->m_inputSamples.push_back(buffer);
1935 // serve sink buffers
1936 busy = m_sinkBuffers->ResampleBuffers();
1937 while(!m_sinkBuffers->m_outputSamples.empty())
1939 CSampleBuffer *out = NULL;
1940 out = m_sinkBuffers->m_outputSamples.front();
1941 m_sinkBuffers->m_outputSamples.pop_front();
1942 m_sink.m_dataPort.SendOutMessage(CSinkDataProtocol::SAMPLE,
1943 &out, sizeof(CSampleBuffer*));
1951 bool CActiveAE::HasWork()
1953 if (!m_sounds_playing.empty())
1955 if (!m_sinkBuffers->m_inputSamples.empty())
1957 if (!m_sinkBuffers->m_outputSamples.empty())
1960 std::list<CActiveAEStream*>::iterator it;
1961 for (it = m_streams.begin(); it != m_streams.end(); ++it)
1963 if (!(*it)->m_resampleBuffers->m_inputSamples.empty())
1965 if (!(*it)->m_resampleBuffers->m_outputSamples.empty())
1967 if (!(*it)->m_processingSamples.empty())
1974 void CActiveAE::MixSounds(CSoundPacket &dstSample)
1976 if (m_sounds_playing.empty())
1981 float *sample_buffer;
1982 int max_samples = dstSample.nb_samples;
1984 std::list<SoundState>::iterator it;
1985 for (it = m_sounds_playing.begin(); it != m_sounds_playing.end(); )
1987 if (!it->sound->IsConverted())
1988 ResampleSound(it->sound);
1989 int available_samples = it->sound->GetSound(false)->nb_samples - it->samples_played;
1990 int mix_samples = std::min(max_samples, available_samples);
1991 int start = it->samples_played *
1992 m_dllAvUtil.av_get_bytes_per_sample(it->sound->GetSound(false)->config.fmt) *
1993 it->sound->GetSound(false)->config.channels /
1994 it->sound->GetSound(false)->planes;
1996 for(int j=0; j<dstSample.planes; j++)
1998 volume = it->sound->GetVolume();
1999 out = (float*)dstSample.data[j];
2000 sample_buffer = (float*)(it->sound->GetSound(false)->data[j]+start);
2001 int nb_floats = mix_samples * dstSample.config.channels / dstSample.planes;
2003 CAEUtil::SSEMulAddArray(out, sample_buffer, volume, nb_floats);
2005 for (int k = 0; k < nb_floats; ++k)
2006 *out++ += *sample_buffer++ * volume;
2010 it->samples_played += mix_samples;
2012 // no more frames, so remove it from the list
2013 if (it->samples_played >= it->sound->GetSound(false)->nb_samples)
2015 it = m_sounds_playing.erase(it);
2022 void CActiveAE::Deamplify(CSoundPacket &dstSample)
2024 if (m_volume < 1.0 || m_muted)
2027 int nb_floats = dstSample.nb_samples * dstSample.config.channels / dstSample.planes;
2029 for(int j=0; j<dstSample.planes; j++)
2031 buffer = (float*)dstSample.data[j];
2033 CAEUtil::SSEMulArray(buffer, m_muted ? 0.0 : m_volume, nb_floats);
2035 float *fbuffer = buffer;
2036 for (int i = 0; i < nb_floats; i++)
2037 *fbuffer++ *= m_volume;
2043 //-----------------------------------------------------------------------------
2045 //-----------------------------------------------------------------------------
2047 void CActiveAE::LoadSettings()
2049 m_settings.device = CSettings::Get().GetString("audiooutput.audiodevice");
2050 m_settings.passthoughdevice = CSettings::Get().GetString("audiooutput.passthroughdevice");
2052 m_settings.config = CSettings::Get().GetInt("audiooutput.config");
2053 m_settings.channels = (m_sink.GetDeviceType(m_settings.device) == AE_DEVTYPE_IEC958) ? AE_CH_LAYOUT_2_0 : CSettings::Get().GetInt("audiooutput.channels");
2054 m_settings.samplerate = CSettings::Get().GetInt("audiooutput.samplerate");
2056 m_settings.stereoupmix = IsSettingVisible("audiooutput.stereoupmix") ? CSettings::Get().GetBool("audiooutput.stereoupmix") : false;
2057 m_settings.normalizelevels = CSettings::Get().GetBool("audiooutput.normalizelevels");
2058 m_settings.guisoundmode = CSettings::Get().GetInt("audiooutput.guisoundmode");
2060 m_settings.passthrough = m_settings.config == AE_CONFIG_FIXED ? false : CSettings::Get().GetBool("audiooutput.passthrough");
2061 if (!m_sink.HasPassthroughDevice())
2062 m_settings.passthrough = false;
2063 m_settings.ac3passthrough = CSettings::Get().GetBool("audiooutput.ac3passthrough");
2064 m_settings.ac3transcode = CSettings::Get().GetBool("audiooutput.ac3transcode");
2065 m_settings.eac3passthrough = CSettings::Get().GetBool("audiooutput.eac3passthrough");
2066 m_settings.truehdpassthrough = CSettings::Get().GetBool("audiooutput.truehdpassthrough");
2067 m_settings.dtspassthrough = CSettings::Get().GetBool("audiooutput.dtspassthrough");
2068 m_settings.dtshdpassthrough = CSettings::Get().GetBool("audiooutput.dtshdpassthrough");
2070 m_settings.resampleQuality = static_cast<AEQuality>(CSettings::Get().GetInt("audiooutput.processquality"));
2073 bool CActiveAE::Initialize()
2075 if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllAvFormat.Load())
2077 CLog::Log(LOGERROR,"CActiveAE::Initialize - failed to load ffmpeg libraries");
2080 m_dllAvFormat.av_register_all();
2084 if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::INIT,
2088 bool success = reply->signal == CActiveAEControlProtocol::ACC;
2092 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
2099 CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__);
2104 // hook into windowing for receiving display reset events
2105 #if defined(HAS_GLX) || defined(TARGET_DARWIN_OSX)
2106 g_Windowing.Register(this);
2109 m_inMsgEvent.Reset();
2113 void CActiveAE::EnumerateOutputDevices(AEDeviceList &devices, bool passthrough)
2115 m_sink.EnumerateOutputDevices(devices, passthrough);
2118 std::string CActiveAE::GetDefaultDevice(bool passthrough)
2120 return m_sink.GetDefaultDevice(passthrough);
2123 void CActiveAE::OnSettingsChange(const std::string& setting)
2125 if (setting == "audiooutput.passthroughdevice" ||
2126 setting == "audiooutput.audiodevice" ||
2127 setting == "audiooutput.config" ||
2128 setting == "audiooutput.ac3passthrough" ||
2129 setting == "audiooutput.ac3transcode" ||
2130 setting == "audiooutput.eac3passthrough" ||
2131 setting == "audiooutput.dtspassthrough" ||
2132 setting == "audiooutput.truehdpassthrough" ||
2133 setting == "audiooutput.dtshdpassthrough" ||
2134 setting == "audiooutput.channels" ||
2135 setting == "audiooutput.stereoupmix" ||
2136 setting == "audiooutput.streamsilence" ||
2137 setting == "audiooutput.processquality" ||
2138 setting == "audiooutput.passthrough" ||
2139 setting == "audiooutput.samplerate" ||
2140 setting == "audiooutput.normalizelevels" ||
2141 setting == "audiooutput.guisoundmode")
2143 m_controlPort.SendOutMessage(CActiveAEControlProtocol::RECONFIGURE);
2147 bool CActiveAE::SupportsRaw(AEDataFormat format)
2149 if (!m_sink.SupportsFormat(CSettings::Get().GetString("audiooutput.passthroughdevice"), format))
2155 bool CActiveAE::SupportsSilenceTimeout()
2160 bool CActiveAE::SupportsQualityLevel(enum AEQuality level)
2162 if (level == AE_QUALITY_LOW || level == AE_QUALITY_MID || level == AE_QUALITY_HIGH)
2168 bool CActiveAE::IsSettingVisible(const std::string &settingId)
2170 if (settingId == "audiooutput.samplerate")
2172 if (m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) == AE_DEVTYPE_IEC958)
2174 if (CSettings::Get().GetInt("audiooutput.config") == AE_CONFIG_FIXED)
2177 else if (settingId == "audiooutput.channels")
2179 if (m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) != AE_DEVTYPE_IEC958)
2182 else if (settingId == "audiooutput.passthrough")
2184 if (m_sink.HasPassthroughDevice() && CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED)
2187 else if (settingId == "audiooutput.truehdpassthrough")
2189 if (m_sink.SupportsFormat(CSettings::Get().GetString("audiooutput.passthroughdevice"), AE_FMT_TRUEHD) &&
2190 CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED)
2193 else if (settingId == "audiooutput.dtshdpassthrough")
2195 if (m_sink.SupportsFormat(CSettings::Get().GetString("audiooutput.passthroughdevice"), AE_FMT_DTSHD) &&
2196 CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED)
2199 else if (settingId == "audiooutput.eac3passthrough")
2201 if (m_sink.SupportsFormat(CSettings::Get().GetString("audiooutput.passthroughdevice"), AE_FMT_EAC3) &&
2202 CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED)
2205 else if (settingId == "audiooutput.stereoupmix")
2207 if (m_sink.HasPassthroughDevice() ||
2208 CSettings::Get().GetInt("audiooutput.channels") > AE_CH_LAYOUT_2_0)
2211 else if (settingId == "audiooutput.ac3transcode")
2213 if (m_sink.HasPassthroughDevice() &&
2214 CSettings::Get().GetBool("audiooutput.ac3passthrough") &&
2215 CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED &&
2216 (CSettings::Get().GetInt("audiooutput.channels") <= AE_CH_LAYOUT_2_0 || m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) == AE_DEVTYPE_IEC958))
2222 void CActiveAE::Shutdown()
2227 bool CActiveAE::Suspend()
2229 return m_controlPort.SendOutMessage(CActiveAEControlProtocol::SUSPEND);
2232 bool CActiveAE::Resume()
2235 if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::INIT,
2239 bool success = reply->signal == CActiveAEControlProtocol::ACC;
2243 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
2249 CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__);
2253 m_inMsgEvent.Reset();
2257 bool CActiveAE::IsSuspended()
2259 return m_stats.IsSuspended();
2262 float CActiveAE::GetVolume()
2267 void CActiveAE::SetVolume(const float volume)
2269 m_aeVolume = std::max( 0.0f, std::min(1.0f, volume));
2270 m_controlPort.SendOutMessage(CActiveAEControlProtocol::VOLUME, &m_aeVolume, sizeof(float));
2273 void CActiveAE::SetMute(const bool enabled)
2275 m_aeMuted = enabled;
2276 m_controlPort.SendOutMessage(CActiveAEControlProtocol::MUTE, &m_aeMuted, sizeof(bool));
2279 bool CActiveAE::IsMuted()
2284 void CActiveAE::SetSoundMode(const int mode)
2289 void CActiveAE::KeepConfiguration(unsigned int millis)
2291 unsigned int timeMs = millis;
2292 m_controlPort.SendOutMessage(CActiveAEControlProtocol::KEEPCONFIG, &timeMs, sizeof(unsigned int));
2295 void CActiveAE::OnLostDevice()
2298 if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::DISPLAYLOST,
2302 bool success = reply->signal == CActiveAEControlProtocol::ACC;
2306 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
2311 CLog::Log(LOGERROR, "ActiveAE::%s - timed out", __FUNCTION__);
2315 void CActiveAE::OnResetDevice()
2317 m_controlPort.SendOutMessage(CActiveAEControlProtocol::DISPLAYRESET);
2320 //-----------------------------------------------------------------------------
2322 //-----------------------------------------------------------------------------
2324 uint8_t **CActiveAE::AllocSoundSample(SampleConfig &config, int &samples, int &bytes_per_sample, int &planes, int &linesize)
2327 planes = m_dllAvUtil.av_sample_fmt_is_planar(config.fmt) ? config.channels : 1;
2328 buffer = new uint8_t*[planes];
2330 // align buffer to 16 in order to be compatible with sse in CAEConvert
2331 m_dllAvUtil.av_samples_alloc(buffer, &linesize, config.channels,
2332 samples, config.fmt, 16);
2333 bytes_per_sample = m_dllAvUtil.av_get_bytes_per_sample(config.fmt);
2337 void CActiveAE::FreeSoundSample(uint8_t **data)
2339 m_dllAvUtil.av_freep(data);
2343 bool CActiveAE::CompareFormat(AEAudioFormat &lhs, AEAudioFormat &rhs)
2345 if (lhs.m_channelLayout != rhs.m_channelLayout ||
2346 lhs.m_dataFormat != rhs.m_dataFormat ||
2347 lhs.m_sampleRate != rhs.m_sampleRate)
2353 //-----------------------------------------------------------------------------
2355 //-----------------------------------------------------------------------------
2358 * load sound from an audio file and store original format
2359 * register the sound in ActiveAE
2360 * later when the engine is idle it will convert the sound to sink format
2363 #define SOUNDBUFFER_SIZE 20480
2365 IAESound *CActiveAE::MakeSound(const std::string& file)
2367 AVFormatContext *fmt_ctx = NULL;
2368 AVCodecContext *dec_ctx = NULL;
2369 AVIOContext *io_ctx;
2370 AVInputFormat *io_fmt;
2371 AVCodec *dec = NULL;
2372 CActiveAESound *sound = NULL;
2373 SampleConfig config;
2375 sound = new CActiveAESound(file);
2376 if (!sound->Prepare())
2381 int fileSize = sound->GetFileSize();
2383 fmt_ctx = m_dllAvFormat.avformat_alloc_context();
2384 unsigned char* buffer = (unsigned char*)m_dllAvUtil.av_malloc(SOUNDBUFFER_SIZE+FF_INPUT_BUFFER_PADDING_SIZE);
2385 io_ctx = m_dllAvFormat.avio_alloc_context(buffer, SOUNDBUFFER_SIZE, 0,
2386 sound, CActiveAESound::Read, NULL, CActiveAESound::Seek);
2387 io_ctx->max_packet_size = sound->GetChunkSize();
2388 if(io_ctx->max_packet_size)
2389 io_ctx->max_packet_size *= SOUNDBUFFER_SIZE / io_ctx->max_packet_size;
2391 if(!sound->IsSeekPosible())
2392 io_ctx->seekable = 0;
2394 fmt_ctx->pb = io_ctx;
2396 m_dllAvFormat.av_probe_input_buffer(io_ctx, &io_fmt, file.c_str(), NULL, 0, 0);
2399 m_dllAvFormat.avformat_close_input(&fmt_ctx);
2405 if (m_dllAvFormat.avformat_open_input(&fmt_ctx, file.c_str(), NULL, NULL) == 0)
2407 fmt_ctx->flags |= AVFMT_FLAG_NOPARSE;
2408 if (m_dllAvFormat.avformat_find_stream_info(fmt_ctx, NULL) >= 0)
2410 dec_ctx = fmt_ctx->streams[0]->codec;
2411 dec = m_dllAvCodec.avcodec_find_decoder(dec_ctx->codec_id);
2412 config.sample_rate = dec_ctx->sample_rate;
2413 config.channels = dec_ctx->channels;
2414 config.channel_layout = dec_ctx->channel_layout;
2419 m_dllAvFormat.avformat_close_input(&fmt_ctx);
2424 dec_ctx = m_dllAvCodec.avcodec_alloc_context3(dec);
2425 dec_ctx->sample_rate = config.sample_rate;
2426 dec_ctx->channels = config.channels;
2427 if (!config.channel_layout)
2428 config.channel_layout = m_dllAvUtil.av_get_default_channel_layout(config.channels);
2429 dec_ctx->channel_layout = config.channel_layout;
2432 AVFrame *decoded_frame = NULL;
2433 decoded_frame = m_dllAvCodec.avcodec_alloc_frame();
2435 if (m_dllAvCodec.avcodec_open2(dec_ctx, dec, NULL) >= 0)
2440 m_dllAvCodec.av_init_packet(&avpkt);
2442 while (m_dllAvFormat.av_read_frame(fmt_ctx, &avpkt) >= 0)
2445 len = m_dllAvCodec.avcodec_decode_audio4(dec_ctx, decoded_frame, &got_frame, &avpkt);
2448 m_dllAvCodec.avcodec_close(dec_ctx);
2449 m_dllAvUtil.av_free(dec_ctx);
2450 m_dllAvUtil.av_free(&decoded_frame);
2451 m_dllAvFormat.avformat_close_input(&fmt_ctx);
2459 int samples = fileSize / m_dllAvUtil.av_get_bytes_per_sample(dec_ctx->sample_fmt) / config.channels;
2460 config.fmt = dec_ctx->sample_fmt;
2461 config.bits_per_sample = dec_ctx->bits_per_coded_sample;
2462 sound->InitSound(true, config, samples);
2465 sound->StoreSound(true, decoded_frame->extended_data,
2466 decoded_frame->nb_samples, decoded_frame->linesize[0]);
2469 m_dllAvCodec.avcodec_close(dec_ctx);
2472 m_dllAvUtil.av_free(dec_ctx);
2473 m_dllAvUtil.av_free(decoded_frame);
2474 m_dllAvFormat.avformat_close_input(&fmt_ctx);
2479 m_dataPort.SendOutMessage(CActiveAEDataProtocol::NEWSOUND, &sound, sizeof(CActiveAESound*));
2484 void CActiveAE::FreeSound(IAESound *sound)
2486 m_dataPort.SendOutMessage(CActiveAEDataProtocol::FREESOUND, &sound, sizeof(CActiveAESound*));
2489 void CActiveAE::PlaySound(CActiveAESound *sound)
2491 m_dataPort.SendOutMessage(CActiveAEDataProtocol::PLAYSOUND, &sound, sizeof(CActiveAESound*));
2494 void CActiveAE::StopSound(CActiveAESound *sound)
2496 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STOPSOUND, &sound, sizeof(CActiveAESound*));
2500 * resample sounds to destination format for mixing
2501 * destination format is either format of stream or
2502 * default sink format when no stream is playing
2504 void CActiveAE::ResampleSounds()
2506 if (m_settings.guisoundmode == AE_SOUND_OFF ||
2507 (m_settings.guisoundmode == AE_SOUND_IDLE && !m_streams.empty()))
2510 std::vector<CActiveAESound*>::iterator it;
2511 for (it = m_sounds.begin(); it != m_sounds.end(); ++it)
2513 if (!(*it)->IsConverted())
2516 // only do one sound, then yield to main loop
2522 bool CActiveAE::ResampleSound(CActiveAESound *sound)
2524 SampleConfig orig_config, dst_config;
2525 uint8_t **dst_buffer;
2528 if (m_mode == MODE_RAW || m_internalFormat.m_dataFormat == AE_FMT_INVALID)
2531 if (!sound->GetSound(true))
2534 orig_config = sound->GetSound(true)->config;
2536 dst_config.channel_layout = CActiveAEResample::GetAVChannelLayout(m_internalFormat.m_channelLayout);
2537 dst_config.channels = m_internalFormat.m_channelLayout.Count();
2538 dst_config.sample_rate = m_internalFormat.m_sampleRate;
2539 dst_config.fmt = CActiveAEResample::GetAVSampleFormat(m_internalFormat.m_dataFormat);
2540 dst_config.bits_per_sample = CAEUtil::DataFormatToUsedBits(m_internalFormat.m_dataFormat);
2542 CActiveAEResample *resampler = new CActiveAEResample();
2543 resampler->Init(dst_config.channel_layout,
2544 dst_config.channels,
2545 dst_config.sample_rate,
2547 dst_config.bits_per_sample,
2548 orig_config.channel_layout,
2549 orig_config.channels,
2550 orig_config.sample_rate,
2552 orig_config.bits_per_sample,
2556 m_settings.resampleQuality);
2558 dst_samples = resampler->CalcDstSampleCount(sound->GetSound(true)->nb_samples,
2559 m_internalFormat.m_sampleRate,
2560 orig_config.sample_rate);
2562 dst_buffer = sound->InitSound(false, dst_config, dst_samples);
2568 int samples = resampler->Resample(dst_buffer, dst_samples,
2569 sound->GetSound(true)->data,
2570 sound->GetSound(true)->nb_samples,
2573 sound->GetSound(false)->nb_samples = samples;
2576 sound->SetConverted(true);
2580 //-----------------------------------------------------------------------------
2582 //-----------------------------------------------------------------------------
2584 IAEStream *CActiveAE::MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSampleRate, CAEChannelInfo channelLayout, unsigned int options)
2586 //TODO: pass number of samples in audio packet
2588 AEAudioFormat format;
2589 format.m_dataFormat = dataFormat;
2590 format.m_sampleRate = sampleRate;
2591 format.m_encodedRate = encodedSampleRate;
2592 format.m_channelLayout = channelLayout;
2593 format.m_frames = format.m_sampleRate / 10;
2594 format.m_frameSize = format.m_channelLayout.Count() *
2595 (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);
2598 msg.format = format;
2599 msg.options = options;
2602 if (m_dataPort.SendOutMessageSync(CActiveAEDataProtocol::NEWSTREAM,
2604 &msg, sizeof(MsgStreamNew)))
2606 bool success = reply->signal == CActiveAEControlProtocol::ACC;
2609 CActiveAEStream *stream = *(CActiveAEStream**)reply->data;
2616 CLog::Log(LOGERROR, "ActiveAE::%s - could not create stream", __FUNCTION__);
2620 IAEStream *CActiveAE::FreeStream(IAEStream *stream)
2622 m_dataPort.SendOutMessage(CActiveAEDataProtocol::FREESTREAM, &stream, sizeof(IAEStream*));
2626 void CActiveAE::FlushStream(CActiveAEStream *stream)
2629 if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::FLUSHSTREAM,
2631 &stream, sizeof(CActiveAEStream*)))
2633 bool success = reply->signal == CActiveAEControlProtocol::ACC;
2637 CLog::Log(LOGERROR, "CActiveAE::FlushStream - failed");
2642 void CActiveAE::PauseStream(CActiveAEStream *stream, bool pause)
2644 // TODO pause sink, needs api change
2646 m_controlPort.SendOutMessage(CActiveAEControlProtocol::PAUSESTREAM,
2647 &stream, sizeof(CActiveAEStream*));
2649 m_controlPort.SendOutMessage(CActiveAEControlProtocol::RESUMESTREAM,
2650 &stream, sizeof(CActiveAEStream*));
2653 void CActiveAE::SetStreamAmplification(CActiveAEStream *stream, float amplify)
2655 MsgStreamParameter msg;
2656 msg.stream = stream;
2657 msg.parameter.float_par = amplify;
2658 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMAMP,
2659 &msg, sizeof(MsgStreamParameter));
2662 void CActiveAE::SetStreamReplaygain(CActiveAEStream *stream, float rgain)
2664 MsgStreamParameter msg;
2665 msg.stream = stream;
2666 msg.parameter.float_par = rgain;
2667 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMRGAIN,
2668 &msg, sizeof(MsgStreamParameter));
2671 void CActiveAE::SetStreamVolume(CActiveAEStream *stream, float volume)
2673 MsgStreamParameter msg;
2674 msg.stream = stream;
2675 msg.parameter.float_par = volume;
2676 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMVOLUME,
2677 &msg, sizeof(MsgStreamParameter));
2680 void CActiveAE::SetStreamResampleRatio(CActiveAEStream *stream, double ratio)
2682 MsgStreamParameter msg;
2683 msg.stream = stream;
2684 msg.parameter.double_par = ratio;
2685 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMRESAMPLERATIO,
2686 &msg, sizeof(MsgStreamParameter));
2689 void CActiveAE::SetStreamFade(CActiveAEStream *stream, float from, float target, unsigned int millis)
2692 msg.stream = stream;
2694 msg.target = target;
2695 msg.millis = millis;
2696 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMFADE,
2697 &msg, sizeof(MsgStreamFade));
2700 void CActiveAE::RegisterAudioCallback(IAudioCallback* pCallback)
2702 CSingleLock lock(m_vizLock);
2703 m_audioCallback = pCallback;
2704 m_vizInitialized = false;
2707 void CActiveAE::UnregisterAudioCallback()
2709 CSingleLock lock(m_vizLock);
2710 m_audioCallback = NULL;