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 "Utils/AEUtil.h"
27 #include "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 float CEngineStats::GetDelay(CActiveAEStream *stream)
94 CSingleLock lock(m_lock);
95 unsigned int now = XbmcThreads::SystemClockMillis();
96 float delay = m_sinkDelay - (double)(now-m_sinkUpdate) / 1000;
97 delay += (float)m_bufferedSamples / m_sinkSampleRate;
102 delay += stream->m_bufferedTime;
106 float CEngineStats::GetCacheTime(CActiveAEStream *stream)
108 CSingleLock lock(m_lock);
109 float delay = (float)m_bufferedSamples / m_sinkSampleRate;
111 delay += stream->m_bufferedTime;
115 float CEngineStats::GetCacheTotal(CActiveAEStream *stream)
117 return MAX_CACHE_LEVEL + m_sinkCacheTotal;
120 float CEngineStats::GetWaterLevel()
122 return (float)m_bufferedSamples / m_sinkSampleRate;
125 void CEngineStats::SetSuspended(bool state)
127 CSingleLock lock(m_lock);
131 bool CEngineStats::IsSuspended()
133 CSingleLock lock(m_lock);
137 CActiveAE::CActiveAE() :
139 m_controlPort("OutputControlPort", &m_inMsgEvent, &m_outMsgEvent),
140 m_dataPort("OutputDataPort", &m_inMsgEvent, &m_outMsgEvent),
141 m_sink(&m_outMsgEvent)
143 m_sinkBuffers = NULL;
144 m_silenceBuffers = NULL;
145 m_encoderBuffers = NULL;
147 m_vizBuffersInput = NULL;
154 m_audioCallback = NULL;
155 m_vizInitialized = false;
156 m_sinkHasVolume = false;
159 CActiveAE::~CActiveAE()
164 void CActiveAE::Dispose()
166 #if defined(HAS_GLX) || defined(TARGET_DARWIN_OSX)
167 g_Windowing.Unregister(this);
173 m_controlPort.Purge();
177 m_dllAvFormat.Unload();
178 m_dllAvCodec.Unload();
179 m_dllAvUtil.Unload();
182 //-----------------------------------------------------------------------------
184 //-----------------------------------------------------------------------------
190 AE_TOP_UNCONFIGURED, // 2
191 AE_TOP_RECONFIGURING, // 3
192 AE_TOP_CONFIGURED, // 4
193 AE_TOP_CONFIGURED_SUSPEND, // 5
194 AE_TOP_CONFIGURED_IDLE, // 6
195 AE_TOP_CONFIGURED_PLAY, // 7
198 int AE_parentStates[] = {
201 0, //TOP_UNCONFIGURED
203 0, //TOP_RECONFIGURING
204 4, //TOP_CONFIGURED_SUSPEND
205 4, //TOP_CONFIGURED_IDLE
206 4, //TOP_CONFIGURED_PLAY
209 void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg)
211 for (int state = m_state; ; state = AE_parentStates[state])
216 if (port == &m_controlPort)
220 case CActiveAEControlProtocol::GETSTATE:
221 msg->Reply(CActiveAEControlProtocol::ACC, &m_state, sizeof(m_state));
223 case CActiveAEControlProtocol::VOLUME:
224 m_volume = *(float*)msg->data;
226 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::VOLUME, &m_volume, sizeof(float));
228 case CActiveAEControlProtocol::MUTE:
229 m_muted = *(bool*)msg->data;
231 case CActiveAEControlProtocol::KEEPCONFIG:
232 m_extKeepConfig = *(unsigned int*)msg->data;
238 else if (port == &m_dataPort)
242 case CActiveAEDataProtocol::NEWSOUND:
243 CActiveAESound *sound;
244 sound = *(CActiveAESound**)msg->data;
247 m_sounds.push_back(sound);
251 case CActiveAEDataProtocol::FREESTREAM:
252 CActiveAEStream *stream;
253 stream = *(CActiveAEStream**)msg->data;
254 DiscardStream(stream);
256 case CActiveAEDataProtocol::FREESOUND:
257 sound = *(CActiveAESound**)msg->data;
260 case CActiveAEDataProtocol::DRAINSTREAM:
261 stream = *(CActiveAEStream**)msg->data;
262 stream->m_drain = true;
263 stream->m_resampleBuffers->m_drain = true;
264 msg->Reply(CActiveAEDataProtocol::ACC);
265 stream->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMDRAINED);
271 else if (port == &m_sink.m_dataPort)
275 case CSinkDataProtocol::RETURNSAMPLE:
276 CSampleBuffer **buffer;
277 buffer = (CSampleBuffer**)msg->data;
288 std::string portName = port == NULL ? "timer" : port->portName;
289 CLog::Log(LOGWARNING, "CActiveAE::%s - signal: %d from port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
294 if (port == NULL) // timeout
298 case CActiveAEControlProtocol::TIMEOUT:
304 m_state = AE_TOP_CONFIGURED_IDLE;
309 m_state = AE_TOP_ERROR;
319 case AE_TOP_UNCONFIGURED:
320 if (port == &m_controlPort)
324 case CActiveAEControlProtocol::INIT:
326 m_sink.EnumerateSinkList(false);
329 msg->Reply(CActiveAEControlProtocol::ACC);
332 m_state = AE_TOP_CONFIGURED_IDLE;
337 m_state = AE_TOP_ERROR;
348 case AE_TOP_RECONFIGURING:
349 if (port == NULL) // timeout
353 case CActiveAEControlProtocol::TIMEOUT:
360 if (!m_sinkBuffers->m_inputSamples.empty() || !m_sinkBuffers->m_outputSamples.empty())
365 if (NeedReconfigureSink())
372 m_state = AE_TOP_CONFIGURED_PLAY;
377 m_state = AE_TOP_ERROR;
380 m_extDeferData = false;
388 case AE_TOP_CONFIGURED:
389 if (port == &m_controlPort)
393 case CActiveAEControlProtocol::RECONFIGURE:
394 if (m_streams.empty())
396 bool silence = false;
397 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::SILENCEMODE, &silence, sizeof(bool));
401 if (!NeedReconfigureBuffers() && !NeedReconfigureSink())
403 m_state = AE_TOP_RECONFIGURING;
405 // don't accept any data until we are reconfigured
406 m_extDeferData = true;
408 case CActiveAEControlProtocol::SUSPEND:
410 m_stats.SetSuspended(true);
411 m_state = AE_TOP_CONFIGURED_SUSPEND;
412 m_extDeferData = true;
414 case CActiveAEControlProtocol::DISPLAYLOST:
415 if (m_sink.GetDeviceType(m_mode == MODE_PCM ? m_settings.device : m_settings.passthoughdevice) == AE_DEVTYPE_HDMI)
418 m_stats.SetSuspended(true);
419 m_state = AE_TOP_CONFIGURED_SUSPEND;
420 m_extDeferData = true;
423 case CActiveAEControlProtocol::PAUSESTREAM:
424 CActiveAEStream *stream;
425 stream = *(CActiveAEStream**)msg->data;
426 if (stream->m_paused != true && m_streams.size() == 1)
428 stream->m_paused = true;
430 case CActiveAEControlProtocol::RESUMESTREAM:
431 stream = *(CActiveAEStream**)msg->data;
432 stream->m_paused = false;
433 m_state = AE_TOP_CONFIGURED_PLAY;
436 case CActiveAEControlProtocol::FLUSHSTREAM:
437 stream = *(CActiveAEStream**)msg->data;
438 SFlushStream(stream);
439 msg->Reply(CActiveAEControlProtocol::ACC);
440 m_state = AE_TOP_CONFIGURED_PLAY;
443 case CActiveAEControlProtocol::STREAMAMP:
444 MsgStreamParameter *par;
445 par = (MsgStreamParameter*)msg->data;
446 par->stream->m_limiter.SetAmplification(par->parameter.float_par);
447 par->stream->m_amplify = par->parameter.float_par;
449 case CActiveAEControlProtocol::STREAMVOLUME:
450 par = (MsgStreamParameter*)msg->data;
451 par->stream->m_volume = par->parameter.float_par;
453 case CActiveAEControlProtocol::STREAMRGAIN:
454 par = (MsgStreamParameter*)msg->data;
455 par->stream->m_rgain = par->parameter.float_par;
457 case CActiveAEControlProtocol::STREAMRESAMPLERATIO:
458 par = (MsgStreamParameter*)msg->data;
459 if (par->stream->m_resampleBuffers)
461 par->stream->m_resampleBuffers->m_resampleRatio = par->parameter.double_par;
464 case CActiveAEControlProtocol::STREAMFADE:
466 fade = (MsgStreamFade*)msg->data;
467 fade->stream->m_fadingBase = fade->from;
468 fade->stream->m_fadingTarget = fade->target;
469 fade->stream->m_fadingTime = fade->millis;
470 fade->stream->m_fadingSamples = -1;
472 case CActiveAEControlProtocol::STOPSOUND:
473 CActiveAESound *sound;
474 sound = *(CActiveAESound**)msg->data;
481 else if (port == &m_dataPort)
485 case CActiveAEDataProtocol::PLAYSOUND:
486 CActiveAESound *sound;
487 sound = *(CActiveAESound**)msg->data;
488 if (m_settings.guisoundmode == AE_SOUND_OFF ||
489 (m_settings.guisoundmode == AE_SOUND_IDLE && !m_streams.empty()))
493 SoundState st = {sound, 0};
494 m_sounds_playing.push_back(st);
496 m_state = AE_TOP_CONFIGURED_PLAY;
499 case CActiveAEDataProtocol::NEWSTREAM:
500 MsgStreamNew *streamMsg;
501 CActiveAEStream *stream;
502 streamMsg = (MsgStreamNew*)msg->data;
503 stream = CreateStream(streamMsg);
506 msg->Reply(CActiveAEDataProtocol::ACC, &stream, sizeof(CActiveAEStream*));
511 m_state = AE_TOP_CONFIGURED_PLAY;
516 m_state = AE_TOP_ERROR;
521 msg->Reply(CActiveAEDataProtocol::ERR);
523 case CActiveAEDataProtocol::STREAMSAMPLE:
524 MsgStreamSample *msgData;
525 CSampleBuffer *samples;
526 msgData = (MsgStreamSample*)msg->data;
527 samples = msgData->stream->m_processingSamples.front();
528 msgData->stream->m_processingSamples.pop_front();
529 if (samples != msgData->buffer)
530 CLog::Log(LOGERROR, "CActiveAE - inconsistency in stream sample message");
531 if (msgData->buffer->pkt->nb_samples == 0)
532 msgData->buffer->Return();
534 msgData->stream->m_resampleBuffers->m_inputSamples.push_back(msgData->buffer);
536 m_state = AE_TOP_CONFIGURED_PLAY;
538 case CActiveAEDataProtocol::FREESTREAM:
539 stream = *(CActiveAEStream**)msg->data;
540 DiscardStream(stream);
541 if (m_streams.empty())
544 m_extDrainTimer.Set(m_extKeepConfig);
546 m_extDrainTimer.Set(m_stats.GetDelay() * 1000);
550 m_state = AE_TOP_CONFIGURED_PLAY;
552 case CActiveAEDataProtocol::DRAINSTREAM:
553 stream = *(CActiveAEStream**)msg->data;
554 stream->m_drain = true;
555 stream->m_resampleBuffers->m_drain = true;
557 m_state = AE_TOP_CONFIGURED_PLAY;
558 msg->Reply(CActiveAEDataProtocol::ACC);
564 else if (port == &m_sink.m_dataPort)
568 case CSinkDataProtocol::RETURNSAMPLE:
569 CSampleBuffer **buffer;
570 buffer = (CSampleBuffer**)msg->data;
576 m_state = AE_TOP_CONFIGURED_PLAY;
584 case AE_TOP_CONFIGURED_SUSPEND:
585 if (port == &m_controlPort)
587 bool displayReset = false;
590 case CActiveAEControlProtocol::DISPLAYRESET:
592 case CActiveAEControlProtocol::INIT:
596 m_sink.EnumerateSinkList(true);
601 msg->Reply(CActiveAEControlProtocol::ACC);
604 m_state = AE_TOP_CONFIGURED_PLAY;
609 m_state = AE_TOP_ERROR;
612 m_stats.SetSuspended(false);
613 m_extDeferData = false;
619 else if (port == &m_sink.m_dataPort)
623 case CSinkDataProtocol::RETURNSAMPLE:
624 CSampleBuffer **buffer;
625 buffer = (CSampleBuffer**)msg->data;
637 case AE_TOP_CONFIGURED_IDLE:
638 if (port == NULL) // timeout
642 case CActiveAEControlProtocol::TIMEOUT:
644 ClearDiscardedBuffers();
647 if (m_extDrainTimer.IsTimePast())
652 m_state = AE_TOP_CONFIGURED_PLAY;
657 m_state = AE_TOP_ERROR;
662 m_extTimeout = m_extDrainTimer.MillisLeft();
673 case AE_TOP_CONFIGURED_PLAY:
674 if (port == NULL) // timeout
678 case CActiveAEControlProtocol::TIMEOUT:
681 m_state = AE_TOP_ERROR;
690 if (!m_extDrain && HasWork())
692 ClearDiscardedBuffers();
697 m_state = AE_TOP_CONFIGURED_IDLE;
705 default: // we are in no state, should not happen
706 CLog::Log(LOGERROR, "CActiveAE::%s - no valid state: %d", __FUNCTION__, m_state);
712 void CActiveAE::Process()
715 Protocol *port = NULL;
717 XbmcThreads::EndTime timer;
719 m_state = AE_TOP_UNCONFIGURED;
721 m_bStateMachineSelfTrigger = false;
723 m_extDeferData = false;
732 timer.Set(m_extTimeout);
734 if (m_bStateMachineSelfTrigger)
736 m_bStateMachineSelfTrigger = false;
737 // self trigger state machine
738 StateMachine(msg->signal, port, msg);
739 if (!m_bStateMachineSelfTrigger)
746 // check control port
747 else if (m_controlPort.ReceiveOutMessage(&msg))
750 port = &m_controlPort;
752 // check sink data port
753 else if (m_sink.m_dataPort.ReceiveInMessage(&msg))
756 port = &m_sink.m_dataPort;
758 else if (!m_extDeferData)
761 if (m_dataPort.ReceiveOutMessage(&msg))
769 std::list<CActiveAEStream*>::iterator it;
770 for(it=m_streams.begin(); it!=m_streams.end(); ++it)
772 if((*it)->m_streamPort->ReceiveOutMessage(&msg))
784 StateMachine(msg->signal, port, msg);
785 if (!m_bStateMachineSelfTrigger)
794 else if (m_outMsgEvent.WaitMSec(m_extTimeout))
796 m_extTimeout = timer.MillisLeft();
802 msg = m_controlPort.GetMessage();
803 msg->signal = CActiveAEControlProtocol::TIMEOUT;
805 // signal timeout to state machine
806 StateMachine(msg->signal, port, msg);
807 if (!m_bStateMachineSelfTrigger)
816 AEAudioFormat CActiveAE::GetInputFormat(AEAudioFormat *desiredFmt)
818 AEAudioFormat inputFormat;
820 if (m_streams.empty())
822 inputFormat.m_dataFormat = AE_FMT_FLOAT;
823 inputFormat.m_sampleRate = 44100;
824 inputFormat.m_encodedRate = 0;
825 inputFormat.m_channelLayout = AE_CH_LAYOUT_2_0;
826 inputFormat.m_frames = 0;
827 inputFormat.m_frameSamples = 0;
828 inputFormat.m_frameSize = 0;
830 // force input format after unpausing slave
831 else if (desiredFmt != NULL)
833 inputFormat = *desiredFmt;
835 // keep format when having multiple streams
836 else if (m_streams.size() > 1 && m_silenceBuffers == NULL)
838 inputFormat = m_inputFormat;
842 inputFormat = m_streams.front()->m_format;
843 m_inputFormat = inputFormat;
849 void CActiveAE::Configure(AEAudioFormat *desiredFmt)
851 bool initSink = false;
853 AEAudioFormat sinkInputFormat, inputFormat;
854 AEAudioFormat oldInternalFormat = m_internalFormat;
856 inputFormat = GetInputFormat(desiredFmt);
858 m_sinkRequestFormat = inputFormat;
859 ApplySettingsToFormat(m_sinkRequestFormat, m_settings, (int*)&m_mode);
862 std::string device = AE_IS_RAW(m_sinkRequestFormat.m_dataFormat) ? m_settings.passthoughdevice : m_settings.device;
864 CAESinkFactory::ParseDevice(device, driver);
865 if (!IsSinkCompatible(m_sinkRequestFormat, device) || m_settings.driver.compare(driver) != 0)
869 m_settings.driver = driver;
871 m_stats.Reset(m_sinkFormat.m_sampleRate);
872 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::VOLUME, &m_volume, sizeof(float));
874 // limit buffer size in case of sink returns large buffer
875 unsigned int buffertime = (m_sinkFormat.m_frames*1000) / m_sinkFormat.m_sampleRate;
878 CLog::Log(LOGWARNING, "ActiveAE::%s - sink returned large buffer of %d ms, reducing to 80 ms", __FUNCTION__, buffertime);
879 m_sinkFormat.m_frames = 80 * m_sinkFormat.m_sampleRate / 1000;
883 if (m_silenceBuffers)
885 m_discardBufferPools.push_back(m_silenceBuffers);
886 m_silenceBuffers = NULL;
889 // buffers for driving gui sounds if no streams are active
890 if (m_streams.empty())
892 inputFormat = m_sinkFormat;
893 inputFormat.m_dataFormat = AE_FMT_FLOAT;
894 inputFormat.m_frameSize = inputFormat.m_channelLayout.Count() *
895 (CAEUtil::DataFormatToBits(inputFormat.m_dataFormat) >> 3);
896 m_silenceBuffers = new CActiveAEBufferPool(inputFormat);
897 m_silenceBuffers->Create(MAX_WATER_LEVEL*1000);
898 sinkInputFormat = inputFormat;
899 m_internalFormat = inputFormat;
901 bool silence = false;
902 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::SILENCEMODE, &silence, sizeof(bool));
907 if (m_encoderBuffers)
909 m_discardBufferPools.push_back(m_encoderBuffers);
910 m_encoderBuffers = NULL;
914 m_discardBufferPools.push_back(m_vizBuffers);
917 if (m_vizBuffersInput)
919 m_discardBufferPools.push_back(m_vizBuffersInput);
920 m_vizBuffersInput = NULL;
923 // resample buffers for streams
927 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::SILENCEMODE, &silence, sizeof(bool));
929 AEAudioFormat outputFormat;
930 if (m_mode == MODE_RAW)
932 outputFormat = inputFormat;
933 sinkInputFormat = m_sinkFormat;
935 // transcode everything with more than 2 channels
936 else if (m_mode == MODE_TRANSCODE)
938 outputFormat = inputFormat;
939 outputFormat.m_dataFormat = AE_FMT_FLOATP;
940 outputFormat.m_sampleRate = 48000;
945 m_encoder = new CAEEncoderFFmpeg();
946 m_encoder->Initialize(outputFormat, true);
947 m_encoderFormat = outputFormat;
950 outputFormat = m_encoderFormat;
952 outputFormat.m_channelLayout = m_encoderFormat.m_channelLayout;
953 outputFormat.m_frames = m_encoderFormat.m_frames;
956 if (m_encoder->GetCodecID() == AV_CODEC_ID_AC3)
958 AEAudioFormat format;
959 format.m_channelLayout = AE_CH_LAYOUT_2_0;
960 format.m_dataFormat = AE_FMT_S16NE;
961 format.m_frameSize = 2* (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);
962 format.m_frames = AC3_FRAME_SIZE;
963 format.m_sampleRate = 48000;
964 if (m_encoderBuffers && initSink)
966 m_discardBufferPools.push_back(m_encoderBuffers);
967 m_encoderBuffers = NULL;
969 if (!m_encoderBuffers)
971 m_encoderBuffers = new CActiveAEBufferPool(format);
972 m_encoderBuffers->Create(MAX_WATER_LEVEL*1000);
976 sinkInputFormat = m_sinkFormat;
980 outputFormat = m_sinkFormat;
981 outputFormat.m_dataFormat = AE_FMT_FLOAT;
982 outputFormat.m_frameSize = outputFormat.m_channelLayout.Count() *
983 (CAEUtil::DataFormatToBits(outputFormat.m_dataFormat) >> 3);
984 // TODO: adjust to decoder
985 sinkInputFormat = outputFormat;
987 m_internalFormat = outputFormat;
989 std::list<CActiveAEStream*>::iterator it;
990 for(it=m_streams.begin(); it!=m_streams.end(); ++it)
992 // check if we support input format of stream
993 if (!AE_IS_RAW((*it)->m_format.m_dataFormat) &&
994 CActiveAEResample::GetAVSampleFormat((*it)->m_format.m_dataFormat) == AV_SAMPLE_FMT_FLT &&
995 (*it)->m_format.m_dataFormat != AE_FMT_FLOAT)
997 (*it)->m_convertFn = CAEConvert::ToFloat((*it)->m_format.m_dataFormat);
998 (*it)->m_format.m_dataFormat = AE_FMT_FLOAT;
1001 if (!(*it)->m_inputBuffers)
1003 // align input buffers with period of sink or encoder
1004 (*it)->m_format.m_frames = m_internalFormat.m_frames * ((float)(*it)->m_format.m_sampleRate / m_internalFormat.m_sampleRate);
1006 // create buffer pool
1007 (*it)->m_inputBuffers = new CActiveAEBufferPool((*it)->m_format);
1008 (*it)->m_inputBuffers->Create(MAX_CACHE_LEVEL*1000);
1009 (*it)->m_streamSpace = (*it)->m_format.m_frameSize * (*it)->m_format.m_frames;
1011 // if input format does not follow ffmpeg channel mask, we may need to remap channels
1012 (*it)->InitRemapper();
1014 if (initSink && (*it)->m_resampleBuffers)
1016 m_discardBufferPools.push_back((*it)->m_resampleBuffers);
1017 (*it)->m_resampleBuffers = NULL;
1019 if (!(*it)->m_resampleBuffers)
1021 (*it)->m_resampleBuffers = new CActiveAEBufferPoolResample((*it)->m_inputBuffers->m_format, outputFormat, m_settings.resampleQuality);
1022 (*it)->m_resampleBuffers->m_changeResampler = (*it)->m_forceResampler;
1023 (*it)->m_resampleBuffers->Create(MAX_CACHE_LEVEL*1000, false, m_settings.stereoupmix, m_settings.normalizelevels);
1025 if (m_mode == MODE_TRANSCODE || m_streams.size() > 1)
1026 (*it)->m_resampleBuffers->m_fillPackets = true;
1029 (*it)->m_limiter.SetSamplerate(outputFormat.m_sampleRate);
1033 if (!AE_IS_RAW(inputFormat.m_dataFormat))
1035 if (initSink && m_vizBuffers)
1037 m_discardBufferPools.push_back(m_vizBuffers);
1038 m_vizBuffers = NULL;
1039 m_discardBufferPools.push_back(m_vizBuffersInput);
1040 m_vizBuffersInput = NULL;
1044 AEAudioFormat vizFormat = m_internalFormat;
1045 vizFormat.m_channelLayout = AE_CH_LAYOUT_2_0;
1046 vizFormat.m_dataFormat = AE_FMT_FLOAT;
1049 m_vizBuffersInput = new CActiveAEBufferPool(m_internalFormat);
1050 m_vizBuffersInput->Create(2000);
1053 m_vizBuffers = new CActiveAEBufferPoolResample(m_internalFormat, vizFormat, m_settings.resampleQuality);
1054 // TODO use cache of sync + water level
1055 m_vizBuffers->Create(2000, false, false);
1056 m_vizInitialized = false;
1061 // resample buffers for sink
1062 if (m_sinkBuffers &&
1063 (!CompareFormat(m_sinkBuffers->m_format,m_sinkFormat) || !CompareFormat(m_sinkBuffers->m_inputFormat, sinkInputFormat)))
1065 m_discardBufferPools.push_back(m_sinkBuffers);
1066 m_sinkBuffers = NULL;
1070 m_sinkBuffers = new CActiveAEBufferPoolResample(sinkInputFormat, m_sinkFormat, m_settings.resampleQuality);
1071 m_sinkBuffers->Create(MAX_WATER_LEVEL*1000, true, false);
1075 if (!CompareFormat(oldInternalFormat, m_internalFormat))
1077 if (m_settings.guisoundmode == AE_SOUND_ALWAYS ||
1078 (m_settings.guisoundmode == AE_SOUND_IDLE && m_streams.empty()))
1080 std::vector<CActiveAESound*>::iterator it;
1081 for (it = m_sounds.begin(); it != m_sounds.end(); ++it)
1083 (*it)->SetConverted(false);
1086 m_sounds_playing.clear();
1089 ClearDiscardedBuffers();
1093 CActiveAEStream* CActiveAE::CreateStream(MsgStreamNew *streamMsg)
1095 // we only can handle a single pass through stream
1096 bool hasRawStream = false;
1097 bool hasStream = false;
1098 std::list<CActiveAEStream*>::iterator it;
1099 for(it = m_streams.begin(); it != m_streams.end(); ++it)
1101 if((*it)->IsDrained())
1103 if(AE_IS_RAW((*it)->m_format.m_dataFormat))
1104 hasRawStream = true;
1107 if (hasRawStream || (hasStream && AE_IS_RAW(streamMsg->format.m_dataFormat)))
1112 // create the stream
1113 CActiveAEStream *stream;
1114 stream = new CActiveAEStream(&streamMsg->format);
1115 stream->m_streamPort = new CActiveAEDataProtocol("stream",
1116 &stream->m_inMsgEvent, &m_outMsgEvent);
1118 // create buffer pool
1119 stream->m_inputBuffers = NULL; // create in Configure when we know the sink format
1120 stream->m_resampleBuffers = NULL; // create in Configure when we know the sink format
1121 stream->m_statsLock = m_stats.GetLock();
1122 stream->m_fadingSamples = 0;
1123 stream->m_started = false;
1125 if (streamMsg->options & AESTREAM_PAUSED)
1126 stream->m_paused = true;
1128 if (streamMsg->options & AESTREAM_FORCE_RESAMPLE)
1129 stream->m_forceResampler = true;
1131 m_streams.push_back(stream);
1136 void CActiveAE::DiscardStream(CActiveAEStream *stream)
1138 std::list<CActiveAEStream*>::iterator it;
1139 for (it=m_streams.begin(); it!=m_streams.end(); )
1141 if (stream == (*it))
1143 while (!(*it)->m_processingSamples.empty())
1145 (*it)->m_processingSamples.front()->Return();
1146 (*it)->m_processingSamples.pop_front();
1148 m_discardBufferPools.push_back((*it)->m_inputBuffers);
1149 m_discardBufferPools.push_back((*it)->m_resampleBuffers);
1150 CLog::Log(LOGDEBUG, "CActiveAE::DiscardStream - audio stream deleted");
1151 delete (*it)->m_streamPort;
1153 it = m_streams.erase(it);
1159 ClearDiscardedBuffers();
1162 void CActiveAE::SFlushStream(CActiveAEStream *stream)
1164 while (!stream->m_processingSamples.empty())
1166 stream->m_processingSamples.front()->Return();
1167 stream->m_processingSamples.pop_front();
1169 stream->m_resampleBuffers->Flush();
1170 stream->m_streamPort->Purge();
1171 stream->m_bufferedTime = 0.0;
1172 stream->m_paused = false;
1174 // flush the engine if we only have a single stream
1175 if (m_streams.size() == 1)
1181 void CActiveAE::FlushEngine()
1184 m_sinkBuffers->Flush();
1186 m_vizBuffers->Flush();
1188 // send message to sink
1190 if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::FLUSH,
1193 bool success = reply->signal == CSinkControlProtocol::ACC ? true : false;
1196 CLog::Log(LOGERROR, "ActiveAE::%s - returned error on flush", __FUNCTION__);
1203 CLog::Log(LOGERROR, "ActiveAE::%s - failed to flush", __FUNCTION__);
1206 m_stats.Reset(m_sinkFormat.m_sampleRate);
1209 void CActiveAE::ClearDiscardedBuffers()
1211 std::list<CActiveAEBufferPool*>::iterator it;
1212 for (it=m_discardBufferPools.begin(); it!=m_discardBufferPools.end(); ++it)
1214 CActiveAEBufferPoolResample *rbuf = dynamic_cast<CActiveAEBufferPoolResample*>(*it);
1219 // if all buffers have returned, we can delete the buffer pool
1220 if ((*it)->m_allSamples.size() == (*it)->m_freeSamples.size())
1223 CLog::Log(LOGDEBUG, "CActiveAE::ClearDiscardedBuffers - buffer pool deleted");
1224 m_discardBufferPools.erase(it);
1230 void CActiveAE::SStopSound(CActiveAESound *sound)
1232 std::list<SoundState>::iterator it;
1233 for (it=m_sounds_playing.begin(); it!=m_sounds_playing.end(); ++it)
1235 if (it->sound == sound)
1237 m_sounds_playing.erase(it);
1243 void CActiveAE::DiscardSound(CActiveAESound *sound)
1247 std::vector<CActiveAESound*>::iterator it;
1248 for (it=m_sounds.begin(); it!=m_sounds.end(); ++it)
1258 void CActiveAE::ChangeResamplers()
1260 std::list<CActiveAEStream*>::iterator it;
1261 for(it=m_streams.begin(); it!=m_streams.end(); ++it)
1263 bool normalize = true;
1264 if (((*it)->m_resampleBuffers->m_format.m_channelLayout.Count() <
1265 (*it)->m_resampleBuffers->m_inputFormat.m_channelLayout.Count()) &&
1266 !m_settings.normalizelevels)
1269 if ((*it)->m_resampleBuffers && (*it)->m_resampleBuffers->m_resampler &&
1270 (((*it)->m_resampleBuffers->m_resampleQuality != m_settings.resampleQuality) ||
1271 (((*it)->m_resampleBuffers->m_stereoUpmix != m_settings.stereoupmix)) ||
1272 ((*it)->m_resampleBuffers->m_normalize != normalize)))
1274 (*it)->m_resampleBuffers->m_changeResampler = true;
1276 (*it)->m_resampleBuffers->m_resampleQuality = m_settings.resampleQuality;
1277 (*it)->m_resampleBuffers->m_stereoUpmix = m_settings.stereoupmix;
1278 (*it)->m_resampleBuffers->m_normalize = normalize;
1282 void CActiveAE::ApplySettingsToFormat(AEAudioFormat &format, AudioSettings &settings, int *mode)
1284 int oldMode = m_mode;
1289 if (AE_IS_RAW(format.m_dataFormat))
1291 if ((format.m_dataFormat == AE_FMT_AC3 && !settings.ac3passthrough) ||
1292 (format.m_dataFormat == AE_FMT_EAC3 && !settings.eac3passthrough) ||
1293 (format.m_dataFormat == AE_FMT_TRUEHD && !settings.truehdpassthrough) ||
1294 (format.m_dataFormat == AE_FMT_DTS && !settings.dtspassthrough) ||
1295 (format.m_dataFormat == AE_FMT_DTSHD && !settings.dtshdpassthrough))
1297 CLog::Log(LOGERROR, "CActiveAE::ApplySettingsToFormat - input audio format is wrong");
1303 else if (settings.channels <= AE_CH_LAYOUT_2_0 && // no multichannel pcm
1304 settings.passthrough &&
1305 settings.ac3passthrough &&
1306 !m_streams.empty() &&
1307 (format.m_channelLayout.Count() > 2 || settings.stereoupmix))
1309 format.m_dataFormat = AE_FMT_AC3;
1310 format.m_sampleRate = 48000;
1311 format.m_channelLayout = AE_CH_LAYOUT_2_0;
1313 *mode = MODE_TRANSCODE;
1317 format.m_dataFormat = AE_FMT_FLOAT;
1318 // consider user channel layout for those cases
1319 // 1. input stream is multichannel
1320 // 2. stereo upmix is selected
1322 if ((format.m_channelLayout.Count() > 2) ||
1323 settings.stereoupmix ||
1324 (settings.config == AE_CONFIG_FIXED))
1326 CAEChannelInfo stdLayout;
1327 switch (settings.channels)
1330 case 0: stdLayout = AE_CH_LAYOUT_2_0; break;
1331 case 1: stdLayout = AE_CH_LAYOUT_2_0; break;
1332 case 2: stdLayout = AE_CH_LAYOUT_2_1; break;
1333 case 3: stdLayout = AE_CH_LAYOUT_3_0; break;
1334 case 4: stdLayout = AE_CH_LAYOUT_3_1; break;
1335 case 5: stdLayout = AE_CH_LAYOUT_4_0; break;
1336 case 6: stdLayout = AE_CH_LAYOUT_4_1; break;
1337 case 7: stdLayout = AE_CH_LAYOUT_5_0; break;
1338 case 8: stdLayout = AE_CH_LAYOUT_5_1; break;
1339 case 9: stdLayout = AE_CH_LAYOUT_7_0; break;
1340 case 10: stdLayout = AE_CH_LAYOUT_7_1; break;
1343 if (m_settings.config == AE_CONFIG_FIXED || (settings.stereoupmix && format.m_channelLayout.Count() <= 2))
1344 format.m_channelLayout = stdLayout;
1345 else if (m_extKeepConfig && (settings.config == AE_CONFIG_AUTO) && (oldMode != MODE_RAW))
1346 format.m_channelLayout = m_internalFormat.m_channelLayout;
1348 format.m_channelLayout.ResolveChannels(stdLayout);
1350 // don't change from multi to stereo in AUTO mode
1351 else if ((settings.config == AE_CONFIG_AUTO) &&
1352 m_stats.GetWaterLevel() > 0 && m_internalFormat.m_channelLayout.Count() > 2)
1354 format.m_channelLayout = m_internalFormat.m_channelLayout;
1357 if (m_sink.GetDeviceType(m_settings.device) == AE_DEVTYPE_IEC958)
1359 if (format.m_sampleRate > m_settings.samplerate)
1361 format.m_sampleRate = m_settings.samplerate;
1362 CLog::Log(LOGINFO, "CActiveAE::ApplySettings - limit samplerate for SPDIF to %d", format.m_sampleRate);
1364 format.m_channelLayout = AE_CH_LAYOUT_2_0;
1367 if (m_settings.config == AE_CONFIG_FIXED)
1369 format.m_sampleRate = m_settings.samplerate;
1370 CLog::Log(LOGINFO, "CActiveAE::ApplySettings - Forcing samplerate to %d", format.m_sampleRate);
1373 // sinks may not support mono
1374 if (format.m_channelLayout.Count() == 1)
1376 format.m_channelLayout = AE_CH_LAYOUT_2_0;
1381 bool CActiveAE::NeedReconfigureBuffers()
1383 AEAudioFormat newFormat = GetInputFormat();
1384 ApplySettingsToFormat(newFormat, m_settings);
1386 if (newFormat.m_dataFormat != m_sinkRequestFormat.m_dataFormat ||
1387 newFormat.m_channelLayout != m_sinkRequestFormat.m_channelLayout ||
1388 newFormat.m_sampleRate != m_sinkRequestFormat.m_sampleRate)
1394 bool CActiveAE::NeedReconfigureSink()
1396 AEAudioFormat newFormat = GetInputFormat();
1397 ApplySettingsToFormat(newFormat, m_settings);
1399 std::string device = AE_IS_RAW(newFormat.m_dataFormat) ? m_settings.passthoughdevice : m_settings.device;
1401 CAESinkFactory::ParseDevice(device, driver);
1402 if (m_settings.driver.compare(driver) != 0)
1405 if (!IsSinkCompatible(newFormat, device))
1411 bool CActiveAE::InitSink()
1414 config.format = m_sinkRequestFormat;
1415 config.stats = &m_stats;
1416 config.device = AE_IS_RAW(m_sinkRequestFormat.m_dataFormat) ? &m_settings.passthoughdevice :
1419 // send message to sink
1421 if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::CONFIGURE,
1424 &config, sizeof(config)))
1426 bool success = reply->signal == CSinkControlProtocol::ACC ? true : false;
1430 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
1434 AEAudioFormat *data;
1435 data = (AEAudioFormat*)reply->data;
1438 m_sinkFormat = *data;
1440 m_sinkHasVolume = m_sink.HasVolume();
1445 CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__);
1450 m_inMsgEvent.Reset();
1454 void CActiveAE::DrainSink()
1456 // send message to sink
1458 if (m_sink.m_dataPort.SendOutMessageSync(CSinkDataProtocol::DRAIN,
1462 bool success = reply->signal == CSinkDataProtocol::ACC ? true : false;
1466 CLog::Log(LOGERROR, "ActiveAE::%s - returned error on drain", __FUNCTION__);
1474 CLog::Log(LOGERROR, "ActiveAE::%s - failed to drain", __FUNCTION__);
1480 bool CActiveAE::IsSinkCompatible(const AEAudioFormat &format, const std::string &device)
1482 bool compatible = false;
1484 config.format = format;
1485 config.device = &device;
1487 // send message to sink
1489 if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::ISCOMPATIBLE,
1492 &config, sizeof(config)))
1494 bool success = reply->signal == CSinkControlProtocol::ACC ? true : false;
1498 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
1502 compatible = *(bool*)reply->data;
1507 CLog::Log(LOGERROR, "ActiveAE::%s - failed to query compatibility", __FUNCTION__);
1514 void CActiveAE::UnconfigureSink()
1516 // send message to sink
1518 if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::UNCONFIGURE,
1522 bool success = reply->signal == CSinkControlProtocol::ACC ? true : false;
1525 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
1532 CLog::Log(LOGERROR, "ActiveAE::%s - failed to unconfigure", __FUNCTION__);
1536 m_inMsgEvent.Reset();
1540 bool CActiveAE::RunStages()
1544 // serve input streams
1545 std::list<CActiveAEStream*>::iterator it;
1546 for (it = m_streams.begin(); it != m_streams.end(); ++it)
1548 if ((*it)->m_resampleBuffers && !(*it)->m_paused)
1549 busy = (*it)->m_resampleBuffers->ResampleBuffers();
1550 else if ((*it)->m_resampleBuffers &&
1551 ((*it)->m_resampleBuffers->m_inputSamples.size() > (*it)->m_resampleBuffers->m_allSamples.size() * 0.5))
1553 CSingleLock lock((*it)->m_streamLock);
1554 (*it)->m_streamIsBuffering = false;
1557 // provide buffers to stream
1558 float time = m_stats.GetCacheTime((*it));
1559 CSampleBuffer *buffer;
1560 if (!(*it)->m_drain)
1562 while (time < MAX_CACHE_LEVEL && !(*it)->m_inputBuffers->m_freeSamples.empty())
1564 buffer = (*it)->m_inputBuffers->GetFreeBuffer();
1565 (*it)->m_processingSamples.push_back(buffer);
1566 (*it)->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMBUFFER, &buffer, sizeof(CSampleBuffer*));
1567 (*it)->IncFreeBuffers();
1568 time += (float)buffer->pkt->max_nb_samples / buffer->pkt->config.sample_rate;
1573 if ((*it)->m_resampleBuffers->m_inputSamples.empty() &&
1574 (*it)->m_resampleBuffers->m_outputSamples.empty() &&
1575 (*it)->m_processingSamples.empty())
1577 (*it)->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMDRAINED);
1578 (*it)->m_drain = false;
1579 (*it)->m_resampleBuffers->m_drain = false;
1580 (*it)->m_started = false;
1582 // set variables being polled via stream interface
1583 CSingleLock lock((*it)->m_streamLock);
1584 if ((*it)->m_streamSlave)
1586 CActiveAEStream *slave = (CActiveAEStream*)((*it)->m_streamSlave);
1587 slave->m_paused = false;
1589 // TODO: find better solution for this
1590 // gapless bites audiophile
1591 if (m_settings.config == AE_CONFIG_MATCH)
1592 Configure(&slave->m_format);
1594 (*it)->m_streamSlave = NULL;
1596 (*it)->m_streamDrained = true;
1597 (*it)->m_streamDraining = false;
1598 (*it)->m_streamFading = false;
1603 if (m_stats.GetWaterLevel() < MAX_WATER_LEVEL &&
1604 (m_mode != MODE_TRANSCODE || (m_encoderBuffers && !m_encoderBuffers->m_freeSamples.empty())))
1606 // mix streams and sounds sounds
1607 if (m_mode != MODE_RAW)
1609 CSampleBuffer *out = NULL;
1610 if (!m_sounds_playing.empty() && m_streams.empty())
1612 if (m_silenceBuffers && !m_silenceBuffers->m_freeSamples.empty())
1614 out = m_silenceBuffers->GetFreeBuffer();
1615 for (int i=0; i<out->pkt->planes; i++)
1617 memset(out->pkt->data[i], 0, out->pkt->linesize);
1619 out->pkt->nb_samples = out->pkt->max_nb_samples;
1624 std::list<CActiveAEStream*>::iterator it;
1626 // if we deal with more than a single stream, all streams
1627 // must provide samples for mixing
1628 bool allStreamsReady = true;
1629 for (it = m_streams.begin(); it != m_streams.end(); ++it)
1631 if ((*it)->m_paused || !(*it)->m_started || !(*it)->m_resampleBuffers)
1634 if ((*it)->m_resampleBuffers->m_outputSamples.empty())
1635 allStreamsReady = false;
1638 bool needClamp = false;
1639 for (it = m_streams.begin(); it != m_streams.end() && allStreamsReady; ++it)
1641 if ((*it)->m_paused || !(*it)->m_resampleBuffers)
1644 if (!(*it)->m_resampleBuffers->m_outputSamples.empty())
1646 (*it)->m_started = true;
1650 out = (*it)->m_resampleBuffers->m_outputSamples.front();
1651 (*it)->m_resampleBuffers->m_outputSamples.pop_front();
1653 int nb_floats = out->pkt->nb_samples * out->pkt->config.channels / out->pkt->planes;
1655 float fadingStep = 0.0f;
1658 if ((*it)->m_fadingSamples == -1)
1660 (*it)->m_fadingSamples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1661 (*it)->m_volume = (*it)->m_fadingBase;
1663 if ((*it)->m_fadingSamples > 0)
1665 nb_floats = out->pkt->config.channels / out->pkt->planes;
1666 nb_loops = out->pkt->nb_samples;
1667 float delta = (*it)->m_fadingTarget - (*it)->m_fadingBase;
1668 int samples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1669 fadingStep = delta / samples;
1672 // for stream amplification,
1673 // turned off downmix normalization,
1674 // or if sink format is float (in order to prevent from clipping)
1675 // we need to run on a per sample basis
1676 if ((*it)->m_amplify != 1.0 || !(*it)->m_resampleBuffers->m_normalize || (m_sinkFormat.m_dataFormat == AE_FMT_FLOAT))
1678 nb_floats = out->pkt->config.channels / out->pkt->planes;
1679 nb_loops = out->pkt->nb_samples;
1682 for(int i=0; i<nb_loops; i++)
1684 if ((*it)->m_fadingSamples > 0)
1686 (*it)->m_volume += fadingStep;
1687 (*it)->m_fadingSamples--;
1689 if ((*it)->m_fadingSamples == 0)
1691 // set variables being polled via stream interface
1692 CSingleLock lock((*it)->m_streamLock);
1693 (*it)->m_streamFading = false;
1697 // volume for stream
1698 float volume = (*it)->m_volume * (*it)->m_rgain;
1700 volume *= (*it)->m_limiter.Run((float**)out->pkt->data, out->pkt->config.channels, i*nb_floats, out->pkt->planes > 1);
1702 for(int j=0; j<out->pkt->planes; j++)
1705 CAEUtil::SSEMulArray((float*)out->pkt->data[j]+i*nb_floats, volume, nb_floats);
1707 float* fbuffer = (float*) out->pkt->data[j]+i*nb_floats;
1708 for (int k = 0; k < nb_floats; ++k)
1710 fbuffer[k] *= volume;
1718 CSampleBuffer *mix = NULL;
1719 mix = (*it)->m_resampleBuffers->m_outputSamples.front();
1720 (*it)->m_resampleBuffers->m_outputSamples.pop_front();
1722 int nb_floats = mix->pkt->nb_samples * mix->pkt->config.channels / mix->pkt->planes;
1724 float fadingStep = 0.0f;
1727 if ((*it)->m_fadingSamples == -1)
1729 (*it)->m_fadingSamples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1730 (*it)->m_volume = (*it)->m_fadingBase;
1732 if ((*it)->m_fadingSamples > 0)
1734 nb_floats = mix->pkt->config.channels / mix->pkt->planes;
1735 nb_loops = mix->pkt->nb_samples;
1736 float delta = (*it)->m_fadingTarget - (*it)->m_fadingBase;
1737 int samples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1738 fadingStep = delta / samples;
1741 // for streams amplification of turned off downmix normalization
1742 // we need to run on a per sample basis
1743 if ((*it)->m_amplify != 1.0 || !(*it)->m_resampleBuffers->m_normalize)
1745 nb_floats = out->pkt->config.channels / out->pkt->planes;
1746 nb_loops = out->pkt->nb_samples;
1749 for(int i=0; i<nb_loops; i++)
1751 if ((*it)->m_fadingSamples > 0)
1753 (*it)->m_volume += fadingStep;
1754 (*it)->m_fadingSamples--;
1756 if ((*it)->m_fadingSamples == 0)
1758 // set variables being polled via stream interface
1759 CSingleLock lock((*it)->m_streamLock);
1760 (*it)->m_streamFading = false;
1764 // volume for stream
1765 float volume = (*it)->m_volume * (*it)->m_rgain;
1767 volume *= (*it)->m_limiter.Run((float**)mix->pkt->data, mix->pkt->config.channels, i*nb_floats, mix->pkt->planes > 1);
1769 for(int j=0; j<out->pkt->planes && j<mix->pkt->planes; j++)
1771 float *dst = (float*)out->pkt->data[j]+i*nb_floats;
1772 float *src = (float*)mix->pkt->data[j]+i*nb_floats;
1774 CAEUtil::SSEMulAddArray(dst, src, volume, nb_floats);
1775 for (int k = 0; k < nb_floats; ++k)
1777 if (fabs(dst[k]) > 1.0f)
1784 for (int k = 0; k < nb_floats; ++k)
1786 dst[k] += src[k] * volume;
1787 if (fabs(dst[k]) > 1.0f)
1799 // finally clamp samples
1800 if(out && needClamp)
1802 int nb_floats = out->pkt->nb_samples * out->pkt->config.channels / out->pkt->planes;
1803 for(int i=0; i<out->pkt->planes; i++)
1805 CAEUtil::ClampArray((float*)out->pkt->data[i], nb_floats);
1809 // process output buffer, gui sounds, encode, viz
1814 CSingleLock lock(m_vizLock);
1815 if (m_audioCallback && m_vizBuffers && !m_streams.empty())
1817 if (!m_vizInitialized)
1819 m_audioCallback->OnInitialize(2, m_vizBuffers->m_format.m_sampleRate, 32);
1820 m_vizInitialized = true;
1823 if (!m_vizBuffersInput->m_freeSamples.empty())
1825 // copy the samples into the viz input buffer
1826 CSampleBuffer *viz = m_vizBuffersInput->GetFreeBuffer();
1827 int samples = std::min(512, out->pkt->nb_samples);
1828 int bytes = samples * out->pkt->config.channels / out->pkt->planes * out->pkt->bytes_per_sample;
1829 for(int i= 0; i < out->pkt->planes; i++)
1831 memcpy(viz->pkt->data[i], out->pkt->data[i], bytes);
1833 viz->pkt->nb_samples = samples;
1834 m_vizBuffers->m_inputSamples.push_back(viz);
1837 CLog::Log(LOGWARNING,"ActiveAE::%s - viz ran out of free buffers", __FUNCTION__);
1838 unsigned int now = XbmcThreads::SystemClockMillis();
1839 unsigned int timestamp = now + m_stats.GetDelay() * 1000;
1840 busy |= m_vizBuffers->ResampleBuffers(timestamp);
1841 while(!m_vizBuffers->m_outputSamples.empty())
1843 CSampleBuffer *buf = m_vizBuffers->m_outputSamples.front();
1844 if ((now - buf->timestamp) & 0x80000000)
1849 samples = std::min(512, buf->pkt->nb_samples);
1850 m_audioCallback->OnAudioData((float*)(buf->pkt->data[0]), samples);
1852 m_vizBuffers->m_outputSamples.pop_front();
1856 else if (m_vizBuffers)
1857 m_vizBuffers->Flush();
1861 MixSounds(*(out->pkt));
1862 if (!m_sinkHasVolume || m_muted)
1863 Deamplify(*(out->pkt));
1865 if (m_mode == MODE_TRANSCODE && m_encoder)
1867 CSampleBuffer *buf = m_encoderBuffers->GetFreeBuffer();
1868 m_encoder->Encode(out->pkt->data[0], out->pkt->planes*out->pkt->linesize,
1869 buf->pkt->data[0], buf->pkt->planes*buf->pkt->linesize);
1870 buf->pkt->nb_samples = buf->pkt->max_nb_samples;
1880 m_stats.AddSamples(out->pkt->nb_samples, m_streams);
1881 m_sinkBuffers->m_inputSamples.push_back(out);
1887 std::list<CActiveAEStream*>::iterator it;
1888 CSampleBuffer *buffer;
1889 for (it = m_streams.begin(); it != m_streams.end(); ++it)
1891 if (!(*it)->m_resampleBuffers->m_outputSamples.empty())
1893 buffer = (*it)->m_resampleBuffers->m_outputSamples.front();
1894 (*it)->m_resampleBuffers->m_outputSamples.pop_front();
1895 m_stats.AddSamples(buffer->pkt->nb_samples, m_streams);
1896 m_sinkBuffers->m_inputSamples.push_back(buffer);
1901 // serve sink buffers
1902 busy = m_sinkBuffers->ResampleBuffers();
1903 while(!m_sinkBuffers->m_outputSamples.empty())
1905 CSampleBuffer *out = NULL;
1906 out = m_sinkBuffers->m_outputSamples.front();
1907 m_sinkBuffers->m_outputSamples.pop_front();
1908 m_sink.m_dataPort.SendOutMessage(CSinkDataProtocol::SAMPLE,
1909 &out, sizeof(CSampleBuffer*));
1917 bool CActiveAE::HasWork()
1919 if (!m_sounds_playing.empty())
1921 if (!m_sinkBuffers->m_inputSamples.empty())
1923 if (!m_sinkBuffers->m_outputSamples.empty())
1926 std::list<CActiveAEStream*>::iterator it;
1927 for (it = m_streams.begin(); it != m_streams.end(); ++it)
1929 if (!(*it)->m_resampleBuffers->m_inputSamples.empty())
1931 if (!(*it)->m_resampleBuffers->m_outputSamples.empty())
1933 if (!(*it)->m_processingSamples.empty())
1940 void CActiveAE::MixSounds(CSoundPacket &dstSample)
1942 if (m_sounds_playing.empty())
1947 float *sample_buffer;
1948 int max_samples = dstSample.nb_samples;
1950 std::list<SoundState>::iterator it;
1951 for (it = m_sounds_playing.begin(); it != m_sounds_playing.end(); )
1953 if (!it->sound->IsConverted())
1954 ResampleSound(it->sound);
1955 int available_samples = it->sound->GetSound(false)->nb_samples - it->samples_played;
1956 int mix_samples = std::min(max_samples, available_samples);
1957 int start = it->samples_played *
1958 m_dllAvUtil.av_get_bytes_per_sample(it->sound->GetSound(false)->config.fmt) *
1959 it->sound->GetSound(false)->config.channels /
1960 it->sound->GetSound(false)->planes;
1962 for(int j=0; j<dstSample.planes; j++)
1964 volume = it->sound->GetVolume();
1965 out = (float*)dstSample.data[j];
1966 sample_buffer = (float*)(it->sound->GetSound(false)->data[j]+start);
1967 int nb_floats = mix_samples * dstSample.config.channels / dstSample.planes;
1969 CAEUtil::SSEMulAddArray(out, sample_buffer, volume, nb_floats);
1971 for (int k = 0; k < nb_floats; ++k)
1972 *out++ += *sample_buffer++ * volume;
1976 it->samples_played += mix_samples;
1978 // no more frames, so remove it from the list
1979 if (it->samples_played >= it->sound->GetSound(false)->nb_samples)
1981 it = m_sounds_playing.erase(it);
1988 void CActiveAE::Deamplify(CSoundPacket &dstSample)
1990 if (m_volume < 1.0 || m_muted)
1993 int nb_floats = dstSample.nb_samples * dstSample.config.channels / dstSample.planes;
1995 for(int j=0; j<dstSample.planes; j++)
1997 buffer = (float*)dstSample.data[j];
1999 CAEUtil::SSEMulArray(buffer, m_muted ? 0.0 : m_volume, nb_floats);
2001 float *fbuffer = buffer;
2002 for (int i = 0; i < nb_floats; i++)
2003 *fbuffer++ *= m_volume;
2009 //-----------------------------------------------------------------------------
2011 //-----------------------------------------------------------------------------
2013 void CActiveAE::LoadSettings()
2015 m_settings.device = CSettings::Get().GetString("audiooutput.audiodevice");
2016 m_settings.passthoughdevice = CSettings::Get().GetString("audiooutput.passthroughdevice");
2018 m_settings.config = CSettings::Get().GetInt("audiooutput.config");
2019 m_settings.channels = (m_sink.GetDeviceType(m_settings.device) == AE_DEVTYPE_IEC958) ? AE_CH_LAYOUT_2_0 : CSettings::Get().GetInt("audiooutput.channels");
2020 m_settings.samplerate = CSettings::Get().GetInt("audiooutput.samplerate");
2022 m_settings.stereoupmix = IsSettingVisible("audiooutput.stereoupmix") ? CSettings::Get().GetBool("audiooutput.stereoupmix") : false;
2023 m_settings.normalizelevels = CSettings::Get().GetBool("audiooutput.normalizelevels");
2024 m_settings.guisoundmode = CSettings::Get().GetInt("audiooutput.guisoundmode");
2026 m_settings.passthrough = m_settings.config == AE_CONFIG_FIXED ? false : CSettings::Get().GetBool("audiooutput.passthrough");
2027 m_settings.ac3passthrough = CSettings::Get().GetBool("audiooutput.ac3passthrough");
2028 m_settings.eac3passthrough = CSettings::Get().GetBool("audiooutput.eac3passthrough");
2029 m_settings.truehdpassthrough = CSettings::Get().GetBool("audiooutput.truehdpassthrough");
2030 m_settings.dtspassthrough = CSettings::Get().GetBool("audiooutput.dtspassthrough");
2031 m_settings.dtshdpassthrough = CSettings::Get().GetBool("audiooutput.dtshdpassthrough");
2033 m_settings.resampleQuality = static_cast<AEQuality>(CSettings::Get().GetInt("audiooutput.processquality"));
2036 bool CActiveAE::Initialize()
2038 if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllAvFormat.Load())
2040 CLog::Log(LOGERROR,"CActiveAE::Initialize - failed to load ffmpeg libraries");
2043 m_dllAvFormat.av_register_all();
2047 if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::INIT,
2051 bool success = reply->signal == CActiveAEControlProtocol::ACC ? true : false;
2055 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
2062 CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__);
2067 // hook into windowing for receiving display reset events
2068 #if defined(HAS_GLX) || defined(TARGET_DARWIN_OSX)
2069 g_Windowing.Register(this);
2072 m_inMsgEvent.Reset();
2076 void CActiveAE::EnumerateOutputDevices(AEDeviceList &devices, bool passthrough)
2078 m_sink.EnumerateOutputDevices(devices, passthrough);
2081 std::string CActiveAE::GetDefaultDevice(bool passthrough)
2083 return m_sink.GetDefaultDevice(passthrough);
2086 void CActiveAE::OnSettingsChange(const std::string& setting)
2088 if (setting == "audiooutput.passthroughdevice" ||
2089 setting == "audiooutput.audiodevice" ||
2090 setting == "audiooutput.config" ||
2091 setting == "audiooutput.ac3passthrough" ||
2092 setting == "audiooutput.eac3passthrough" ||
2093 setting == "audiooutput.dtspassthrough" ||
2094 setting == "audiooutput.truehdpassthrough" ||
2095 setting == "audiooutput.dtshdpassthrough" ||
2096 setting == "audiooutput.channels" ||
2097 setting == "audiooutput.stereoupmix" ||
2098 setting == "audiooutput.streamsilence" ||
2099 setting == "audiooutput.processquality" ||
2100 setting == "audiooutput.passthrough" ||
2101 setting == "audiooutput.samplerate" ||
2102 setting == "audiooutput.normalizelevels" ||
2103 setting == "audiooutput.guisoundmode")
2105 m_controlPort.SendOutMessage(CActiveAEControlProtocol::RECONFIGURE);
2109 bool CActiveAE::SupportsRaw(AEDataFormat format)
2111 if (!m_sink.HasPassthroughDevice())
2114 // those formats require HDMI
2115 if (format == AE_FMT_DTSHD || format == AE_FMT_TRUEHD)
2117 if(m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.passthroughdevice")) != AE_DEVTYPE_HDMI)
2125 bool CActiveAE::SupportsSilenceTimeout()
2130 bool CActiveAE::SupportsQualityLevel(enum AEQuality level)
2132 if (level == AE_QUALITY_LOW || level == AE_QUALITY_MID || level == AE_QUALITY_HIGH)
2138 bool CActiveAE::IsSettingVisible(const std::string &settingId)
2140 if (settingId == "audiooutput.samplerate")
2142 if (m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) == AE_DEVTYPE_IEC958)
2144 if (CSettings::Get().GetInt("audiooutput.config") == AE_CONFIG_FIXED)
2147 else if (settingId == "audiooutput.channels")
2149 if (m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) != AE_DEVTYPE_IEC958)
2152 else if (settingId == "audiooutput.passthrough")
2154 if (m_sink.HasPassthroughDevice() && CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED)
2157 else if (settingId == "audiooutput.truehdpassthrough")
2159 if (m_sink.HasPassthroughDevice() &&
2160 CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED &&
2161 m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.passthroughdevice")) == AE_DEVTYPE_HDMI)
2164 else if (settingId == "audiooutput.dtshdpassthrough")
2166 if (m_sink.HasPassthroughDevice() &&
2167 CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED &&
2168 m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.passthroughdevice")) == AE_DEVTYPE_HDMI)
2171 else if (settingId == "audiooutput.stereoupmix")
2173 if (m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) != AE_DEVTYPE_IEC958)
2175 if (CSettings::Get().GetInt("audiooutput.channels") > AE_CH_LAYOUT_2_0)
2180 if (m_sink.HasPassthroughDevice() &&
2181 CSettings::Get().GetBool("audiooutput.passthrough") &&
2182 CSettings::Get().GetBool("audiooutput.ac3passthrough"))
2189 void CActiveAE::Shutdown()
2194 bool CActiveAE::Suspend()
2196 return m_controlPort.SendOutMessage(CActiveAEControlProtocol::SUSPEND);
2199 bool CActiveAE::Resume()
2202 if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::INIT,
2206 bool success = reply->signal == CActiveAEControlProtocol::ACC ? true : false;
2210 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
2216 CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__);
2220 m_inMsgEvent.Reset();
2224 bool CActiveAE::IsSuspended()
2226 return m_stats.IsSuspended();
2229 float CActiveAE::GetVolume()
2234 void CActiveAE::SetVolume(const float volume)
2236 m_aeVolume = std::max( 0.0f, std::min(1.0f, volume));
2237 m_controlPort.SendOutMessage(CActiveAEControlProtocol::VOLUME, &m_aeVolume, sizeof(float));
2240 void CActiveAE::SetMute(const bool enabled)
2242 m_aeMuted = enabled;
2243 m_controlPort.SendOutMessage(CActiveAEControlProtocol::MUTE, &m_aeMuted, sizeof(bool));
2246 bool CActiveAE::IsMuted()
2251 void CActiveAE::SetSoundMode(const int mode)
2256 void CActiveAE::KeepConfiguration(unsigned int millis)
2258 unsigned int timeMs = millis;
2259 m_controlPort.SendOutMessage(CActiveAEControlProtocol::KEEPCONFIG, &timeMs, sizeof(unsigned int));
2262 void CActiveAE::OnLostDevice()
2264 // m_controlPort.SendOutMessage(CActiveAEControlProtocol::DISPLAYLOST);
2267 void CActiveAE::OnResetDevice()
2269 // m_controlPort.SendOutMessage(CActiveAEControlProtocol::DISPLAYRESET);
2272 //-----------------------------------------------------------------------------
2274 //-----------------------------------------------------------------------------
2276 uint8_t **CActiveAE::AllocSoundSample(SampleConfig &config, int &samples, int &bytes_per_sample, int &planes, int &linesize)
2279 planes = m_dllAvUtil.av_sample_fmt_is_planar(config.fmt) ? config.channels : 1;
2280 buffer = new uint8_t*[planes];
2282 // align buffer to 16 in order to be compatible with sse in CAEConvert
2283 m_dllAvUtil.av_samples_alloc(buffer, &linesize, config.channels,
2284 samples, config.fmt, 16);
2285 bytes_per_sample = m_dllAvUtil.av_get_bytes_per_sample(config.fmt);
2289 void CActiveAE::FreeSoundSample(uint8_t **data)
2291 m_dllAvUtil.av_freep(data);
2295 bool CActiveAE::CompareFormat(AEAudioFormat &lhs, AEAudioFormat &rhs)
2297 if (lhs.m_channelLayout != rhs.m_channelLayout ||
2298 lhs.m_dataFormat != rhs.m_dataFormat ||
2299 lhs.m_sampleRate != rhs.m_sampleRate ||
2300 lhs.m_frames != rhs.m_frames)
2306 //-----------------------------------------------------------------------------
2308 //-----------------------------------------------------------------------------
2311 * load sound from an audio file and store original format
2312 * register the sound in ActiveAE
2313 * later when the engine is idle it will convert the sound to sink format
2316 #define SOUNDBUFFER_SIZE 20480
2318 IAESound *CActiveAE::MakeSound(const std::string& file)
2320 AVFormatContext *fmt_ctx = NULL;
2321 AVCodecContext *dec_ctx = NULL;
2322 AVIOContext *io_ctx;
2323 AVInputFormat *io_fmt;
2324 AVCodec *dec = NULL;
2325 CActiveAESound *sound = NULL;
2326 SampleConfig config;
2328 sound = new CActiveAESound(file);
2329 if (!sound->Prepare())
2334 int fileSize = sound->GetFileSize();
2336 fmt_ctx = m_dllAvFormat.avformat_alloc_context();
2337 unsigned char* buffer = (unsigned char*)m_dllAvUtil.av_malloc(SOUNDBUFFER_SIZE+FF_INPUT_BUFFER_PADDING_SIZE);
2338 io_ctx = m_dllAvFormat.avio_alloc_context(buffer, SOUNDBUFFER_SIZE, 0,
2339 sound, CActiveAESound::Read, NULL, CActiveAESound::Seek);
2340 io_ctx->max_packet_size = sound->GetChunkSize();
2341 if(io_ctx->max_packet_size)
2342 io_ctx->max_packet_size *= SOUNDBUFFER_SIZE / io_ctx->max_packet_size;
2344 if(!sound->IsSeekPosible())
2345 io_ctx->seekable = 0;
2347 fmt_ctx->pb = io_ctx;
2349 m_dllAvFormat.av_probe_input_buffer(io_ctx, &io_fmt, file.c_str(), NULL, 0, 0);
2352 m_dllAvFormat.avformat_close_input(&fmt_ctx);
2358 if (m_dllAvFormat.avformat_open_input(&fmt_ctx, file.c_str(), NULL, NULL) == 0)
2360 fmt_ctx->flags |= AVFMT_FLAG_NOPARSE;
2361 if (m_dllAvFormat.avformat_find_stream_info(fmt_ctx, NULL) >= 0)
2363 dec_ctx = fmt_ctx->streams[0]->codec;
2364 dec = m_dllAvCodec.avcodec_find_decoder(dec_ctx->codec_id);
2365 config.sample_rate = dec_ctx->sample_rate;
2366 config.channels = dec_ctx->channels;
2367 config.channel_layout = dec_ctx->channel_layout;
2372 m_dllAvFormat.avformat_close_input(&fmt_ctx);
2377 dec_ctx = m_dllAvCodec.avcodec_alloc_context3(dec);
2378 dec_ctx->sample_rate = config.sample_rate;
2379 dec_ctx->channels = config.channels;
2380 if (!config.channel_layout)
2381 config.channel_layout = m_dllAvUtil.av_get_default_channel_layout(config.channels);
2382 dec_ctx->channel_layout = config.channel_layout;
2385 AVFrame *decoded_frame = NULL;
2386 decoded_frame = m_dllAvCodec.avcodec_alloc_frame();
2388 if (m_dllAvCodec.avcodec_open2(dec_ctx, dec, NULL) >= 0)
2393 m_dllAvCodec.av_init_packet(&avpkt);
2395 while (m_dllAvFormat.av_read_frame(fmt_ctx, &avpkt) >= 0)
2398 len = m_dllAvCodec.avcodec_decode_audio4(dec_ctx, decoded_frame, &got_frame, &avpkt);
2401 m_dllAvCodec.avcodec_close(dec_ctx);
2402 m_dllAvUtil.av_free(dec_ctx);
2403 m_dllAvUtil.av_free(&decoded_frame);
2404 m_dllAvFormat.avformat_close_input(&fmt_ctx);
2412 int samples = fileSize / m_dllAvUtil.av_get_bytes_per_sample(dec_ctx->sample_fmt) / config.channels;
2413 config.fmt = dec_ctx->sample_fmt;
2414 config.bits_per_sample = dec_ctx->bits_per_coded_sample;
2415 sound->InitSound(true, config, samples);
2418 sound->StoreSound(true, decoded_frame->extended_data,
2419 decoded_frame->nb_samples, decoded_frame->linesize[0]);
2422 m_dllAvCodec.avcodec_close(dec_ctx);
2425 m_dllAvUtil.av_free(dec_ctx);
2426 m_dllAvUtil.av_free(decoded_frame);
2427 m_dllAvFormat.avformat_close_input(&fmt_ctx);
2432 m_dataPort.SendOutMessage(CActiveAEDataProtocol::NEWSOUND, &sound, sizeof(CActiveAESound*));
2437 void CActiveAE::FreeSound(IAESound *sound)
2439 m_dataPort.SendOutMessage(CActiveAEDataProtocol::FREESOUND, &sound, sizeof(CActiveAESound*));
2442 void CActiveAE::PlaySound(CActiveAESound *sound)
2444 m_dataPort.SendOutMessage(CActiveAEDataProtocol::PLAYSOUND, &sound, sizeof(CActiveAESound*));
2447 void CActiveAE::StopSound(CActiveAESound *sound)
2449 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STOPSOUND, &sound, sizeof(CActiveAESound*));
2453 * resample sounds to destination format for mixing
2454 * destination format is either format of stream or
2455 * default sink format when no stream is playing
2457 void CActiveAE::ResampleSounds()
2459 if (m_settings.guisoundmode == AE_SOUND_OFF ||
2460 (m_settings.guisoundmode == AE_SOUND_IDLE && !m_streams.empty()))
2463 std::vector<CActiveAESound*>::iterator it;
2464 for (it = m_sounds.begin(); it != m_sounds.end(); ++it)
2466 if (!(*it)->IsConverted())
2469 // only do one sound, then yield to main loop
2475 bool CActiveAE::ResampleSound(CActiveAESound *sound)
2477 SampleConfig orig_config, dst_config;
2478 uint8_t **dst_buffer;
2481 if (m_mode == MODE_RAW || m_internalFormat.m_dataFormat == AE_FMT_INVALID)
2484 if (!sound->GetSound(true))
2487 orig_config = sound->GetSound(true)->config;
2489 dst_config.channel_layout = CActiveAEResample::GetAVChannelLayout(m_internalFormat.m_channelLayout);
2490 dst_config.channels = m_internalFormat.m_channelLayout.Count();
2491 dst_config.sample_rate = m_internalFormat.m_sampleRate;
2492 dst_config.fmt = CActiveAEResample::GetAVSampleFormat(m_internalFormat.m_dataFormat);
2493 dst_config.bits_per_sample = CAEUtil::DataFormatToUsedBits(m_internalFormat.m_dataFormat);
2495 CActiveAEResample *resampler = new CActiveAEResample();
2496 resampler->Init(dst_config.channel_layout,
2497 dst_config.channels,
2498 dst_config.sample_rate,
2500 dst_config.bits_per_sample,
2501 orig_config.channel_layout,
2502 orig_config.channels,
2503 orig_config.sample_rate,
2505 orig_config.bits_per_sample,
2509 m_settings.resampleQuality);
2511 dst_samples = resampler->CalcDstSampleCount(sound->GetSound(true)->nb_samples,
2512 m_internalFormat.m_sampleRate,
2513 orig_config.sample_rate);
2515 dst_buffer = sound->InitSound(false, dst_config, dst_samples);
2521 int samples = resampler->Resample(dst_buffer, dst_samples,
2522 sound->GetSound(true)->data,
2523 sound->GetSound(true)->nb_samples,
2526 sound->GetSound(false)->nb_samples = samples;
2529 sound->SetConverted(true);
2533 //-----------------------------------------------------------------------------
2535 //-----------------------------------------------------------------------------
2537 IAEStream *CActiveAE::MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSampleRate, CAEChannelInfo channelLayout, unsigned int options)
2539 //TODO: pass number of samples in audio packet
2541 AEAudioFormat format;
2542 format.m_dataFormat = dataFormat;
2543 format.m_sampleRate = sampleRate;
2544 format.m_encodedRate = encodedSampleRate;
2545 format.m_channelLayout = channelLayout;
2546 format.m_frames = format.m_sampleRate / 10;
2547 format.m_frameSize = format.m_channelLayout.Count() *
2548 (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);
2551 msg.format = format;
2552 msg.options = options;
2555 if (m_dataPort.SendOutMessageSync(CActiveAEDataProtocol::NEWSTREAM,
2557 &msg, sizeof(MsgStreamNew)))
2559 bool success = reply->signal == CActiveAEControlProtocol::ACC ? true : false;
2562 CActiveAEStream *stream = *(CActiveAEStream**)reply->data;
2569 CLog::Log(LOGERROR, "ActiveAE::%s - could not create stream", __FUNCTION__);
2573 IAEStream *CActiveAE::FreeStream(IAEStream *stream)
2575 m_dataPort.SendOutMessage(CActiveAEDataProtocol::FREESTREAM, &stream, sizeof(IAEStream*));
2579 void CActiveAE::FlushStream(CActiveAEStream *stream)
2582 if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::FLUSHSTREAM,
2584 &stream, sizeof(CActiveAEStream*)))
2586 bool success = reply->signal == CActiveAEControlProtocol::ACC ? true : false;
2590 CLog::Log(LOGERROR, "CActiveAE::FlushStream - failed");
2595 void CActiveAE::PauseStream(CActiveAEStream *stream, bool pause)
2597 // TODO pause sink, needs api change
2599 m_controlPort.SendOutMessage(CActiveAEControlProtocol::PAUSESTREAM,
2600 &stream, sizeof(CActiveAEStream*));
2602 m_controlPort.SendOutMessage(CActiveAEControlProtocol::RESUMESTREAM,
2603 &stream, sizeof(CActiveAEStream*));
2606 void CActiveAE::SetStreamAmplification(CActiveAEStream *stream, float amplify)
2608 MsgStreamParameter msg;
2609 msg.stream = stream;
2610 msg.parameter.float_par = amplify;
2611 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMAMP,
2612 &msg, sizeof(MsgStreamParameter));
2615 void CActiveAE::SetStreamReplaygain(CActiveAEStream *stream, float rgain)
2617 MsgStreamParameter msg;
2618 msg.stream = stream;
2619 msg.parameter.float_par = rgain;
2620 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMRGAIN,
2621 &msg, sizeof(MsgStreamParameter));
2624 void CActiveAE::SetStreamVolume(CActiveAEStream *stream, float volume)
2626 MsgStreamParameter msg;
2627 msg.stream = stream;
2628 msg.parameter.float_par = volume;
2629 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMVOLUME,
2630 &msg, sizeof(MsgStreamParameter));
2633 void CActiveAE::SetStreamResampleRatio(CActiveAEStream *stream, double ratio)
2635 MsgStreamParameter msg;
2636 msg.stream = stream;
2637 msg.parameter.double_par = ratio;
2638 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMRESAMPLERATIO,
2639 &msg, sizeof(MsgStreamParameter));
2642 void CActiveAE::SetStreamFade(CActiveAEStream *stream, float from, float target, unsigned int millis)
2645 msg.stream = stream;
2647 msg.target = target;
2648 msg.millis = millis;
2649 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMFADE,
2650 &msg, sizeof(MsgStreamFade));
2653 void CActiveAE::RegisterAudioCallback(IAudioCallback* pCallback)
2655 CSingleLock lock(m_vizLock);
2656 m_audioCallback = pCallback;
2657 m_vizInitialized = false;
2660 void CActiveAE::UnregisterAudioCallback()
2662 CSingleLock lock(m_vizLock);
2663 m_audioCallback = NULL;