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
35 #define MAX_BUFFER_TIME 0.1 // max time of a buffer in seconds
37 void CEngineStats::Reset(unsigned int sampleRate)
39 CSingleLock lock(m_lock);
40 m_sinkUpdate = XbmcThreads::SystemClockMillis();
42 m_sinkSampleRate = sampleRate;
43 m_bufferedSamples = 0;
47 void CEngineStats::UpdateSinkDelay(double delay, int samples)
49 CSingleLock lock(m_lock);
50 m_sinkUpdate = XbmcThreads::SystemClockMillis();
52 if (samples > m_bufferedSamples)
54 CLog::Log(LOGERROR, "CEngineStats::UpdateSinkDelay - inconsistency in buffer time");
57 m_bufferedSamples -= samples;
60 void CEngineStats::AddSamples(int samples, std::list<CActiveAEStream*> &streams)
62 CSingleLock lock(m_lock);
63 m_bufferedSamples += samples;
65 //update buffered time of streams
66 std::list<CActiveAEStream*>::iterator it;
67 for(it=streams.begin(); it!=streams.end(); ++it)
70 std::deque<CSampleBuffer*>::iterator itBuf;
71 for(itBuf=(*it)->m_processingSamples.begin(); itBuf!=(*it)->m_processingSamples.end(); ++itBuf)
73 delay += (float)(*itBuf)->pkt->nb_samples / (*itBuf)->pkt->config.sample_rate;
75 delay += (*it)->m_resampleBuffers->GetDelay();
76 (*it)->m_bufferedTime = delay;
80 float CEngineStats::GetDelay()
82 CSingleLock lock(m_lock);
83 unsigned int now = XbmcThreads::SystemClockMillis();
84 float delay = m_sinkDelay - (double)(now-m_sinkUpdate) / 1000;
85 delay += (float)m_bufferedSamples / m_sinkSampleRate;
93 // this is used to sync a/v so we need to add sink latency here
94 float CEngineStats::GetDelay(CActiveAEStream *stream)
96 CSingleLock lock(m_lock);
97 unsigned int now = XbmcThreads::SystemClockMillis();
98 float delay = m_sinkDelay - (double)(now-m_sinkUpdate) / 1000;
99 delay += m_sinkLatency;
100 delay += (float)m_bufferedSamples / m_sinkSampleRate;
105 delay += stream->m_bufferedTime;
109 float CEngineStats::GetCacheTime(CActiveAEStream *stream)
111 CSingleLock lock(m_lock);
112 float delay = (float)m_bufferedSamples / m_sinkSampleRate;
114 delay += stream->m_bufferedTime;
118 float CEngineStats::GetCacheTotal(CActiveAEStream *stream)
120 return MAX_CACHE_LEVEL + m_sinkCacheTotal;
123 float CEngineStats::GetWaterLevel()
125 return (float)m_bufferedSamples / m_sinkSampleRate;
128 void CEngineStats::SetSuspended(bool state)
130 CSingleLock lock(m_lock);
134 bool CEngineStats::IsSuspended()
136 CSingleLock lock(m_lock);
140 CActiveAE::CActiveAE() :
142 m_controlPort("OutputControlPort", &m_inMsgEvent, &m_outMsgEvent),
143 m_dataPort("OutputDataPort", &m_inMsgEvent, &m_outMsgEvent),
144 m_sink(&m_outMsgEvent)
146 m_sinkBuffers = NULL;
147 m_silenceBuffers = NULL;
148 m_encoderBuffers = NULL;
150 m_vizBuffersInput = NULL;
157 m_audioCallback = NULL;
158 m_vizInitialized = false;
159 m_sinkHasVolume = false;
162 CActiveAE::~CActiveAE()
167 void CActiveAE::Dispose()
169 #if defined(HAS_GLX) || defined(TARGET_DARWIN_OSX)
170 g_Windowing.Unregister(this);
176 m_controlPort.Purge();
180 m_dllAvFormat.Unload();
181 m_dllAvCodec.Unload();
182 m_dllAvUtil.Unload();
185 //-----------------------------------------------------------------------------
187 //-----------------------------------------------------------------------------
193 AE_TOP_UNCONFIGURED, // 2
194 AE_TOP_RECONFIGURING, // 3
195 AE_TOP_CONFIGURED, // 4
196 AE_TOP_CONFIGURED_SUSPEND, // 5
197 AE_TOP_CONFIGURED_IDLE, // 6
198 AE_TOP_CONFIGURED_PLAY, // 7
201 int AE_parentStates[] = {
204 0, //TOP_UNCONFIGURED
206 0, //TOP_RECONFIGURING
207 4, //TOP_CONFIGURED_SUSPEND
208 4, //TOP_CONFIGURED_IDLE
209 4, //TOP_CONFIGURED_PLAY
212 void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg)
214 for (int state = m_state; ; state = AE_parentStates[state])
219 if (port == &m_controlPort)
223 case CActiveAEControlProtocol::GETSTATE:
224 msg->Reply(CActiveAEControlProtocol::ACC, &m_state, sizeof(m_state));
226 case CActiveAEControlProtocol::VOLUME:
227 m_volume = *(float*)msg->data;
229 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::VOLUME, &m_volume, sizeof(float));
231 case CActiveAEControlProtocol::MUTE:
232 m_muted = *(bool*)msg->data;
234 case CActiveAEControlProtocol::KEEPCONFIG:
235 m_extKeepConfig = *(unsigned int*)msg->data;
237 case CActiveAEControlProtocol::DISPLAYRESET:
243 else if (port == &m_dataPort)
247 case CActiveAEDataProtocol::NEWSOUND:
248 CActiveAESound *sound;
249 sound = *(CActiveAESound**)msg->data;
252 m_sounds.push_back(sound);
256 case CActiveAEDataProtocol::FREESTREAM:
257 CActiveAEStream *stream;
258 stream = *(CActiveAEStream**)msg->data;
259 DiscardStream(stream);
261 case CActiveAEDataProtocol::FREESOUND:
262 sound = *(CActiveAESound**)msg->data;
265 case CActiveAEDataProtocol::DRAINSTREAM:
266 stream = *(CActiveAEStream**)msg->data;
267 stream->m_drain = true;
268 stream->m_resampleBuffers->m_drain = true;
269 msg->Reply(CActiveAEDataProtocol::ACC);
270 stream->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMDRAINED);
276 else if (port == &m_sink.m_dataPort)
280 case CSinkDataProtocol::RETURNSAMPLE:
281 CSampleBuffer **buffer;
282 buffer = (CSampleBuffer**)msg->data;
293 std::string portName = port == NULL ? "timer" : port->portName;
294 CLog::Log(LOGWARNING, "CActiveAE::%s - signal: %d from port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
299 if (port == NULL) // timeout
303 case CActiveAEControlProtocol::TIMEOUT:
309 m_state = AE_TOP_CONFIGURED_IDLE;
314 m_state = AE_TOP_ERROR;
324 case AE_TOP_UNCONFIGURED:
325 if (port == &m_controlPort)
329 case CActiveAEControlProtocol::INIT:
331 m_sink.EnumerateSinkList(false);
334 msg->Reply(CActiveAEControlProtocol::ACC);
337 m_state = AE_TOP_CONFIGURED_IDLE;
342 m_state = AE_TOP_ERROR;
353 case AE_TOP_RECONFIGURING:
354 if (port == NULL) // timeout
358 case CActiveAEControlProtocol::TIMEOUT:
365 if (!m_sinkBuffers->m_inputSamples.empty() || !m_sinkBuffers->m_outputSamples.empty())
370 if (NeedReconfigureSink())
377 m_state = AE_TOP_CONFIGURED_PLAY;
382 m_state = AE_TOP_ERROR;
385 m_extDeferData = false;
393 case AE_TOP_CONFIGURED:
394 if (port == &m_controlPort)
399 case CActiveAEControlProtocol::RECONFIGURE:
400 if (m_streams.empty())
403 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::STREAMING, &streaming, sizeof(bool));
407 if (!NeedReconfigureBuffers() && !NeedReconfigureSink())
409 m_state = AE_TOP_RECONFIGURING;
411 // don't accept any data until we are reconfigured
412 m_extDeferData = true;
414 case CActiveAEControlProtocol::SUSPEND:
416 m_stats.SetSuspended(true);
417 m_state = AE_TOP_CONFIGURED_SUSPEND;
418 m_extDeferData = true;
420 case CActiveAEControlProtocol::DISPLAYLOST:
421 if (m_sink.GetDeviceType(m_mode == MODE_PCM ? m_settings.device : m_settings.passthoughdevice) == AE_DEVTYPE_HDMI)
424 m_stats.SetSuspended(true);
425 m_state = AE_TOP_CONFIGURED_SUSPEND;
426 m_extDeferData = true;
428 msg->Reply(CActiveAEControlProtocol::ACC);
430 case CActiveAEControlProtocol::DEVICECHANGE:
433 while (!m_extLastDeviceChange.empty() && (now - m_extLastDeviceChange.front() > 0))
435 m_extLastDeviceChange.pop();
437 if (m_extLastDeviceChange.size() > 2)
439 CLog::Log(LOGWARNING,"CActiveAE - received %ld device change events within one second", m_extLastDeviceChange.size());
442 m_extLastDeviceChange.push(now);
444 m_sink.EnumerateSinkList(true);
450 m_state = AE_TOP_CONFIGURED_PLAY;
455 m_state = AE_TOP_ERROR;
458 m_controlPort.PurgeOut(CActiveAEControlProtocol::DEVICECHANGE);
460 case CActiveAEControlProtocol::PAUSESTREAM:
461 CActiveAEStream *stream;
462 stream = *(CActiveAEStream**)msg->data;
463 if (stream->m_paused != true && m_streams.size() == 1)
467 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::STREAMING, &streaming, sizeof(bool));
469 stream->m_paused = true;
471 case CActiveAEControlProtocol::RESUMESTREAM:
472 stream = *(CActiveAEStream**)msg->data;
473 stream->m_paused = false;
475 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::STREAMING, &streaming, sizeof(bool));
478 case CActiveAEControlProtocol::FLUSHSTREAM:
479 stream = *(CActiveAEStream**)msg->data;
480 SFlushStream(stream);
481 msg->Reply(CActiveAEControlProtocol::ACC);
484 case CActiveAEControlProtocol::STREAMAMP:
485 MsgStreamParameter *par;
486 par = (MsgStreamParameter*)msg->data;
487 par->stream->m_limiter.SetAmplification(par->parameter.float_par);
488 par->stream->m_amplify = par->parameter.float_par;
490 case CActiveAEControlProtocol::STREAMVOLUME:
491 par = (MsgStreamParameter*)msg->data;
492 par->stream->m_volume = par->parameter.float_par;
494 case CActiveAEControlProtocol::STREAMRGAIN:
495 par = (MsgStreamParameter*)msg->data;
496 par->stream->m_rgain = par->parameter.float_par;
498 case CActiveAEControlProtocol::STREAMRESAMPLERATIO:
499 par = (MsgStreamParameter*)msg->data;
500 if (par->stream->m_resampleBuffers)
502 par->stream->m_resampleBuffers->m_resampleRatio = par->parameter.double_par;
505 case CActiveAEControlProtocol::STREAMFADE:
507 fade = (MsgStreamFade*)msg->data;
508 fade->stream->m_fadingBase = fade->from;
509 fade->stream->m_fadingTarget = fade->target;
510 fade->stream->m_fadingTime = fade->millis;
511 fade->stream->m_fadingSamples = -1;
513 case CActiveAEControlProtocol::STOPSOUND:
514 CActiveAESound *sound;
515 sound = *(CActiveAESound**)msg->data;
522 else if (port == &m_dataPort)
526 case CActiveAEDataProtocol::PLAYSOUND:
527 CActiveAESound *sound;
528 sound = *(CActiveAESound**)msg->data;
529 if (m_settings.guisoundmode == AE_SOUND_OFF ||
530 (m_settings.guisoundmode == AE_SOUND_IDLE && !m_streams.empty()))
534 SoundState st = {sound, 0};
535 m_sounds_playing.push_back(st);
537 m_state = AE_TOP_CONFIGURED_PLAY;
540 case CActiveAEDataProtocol::NEWSTREAM:
541 MsgStreamNew *streamMsg;
542 CActiveAEStream *stream;
543 streamMsg = (MsgStreamNew*)msg->data;
544 stream = CreateStream(streamMsg);
547 msg->Reply(CActiveAEDataProtocol::ACC, &stream, sizeof(CActiveAEStream*));
552 m_state = AE_TOP_CONFIGURED_PLAY;
557 m_state = AE_TOP_ERROR;
562 msg->Reply(CActiveAEDataProtocol::ERR);
564 case CActiveAEDataProtocol::STREAMSAMPLE:
565 MsgStreamSample *msgData;
566 CSampleBuffer *samples;
567 msgData = (MsgStreamSample*)msg->data;
568 samples = msgData->stream->m_processingSamples.front();
569 msgData->stream->m_processingSamples.pop_front();
570 if (samples != msgData->buffer)
571 CLog::Log(LOGERROR, "CActiveAE - inconsistency in stream sample message");
572 if (msgData->buffer->pkt->nb_samples == 0)
573 msgData->buffer->Return();
575 msgData->stream->m_resampleBuffers->m_inputSamples.push_back(msgData->buffer);
577 m_state = AE_TOP_CONFIGURED_PLAY;
579 case CActiveAEDataProtocol::FREESTREAM:
580 stream = *(CActiveAEStream**)msg->data;
581 DiscardStream(stream);
582 if (m_streams.empty())
585 m_extDrainTimer.Set(m_extKeepConfig);
587 m_extDrainTimer.Set(m_stats.GetDelay() * 1000);
591 m_state = AE_TOP_CONFIGURED_PLAY;
593 case CActiveAEDataProtocol::DRAINSTREAM:
594 stream = *(CActiveAEStream**)msg->data;
595 stream->m_drain = true;
596 stream->m_resampleBuffers->m_drain = true;
598 m_state = AE_TOP_CONFIGURED_PLAY;
599 msg->Reply(CActiveAEDataProtocol::ACC);
605 else if (port == &m_sink.m_dataPort)
609 case CSinkDataProtocol::RETURNSAMPLE:
610 CSampleBuffer **buffer;
611 buffer = (CSampleBuffer**)msg->data;
617 m_state = AE_TOP_CONFIGURED_PLAY;
625 case AE_TOP_CONFIGURED_SUSPEND:
626 if (port == &m_controlPort)
628 bool displayReset = false;
631 case CActiveAEControlProtocol::DISPLAYRESET:
633 case CActiveAEControlProtocol::INIT:
637 m_sink.EnumerateSinkList(true);
642 msg->Reply(CActiveAEControlProtocol::ACC);
645 m_state = AE_TOP_CONFIGURED_PLAY;
650 m_state = AE_TOP_ERROR;
653 m_stats.SetSuspended(false);
654 m_extDeferData = false;
660 else if (port == &m_sink.m_dataPort)
664 case CSinkDataProtocol::RETURNSAMPLE:
665 CSampleBuffer **buffer;
666 buffer = (CSampleBuffer**)msg->data;
676 else if (port == NULL) // timeout
680 case CActiveAEControlProtocol::TIMEOUT:
689 case AE_TOP_CONFIGURED_IDLE:
690 if (port == &m_controlPort)
694 case CActiveAEControlProtocol::RESUMESTREAM:
695 CActiveAEStream *stream;
696 stream = *(CActiveAEStream**)msg->data;
697 stream->m_paused = false;
698 m_state = AE_TOP_CONFIGURED_PLAY;
701 case CActiveAEControlProtocol::FLUSHSTREAM:
702 stream = *(CActiveAEStream**)msg->data;
703 SFlushStream(stream);
704 msg->Reply(CActiveAEControlProtocol::ACC);
705 m_state = AE_TOP_CONFIGURED_PLAY;
712 else if (port == NULL) // timeout
716 case CActiveAEControlProtocol::TIMEOUT:
718 ClearDiscardedBuffers();
721 if (m_extDrainTimer.IsTimePast())
726 m_state = AE_TOP_CONFIGURED_PLAY;
731 m_state = AE_TOP_ERROR;
736 m_extTimeout = m_extDrainTimer.MillisLeft();
747 case AE_TOP_CONFIGURED_PLAY:
748 if (port == NULL) // timeout
752 case CActiveAEControlProtocol::TIMEOUT:
755 m_state = AE_TOP_ERROR;
764 if (!m_extDrain && HasWork())
766 ClearDiscardedBuffers();
771 m_state = AE_TOP_CONFIGURED_IDLE;
779 default: // we are in no state, should not happen
780 CLog::Log(LOGERROR, "CActiveAE::%s - no valid state: %d", __FUNCTION__, m_state);
786 void CActiveAE::Process()
789 Protocol *port = NULL;
791 XbmcThreads::EndTime timer;
793 m_state = AE_TOP_UNCONFIGURED;
795 m_bStateMachineSelfTrigger = false;
797 m_extDeferData = false;
806 timer.Set(m_extTimeout);
808 if (m_bStateMachineSelfTrigger)
810 m_bStateMachineSelfTrigger = false;
811 // self trigger state machine
812 StateMachine(msg->signal, port, msg);
813 if (!m_bStateMachineSelfTrigger)
820 // check control port
821 else if (m_controlPort.ReceiveOutMessage(&msg))
824 port = &m_controlPort;
826 // check sink data port
827 else if (m_sink.m_dataPort.ReceiveInMessage(&msg))
830 port = &m_sink.m_dataPort;
832 else if (!m_extDeferData)
835 if (m_dataPort.ReceiveOutMessage(&msg))
843 std::list<CActiveAEStream*>::iterator it;
844 for(it=m_streams.begin(); it!=m_streams.end(); ++it)
846 if((*it)->m_streamPort->ReceiveOutMessage(&msg))
858 StateMachine(msg->signal, port, msg);
859 if (!m_bStateMachineSelfTrigger)
868 else if (m_outMsgEvent.WaitMSec(m_extTimeout))
870 m_extTimeout = timer.MillisLeft();
876 msg = m_controlPort.GetMessage();
877 msg->signal = CActiveAEControlProtocol::TIMEOUT;
879 // signal timeout to state machine
880 StateMachine(msg->signal, port, msg);
881 if (!m_bStateMachineSelfTrigger)
890 AEAudioFormat CActiveAE::GetInputFormat(AEAudioFormat *desiredFmt)
892 AEAudioFormat inputFormat;
894 if (m_streams.empty())
896 inputFormat.m_dataFormat = AE_FMT_FLOAT;
897 inputFormat.m_sampleRate = 44100;
898 inputFormat.m_encodedRate = 0;
899 inputFormat.m_channelLayout = AE_CH_LAYOUT_2_0;
900 inputFormat.m_frames = 0;
901 inputFormat.m_frameSamples = 0;
902 inputFormat.m_frameSize = 0;
904 // force input format after unpausing slave
905 else if (desiredFmt != NULL)
907 inputFormat = *desiredFmt;
909 // keep format when having multiple streams
910 else if (m_streams.size() > 1 && m_silenceBuffers == NULL)
912 inputFormat = m_inputFormat;
916 inputFormat = m_streams.front()->m_format;
917 m_inputFormat = inputFormat;
923 void CActiveAE::Configure(AEAudioFormat *desiredFmt)
925 bool initSink = false;
927 AEAudioFormat sinkInputFormat, inputFormat;
928 AEAudioFormat oldInternalFormat = m_internalFormat;
929 AEAudioFormat oldSinkRequestFormat = m_sinkRequestFormat;
931 inputFormat = GetInputFormat(desiredFmt);
933 m_sinkRequestFormat = inputFormat;
934 ApplySettingsToFormat(m_sinkRequestFormat, m_settings, (int*)&m_mode);
937 std::string device = AE_IS_RAW(m_sinkRequestFormat.m_dataFormat) ? m_settings.passthoughdevice : m_settings.device;
939 CAESinkFactory::ParseDevice(device, driver);
940 if ((!CompareFormat(m_sinkRequestFormat, m_sinkFormat) && !CompareFormat(m_sinkRequestFormat, oldSinkRequestFormat)) ||
941 m_currDevice.compare(device) != 0 ||
942 m_settings.driver.compare(driver) != 0)
946 m_settings.driver = driver;
947 m_currDevice = device;
949 m_stats.Reset(m_sinkFormat.m_sampleRate);
950 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::VOLUME, &m_volume, sizeof(float));
952 // limit buffer size in case of sink returns large buffer
953 unsigned int buffertime = m_sinkFormat.m_frames / m_sinkFormat.m_sampleRate;
954 if (buffertime > MAX_BUFFER_TIME)
956 CLog::Log(LOGWARNING, "ActiveAE::%s - sink returned large buffer of %d ms, reducing to %d ms", __FUNCTION__, buffertime, MAX_BUFFER_TIME*1000);
957 m_sinkFormat.m_frames = MAX_BUFFER_TIME * m_sinkFormat.m_sampleRate;
961 if (m_silenceBuffers)
963 m_discardBufferPools.push_back(m_silenceBuffers);
964 m_silenceBuffers = NULL;
967 // buffers for driving gui sounds if no streams are active
968 if (m_streams.empty())
970 inputFormat = m_sinkFormat;
971 if (m_sinkFormat.m_channelLayout.Count() > m_sinkRequestFormat.m_channelLayout.Count())
973 inputFormat.m_channelLayout = m_sinkRequestFormat.m_channelLayout;
974 inputFormat.m_channelLayout.ResolveChannels(m_sinkFormat.m_channelLayout);
976 inputFormat.m_dataFormat = AE_FMT_FLOAT;
977 inputFormat.m_frameSize = inputFormat.m_channelLayout.Count() *
978 (CAEUtil::DataFormatToBits(inputFormat.m_dataFormat) >> 3);
979 m_silenceBuffers = new CActiveAEBufferPool(inputFormat);
980 m_silenceBuffers->Create(MAX_WATER_LEVEL*1000);
981 sinkInputFormat = inputFormat;
982 m_internalFormat = inputFormat;
984 bool streaming = false;
985 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::STREAMING, &streaming, sizeof(bool));
990 if (m_encoderBuffers)
992 m_discardBufferPools.push_back(m_encoderBuffers);
993 m_encoderBuffers = NULL;
997 m_discardBufferPools.push_back(m_vizBuffers);
1000 if (m_vizBuffersInput)
1002 m_discardBufferPools.push_back(m_vizBuffersInput);
1003 m_vizBuffersInput = NULL;
1006 // resample buffers for streams
1009 bool streaming = true;
1010 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::STREAMING, &streaming, sizeof(bool));
1012 AEAudioFormat outputFormat;
1013 if (m_mode == MODE_RAW)
1015 inputFormat.m_frames = m_sinkFormat.m_frames;
1016 outputFormat = inputFormat;
1017 sinkInputFormat = m_sinkFormat;
1019 // transcode everything with more than 2 channels
1020 else if (m_mode == MODE_TRANSCODE)
1022 outputFormat = inputFormat;
1023 outputFormat.m_dataFormat = AE_FMT_FLOATP;
1024 outputFormat.m_sampleRate = 48000;
1029 m_encoder = new CAEEncoderFFmpeg();
1030 m_encoder->Initialize(outputFormat, true);
1031 m_encoderFormat = outputFormat;
1034 outputFormat = m_encoderFormat;
1036 outputFormat.m_channelLayout = m_encoderFormat.m_channelLayout;
1037 outputFormat.m_frames = m_encoderFormat.m_frames;
1040 if (m_encoder->GetCodecID() == AV_CODEC_ID_AC3)
1042 AEAudioFormat format;
1043 format.m_channelLayout = AE_CH_LAYOUT_2_0;
1044 format.m_dataFormat = AE_FMT_S16NE;
1045 format.m_frameSize = 2* (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);
1046 format.m_frames = AC3_FRAME_SIZE;
1047 format.m_sampleRate = 48000;
1048 format.m_encodedRate = m_encoderFormat.m_sampleRate;
1049 if (m_encoderBuffers && initSink)
1051 m_discardBufferPools.push_back(m_encoderBuffers);
1052 m_encoderBuffers = NULL;
1054 if (!m_encoderBuffers)
1056 m_encoderBuffers = new CActiveAEBufferPool(format);
1057 m_encoderBuffers->Create(MAX_WATER_LEVEL*1000);
1061 sinkInputFormat = m_sinkFormat;
1065 outputFormat = m_sinkFormat;
1066 outputFormat.m_dataFormat = AE_FMT_FLOAT;
1067 outputFormat.m_frameSize = outputFormat.m_channelLayout.Count() *
1068 (CAEUtil::DataFormatToBits(outputFormat.m_dataFormat) >> 3);
1070 // due to channel ordering of the driver, a sink may return more channels than
1071 // requested, i.e. 2.1 request returns FL,FR,BL,BR,FC,LFE for ALSA
1072 // in this case we need to downmix to requested format
1073 if (m_sinkFormat.m_channelLayout.Count() > m_sinkRequestFormat.m_channelLayout.Count())
1075 outputFormat.m_channelLayout = m_sinkRequestFormat.m_channelLayout;
1076 outputFormat.m_channelLayout.ResolveChannels(m_sinkFormat.m_channelLayout);
1079 // TODO: adjust to decoder
1080 sinkInputFormat = outputFormat;
1082 m_internalFormat = outputFormat;
1084 std::list<CActiveAEStream*>::iterator it;
1085 for(it=m_streams.begin(); it!=m_streams.end(); ++it)
1087 // check if we support input format of stream
1088 if (!AE_IS_RAW((*it)->m_format.m_dataFormat) &&
1089 CActiveAEResample::GetAVSampleFormat((*it)->m_format.m_dataFormat) == AV_SAMPLE_FMT_FLT &&
1090 (*it)->m_format.m_dataFormat != AE_FMT_FLOAT)
1092 (*it)->m_convertFn = CAEConvert::ToFloat((*it)->m_format.m_dataFormat);
1093 (*it)->m_format.m_dataFormat = AE_FMT_FLOAT;
1096 if (!(*it)->m_inputBuffers)
1098 // align input buffers with period of sink or encoder
1099 (*it)->m_format.m_frames = m_internalFormat.m_frames * ((float)(*it)->m_format.m_sampleRate / m_internalFormat.m_sampleRate);
1101 // create buffer pool
1102 (*it)->m_inputBuffers = new CActiveAEBufferPool((*it)->m_format);
1103 (*it)->m_inputBuffers->Create(MAX_CACHE_LEVEL*1000);
1104 (*it)->m_streamSpace = (*it)->m_format.m_frameSize * (*it)->m_format.m_frames;
1106 // if input format does not follow ffmpeg channel mask, we may need to remap channels
1107 (*it)->InitRemapper();
1109 if (initSink && (*it)->m_resampleBuffers)
1111 m_discardBufferPools.push_back((*it)->m_resampleBuffers);
1112 (*it)->m_resampleBuffers = NULL;
1114 if (!(*it)->m_resampleBuffers)
1116 (*it)->m_resampleBuffers = new CActiveAEBufferPoolResample((*it)->m_inputBuffers->m_format, outputFormat, m_settings.resampleQuality);
1117 (*it)->m_resampleBuffers->m_changeResampler = (*it)->m_forceResampler;
1118 (*it)->m_resampleBuffers->Create(MAX_CACHE_LEVEL*1000, false, m_settings.stereoupmix, m_settings.normalizelevels);
1120 if (m_mode == MODE_TRANSCODE || m_streams.size() > 1)
1121 (*it)->m_resampleBuffers->m_fillPackets = true;
1124 (*it)->m_limiter.SetSamplerate(outputFormat.m_sampleRate);
1127 // update buffered time of streams
1128 m_stats.AddSamples(0, m_streams);
1131 if (!AE_IS_RAW(inputFormat.m_dataFormat))
1133 if (initSink && m_vizBuffers)
1135 m_discardBufferPools.push_back(m_vizBuffers);
1136 m_vizBuffers = NULL;
1137 m_discardBufferPools.push_back(m_vizBuffersInput);
1138 m_vizBuffersInput = NULL;
1142 AEAudioFormat vizFormat = m_internalFormat;
1143 vizFormat.m_channelLayout = AE_CH_LAYOUT_2_0;
1144 vizFormat.m_dataFormat = AE_FMT_FLOAT;
1147 m_vizBuffersInput = new CActiveAEBufferPool(m_internalFormat);
1148 m_vizBuffersInput->Create(2000);
1151 m_vizBuffers = new CActiveAEBufferPoolResample(m_internalFormat, vizFormat, m_settings.resampleQuality);
1152 // TODO use cache of sync + water level
1153 m_vizBuffers->Create(2000, false, false);
1154 m_vizInitialized = false;
1159 // resample buffers for sink
1160 if (m_sinkBuffers &&
1161 (!CompareFormat(m_sinkBuffers->m_format,m_sinkFormat) || !CompareFormat(m_sinkBuffers->m_inputFormat, sinkInputFormat)))
1163 m_discardBufferPools.push_back(m_sinkBuffers);
1164 m_sinkBuffers = NULL;
1168 m_sinkBuffers = new CActiveAEBufferPoolResample(sinkInputFormat, m_sinkFormat, m_settings.resampleQuality);
1169 m_sinkBuffers->Create(MAX_WATER_LEVEL*1000, true, false);
1173 if (!CompareFormat(oldInternalFormat, m_internalFormat))
1175 if (m_settings.guisoundmode == AE_SOUND_ALWAYS ||
1176 (m_settings.guisoundmode == AE_SOUND_IDLE && m_streams.empty()))
1178 std::vector<CActiveAESound*>::iterator it;
1179 for (it = m_sounds.begin(); it != m_sounds.end(); ++it)
1181 (*it)->SetConverted(false);
1184 m_sounds_playing.clear();
1187 ClearDiscardedBuffers();
1191 CActiveAEStream* CActiveAE::CreateStream(MsgStreamNew *streamMsg)
1193 // we only can handle a single pass through stream
1194 bool hasRawStream = false;
1195 bool hasStream = false;
1196 std::list<CActiveAEStream*>::iterator it;
1197 for(it = m_streams.begin(); it != m_streams.end(); ++it)
1199 if((*it)->IsDrained())
1201 if(AE_IS_RAW((*it)->m_format.m_dataFormat))
1202 hasRawStream = true;
1205 if (hasRawStream || (hasStream && AE_IS_RAW(streamMsg->format.m_dataFormat)))
1210 // create the stream
1211 CActiveAEStream *stream;
1212 stream = new CActiveAEStream(&streamMsg->format);
1213 stream->m_streamPort = new CActiveAEDataProtocol("stream",
1214 &stream->m_inMsgEvent, &m_outMsgEvent);
1216 // create buffer pool
1217 stream->m_inputBuffers = NULL; // create in Configure when we know the sink format
1218 stream->m_resampleBuffers = NULL; // create in Configure when we know the sink format
1219 stream->m_statsLock = m_stats.GetLock();
1220 stream->m_fadingSamples = 0;
1221 stream->m_started = false;
1223 if (streamMsg->options & AESTREAM_PAUSED)
1224 stream->m_paused = true;
1226 if (streamMsg->options & AESTREAM_FORCE_RESAMPLE)
1227 stream->m_forceResampler = true;
1229 m_streams.push_back(stream);
1234 void CActiveAE::DiscardStream(CActiveAEStream *stream)
1236 std::list<CActiveAEStream*>::iterator it;
1237 for (it=m_streams.begin(); it!=m_streams.end(); )
1239 if (stream == (*it))
1241 while (!(*it)->m_processingSamples.empty())
1243 (*it)->m_processingSamples.front()->Return();
1244 (*it)->m_processingSamples.pop_front();
1246 m_discardBufferPools.push_back((*it)->m_inputBuffers);
1247 m_discardBufferPools.push_back((*it)->m_resampleBuffers);
1248 CLog::Log(LOGDEBUG, "CActiveAE::DiscardStream - audio stream deleted");
1249 delete (*it)->m_streamPort;
1251 it = m_streams.erase(it);
1257 ClearDiscardedBuffers();
1260 void CActiveAE::SFlushStream(CActiveAEStream *stream)
1262 while (!stream->m_processingSamples.empty())
1264 stream->m_processingSamples.front()->Return();
1265 stream->m_processingSamples.pop_front();
1267 stream->m_resampleBuffers->Flush();
1268 stream->m_streamPort->Purge();
1269 stream->m_bufferedTime = 0.0;
1270 stream->m_paused = false;
1272 // flush the engine if we only have a single stream
1273 if (m_streams.size() == 1)
1279 void CActiveAE::FlushEngine()
1282 m_sinkBuffers->Flush();
1284 m_vizBuffers->Flush();
1286 // send message to sink
1288 if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::FLUSH,
1291 bool success = reply->signal == CSinkControlProtocol::ACC;
1294 CLog::Log(LOGERROR, "ActiveAE::%s - returned error on flush", __FUNCTION__);
1301 CLog::Log(LOGERROR, "ActiveAE::%s - failed to flush", __FUNCTION__);
1304 m_stats.Reset(m_sinkFormat.m_sampleRate);
1307 void CActiveAE::ClearDiscardedBuffers()
1309 std::list<CActiveAEBufferPool*>::iterator it;
1310 for (it=m_discardBufferPools.begin(); it!=m_discardBufferPools.end(); ++it)
1312 CActiveAEBufferPoolResample *rbuf = dynamic_cast<CActiveAEBufferPoolResample*>(*it);
1317 // if all buffers have returned, we can delete the buffer pool
1318 if ((*it)->m_allSamples.size() == (*it)->m_freeSamples.size())
1321 CLog::Log(LOGDEBUG, "CActiveAE::ClearDiscardedBuffers - buffer pool deleted");
1322 m_discardBufferPools.erase(it);
1328 void CActiveAE::SStopSound(CActiveAESound *sound)
1330 std::list<SoundState>::iterator it;
1331 for (it=m_sounds_playing.begin(); it!=m_sounds_playing.end(); ++it)
1333 if (it->sound == sound)
1335 m_sounds_playing.erase(it);
1341 void CActiveAE::DiscardSound(CActiveAESound *sound)
1345 std::vector<CActiveAESound*>::iterator it;
1346 for (it=m_sounds.begin(); it!=m_sounds.end(); ++it)
1356 void CActiveAE::ChangeResamplers()
1358 std::list<CActiveAEStream*>::iterator it;
1359 for(it=m_streams.begin(); it!=m_streams.end(); ++it)
1361 bool normalize = true;
1362 if (((*it)->m_resampleBuffers->m_format.m_channelLayout.Count() <
1363 (*it)->m_resampleBuffers->m_inputFormat.m_channelLayout.Count()) &&
1364 !m_settings.normalizelevels)
1367 if ((*it)->m_resampleBuffers && (*it)->m_resampleBuffers->m_resampler &&
1368 (((*it)->m_resampleBuffers->m_resampleQuality != m_settings.resampleQuality) ||
1369 (((*it)->m_resampleBuffers->m_stereoUpmix != m_settings.stereoupmix)) ||
1370 ((*it)->m_resampleBuffers->m_normalize != normalize)))
1372 (*it)->m_resampleBuffers->m_changeResampler = true;
1374 (*it)->m_resampleBuffers->m_resampleQuality = m_settings.resampleQuality;
1375 (*it)->m_resampleBuffers->m_stereoUpmix = m_settings.stereoupmix;
1376 (*it)->m_resampleBuffers->m_normalize = normalize;
1380 void CActiveAE::ApplySettingsToFormat(AEAudioFormat &format, AudioSettings &settings, int *mode)
1382 int oldMode = m_mode;
1387 if (AE_IS_RAW(format.m_dataFormat))
1389 if ((format.m_dataFormat == AE_FMT_AC3 && !settings.ac3passthrough) ||
1390 (format.m_dataFormat == AE_FMT_EAC3 && !settings.eac3passthrough) ||
1391 (format.m_dataFormat == AE_FMT_TRUEHD && !settings.truehdpassthrough) ||
1392 (format.m_dataFormat == AE_FMT_DTS && !settings.dtspassthrough) ||
1393 (format.m_dataFormat == AE_FMT_DTSHD && !settings.dtshdpassthrough))
1395 CLog::Log(LOGERROR, "CActiveAE::ApplySettingsToFormat - input audio format is wrong");
1401 else if (settings.channels <= AE_CH_LAYOUT_2_0 && // no multichannel pcm
1402 settings.passthrough &&
1403 settings.ac3passthrough &&
1404 settings.ac3transcode &&
1405 !m_streams.empty() &&
1406 (format.m_channelLayout.Count() > 2 || settings.stereoupmix))
1408 format.m_dataFormat = AE_FMT_AC3;
1409 format.m_sampleRate = 48000;
1410 format.m_channelLayout = AE_CH_LAYOUT_2_0;
1412 *mode = MODE_TRANSCODE;
1416 format.m_dataFormat = AE_FMT_FLOAT;
1417 // consider user channel layout for those cases
1418 // 1. input stream is multichannel
1419 // 2. stereo upmix is selected
1421 if ((format.m_channelLayout.Count() > 2) ||
1422 settings.stereoupmix ||
1423 (settings.config == AE_CONFIG_FIXED))
1425 CAEChannelInfo stdLayout;
1426 switch (settings.channels)
1429 case 0: stdLayout = AE_CH_LAYOUT_2_0; break;
1430 case 1: stdLayout = AE_CH_LAYOUT_2_0; break;
1431 case 2: stdLayout = AE_CH_LAYOUT_2_1; break;
1432 case 3: stdLayout = AE_CH_LAYOUT_3_0; break;
1433 case 4: stdLayout = AE_CH_LAYOUT_3_1; break;
1434 case 5: stdLayout = AE_CH_LAYOUT_4_0; break;
1435 case 6: stdLayout = AE_CH_LAYOUT_4_1; break;
1436 case 7: stdLayout = AE_CH_LAYOUT_5_0; break;
1437 case 8: stdLayout = AE_CH_LAYOUT_5_1; break;
1438 case 9: stdLayout = AE_CH_LAYOUT_7_0; break;
1439 case 10: stdLayout = AE_CH_LAYOUT_7_1; break;
1442 if (m_settings.config == AE_CONFIG_FIXED || (settings.stereoupmix && format.m_channelLayout.Count() <= 2))
1443 format.m_channelLayout = stdLayout;
1444 else if (m_extKeepConfig && (settings.config == AE_CONFIG_AUTO) && (oldMode != MODE_RAW))
1445 format.m_channelLayout = m_internalFormat.m_channelLayout;
1447 format.m_channelLayout.ResolveChannels(stdLayout);
1449 // don't change from multi to stereo in AUTO mode
1450 else if ((settings.config == AE_CONFIG_AUTO) &&
1451 m_stats.GetWaterLevel() > 0 && m_internalFormat.m_channelLayout.Count() > 2)
1453 format.m_channelLayout = m_internalFormat.m_channelLayout;
1456 if (m_sink.GetDeviceType(m_settings.device) == AE_DEVTYPE_IEC958)
1458 if (format.m_sampleRate > m_settings.samplerate)
1460 format.m_sampleRate = m_settings.samplerate;
1461 CLog::Log(LOGINFO, "CActiveAE::ApplySettings - limit samplerate for SPDIF to %d", format.m_sampleRate);
1463 format.m_channelLayout = AE_CH_LAYOUT_2_0;
1466 if (m_settings.config == AE_CONFIG_FIXED)
1468 format.m_sampleRate = m_settings.samplerate;
1469 CLog::Log(LOGINFO, "CActiveAE::ApplySettings - Forcing samplerate to %d", format.m_sampleRate);
1472 // sinks may not support mono
1473 if (format.m_channelLayout.Count() == 1)
1475 format.m_channelLayout = AE_CH_LAYOUT_2_0;
1480 bool CActiveAE::NeedReconfigureBuffers()
1482 AEAudioFormat newFormat = GetInputFormat();
1483 ApplySettingsToFormat(newFormat, m_settings);
1485 if (newFormat.m_dataFormat != m_sinkRequestFormat.m_dataFormat ||
1486 newFormat.m_channelLayout != m_sinkRequestFormat.m_channelLayout ||
1487 newFormat.m_sampleRate != m_sinkRequestFormat.m_sampleRate)
1493 bool CActiveAE::NeedReconfigureSink()
1495 AEAudioFormat newFormat = GetInputFormat();
1496 ApplySettingsToFormat(newFormat, m_settings);
1498 std::string device = AE_IS_RAW(newFormat.m_dataFormat) ? m_settings.passthoughdevice : m_settings.device;
1500 CAESinkFactory::ParseDevice(device, driver);
1502 if (!CompareFormat(newFormat, m_sinkFormat) ||
1503 m_currDevice.compare(device) != 0 ||
1504 m_settings.driver.compare(driver) != 0)
1510 bool CActiveAE::InitSink()
1513 config.format = m_sinkRequestFormat;
1514 config.stats = &m_stats;
1515 config.device = AE_IS_RAW(m_sinkRequestFormat.m_dataFormat) ? &m_settings.passthoughdevice :
1518 // send message to sink
1520 if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::CONFIGURE,
1523 &config, sizeof(config)))
1525 bool success = reply->signal == CSinkControlProtocol::ACC;
1529 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
1534 data = (SinkReply*)reply->data;
1537 m_sinkFormat = data->format;
1538 m_sinkHasVolume = data->hasVolume;
1539 m_stats.SetSinkCacheTotal(data->cacheTotal);
1540 m_stats.SetSinkLatency(data->latency);
1546 CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__);
1547 m_stats.SetSinkCacheTotal(0);
1548 m_stats.SetSinkLatency(0);
1553 m_inMsgEvent.Reset();
1557 void CActiveAE::DrainSink()
1559 // send message to sink
1561 if (m_sink.m_dataPort.SendOutMessageSync(CSinkDataProtocol::DRAIN,
1565 bool success = reply->signal == CSinkDataProtocol::ACC;
1569 CLog::Log(LOGERROR, "ActiveAE::%s - returned error on drain", __FUNCTION__);
1577 CLog::Log(LOGERROR, "ActiveAE::%s - failed to drain", __FUNCTION__);
1583 void CActiveAE::UnconfigureSink()
1585 // send message to sink
1587 if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::UNCONFIGURE,
1591 bool success = reply->signal == CSinkControlProtocol::ACC;
1594 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
1601 CLog::Log(LOGERROR, "ActiveAE::%s - failed to unconfigure", __FUNCTION__);
1605 // make sure we open sink on next configure
1608 m_inMsgEvent.Reset();
1612 bool CActiveAE::RunStages()
1616 // serve input streams
1617 std::list<CActiveAEStream*>::iterator it;
1618 for (it = m_streams.begin(); it != m_streams.end(); ++it)
1620 if ((*it)->m_resampleBuffers && !(*it)->m_paused)
1621 busy = (*it)->m_resampleBuffers->ResampleBuffers();
1622 else if ((*it)->m_resampleBuffers &&
1623 ((*it)->m_resampleBuffers->m_inputSamples.size() > (*it)->m_resampleBuffers->m_allSamples.size() * 0.5))
1625 CSingleLock lock((*it)->m_streamLock);
1626 (*it)->m_streamIsBuffering = false;
1629 // provide buffers to stream
1630 float time = m_stats.GetCacheTime((*it));
1631 CSampleBuffer *buffer;
1632 if (!(*it)->m_drain)
1634 while (time < MAX_CACHE_LEVEL && !(*it)->m_inputBuffers->m_freeSamples.empty())
1636 buffer = (*it)->m_inputBuffers->GetFreeBuffer();
1637 (*it)->m_processingSamples.push_back(buffer);
1638 (*it)->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMBUFFER, &buffer, sizeof(CSampleBuffer*));
1639 (*it)->IncFreeBuffers();
1640 time += (float)buffer->pkt->max_nb_samples / buffer->pkt->config.sample_rate;
1645 if ((*it)->m_resampleBuffers->m_inputSamples.empty() &&
1646 (*it)->m_resampleBuffers->m_outputSamples.empty() &&
1647 (*it)->m_processingSamples.empty())
1649 (*it)->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMDRAINED);
1650 (*it)->m_drain = false;
1651 (*it)->m_resampleBuffers->m_drain = false;
1652 (*it)->m_started = false;
1654 // set variables being polled via stream interface
1655 CSingleLock lock((*it)->m_streamLock);
1656 if ((*it)->m_streamSlave)
1658 CActiveAEStream *slave = (CActiveAEStream*)((*it)->m_streamSlave);
1659 slave->m_paused = false;
1661 // TODO: find better solution for this
1662 // gapless bites audiophile
1663 if (m_settings.config == AE_CONFIG_MATCH)
1664 Configure(&slave->m_format);
1666 (*it)->m_streamSlave = NULL;
1668 (*it)->m_streamDrained = true;
1669 (*it)->m_streamDraining = false;
1670 (*it)->m_streamFading = false;
1675 if (m_stats.GetWaterLevel() < MAX_WATER_LEVEL &&
1676 (m_mode != MODE_TRANSCODE || (m_encoderBuffers && !m_encoderBuffers->m_freeSamples.empty())))
1678 // mix streams and sounds sounds
1679 if (m_mode != MODE_RAW)
1681 CSampleBuffer *out = NULL;
1682 if (!m_sounds_playing.empty() && m_streams.empty())
1684 if (m_silenceBuffers && !m_silenceBuffers->m_freeSamples.empty())
1686 out = m_silenceBuffers->GetFreeBuffer();
1687 for (int i=0; i<out->pkt->planes; i++)
1689 memset(out->pkt->data[i], 0, out->pkt->linesize);
1691 out->pkt->nb_samples = out->pkt->max_nb_samples;
1696 std::list<CActiveAEStream*>::iterator it;
1698 // if we deal with more than a single stream, all streams
1699 // must provide samples for mixing
1700 bool allStreamsReady = true;
1701 for (it = m_streams.begin(); it != m_streams.end(); ++it)
1703 if ((*it)->m_paused || !(*it)->m_started || !(*it)->m_resampleBuffers)
1706 if ((*it)->m_resampleBuffers->m_outputSamples.empty())
1707 allStreamsReady = false;
1710 bool needClamp = false;
1711 for (it = m_streams.begin(); it != m_streams.end() && allStreamsReady; ++it)
1713 if ((*it)->m_paused || !(*it)->m_resampleBuffers)
1716 if (!(*it)->m_resampleBuffers->m_outputSamples.empty())
1718 (*it)->m_started = true;
1722 out = (*it)->m_resampleBuffers->m_outputSamples.front();
1723 (*it)->m_resampleBuffers->m_outputSamples.pop_front();
1725 int nb_floats = out->pkt->nb_samples * out->pkt->config.channels / out->pkt->planes;
1727 float fadingStep = 0.0f;
1730 if ((*it)->m_fadingSamples == -1)
1732 (*it)->m_fadingSamples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1733 (*it)->m_volume = (*it)->m_fadingBase;
1735 if ((*it)->m_fadingSamples > 0)
1737 nb_floats = out->pkt->config.channels / out->pkt->planes;
1738 nb_loops = out->pkt->nb_samples;
1739 float delta = (*it)->m_fadingTarget - (*it)->m_fadingBase;
1740 int samples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1741 fadingStep = delta / samples;
1744 // for stream amplification,
1745 // turned off downmix normalization,
1746 // or if sink format is float (in order to prevent from clipping)
1747 // we need to run on a per sample basis
1748 if ((*it)->m_amplify != 1.0 || !(*it)->m_resampleBuffers->m_normalize || (m_sinkFormat.m_dataFormat == AE_FMT_FLOAT))
1750 nb_floats = out->pkt->config.channels / out->pkt->planes;
1751 nb_loops = out->pkt->nb_samples;
1754 for(int i=0; i<nb_loops; i++)
1756 if ((*it)->m_fadingSamples > 0)
1758 (*it)->m_volume += fadingStep;
1759 (*it)->m_fadingSamples--;
1761 if ((*it)->m_fadingSamples == 0)
1763 // set variables being polled via stream interface
1764 CSingleLock lock((*it)->m_streamLock);
1765 (*it)->m_streamFading = false;
1769 // volume for stream
1770 float volume = (*it)->m_volume * (*it)->m_rgain;
1772 volume *= (*it)->m_limiter.Run((float**)out->pkt->data, out->pkt->config.channels, i*nb_floats, out->pkt->planes > 1);
1774 for(int j=0; j<out->pkt->planes; j++)
1777 CAEUtil::SSEMulArray((float*)out->pkt->data[j]+i*nb_floats, volume, nb_floats);
1779 float* fbuffer = (float*) out->pkt->data[j]+i*nb_floats;
1780 for (int k = 0; k < nb_floats; ++k)
1782 fbuffer[k] *= volume;
1790 CSampleBuffer *mix = NULL;
1791 mix = (*it)->m_resampleBuffers->m_outputSamples.front();
1792 (*it)->m_resampleBuffers->m_outputSamples.pop_front();
1794 int nb_floats = mix->pkt->nb_samples * mix->pkt->config.channels / mix->pkt->planes;
1796 float fadingStep = 0.0f;
1799 if ((*it)->m_fadingSamples == -1)
1801 (*it)->m_fadingSamples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1802 (*it)->m_volume = (*it)->m_fadingBase;
1804 if ((*it)->m_fadingSamples > 0)
1806 nb_floats = mix->pkt->config.channels / mix->pkt->planes;
1807 nb_loops = mix->pkt->nb_samples;
1808 float delta = (*it)->m_fadingTarget - (*it)->m_fadingBase;
1809 int samples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1810 fadingStep = delta / samples;
1813 // for streams amplification of turned off downmix normalization
1814 // we need to run on a per sample basis
1815 if ((*it)->m_amplify != 1.0 || !(*it)->m_resampleBuffers->m_normalize)
1817 nb_floats = out->pkt->config.channels / out->pkt->planes;
1818 nb_loops = out->pkt->nb_samples;
1821 for(int i=0; i<nb_loops; i++)
1823 if ((*it)->m_fadingSamples > 0)
1825 (*it)->m_volume += fadingStep;
1826 (*it)->m_fadingSamples--;
1828 if ((*it)->m_fadingSamples == 0)
1830 // set variables being polled via stream interface
1831 CSingleLock lock((*it)->m_streamLock);
1832 (*it)->m_streamFading = false;
1836 // volume for stream
1837 float volume = (*it)->m_volume * (*it)->m_rgain;
1839 volume *= (*it)->m_limiter.Run((float**)mix->pkt->data, mix->pkt->config.channels, i*nb_floats, mix->pkt->planes > 1);
1841 for(int j=0; j<out->pkt->planes && j<mix->pkt->planes; j++)
1843 float *dst = (float*)out->pkt->data[j]+i*nb_floats;
1844 float *src = (float*)mix->pkt->data[j]+i*nb_floats;
1846 CAEUtil::SSEMulAddArray(dst, src, volume, nb_floats);
1847 for (int k = 0; k < nb_floats; ++k)
1849 if (fabs(dst[k]) > 1.0f)
1856 for (int k = 0; k < nb_floats; ++k)
1858 dst[k] += src[k] * volume;
1859 if (fabs(dst[k]) > 1.0f)
1871 // finally clamp samples
1872 if(out && needClamp)
1874 int nb_floats = out->pkt->nb_samples * out->pkt->config.channels / out->pkt->planes;
1875 for(int i=0; i<out->pkt->planes; i++)
1877 CAEUtil::ClampArray((float*)out->pkt->data[i], nb_floats);
1881 // process output buffer, gui sounds, encode, viz
1886 CSingleLock lock(m_vizLock);
1887 if (m_audioCallback && m_vizBuffers && !m_streams.empty())
1889 if (!m_vizInitialized)
1891 m_audioCallback->OnInitialize(2, m_vizBuffers->m_format.m_sampleRate, 32);
1892 m_vizInitialized = true;
1895 if (!m_vizBuffersInput->m_freeSamples.empty())
1897 // copy the samples into the viz input buffer
1898 CSampleBuffer *viz = m_vizBuffersInput->GetFreeBuffer();
1899 int samples = std::min(512, out->pkt->nb_samples);
1900 int bytes = samples * out->pkt->config.channels / out->pkt->planes * out->pkt->bytes_per_sample;
1901 for(int i= 0; i < out->pkt->planes; i++)
1903 memcpy(viz->pkt->data[i], out->pkt->data[i], bytes);
1905 viz->pkt->nb_samples = samples;
1906 m_vizBuffers->m_inputSamples.push_back(viz);
1909 CLog::Log(LOGWARNING,"ActiveAE::%s - viz ran out of free buffers", __FUNCTION__);
1910 unsigned int now = XbmcThreads::SystemClockMillis();
1911 unsigned int timestamp = now + m_stats.GetDelay() * 1000;
1912 busy |= m_vizBuffers->ResampleBuffers(timestamp);
1913 while(!m_vizBuffers->m_outputSamples.empty())
1915 CSampleBuffer *buf = m_vizBuffers->m_outputSamples.front();
1916 if ((now - buf->timestamp) & 0x80000000)
1921 samples = std::min(512, buf->pkt->nb_samples);
1922 m_audioCallback->OnAudioData((float*)(buf->pkt->data[0]), samples);
1924 m_vizBuffers->m_outputSamples.pop_front();
1928 else if (m_vizBuffers)
1929 m_vizBuffers->Flush();
1933 MixSounds(*(out->pkt));
1934 if (!m_sinkHasVolume || m_muted)
1935 Deamplify(*(out->pkt));
1937 if (m_mode == MODE_TRANSCODE && m_encoder)
1939 CSampleBuffer *buf = m_encoderBuffers->GetFreeBuffer();
1940 m_encoder->Encode(out->pkt->data[0], out->pkt->planes*out->pkt->linesize,
1941 buf->pkt->data[0], buf->pkt->planes*buf->pkt->linesize);
1942 buf->pkt->nb_samples = buf->pkt->max_nb_samples;
1952 m_stats.AddSamples(out->pkt->nb_samples, m_streams);
1953 m_sinkBuffers->m_inputSamples.push_back(out);
1959 std::list<CActiveAEStream*>::iterator it;
1960 CSampleBuffer *buffer;
1961 for (it = m_streams.begin(); it != m_streams.end(); ++it)
1963 if (!(*it)->m_resampleBuffers->m_outputSamples.empty())
1965 buffer = (*it)->m_resampleBuffers->m_outputSamples.front();
1966 (*it)->m_resampleBuffers->m_outputSamples.pop_front();
1967 m_stats.AddSamples(buffer->pkt->nb_samples, m_streams);
1968 m_sinkBuffers->m_inputSamples.push_back(buffer);
1973 // serve sink buffers
1974 busy = m_sinkBuffers->ResampleBuffers();
1975 while(!m_sinkBuffers->m_outputSamples.empty())
1977 CSampleBuffer *out = NULL;
1978 out = m_sinkBuffers->m_outputSamples.front();
1979 m_sinkBuffers->m_outputSamples.pop_front();
1980 m_sink.m_dataPort.SendOutMessage(CSinkDataProtocol::SAMPLE,
1981 &out, sizeof(CSampleBuffer*));
1989 bool CActiveAE::HasWork()
1991 if (!m_sounds_playing.empty())
1993 if (!m_sinkBuffers->m_inputSamples.empty())
1995 if (!m_sinkBuffers->m_outputSamples.empty())
1998 std::list<CActiveAEStream*>::iterator it;
1999 for (it = m_streams.begin(); it != m_streams.end(); ++it)
2001 if (!(*it)->m_resampleBuffers->m_inputSamples.empty())
2003 if (!(*it)->m_resampleBuffers->m_outputSamples.empty())
2005 if (!(*it)->m_processingSamples.empty())
2012 void CActiveAE::MixSounds(CSoundPacket &dstSample)
2014 if (m_sounds_playing.empty())
2019 float *sample_buffer;
2020 int max_samples = dstSample.nb_samples;
2022 std::list<SoundState>::iterator it;
2023 for (it = m_sounds_playing.begin(); it != m_sounds_playing.end(); )
2025 if (!it->sound->IsConverted())
2026 ResampleSound(it->sound);
2027 int available_samples = it->sound->GetSound(false)->nb_samples - it->samples_played;
2028 int mix_samples = std::min(max_samples, available_samples);
2029 int start = it->samples_played *
2030 m_dllAvUtil.av_get_bytes_per_sample(it->sound->GetSound(false)->config.fmt) *
2031 it->sound->GetSound(false)->config.channels /
2032 it->sound->GetSound(false)->planes;
2034 for(int j=0; j<dstSample.planes; j++)
2036 volume = it->sound->GetVolume();
2037 out = (float*)dstSample.data[j];
2038 sample_buffer = (float*)(it->sound->GetSound(false)->data[j]+start);
2039 int nb_floats = mix_samples * dstSample.config.channels / dstSample.planes;
2041 CAEUtil::SSEMulAddArray(out, sample_buffer, volume, nb_floats);
2043 for (int k = 0; k < nb_floats; ++k)
2044 *out++ += *sample_buffer++ * volume;
2048 it->samples_played += mix_samples;
2050 // no more frames, so remove it from the list
2051 if (it->samples_played >= it->sound->GetSound(false)->nb_samples)
2053 it = m_sounds_playing.erase(it);
2060 void CActiveAE::Deamplify(CSoundPacket &dstSample)
2062 if (m_volume < 1.0 || m_muted)
2065 int nb_floats = dstSample.nb_samples * dstSample.config.channels / dstSample.planes;
2066 float volume = m_muted ? 0.0f : m_volume;
2068 for(int j=0; j<dstSample.planes; j++)
2070 buffer = (float*)dstSample.data[j];
2072 CAEUtil::SSEMulArray(buffer, volume, nb_floats);
2074 float *fbuffer = buffer;
2075 for (int i = 0; i < nb_floats; i++)
2076 *fbuffer++ *= volume;
2082 //-----------------------------------------------------------------------------
2084 //-----------------------------------------------------------------------------
2086 void CActiveAE::LoadSettings()
2088 m_settings.device = CSettings::Get().GetString("audiooutput.audiodevice");
2089 m_settings.passthoughdevice = CSettings::Get().GetString("audiooutput.passthroughdevice");
2091 m_settings.config = CSettings::Get().GetInt("audiooutput.config");
2092 m_settings.channels = (m_sink.GetDeviceType(m_settings.device) == AE_DEVTYPE_IEC958) ? AE_CH_LAYOUT_2_0 : CSettings::Get().GetInt("audiooutput.channels");
2093 m_settings.samplerate = CSettings::Get().GetInt("audiooutput.samplerate");
2095 m_settings.stereoupmix = IsSettingVisible("audiooutput.stereoupmix") ? CSettings::Get().GetBool("audiooutput.stereoupmix") : false;
2096 m_settings.normalizelevels = CSettings::Get().GetBool("audiooutput.normalizelevels");
2097 m_settings.guisoundmode = CSettings::Get().GetInt("audiooutput.guisoundmode");
2099 m_settings.passthrough = m_settings.config == AE_CONFIG_FIXED ? false : CSettings::Get().GetBool("audiooutput.passthrough");
2100 if (!m_sink.HasPassthroughDevice())
2101 m_settings.passthrough = false;
2102 m_settings.ac3passthrough = CSettings::Get().GetBool("audiooutput.ac3passthrough");
2103 m_settings.ac3transcode = CSettings::Get().GetBool("audiooutput.ac3transcode");
2104 m_settings.eac3passthrough = CSettings::Get().GetBool("audiooutput.eac3passthrough");
2105 m_settings.truehdpassthrough = CSettings::Get().GetBool("audiooutput.truehdpassthrough");
2106 m_settings.dtspassthrough = CSettings::Get().GetBool("audiooutput.dtspassthrough");
2107 m_settings.dtshdpassthrough = CSettings::Get().GetBool("audiooutput.dtshdpassthrough");
2109 m_settings.resampleQuality = static_cast<AEQuality>(CSettings::Get().GetInt("audiooutput.processquality"));
2112 bool CActiveAE::Initialize()
2114 if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllAvFormat.Load())
2116 CLog::Log(LOGERROR,"CActiveAE::Initialize - failed to load ffmpeg libraries");
2119 m_dllAvFormat.av_register_all();
2123 if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::INIT,
2127 bool success = reply->signal == CActiveAEControlProtocol::ACC;
2131 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
2138 CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__);
2143 // hook into windowing for receiving display reset events
2144 #if defined(HAS_GLX) || defined(TARGET_DARWIN_OSX)
2145 g_Windowing.Register(this);
2148 m_inMsgEvent.Reset();
2152 void CActiveAE::EnumerateOutputDevices(AEDeviceList &devices, bool passthrough)
2154 m_sink.EnumerateOutputDevices(devices, passthrough);
2157 std::string CActiveAE::GetDefaultDevice(bool passthrough)
2159 return m_sink.GetDefaultDevice(passthrough);
2162 void CActiveAE::OnSettingsChange(const std::string& setting)
2164 if (setting == "audiooutput.passthroughdevice" ||
2165 setting == "audiooutput.audiodevice" ||
2166 setting == "audiooutput.config" ||
2167 setting == "audiooutput.ac3passthrough" ||
2168 setting == "audiooutput.ac3transcode" ||
2169 setting == "audiooutput.eac3passthrough" ||
2170 setting == "audiooutput.dtspassthrough" ||
2171 setting == "audiooutput.truehdpassthrough" ||
2172 setting == "audiooutput.dtshdpassthrough" ||
2173 setting == "audiooutput.channels" ||
2174 setting == "audiooutput.stereoupmix" ||
2175 setting == "audiooutput.streamsilence" ||
2176 setting == "audiooutput.processquality" ||
2177 setting == "audiooutput.passthrough" ||
2178 setting == "audiooutput.samplerate" ||
2179 setting == "audiooutput.normalizelevels" ||
2180 setting == "audiooutput.guisoundmode")
2182 m_controlPort.SendOutMessage(CActiveAEControlProtocol::RECONFIGURE);
2186 bool CActiveAE::SupportsRaw(AEDataFormat format)
2188 if (!m_sink.SupportsFormat(CSettings::Get().GetString("audiooutput.passthroughdevice"), format))
2194 bool CActiveAE::SupportsSilenceTimeout()
2199 bool CActiveAE::SupportsQualityLevel(enum AEQuality level)
2201 if (level == AE_QUALITY_LOW || level == AE_QUALITY_MID || level == AE_QUALITY_HIGH)
2207 bool CActiveAE::IsSettingVisible(const std::string &settingId)
2209 if (settingId == "audiooutput.samplerate")
2211 if (m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) == AE_DEVTYPE_IEC958)
2213 if (CSettings::Get().GetInt("audiooutput.config") == AE_CONFIG_FIXED)
2216 else if (settingId == "audiooutput.channels")
2218 if (m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) != AE_DEVTYPE_IEC958)
2221 else if (settingId == "audiooutput.passthrough")
2223 if (m_sink.HasPassthroughDevice() && CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED)
2226 else if (settingId == "audiooutput.truehdpassthrough")
2228 if (m_sink.SupportsFormat(CSettings::Get().GetString("audiooutput.passthroughdevice"), AE_FMT_TRUEHD) &&
2229 CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED)
2232 else if (settingId == "audiooutput.dtshdpassthrough")
2234 if (m_sink.SupportsFormat(CSettings::Get().GetString("audiooutput.passthroughdevice"), AE_FMT_DTSHD) &&
2235 CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED)
2238 else if (settingId == "audiooutput.eac3passthrough")
2240 if (m_sink.SupportsFormat(CSettings::Get().GetString("audiooutput.passthroughdevice"), AE_FMT_EAC3) &&
2241 CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED)
2244 else if (settingId == "audiooutput.stereoupmix")
2246 if (m_sink.HasPassthroughDevice() ||
2247 CSettings::Get().GetInt("audiooutput.channels") > AE_CH_LAYOUT_2_0)
2250 else if (settingId == "audiooutput.ac3transcode")
2252 if (m_sink.HasPassthroughDevice() &&
2253 CSettings::Get().GetBool("audiooutput.ac3passthrough") &&
2254 CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED &&
2255 (CSettings::Get().GetInt("audiooutput.channels") <= AE_CH_LAYOUT_2_0 || m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) == AE_DEVTYPE_IEC958))
2261 void CActiveAE::Shutdown()
2266 bool CActiveAE::Suspend()
2268 return m_controlPort.SendOutMessage(CActiveAEControlProtocol::SUSPEND);
2271 bool CActiveAE::Resume()
2274 if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::INIT,
2278 bool success = reply->signal == CActiveAEControlProtocol::ACC;
2282 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
2288 CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__);
2292 m_inMsgEvent.Reset();
2296 bool CActiveAE::IsSuspended()
2298 return m_stats.IsSuspended();
2301 float CActiveAE::GetVolume()
2306 void CActiveAE::SetVolume(const float volume)
2308 m_aeVolume = std::max( 0.0f, std::min(1.0f, volume));
2309 m_controlPort.SendOutMessage(CActiveAEControlProtocol::VOLUME, &m_aeVolume, sizeof(float));
2312 void CActiveAE::SetMute(const bool enabled)
2314 m_aeMuted = enabled;
2315 m_controlPort.SendOutMessage(CActiveAEControlProtocol::MUTE, &m_aeMuted, sizeof(bool));
2318 bool CActiveAE::IsMuted()
2323 void CActiveAE::SetSoundMode(const int mode)
2328 void CActiveAE::KeepConfiguration(unsigned int millis)
2330 unsigned int timeMs = millis;
2331 m_controlPort.SendOutMessage(CActiveAEControlProtocol::KEEPCONFIG, &timeMs, sizeof(unsigned int));
2334 void CActiveAE::DeviceChange()
2336 m_controlPort.SendOutMessage(CActiveAEControlProtocol::DEVICECHANGE);
2339 void CActiveAE::OnLostDevice()
2342 if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::DISPLAYLOST,
2346 bool success = reply->signal == CActiveAEControlProtocol::ACC;
2350 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
2355 CLog::Log(LOGERROR, "ActiveAE::%s - timed out", __FUNCTION__);
2359 void CActiveAE::OnResetDevice()
2361 m_controlPort.SendOutMessage(CActiveAEControlProtocol::DISPLAYRESET);
2364 //-----------------------------------------------------------------------------
2366 //-----------------------------------------------------------------------------
2368 uint8_t **CActiveAE::AllocSoundSample(SampleConfig &config, int &samples, int &bytes_per_sample, int &planes, int &linesize)
2371 planes = m_dllAvUtil.av_sample_fmt_is_planar(config.fmt) ? config.channels : 1;
2372 buffer = new uint8_t*[planes];
2374 // align buffer to 16 in order to be compatible with sse in CAEConvert
2375 m_dllAvUtil.av_samples_alloc(buffer, &linesize, config.channels,
2376 samples, config.fmt, 16);
2377 bytes_per_sample = m_dllAvUtil.av_get_bytes_per_sample(config.fmt);
2381 void CActiveAE::FreeSoundSample(uint8_t **data)
2383 m_dllAvUtil.av_freep(data);
2387 bool CActiveAE::CompareFormat(AEAudioFormat &lhs, AEAudioFormat &rhs)
2389 if (lhs.m_channelLayout != rhs.m_channelLayout ||
2390 lhs.m_dataFormat != rhs.m_dataFormat ||
2391 lhs.m_sampleRate != rhs.m_sampleRate)
2397 //-----------------------------------------------------------------------------
2399 //-----------------------------------------------------------------------------
2402 * load sound from an audio file and store original format
2403 * register the sound in ActiveAE
2404 * later when the engine is idle it will convert the sound to sink format
2407 #define SOUNDBUFFER_SIZE 20480
2409 IAESound *CActiveAE::MakeSound(const std::string& file)
2411 AVFormatContext *fmt_ctx = NULL;
2412 AVCodecContext *dec_ctx = NULL;
2413 AVIOContext *io_ctx;
2414 AVInputFormat *io_fmt;
2415 AVCodec *dec = NULL;
2416 CActiveAESound *sound = NULL;
2417 SampleConfig config;
2419 sound = new CActiveAESound(file);
2420 if (!sound->Prepare())
2425 int fileSize = sound->GetFileSize();
2427 fmt_ctx = m_dllAvFormat.avformat_alloc_context();
2428 unsigned char* buffer = (unsigned char*)m_dllAvUtil.av_malloc(SOUNDBUFFER_SIZE+FF_INPUT_BUFFER_PADDING_SIZE);
2429 io_ctx = m_dllAvFormat.avio_alloc_context(buffer, SOUNDBUFFER_SIZE, 0,
2430 sound, CActiveAESound::Read, NULL, CActiveAESound::Seek);
2431 io_ctx->max_packet_size = sound->GetChunkSize();
2432 if(io_ctx->max_packet_size)
2433 io_ctx->max_packet_size *= SOUNDBUFFER_SIZE / io_ctx->max_packet_size;
2435 if(!sound->IsSeekPosible())
2436 io_ctx->seekable = 0;
2438 fmt_ctx->pb = io_ctx;
2440 m_dllAvFormat.av_probe_input_buffer(io_ctx, &io_fmt, file.c_str(), NULL, 0, 0);
2443 m_dllAvFormat.avformat_close_input(&fmt_ctx);
2449 if (m_dllAvFormat.avformat_open_input(&fmt_ctx, file.c_str(), NULL, NULL) == 0)
2451 fmt_ctx->flags |= AVFMT_FLAG_NOPARSE;
2452 if (m_dllAvFormat.avformat_find_stream_info(fmt_ctx, NULL) >= 0)
2454 dec_ctx = fmt_ctx->streams[0]->codec;
2455 dec = m_dllAvCodec.avcodec_find_decoder(dec_ctx->codec_id);
2456 config.sample_rate = dec_ctx->sample_rate;
2457 config.channels = dec_ctx->channels;
2458 config.channel_layout = dec_ctx->channel_layout;
2463 m_dllAvFormat.avformat_close_input(&fmt_ctx);
2468 dec_ctx = m_dllAvCodec.avcodec_alloc_context3(dec);
2469 dec_ctx->sample_rate = config.sample_rate;
2470 dec_ctx->channels = config.channels;
2471 if (!config.channel_layout)
2472 config.channel_layout = m_dllAvUtil.av_get_default_channel_layout(config.channels);
2473 dec_ctx->channel_layout = config.channel_layout;
2476 AVFrame *decoded_frame = NULL;
2477 decoded_frame = m_dllAvCodec.avcodec_alloc_frame();
2479 if (m_dllAvCodec.avcodec_open2(dec_ctx, dec, NULL) >= 0)
2484 m_dllAvCodec.av_init_packet(&avpkt);
2486 while (m_dllAvFormat.av_read_frame(fmt_ctx, &avpkt) >= 0)
2489 len = m_dllAvCodec.avcodec_decode_audio4(dec_ctx, decoded_frame, &got_frame, &avpkt);
2492 m_dllAvCodec.avcodec_close(dec_ctx);
2493 m_dllAvUtil.av_free(dec_ctx);
2494 m_dllAvUtil.av_free(&decoded_frame);
2495 m_dllAvFormat.avformat_close_input(&fmt_ctx);
2503 int samples = fileSize / m_dllAvUtil.av_get_bytes_per_sample(dec_ctx->sample_fmt) / config.channels;
2504 config.fmt = dec_ctx->sample_fmt;
2505 config.bits_per_sample = dec_ctx->bits_per_coded_sample;
2506 sound->InitSound(true, config, samples);
2509 sound->StoreSound(true, decoded_frame->extended_data,
2510 decoded_frame->nb_samples, decoded_frame->linesize[0]);
2513 m_dllAvCodec.avcodec_close(dec_ctx);
2516 m_dllAvUtil.av_free(dec_ctx);
2517 m_dllAvUtil.av_free(decoded_frame);
2518 m_dllAvFormat.avformat_close_input(&fmt_ctx);
2523 m_dataPort.SendOutMessage(CActiveAEDataProtocol::NEWSOUND, &sound, sizeof(CActiveAESound*));
2528 void CActiveAE::FreeSound(IAESound *sound)
2530 m_dataPort.SendOutMessage(CActiveAEDataProtocol::FREESOUND, &sound, sizeof(CActiveAESound*));
2533 void CActiveAE::PlaySound(CActiveAESound *sound)
2535 m_dataPort.SendOutMessage(CActiveAEDataProtocol::PLAYSOUND, &sound, sizeof(CActiveAESound*));
2538 void CActiveAE::StopSound(CActiveAESound *sound)
2540 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STOPSOUND, &sound, sizeof(CActiveAESound*));
2544 * resample sounds to destination format for mixing
2545 * destination format is either format of stream or
2546 * default sink format when no stream is playing
2548 void CActiveAE::ResampleSounds()
2550 if (m_settings.guisoundmode == AE_SOUND_OFF ||
2551 (m_settings.guisoundmode == AE_SOUND_IDLE && !m_streams.empty()))
2554 std::vector<CActiveAESound*>::iterator it;
2555 for (it = m_sounds.begin(); it != m_sounds.end(); ++it)
2557 if (!(*it)->IsConverted())
2560 // only do one sound, then yield to main loop
2566 bool CActiveAE::ResampleSound(CActiveAESound *sound)
2568 SampleConfig orig_config, dst_config;
2569 uint8_t **dst_buffer;
2572 if (m_mode == MODE_RAW || m_internalFormat.m_dataFormat == AE_FMT_INVALID)
2575 if (!sound->GetSound(true))
2578 orig_config = sound->GetSound(true)->config;
2580 dst_config.channel_layout = CActiveAEResample::GetAVChannelLayout(m_internalFormat.m_channelLayout);
2581 dst_config.channels = m_internalFormat.m_channelLayout.Count();
2582 dst_config.sample_rate = m_internalFormat.m_sampleRate;
2583 dst_config.fmt = CActiveAEResample::GetAVSampleFormat(m_internalFormat.m_dataFormat);
2584 dst_config.bits_per_sample = CAEUtil::DataFormatToUsedBits(m_internalFormat.m_dataFormat);
2586 CActiveAEResample *resampler = new CActiveAEResample();
2587 resampler->Init(dst_config.channel_layout,
2588 dst_config.channels,
2589 dst_config.sample_rate,
2591 dst_config.bits_per_sample,
2592 orig_config.channel_layout,
2593 orig_config.channels,
2594 orig_config.sample_rate,
2596 orig_config.bits_per_sample,
2600 m_settings.resampleQuality);
2602 dst_samples = resampler->CalcDstSampleCount(sound->GetSound(true)->nb_samples,
2603 m_internalFormat.m_sampleRate,
2604 orig_config.sample_rate);
2606 dst_buffer = sound->InitSound(false, dst_config, dst_samples);
2612 int samples = resampler->Resample(dst_buffer, dst_samples,
2613 sound->GetSound(true)->data,
2614 sound->GetSound(true)->nb_samples,
2617 sound->GetSound(false)->nb_samples = samples;
2620 sound->SetConverted(true);
2624 //-----------------------------------------------------------------------------
2626 //-----------------------------------------------------------------------------
2628 IAEStream *CActiveAE::MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSampleRate, CAEChannelInfo channelLayout, unsigned int options)
2630 //TODO: pass number of samples in audio packet
2632 AEAudioFormat format;
2633 format.m_dataFormat = dataFormat;
2634 format.m_sampleRate = sampleRate;
2635 format.m_encodedRate = encodedSampleRate;
2636 format.m_channelLayout = channelLayout;
2637 format.m_frames = format.m_sampleRate / 10;
2638 format.m_frameSize = format.m_channelLayout.Count() *
2639 (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);
2642 msg.format = format;
2643 msg.options = options;
2646 if (m_dataPort.SendOutMessageSync(CActiveAEDataProtocol::NEWSTREAM,
2648 &msg, sizeof(MsgStreamNew)))
2650 bool success = reply->signal == CActiveAEControlProtocol::ACC;
2653 CActiveAEStream *stream = *(CActiveAEStream**)reply->data;
2660 CLog::Log(LOGERROR, "ActiveAE::%s - could not create stream", __FUNCTION__);
2664 IAEStream *CActiveAE::FreeStream(IAEStream *stream)
2666 m_dataPort.SendOutMessage(CActiveAEDataProtocol::FREESTREAM, &stream, sizeof(IAEStream*));
2670 void CActiveAE::FlushStream(CActiveAEStream *stream)
2673 if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::FLUSHSTREAM,
2675 &stream, sizeof(CActiveAEStream*)))
2677 bool success = reply->signal == CActiveAEControlProtocol::ACC;
2681 CLog::Log(LOGERROR, "CActiveAE::FlushStream - failed");
2686 void CActiveAE::PauseStream(CActiveAEStream *stream, bool pause)
2688 // TODO pause sink, needs api change
2690 m_controlPort.SendOutMessage(CActiveAEControlProtocol::PAUSESTREAM,
2691 &stream, sizeof(CActiveAEStream*));
2693 m_controlPort.SendOutMessage(CActiveAEControlProtocol::RESUMESTREAM,
2694 &stream, sizeof(CActiveAEStream*));
2697 void CActiveAE::SetStreamAmplification(CActiveAEStream *stream, float amplify)
2699 MsgStreamParameter msg;
2700 msg.stream = stream;
2701 msg.parameter.float_par = amplify;
2702 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMAMP,
2703 &msg, sizeof(MsgStreamParameter));
2706 void CActiveAE::SetStreamReplaygain(CActiveAEStream *stream, float rgain)
2708 MsgStreamParameter msg;
2709 msg.stream = stream;
2710 msg.parameter.float_par = rgain;
2711 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMRGAIN,
2712 &msg, sizeof(MsgStreamParameter));
2715 void CActiveAE::SetStreamVolume(CActiveAEStream *stream, float volume)
2717 MsgStreamParameter msg;
2718 msg.stream = stream;
2719 msg.parameter.float_par = volume;
2720 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMVOLUME,
2721 &msg, sizeof(MsgStreamParameter));
2724 void CActiveAE::SetStreamResampleRatio(CActiveAEStream *stream, double ratio)
2726 MsgStreamParameter msg;
2727 msg.stream = stream;
2728 msg.parameter.double_par = ratio;
2729 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMRESAMPLERATIO,
2730 &msg, sizeof(MsgStreamParameter));
2733 void CActiveAE::SetStreamFade(CActiveAEStream *stream, float from, float target, unsigned int millis)
2736 msg.stream = stream;
2738 msg.target = target;
2739 msg.millis = millis;
2740 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMFADE,
2741 &msg, sizeof(MsgStreamFade));
2744 void CActiveAE::RegisterAudioCallback(IAudioCallback* pCallback)
2746 CSingleLock lock(m_vizLock);
2747 m_audioCallback = pCallback;
2748 m_vizInitialized = false;
2751 void CActiveAE::UnregisterAudioCallback()
2753 CSingleLock lock(m_vizLock);
2754 m_audioCallback = NULL;