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();
43 m_sinkSampleRate = sampleRate;
44 m_bufferedSamples = 0;
48 void CEngineStats::UpdateSinkDelay(double delay, int samples)
50 CSingleLock lock(m_lock);
51 m_sinkUpdate = XbmcThreads::SystemClockMillis();
53 if (samples > m_bufferedSamples)
55 CLog::Log(LOGERROR, "CEngineStats::UpdateSinkDelay - inconsistency in buffer time");
58 m_bufferedSamples -= samples;
61 void CEngineStats::AddSamples(int samples, std::list<CActiveAEStream*> &streams)
63 CSingleLock lock(m_lock);
64 m_bufferedSamples += samples;
66 //update buffered time of streams
67 std::list<CActiveAEStream*>::iterator it;
68 for(it=streams.begin(); it!=streams.end(); ++it)
71 std::deque<CSampleBuffer*>::iterator itBuf;
72 for(itBuf=(*it)->m_processingSamples.begin(); itBuf!=(*it)->m_processingSamples.end(); ++itBuf)
74 delay += (float)(*itBuf)->pkt->nb_samples / (*itBuf)->pkt->config.sample_rate;
76 delay += (*it)->m_resampleBuffers->GetDelay();
77 (*it)->m_bufferedTime = delay;
81 float CEngineStats::GetDelay()
83 CSingleLock lock(m_lock);
84 unsigned int now = XbmcThreads::SystemClockMillis();
85 float delay = m_sinkDelay - (double)(now-m_sinkUpdate) / 1000;
86 delay += (float)m_bufferedSamples / m_sinkSampleRate;
94 // this is used to sync a/v so we need to add sink latency here
95 float CEngineStats::GetDelay(CActiveAEStream *stream)
97 CSingleLock lock(m_lock);
98 unsigned int now = XbmcThreads::SystemClockMillis();
99 float delay = m_sinkDelay - (double)(now-m_sinkUpdate) / 1000;
100 delay += m_sinkLatency;
101 delay += (float)m_bufferedSamples / m_sinkSampleRate;
106 delay += stream->m_bufferedTime;
110 float CEngineStats::GetCacheTime(CActiveAEStream *stream)
112 CSingleLock lock(m_lock);
113 float delay = (float)m_bufferedSamples / m_sinkSampleRate;
115 delay += stream->m_bufferedTime;
119 float CEngineStats::GetCacheTotal(CActiveAEStream *stream)
121 return MAX_CACHE_LEVEL + m_sinkCacheTotal;
124 float CEngineStats::GetWaterLevel()
126 return (float)m_bufferedSamples / m_sinkSampleRate;
129 void CEngineStats::SetSuspended(bool state)
131 CSingleLock lock(m_lock);
135 bool CEngineStats::IsSuspended()
137 CSingleLock lock(m_lock);
141 CActiveAE::CActiveAE() :
143 m_controlPort("OutputControlPort", &m_inMsgEvent, &m_outMsgEvent),
144 m_dataPort("OutputDataPort", &m_inMsgEvent, &m_outMsgEvent),
145 m_sink(&m_outMsgEvent)
147 m_sinkBuffers = NULL;
148 m_silenceBuffers = NULL;
149 m_encoderBuffers = NULL;
151 m_vizBuffersInput = NULL;
158 m_audioCallback = NULL;
159 m_vizInitialized = false;
160 m_sinkHasVolume = false;
163 CActiveAE::~CActiveAE()
168 void CActiveAE::Dispose()
170 #if defined(HAS_GLX) || defined(TARGET_DARWIN_OSX)
171 g_Windowing.Unregister(this);
177 m_controlPort.Purge();
181 m_dllAvFormat.Unload();
182 m_dllAvCodec.Unload();
183 m_dllAvUtil.Unload();
186 //-----------------------------------------------------------------------------
188 //-----------------------------------------------------------------------------
194 AE_TOP_UNCONFIGURED, // 2
195 AE_TOP_RECONFIGURING, // 3
196 AE_TOP_CONFIGURED, // 4
197 AE_TOP_CONFIGURED_SUSPEND, // 5
198 AE_TOP_CONFIGURED_IDLE, // 6
199 AE_TOP_CONFIGURED_PLAY, // 7
202 int AE_parentStates[] = {
205 0, //TOP_UNCONFIGURED
207 0, //TOP_RECONFIGURING
208 4, //TOP_CONFIGURED_SUSPEND
209 4, //TOP_CONFIGURED_IDLE
210 4, //TOP_CONFIGURED_PLAY
213 void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg)
215 for (int state = m_state; ; state = AE_parentStates[state])
220 if (port == &m_controlPort)
224 case CActiveAEControlProtocol::GETSTATE:
225 msg->Reply(CActiveAEControlProtocol::ACC, &m_state, sizeof(m_state));
227 case CActiveAEControlProtocol::VOLUME:
228 m_volume = *(float*)msg->data;
230 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::VOLUME, &m_volume, sizeof(float));
232 case CActiveAEControlProtocol::MUTE:
233 m_muted = *(bool*)msg->data;
235 case CActiveAEControlProtocol::KEEPCONFIG:
236 m_extKeepConfig = *(unsigned int*)msg->data;
242 else if (port == &m_dataPort)
246 case CActiveAEDataProtocol::NEWSOUND:
247 CActiveAESound *sound;
248 sound = *(CActiveAESound**)msg->data;
251 m_sounds.push_back(sound);
255 case CActiveAEDataProtocol::FREESTREAM:
256 CActiveAEStream *stream;
257 stream = *(CActiveAEStream**)msg->data;
258 DiscardStream(stream);
260 case CActiveAEDataProtocol::FREESOUND:
261 sound = *(CActiveAESound**)msg->data;
264 case CActiveAEDataProtocol::DRAINSTREAM:
265 stream = *(CActiveAEStream**)msg->data;
266 stream->m_drain = true;
267 stream->m_resampleBuffers->m_drain = true;
268 msg->Reply(CActiveAEDataProtocol::ACC);
269 stream->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMDRAINED);
275 else if (port == &m_sink.m_dataPort)
279 case CSinkDataProtocol::RETURNSAMPLE:
280 CSampleBuffer **buffer;
281 buffer = (CSampleBuffer**)msg->data;
292 std::string portName = port == NULL ? "timer" : port->portName;
293 CLog::Log(LOGWARNING, "CActiveAE::%s - signal: %d from port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
298 if (port == NULL) // timeout
302 case CActiveAEControlProtocol::TIMEOUT:
308 m_state = AE_TOP_CONFIGURED_IDLE;
313 m_state = AE_TOP_ERROR;
323 case AE_TOP_UNCONFIGURED:
324 if (port == &m_controlPort)
328 case CActiveAEControlProtocol::INIT:
330 m_sink.EnumerateSinkList(false);
333 msg->Reply(CActiveAEControlProtocol::ACC);
336 m_state = AE_TOP_CONFIGURED_IDLE;
341 m_state = AE_TOP_ERROR;
352 case AE_TOP_RECONFIGURING:
353 if (port == NULL) // timeout
357 case CActiveAEControlProtocol::TIMEOUT:
364 if (!m_sinkBuffers->m_inputSamples.empty() || !m_sinkBuffers->m_outputSamples.empty())
369 if (NeedReconfigureSink())
376 m_state = AE_TOP_CONFIGURED_PLAY;
381 m_state = AE_TOP_ERROR;
384 m_extDeferData = false;
392 case AE_TOP_CONFIGURED:
393 if (port == &m_controlPort)
397 case CActiveAEControlProtocol::RECONFIGURE:
398 if (m_streams.empty())
400 bool silence = false;
401 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::SILENCEMODE, &silence, sizeof(bool));
405 if (!NeedReconfigureBuffers() && !NeedReconfigureSink())
407 m_state = AE_TOP_RECONFIGURING;
409 // don't accept any data until we are reconfigured
410 m_extDeferData = true;
412 case CActiveAEControlProtocol::SUSPEND:
414 m_stats.SetSuspended(true);
415 m_state = AE_TOP_CONFIGURED_SUSPEND;
416 m_extDeferData = true;
418 case CActiveAEControlProtocol::DISPLAYLOST:
419 if (m_sink.GetDeviceType(m_mode == MODE_PCM ? m_settings.device : m_settings.passthoughdevice) == AE_DEVTYPE_HDMI)
422 m_stats.SetSuspended(true);
423 m_state = AE_TOP_CONFIGURED_SUSPEND;
424 m_extDeferData = true;
427 case CActiveAEControlProtocol::PAUSESTREAM:
428 CActiveAEStream *stream;
429 stream = *(CActiveAEStream**)msg->data;
430 if (stream->m_paused != true && m_streams.size() == 1)
432 stream->m_paused = true;
434 case CActiveAEControlProtocol::RESUMESTREAM:
435 stream = *(CActiveAEStream**)msg->data;
436 stream->m_paused = false;
437 m_state = AE_TOP_CONFIGURED_PLAY;
440 case CActiveAEControlProtocol::FLUSHSTREAM:
441 stream = *(CActiveAEStream**)msg->data;
442 SFlushStream(stream);
443 msg->Reply(CActiveAEControlProtocol::ACC);
444 m_state = AE_TOP_CONFIGURED_PLAY;
447 case CActiveAEControlProtocol::STREAMAMP:
448 MsgStreamParameter *par;
449 par = (MsgStreamParameter*)msg->data;
450 par->stream->m_limiter.SetAmplification(par->parameter.float_par);
451 par->stream->m_amplify = par->parameter.float_par;
453 case CActiveAEControlProtocol::STREAMVOLUME:
454 par = (MsgStreamParameter*)msg->data;
455 par->stream->m_volume = par->parameter.float_par;
457 case CActiveAEControlProtocol::STREAMRGAIN:
458 par = (MsgStreamParameter*)msg->data;
459 par->stream->m_rgain = par->parameter.float_par;
461 case CActiveAEControlProtocol::STREAMRESAMPLERATIO:
462 par = (MsgStreamParameter*)msg->data;
463 if (par->stream->m_resampleBuffers)
465 par->stream->m_resampleBuffers->m_resampleRatio = par->parameter.double_par;
468 case CActiveAEControlProtocol::STREAMFADE:
470 fade = (MsgStreamFade*)msg->data;
471 fade->stream->m_fadingBase = fade->from;
472 fade->stream->m_fadingTarget = fade->target;
473 fade->stream->m_fadingTime = fade->millis;
474 fade->stream->m_fadingSamples = -1;
476 case CActiveAEControlProtocol::STOPSOUND:
477 CActiveAESound *sound;
478 sound = *(CActiveAESound**)msg->data;
485 else if (port == &m_dataPort)
489 case CActiveAEDataProtocol::PLAYSOUND:
490 CActiveAESound *sound;
491 sound = *(CActiveAESound**)msg->data;
492 if (m_settings.guisoundmode == AE_SOUND_OFF ||
493 (m_settings.guisoundmode == AE_SOUND_IDLE && !m_streams.empty()))
497 SoundState st = {sound, 0};
498 m_sounds_playing.push_back(st);
500 m_state = AE_TOP_CONFIGURED_PLAY;
503 case CActiveAEDataProtocol::NEWSTREAM:
504 MsgStreamNew *streamMsg;
505 CActiveAEStream *stream;
506 streamMsg = (MsgStreamNew*)msg->data;
507 stream = CreateStream(streamMsg);
510 msg->Reply(CActiveAEDataProtocol::ACC, &stream, sizeof(CActiveAEStream*));
515 m_state = AE_TOP_CONFIGURED_PLAY;
520 m_state = AE_TOP_ERROR;
525 msg->Reply(CActiveAEDataProtocol::ERR);
527 case CActiveAEDataProtocol::STREAMSAMPLE:
528 MsgStreamSample *msgData;
529 CSampleBuffer *samples;
530 msgData = (MsgStreamSample*)msg->data;
531 samples = msgData->stream->m_processingSamples.front();
532 msgData->stream->m_processingSamples.pop_front();
533 if (samples != msgData->buffer)
534 CLog::Log(LOGERROR, "CActiveAE - inconsistency in stream sample message");
535 if (msgData->buffer->pkt->nb_samples == 0)
536 msgData->buffer->Return();
538 msgData->stream->m_resampleBuffers->m_inputSamples.push_back(msgData->buffer);
540 m_state = AE_TOP_CONFIGURED_PLAY;
542 case CActiveAEDataProtocol::FREESTREAM:
543 stream = *(CActiveAEStream**)msg->data;
544 DiscardStream(stream);
545 if (m_streams.empty())
548 m_extDrainTimer.Set(m_extKeepConfig);
550 m_extDrainTimer.Set(m_stats.GetDelay() * 1000);
554 m_state = AE_TOP_CONFIGURED_PLAY;
556 case CActiveAEDataProtocol::DRAINSTREAM:
557 stream = *(CActiveAEStream**)msg->data;
558 stream->m_drain = true;
559 stream->m_resampleBuffers->m_drain = true;
561 m_state = AE_TOP_CONFIGURED_PLAY;
562 msg->Reply(CActiveAEDataProtocol::ACC);
568 else if (port == &m_sink.m_dataPort)
572 case CSinkDataProtocol::RETURNSAMPLE:
573 CSampleBuffer **buffer;
574 buffer = (CSampleBuffer**)msg->data;
580 m_state = AE_TOP_CONFIGURED_PLAY;
588 case AE_TOP_CONFIGURED_SUSPEND:
589 if (port == &m_controlPort)
591 bool displayReset = false;
594 case CActiveAEControlProtocol::DISPLAYRESET:
596 case CActiveAEControlProtocol::INIT:
600 m_sink.EnumerateSinkList(true);
605 msg->Reply(CActiveAEControlProtocol::ACC);
608 m_state = AE_TOP_CONFIGURED_PLAY;
613 m_state = AE_TOP_ERROR;
616 m_stats.SetSuspended(false);
617 m_extDeferData = false;
623 else if (port == &m_sink.m_dataPort)
627 case CSinkDataProtocol::RETURNSAMPLE:
628 CSampleBuffer **buffer;
629 buffer = (CSampleBuffer**)msg->data;
641 case AE_TOP_CONFIGURED_IDLE:
642 if (port == NULL) // timeout
646 case CActiveAEControlProtocol::TIMEOUT:
648 ClearDiscardedBuffers();
651 if (m_extDrainTimer.IsTimePast())
656 m_state = AE_TOP_CONFIGURED_PLAY;
661 m_state = AE_TOP_ERROR;
666 m_extTimeout = m_extDrainTimer.MillisLeft();
677 case AE_TOP_CONFIGURED_PLAY:
678 if (port == NULL) // timeout
682 case CActiveAEControlProtocol::TIMEOUT:
685 m_state = AE_TOP_ERROR;
694 if (!m_extDrain && HasWork())
696 ClearDiscardedBuffers();
701 m_state = AE_TOP_CONFIGURED_IDLE;
709 default: // we are in no state, should not happen
710 CLog::Log(LOGERROR, "CActiveAE::%s - no valid state: %d", __FUNCTION__, m_state);
716 void CActiveAE::Process()
719 Protocol *port = NULL;
721 XbmcThreads::EndTime timer;
723 m_state = AE_TOP_UNCONFIGURED;
725 m_bStateMachineSelfTrigger = false;
727 m_extDeferData = false;
736 timer.Set(m_extTimeout);
738 if (m_bStateMachineSelfTrigger)
740 m_bStateMachineSelfTrigger = false;
741 // self trigger state machine
742 StateMachine(msg->signal, port, msg);
743 if (!m_bStateMachineSelfTrigger)
750 // check control port
751 else if (m_controlPort.ReceiveOutMessage(&msg))
754 port = &m_controlPort;
756 // check sink data port
757 else if (m_sink.m_dataPort.ReceiveInMessage(&msg))
760 port = &m_sink.m_dataPort;
762 else if (!m_extDeferData)
765 if (m_dataPort.ReceiveOutMessage(&msg))
773 std::list<CActiveAEStream*>::iterator it;
774 for(it=m_streams.begin(); it!=m_streams.end(); ++it)
776 if((*it)->m_streamPort->ReceiveOutMessage(&msg))
788 StateMachine(msg->signal, port, msg);
789 if (!m_bStateMachineSelfTrigger)
798 else if (m_outMsgEvent.WaitMSec(m_extTimeout))
800 m_extTimeout = timer.MillisLeft();
806 msg = m_controlPort.GetMessage();
807 msg->signal = CActiveAEControlProtocol::TIMEOUT;
809 // signal timeout to state machine
810 StateMachine(msg->signal, port, msg);
811 if (!m_bStateMachineSelfTrigger)
820 AEAudioFormat CActiveAE::GetInputFormat(AEAudioFormat *desiredFmt)
822 AEAudioFormat inputFormat;
824 if (m_streams.empty())
826 inputFormat.m_dataFormat = AE_FMT_FLOAT;
827 inputFormat.m_sampleRate = 44100;
828 inputFormat.m_encodedRate = 0;
829 inputFormat.m_channelLayout = AE_CH_LAYOUT_2_0;
830 inputFormat.m_frames = 0;
831 inputFormat.m_frameSamples = 0;
832 inputFormat.m_frameSize = 0;
834 // force input format after unpausing slave
835 else if (desiredFmt != NULL)
837 inputFormat = *desiredFmt;
839 // keep format when having multiple streams
840 else if (m_streams.size() > 1 && m_silenceBuffers == NULL)
842 inputFormat = m_inputFormat;
846 inputFormat = m_streams.front()->m_format;
847 m_inputFormat = inputFormat;
853 void CActiveAE::Configure(AEAudioFormat *desiredFmt)
855 bool initSink = false;
857 AEAudioFormat sinkInputFormat, inputFormat;
858 AEAudioFormat oldInternalFormat = m_internalFormat;
859 AEAudioFormat oldSinkRequestFormat = m_sinkRequestFormat;
861 inputFormat = GetInputFormat(desiredFmt);
863 m_sinkRequestFormat = inputFormat;
864 ApplySettingsToFormat(m_sinkRequestFormat, m_settings, (int*)&m_mode);
867 std::string device = AE_IS_RAW(m_sinkRequestFormat.m_dataFormat) ? m_settings.passthoughdevice : m_settings.device;
869 CAESinkFactory::ParseDevice(device, driver);
870 if ((!CompareFormat(m_sinkRequestFormat, m_sinkFormat) && !CompareFormat(m_sinkRequestFormat, oldSinkRequestFormat)) ||
871 m_currDevice.compare(device) != 0 ||
872 m_settings.driver.compare(driver) != 0)
876 m_settings.driver = driver;
877 m_currDevice = device;
879 m_stats.Reset(m_sinkFormat.m_sampleRate);
880 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::VOLUME, &m_volume, sizeof(float));
882 // limit buffer size in case of sink returns large buffer
883 unsigned int buffertime = (m_sinkFormat.m_frames*1000) / m_sinkFormat.m_sampleRate;
886 CLog::Log(LOGWARNING, "ActiveAE::%s - sink returned large buffer of %d ms, reducing to 80 ms", __FUNCTION__, buffertime);
887 m_sinkFormat.m_frames = 80 * m_sinkFormat.m_sampleRate / 1000;
891 if (m_silenceBuffers)
893 m_discardBufferPools.push_back(m_silenceBuffers);
894 m_silenceBuffers = NULL;
897 // buffers for driving gui sounds if no streams are active
898 if (m_streams.empty())
900 inputFormat = m_sinkFormat;
901 inputFormat.m_dataFormat = AE_FMT_FLOAT;
902 inputFormat.m_frameSize = inputFormat.m_channelLayout.Count() *
903 (CAEUtil::DataFormatToBits(inputFormat.m_dataFormat) >> 3);
904 m_silenceBuffers = new CActiveAEBufferPool(inputFormat);
905 m_silenceBuffers->Create(MAX_WATER_LEVEL*1000);
906 sinkInputFormat = inputFormat;
907 m_internalFormat = inputFormat;
909 bool silence = false;
910 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::SILENCEMODE, &silence, sizeof(bool));
915 if (m_encoderBuffers)
917 m_discardBufferPools.push_back(m_encoderBuffers);
918 m_encoderBuffers = NULL;
922 m_discardBufferPools.push_back(m_vizBuffers);
925 if (m_vizBuffersInput)
927 m_discardBufferPools.push_back(m_vizBuffersInput);
928 m_vizBuffersInput = NULL;
931 // resample buffers for streams
935 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::SILENCEMODE, &silence, sizeof(bool));
937 AEAudioFormat outputFormat;
938 if (m_mode == MODE_RAW)
940 outputFormat = inputFormat;
941 sinkInputFormat = m_sinkFormat;
943 // transcode everything with more than 2 channels
944 else if (m_mode == MODE_TRANSCODE)
946 outputFormat = inputFormat;
947 outputFormat.m_dataFormat = AE_FMT_FLOATP;
948 outputFormat.m_sampleRate = 48000;
953 m_encoder = new CAEEncoderFFmpeg();
954 m_encoder->Initialize(outputFormat, true);
955 m_encoderFormat = outputFormat;
958 outputFormat = m_encoderFormat;
960 outputFormat.m_channelLayout = m_encoderFormat.m_channelLayout;
961 outputFormat.m_frames = m_encoderFormat.m_frames;
964 if (m_encoder->GetCodecID() == AV_CODEC_ID_AC3)
966 AEAudioFormat format;
967 format.m_channelLayout = AE_CH_LAYOUT_2_0;
968 format.m_dataFormat = AE_FMT_S16NE;
969 format.m_frameSize = 2* (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);
970 format.m_frames = AC3_FRAME_SIZE;
971 format.m_sampleRate = 48000;
972 if (m_encoderBuffers && initSink)
974 m_discardBufferPools.push_back(m_encoderBuffers);
975 m_encoderBuffers = NULL;
977 if (!m_encoderBuffers)
979 m_encoderBuffers = new CActiveAEBufferPool(format);
980 m_encoderBuffers->Create(MAX_WATER_LEVEL*1000);
984 sinkInputFormat = m_sinkFormat;
988 outputFormat = m_sinkFormat;
989 outputFormat.m_dataFormat = AE_FMT_FLOAT;
990 outputFormat.m_frameSize = outputFormat.m_channelLayout.Count() *
991 (CAEUtil::DataFormatToBits(outputFormat.m_dataFormat) >> 3);
992 // TODO: adjust to decoder
993 sinkInputFormat = outputFormat;
995 m_internalFormat = outputFormat;
997 std::list<CActiveAEStream*>::iterator it;
998 for(it=m_streams.begin(); it!=m_streams.end(); ++it)
1000 // check if we support input format of stream
1001 if (!AE_IS_RAW((*it)->m_format.m_dataFormat) &&
1002 CActiveAEResample::GetAVSampleFormat((*it)->m_format.m_dataFormat) == AV_SAMPLE_FMT_FLT &&
1003 (*it)->m_format.m_dataFormat != AE_FMT_FLOAT)
1005 (*it)->m_convertFn = CAEConvert::ToFloat((*it)->m_format.m_dataFormat);
1006 (*it)->m_format.m_dataFormat = AE_FMT_FLOAT;
1009 if (!(*it)->m_inputBuffers)
1011 // align input buffers with period of sink or encoder
1012 (*it)->m_format.m_frames = m_internalFormat.m_frames * ((float)(*it)->m_format.m_sampleRate / m_internalFormat.m_sampleRate);
1014 // create buffer pool
1015 (*it)->m_inputBuffers = new CActiveAEBufferPool((*it)->m_format);
1016 (*it)->m_inputBuffers->Create(MAX_CACHE_LEVEL*1000);
1017 (*it)->m_streamSpace = (*it)->m_format.m_frameSize * (*it)->m_format.m_frames;
1019 // if input format does not follow ffmpeg channel mask, we may need to remap channels
1020 (*it)->InitRemapper();
1022 if (initSink && (*it)->m_resampleBuffers)
1024 m_discardBufferPools.push_back((*it)->m_resampleBuffers);
1025 (*it)->m_resampleBuffers = NULL;
1027 if (!(*it)->m_resampleBuffers)
1029 (*it)->m_resampleBuffers = new CActiveAEBufferPoolResample((*it)->m_inputBuffers->m_format, outputFormat, m_settings.resampleQuality);
1030 (*it)->m_resampleBuffers->m_changeResampler = (*it)->m_forceResampler;
1031 (*it)->m_resampleBuffers->Create(MAX_CACHE_LEVEL*1000, false, m_settings.stereoupmix, m_settings.normalizelevels);
1033 if (m_mode == MODE_TRANSCODE || m_streams.size() > 1)
1034 (*it)->m_resampleBuffers->m_fillPackets = true;
1037 (*it)->m_limiter.SetSamplerate(outputFormat.m_sampleRate);
1041 if (!AE_IS_RAW(inputFormat.m_dataFormat))
1043 if (initSink && m_vizBuffers)
1045 m_discardBufferPools.push_back(m_vizBuffers);
1046 m_vizBuffers = NULL;
1047 m_discardBufferPools.push_back(m_vizBuffersInput);
1048 m_vizBuffersInput = NULL;
1052 AEAudioFormat vizFormat = m_internalFormat;
1053 vizFormat.m_channelLayout = AE_CH_LAYOUT_2_0;
1054 vizFormat.m_dataFormat = AE_FMT_FLOAT;
1057 m_vizBuffersInput = new CActiveAEBufferPool(m_internalFormat);
1058 m_vizBuffersInput->Create(2000);
1061 m_vizBuffers = new CActiveAEBufferPoolResample(m_internalFormat, vizFormat, m_settings.resampleQuality);
1062 // TODO use cache of sync + water level
1063 m_vizBuffers->Create(2000, false, false);
1064 m_vizInitialized = false;
1069 // resample buffers for sink
1070 if (m_sinkBuffers &&
1071 (!CompareFormat(m_sinkBuffers->m_format,m_sinkFormat) || !CompareFormat(m_sinkBuffers->m_inputFormat, sinkInputFormat)))
1073 m_discardBufferPools.push_back(m_sinkBuffers);
1074 m_sinkBuffers = NULL;
1078 m_sinkBuffers = new CActiveAEBufferPoolResample(sinkInputFormat, m_sinkFormat, m_settings.resampleQuality);
1079 m_sinkBuffers->Create(MAX_WATER_LEVEL*1000, true, false);
1083 if (!CompareFormat(oldInternalFormat, m_internalFormat))
1085 if (m_settings.guisoundmode == AE_SOUND_ALWAYS ||
1086 (m_settings.guisoundmode == AE_SOUND_IDLE && m_streams.empty()))
1088 std::vector<CActiveAESound*>::iterator it;
1089 for (it = m_sounds.begin(); it != m_sounds.end(); ++it)
1091 (*it)->SetConverted(false);
1094 m_sounds_playing.clear();
1097 ClearDiscardedBuffers();
1101 CActiveAEStream* CActiveAE::CreateStream(MsgStreamNew *streamMsg)
1103 // we only can handle a single pass through stream
1104 bool hasRawStream = false;
1105 bool hasStream = false;
1106 std::list<CActiveAEStream*>::iterator it;
1107 for(it = m_streams.begin(); it != m_streams.end(); ++it)
1109 if((*it)->IsDrained())
1111 if(AE_IS_RAW((*it)->m_format.m_dataFormat))
1112 hasRawStream = true;
1115 if (hasRawStream || (hasStream && AE_IS_RAW(streamMsg->format.m_dataFormat)))
1120 // create the stream
1121 CActiveAEStream *stream;
1122 stream = new CActiveAEStream(&streamMsg->format);
1123 stream->m_streamPort = new CActiveAEDataProtocol("stream",
1124 &stream->m_inMsgEvent, &m_outMsgEvent);
1126 // create buffer pool
1127 stream->m_inputBuffers = NULL; // create in Configure when we know the sink format
1128 stream->m_resampleBuffers = NULL; // create in Configure when we know the sink format
1129 stream->m_statsLock = m_stats.GetLock();
1130 stream->m_fadingSamples = 0;
1131 stream->m_started = false;
1133 if (streamMsg->options & AESTREAM_PAUSED)
1134 stream->m_paused = true;
1136 if (streamMsg->options & AESTREAM_FORCE_RESAMPLE)
1137 stream->m_forceResampler = true;
1139 m_streams.push_back(stream);
1144 void CActiveAE::DiscardStream(CActiveAEStream *stream)
1146 std::list<CActiveAEStream*>::iterator it;
1147 for (it=m_streams.begin(); it!=m_streams.end(); )
1149 if (stream == (*it))
1151 while (!(*it)->m_processingSamples.empty())
1153 (*it)->m_processingSamples.front()->Return();
1154 (*it)->m_processingSamples.pop_front();
1156 m_discardBufferPools.push_back((*it)->m_inputBuffers);
1157 m_discardBufferPools.push_back((*it)->m_resampleBuffers);
1158 CLog::Log(LOGDEBUG, "CActiveAE::DiscardStream - audio stream deleted");
1159 delete (*it)->m_streamPort;
1161 it = m_streams.erase(it);
1167 ClearDiscardedBuffers();
1170 void CActiveAE::SFlushStream(CActiveAEStream *stream)
1172 while (!stream->m_processingSamples.empty())
1174 stream->m_processingSamples.front()->Return();
1175 stream->m_processingSamples.pop_front();
1177 stream->m_resampleBuffers->Flush();
1178 stream->m_streamPort->Purge();
1179 stream->m_bufferedTime = 0.0;
1180 stream->m_paused = false;
1182 // flush the engine if we only have a single stream
1183 if (m_streams.size() == 1)
1189 void CActiveAE::FlushEngine()
1192 m_sinkBuffers->Flush();
1194 m_vizBuffers->Flush();
1196 // send message to sink
1198 if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::FLUSH,
1201 bool success = reply->signal == CSinkControlProtocol::ACC ? true : false;
1204 CLog::Log(LOGERROR, "ActiveAE::%s - returned error on flush", __FUNCTION__);
1211 CLog::Log(LOGERROR, "ActiveAE::%s - failed to flush", __FUNCTION__);
1214 m_stats.Reset(m_sinkFormat.m_sampleRate);
1217 void CActiveAE::ClearDiscardedBuffers()
1219 std::list<CActiveAEBufferPool*>::iterator it;
1220 for (it=m_discardBufferPools.begin(); it!=m_discardBufferPools.end(); ++it)
1222 CActiveAEBufferPoolResample *rbuf = dynamic_cast<CActiveAEBufferPoolResample*>(*it);
1227 // if all buffers have returned, we can delete the buffer pool
1228 if ((*it)->m_allSamples.size() == (*it)->m_freeSamples.size())
1231 CLog::Log(LOGDEBUG, "CActiveAE::ClearDiscardedBuffers - buffer pool deleted");
1232 m_discardBufferPools.erase(it);
1238 void CActiveAE::SStopSound(CActiveAESound *sound)
1240 std::list<SoundState>::iterator it;
1241 for (it=m_sounds_playing.begin(); it!=m_sounds_playing.end(); ++it)
1243 if (it->sound == sound)
1245 m_sounds_playing.erase(it);
1251 void CActiveAE::DiscardSound(CActiveAESound *sound)
1255 std::vector<CActiveAESound*>::iterator it;
1256 for (it=m_sounds.begin(); it!=m_sounds.end(); ++it)
1266 void CActiveAE::ChangeResamplers()
1268 std::list<CActiveAEStream*>::iterator it;
1269 for(it=m_streams.begin(); it!=m_streams.end(); ++it)
1271 bool normalize = true;
1272 if (((*it)->m_resampleBuffers->m_format.m_channelLayout.Count() <
1273 (*it)->m_resampleBuffers->m_inputFormat.m_channelLayout.Count()) &&
1274 !m_settings.normalizelevels)
1277 if ((*it)->m_resampleBuffers && (*it)->m_resampleBuffers->m_resampler &&
1278 (((*it)->m_resampleBuffers->m_resampleQuality != m_settings.resampleQuality) ||
1279 (((*it)->m_resampleBuffers->m_stereoUpmix != m_settings.stereoupmix)) ||
1280 ((*it)->m_resampleBuffers->m_normalize != normalize)))
1282 (*it)->m_resampleBuffers->m_changeResampler = true;
1284 (*it)->m_resampleBuffers->m_resampleQuality = m_settings.resampleQuality;
1285 (*it)->m_resampleBuffers->m_stereoUpmix = m_settings.stereoupmix;
1286 (*it)->m_resampleBuffers->m_normalize = normalize;
1290 void CActiveAE::ApplySettingsToFormat(AEAudioFormat &format, AudioSettings &settings, int *mode)
1292 int oldMode = m_mode;
1297 if (AE_IS_RAW(format.m_dataFormat))
1299 if ((format.m_dataFormat == AE_FMT_AC3 && !settings.ac3passthrough) ||
1300 (format.m_dataFormat == AE_FMT_EAC3 && !settings.eac3passthrough) ||
1301 (format.m_dataFormat == AE_FMT_TRUEHD && !settings.truehdpassthrough) ||
1302 (format.m_dataFormat == AE_FMT_DTS && !settings.dtspassthrough) ||
1303 (format.m_dataFormat == AE_FMT_DTSHD && !settings.dtshdpassthrough))
1305 CLog::Log(LOGERROR, "CActiveAE::ApplySettingsToFormat - input audio format is wrong");
1311 else if (settings.channels <= AE_CH_LAYOUT_2_0 && // no multichannel pcm
1312 settings.passthrough &&
1313 settings.ac3passthrough &&
1314 !m_streams.empty() &&
1315 (format.m_channelLayout.Count() > 2 || settings.stereoupmix))
1317 format.m_dataFormat = AE_FMT_AC3;
1318 format.m_sampleRate = 48000;
1319 format.m_channelLayout = AE_CH_LAYOUT_2_0;
1321 *mode = MODE_TRANSCODE;
1325 format.m_dataFormat = AE_FMT_FLOAT;
1326 // consider user channel layout for those cases
1327 // 1. input stream is multichannel
1328 // 2. stereo upmix is selected
1330 if ((format.m_channelLayout.Count() > 2) ||
1331 settings.stereoupmix ||
1332 (settings.config == AE_CONFIG_FIXED))
1334 CAEChannelInfo stdLayout;
1335 switch (settings.channels)
1338 case 0: stdLayout = AE_CH_LAYOUT_2_0; break;
1339 case 1: stdLayout = AE_CH_LAYOUT_2_0; break;
1340 case 2: stdLayout = AE_CH_LAYOUT_2_1; break;
1341 case 3: stdLayout = AE_CH_LAYOUT_3_0; break;
1342 case 4: stdLayout = AE_CH_LAYOUT_3_1; break;
1343 case 5: stdLayout = AE_CH_LAYOUT_4_0; break;
1344 case 6: stdLayout = AE_CH_LAYOUT_4_1; break;
1345 case 7: stdLayout = AE_CH_LAYOUT_5_0; break;
1346 case 8: stdLayout = AE_CH_LAYOUT_5_1; break;
1347 case 9: stdLayout = AE_CH_LAYOUT_7_0; break;
1348 case 10: stdLayout = AE_CH_LAYOUT_7_1; break;
1351 if (m_settings.config == AE_CONFIG_FIXED || (settings.stereoupmix && format.m_channelLayout.Count() <= 2))
1352 format.m_channelLayout = stdLayout;
1353 else if (m_extKeepConfig && (settings.config == AE_CONFIG_AUTO) && (oldMode != MODE_RAW))
1354 format.m_channelLayout = m_internalFormat.m_channelLayout;
1356 format.m_channelLayout.ResolveChannels(stdLayout);
1358 // don't change from multi to stereo in AUTO mode
1359 else if ((settings.config == AE_CONFIG_AUTO) &&
1360 m_stats.GetWaterLevel() > 0 && m_internalFormat.m_channelLayout.Count() > 2)
1362 format.m_channelLayout = m_internalFormat.m_channelLayout;
1365 if (m_sink.GetDeviceType(m_settings.device) == AE_DEVTYPE_IEC958)
1367 if (format.m_sampleRate > m_settings.samplerate)
1369 format.m_sampleRate = m_settings.samplerate;
1370 CLog::Log(LOGINFO, "CActiveAE::ApplySettings - limit samplerate for SPDIF to %d", format.m_sampleRate);
1372 format.m_channelLayout = AE_CH_LAYOUT_2_0;
1375 if (m_settings.config == AE_CONFIG_FIXED)
1377 format.m_sampleRate = m_settings.samplerate;
1378 CLog::Log(LOGINFO, "CActiveAE::ApplySettings - Forcing samplerate to %d", format.m_sampleRate);
1381 // sinks may not support mono
1382 if (format.m_channelLayout.Count() == 1)
1384 format.m_channelLayout = AE_CH_LAYOUT_2_0;
1389 bool CActiveAE::NeedReconfigureBuffers()
1391 AEAudioFormat newFormat = GetInputFormat();
1392 ApplySettingsToFormat(newFormat, m_settings);
1394 if (newFormat.m_dataFormat != m_sinkRequestFormat.m_dataFormat ||
1395 newFormat.m_channelLayout != m_sinkRequestFormat.m_channelLayout ||
1396 newFormat.m_sampleRate != m_sinkRequestFormat.m_sampleRate)
1402 bool CActiveAE::NeedReconfigureSink()
1404 AEAudioFormat newFormat = GetInputFormat();
1405 ApplySettingsToFormat(newFormat, m_settings);
1407 std::string device = AE_IS_RAW(newFormat.m_dataFormat) ? m_settings.passthoughdevice : m_settings.device;
1409 CAESinkFactory::ParseDevice(device, driver);
1411 if (!CompareFormat(newFormat, m_sinkFormat) ||
1412 m_currDevice.compare(device) != 0 ||
1413 m_settings.driver.compare(driver) != 0)
1419 bool CActiveAE::InitSink()
1422 config.format = m_sinkRequestFormat;
1423 config.stats = &m_stats;
1424 config.device = AE_IS_RAW(m_sinkRequestFormat.m_dataFormat) ? &m_settings.passthoughdevice :
1427 // send message to sink
1429 if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::CONFIGURE,
1432 &config, sizeof(config)))
1434 bool success = reply->signal == CSinkControlProtocol::ACC ? true : false;
1438 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
1442 AEAudioFormat *data;
1443 data = (AEAudioFormat*)reply->data;
1446 m_sinkFormat = *data;
1448 m_sinkHasVolume = m_sink.HasVolume();
1453 CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__);
1458 m_inMsgEvent.Reset();
1462 void CActiveAE::DrainSink()
1464 // send message to sink
1466 if (m_sink.m_dataPort.SendOutMessageSync(CSinkDataProtocol::DRAIN,
1470 bool success = reply->signal == CSinkDataProtocol::ACC ? true : false;
1474 CLog::Log(LOGERROR, "ActiveAE::%s - returned error on drain", __FUNCTION__);
1482 CLog::Log(LOGERROR, "ActiveAE::%s - failed to drain", __FUNCTION__);
1488 void CActiveAE::UnconfigureSink()
1490 // send message to sink
1492 if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::UNCONFIGURE,
1496 bool success = reply->signal == CSinkControlProtocol::ACC ? true : false;
1499 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
1506 CLog::Log(LOGERROR, "ActiveAE::%s - failed to unconfigure", __FUNCTION__);
1510 // make sure we open sink on next configure
1513 m_inMsgEvent.Reset();
1517 bool CActiveAE::RunStages()
1521 // serve input streams
1522 std::list<CActiveAEStream*>::iterator it;
1523 for (it = m_streams.begin(); it != m_streams.end(); ++it)
1525 if ((*it)->m_resampleBuffers && !(*it)->m_paused)
1526 busy = (*it)->m_resampleBuffers->ResampleBuffers();
1527 else if ((*it)->m_resampleBuffers &&
1528 ((*it)->m_resampleBuffers->m_inputSamples.size() > (*it)->m_resampleBuffers->m_allSamples.size() * 0.5))
1530 CSingleLock lock((*it)->m_streamLock);
1531 (*it)->m_streamIsBuffering = false;
1534 // provide buffers to stream
1535 float time = m_stats.GetCacheTime((*it));
1536 CSampleBuffer *buffer;
1537 if (!(*it)->m_drain)
1539 while (time < MAX_CACHE_LEVEL && !(*it)->m_inputBuffers->m_freeSamples.empty())
1541 buffer = (*it)->m_inputBuffers->GetFreeBuffer();
1542 (*it)->m_processingSamples.push_back(buffer);
1543 (*it)->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMBUFFER, &buffer, sizeof(CSampleBuffer*));
1544 (*it)->IncFreeBuffers();
1545 time += (float)buffer->pkt->max_nb_samples / buffer->pkt->config.sample_rate;
1550 if ((*it)->m_resampleBuffers->m_inputSamples.empty() &&
1551 (*it)->m_resampleBuffers->m_outputSamples.empty() &&
1552 (*it)->m_processingSamples.empty())
1554 (*it)->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMDRAINED);
1555 (*it)->m_drain = false;
1556 (*it)->m_resampleBuffers->m_drain = false;
1557 (*it)->m_started = false;
1559 // set variables being polled via stream interface
1560 CSingleLock lock((*it)->m_streamLock);
1561 if ((*it)->m_streamSlave)
1563 CActiveAEStream *slave = (CActiveAEStream*)((*it)->m_streamSlave);
1564 slave->m_paused = false;
1566 // TODO: find better solution for this
1567 // gapless bites audiophile
1568 if (m_settings.config == AE_CONFIG_MATCH)
1569 Configure(&slave->m_format);
1571 (*it)->m_streamSlave = NULL;
1573 (*it)->m_streamDrained = true;
1574 (*it)->m_streamDraining = false;
1575 (*it)->m_streamFading = false;
1580 if (m_stats.GetWaterLevel() < MAX_WATER_LEVEL &&
1581 (m_mode != MODE_TRANSCODE || (m_encoderBuffers && !m_encoderBuffers->m_freeSamples.empty())))
1583 // mix streams and sounds sounds
1584 if (m_mode != MODE_RAW)
1586 CSampleBuffer *out = NULL;
1587 if (!m_sounds_playing.empty() && m_streams.empty())
1589 if (m_silenceBuffers && !m_silenceBuffers->m_freeSamples.empty())
1591 out = m_silenceBuffers->GetFreeBuffer();
1592 for (int i=0; i<out->pkt->planes; i++)
1594 memset(out->pkt->data[i], 0, out->pkt->linesize);
1596 out->pkt->nb_samples = out->pkt->max_nb_samples;
1601 std::list<CActiveAEStream*>::iterator it;
1603 // if we deal with more than a single stream, all streams
1604 // must provide samples for mixing
1605 bool allStreamsReady = true;
1606 for (it = m_streams.begin(); it != m_streams.end(); ++it)
1608 if ((*it)->m_paused || !(*it)->m_started || !(*it)->m_resampleBuffers)
1611 if ((*it)->m_resampleBuffers->m_outputSamples.empty())
1612 allStreamsReady = false;
1615 bool needClamp = false;
1616 for (it = m_streams.begin(); it != m_streams.end() && allStreamsReady; ++it)
1618 if ((*it)->m_paused || !(*it)->m_resampleBuffers)
1621 if (!(*it)->m_resampleBuffers->m_outputSamples.empty())
1623 (*it)->m_started = true;
1627 out = (*it)->m_resampleBuffers->m_outputSamples.front();
1628 (*it)->m_resampleBuffers->m_outputSamples.pop_front();
1630 int nb_floats = out->pkt->nb_samples * out->pkt->config.channels / out->pkt->planes;
1632 float fadingStep = 0.0f;
1635 if ((*it)->m_fadingSamples == -1)
1637 (*it)->m_fadingSamples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1638 (*it)->m_volume = (*it)->m_fadingBase;
1640 if ((*it)->m_fadingSamples > 0)
1642 nb_floats = out->pkt->config.channels / out->pkt->planes;
1643 nb_loops = out->pkt->nb_samples;
1644 float delta = (*it)->m_fadingTarget - (*it)->m_fadingBase;
1645 int samples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1646 fadingStep = delta / samples;
1649 // for stream amplification,
1650 // turned off downmix normalization,
1651 // or if sink format is float (in order to prevent from clipping)
1652 // we need to run on a per sample basis
1653 if ((*it)->m_amplify != 1.0 || !(*it)->m_resampleBuffers->m_normalize || (m_sinkFormat.m_dataFormat == AE_FMT_FLOAT))
1655 nb_floats = out->pkt->config.channels / out->pkt->planes;
1656 nb_loops = out->pkt->nb_samples;
1659 for(int i=0; i<nb_loops; i++)
1661 if ((*it)->m_fadingSamples > 0)
1663 (*it)->m_volume += fadingStep;
1664 (*it)->m_fadingSamples--;
1666 if ((*it)->m_fadingSamples == 0)
1668 // set variables being polled via stream interface
1669 CSingleLock lock((*it)->m_streamLock);
1670 (*it)->m_streamFading = false;
1674 // volume for stream
1675 float volume = (*it)->m_volume * (*it)->m_rgain;
1677 volume *= (*it)->m_limiter.Run((float**)out->pkt->data, out->pkt->config.channels, i*nb_floats, out->pkt->planes > 1);
1679 for(int j=0; j<out->pkt->planes; j++)
1682 CAEUtil::SSEMulArray((float*)out->pkt->data[j]+i*nb_floats, volume, nb_floats);
1684 float* fbuffer = (float*) out->pkt->data[j]+i*nb_floats;
1685 for (int k = 0; k < nb_floats; ++k)
1687 fbuffer[k] *= volume;
1695 CSampleBuffer *mix = NULL;
1696 mix = (*it)->m_resampleBuffers->m_outputSamples.front();
1697 (*it)->m_resampleBuffers->m_outputSamples.pop_front();
1699 int nb_floats = mix->pkt->nb_samples * mix->pkt->config.channels / mix->pkt->planes;
1701 float fadingStep = 0.0f;
1704 if ((*it)->m_fadingSamples == -1)
1706 (*it)->m_fadingSamples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1707 (*it)->m_volume = (*it)->m_fadingBase;
1709 if ((*it)->m_fadingSamples > 0)
1711 nb_floats = mix->pkt->config.channels / mix->pkt->planes;
1712 nb_loops = mix->pkt->nb_samples;
1713 float delta = (*it)->m_fadingTarget - (*it)->m_fadingBase;
1714 int samples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1715 fadingStep = delta / samples;
1718 // for streams amplification of turned off downmix normalization
1719 // we need to run on a per sample basis
1720 if ((*it)->m_amplify != 1.0 || !(*it)->m_resampleBuffers->m_normalize)
1722 nb_floats = out->pkt->config.channels / out->pkt->planes;
1723 nb_loops = out->pkt->nb_samples;
1726 for(int i=0; i<nb_loops; i++)
1728 if ((*it)->m_fadingSamples > 0)
1730 (*it)->m_volume += fadingStep;
1731 (*it)->m_fadingSamples--;
1733 if ((*it)->m_fadingSamples == 0)
1735 // set variables being polled via stream interface
1736 CSingleLock lock((*it)->m_streamLock);
1737 (*it)->m_streamFading = false;
1741 // volume for stream
1742 float volume = (*it)->m_volume * (*it)->m_rgain;
1744 volume *= (*it)->m_limiter.Run((float**)mix->pkt->data, mix->pkt->config.channels, i*nb_floats, mix->pkt->planes > 1);
1746 for(int j=0; j<out->pkt->planes && j<mix->pkt->planes; j++)
1748 float *dst = (float*)out->pkt->data[j]+i*nb_floats;
1749 float *src = (float*)mix->pkt->data[j]+i*nb_floats;
1751 CAEUtil::SSEMulAddArray(dst, src, volume, nb_floats);
1752 for (int k = 0; k < nb_floats; ++k)
1754 if (fabs(dst[k]) > 1.0f)
1761 for (int k = 0; k < nb_floats; ++k)
1763 dst[k] += src[k] * volume;
1764 if (fabs(dst[k]) > 1.0f)
1776 // finally clamp samples
1777 if(out && needClamp)
1779 int nb_floats = out->pkt->nb_samples * out->pkt->config.channels / out->pkt->planes;
1780 for(int i=0; i<out->pkt->planes; i++)
1782 CAEUtil::ClampArray((float*)out->pkt->data[i], nb_floats);
1786 // process output buffer, gui sounds, encode, viz
1791 CSingleLock lock(m_vizLock);
1792 if (m_audioCallback && m_vizBuffers && !m_streams.empty())
1794 if (!m_vizInitialized)
1796 m_audioCallback->OnInitialize(2, m_vizBuffers->m_format.m_sampleRate, 32);
1797 m_vizInitialized = true;
1800 if (!m_vizBuffersInput->m_freeSamples.empty())
1802 // copy the samples into the viz input buffer
1803 CSampleBuffer *viz = m_vizBuffersInput->GetFreeBuffer();
1804 int samples = std::min(512, out->pkt->nb_samples);
1805 int bytes = samples * out->pkt->config.channels / out->pkt->planes * out->pkt->bytes_per_sample;
1806 for(int i= 0; i < out->pkt->planes; i++)
1808 memcpy(viz->pkt->data[i], out->pkt->data[i], bytes);
1810 viz->pkt->nb_samples = samples;
1811 m_vizBuffers->m_inputSamples.push_back(viz);
1814 CLog::Log(LOGWARNING,"ActiveAE::%s - viz ran out of free buffers", __FUNCTION__);
1815 unsigned int now = XbmcThreads::SystemClockMillis();
1816 unsigned int timestamp = now + m_stats.GetDelay() * 1000;
1817 busy |= m_vizBuffers->ResampleBuffers(timestamp);
1818 while(!m_vizBuffers->m_outputSamples.empty())
1820 CSampleBuffer *buf = m_vizBuffers->m_outputSamples.front();
1821 if ((now - buf->timestamp) & 0x80000000)
1826 samples = std::min(512, buf->pkt->nb_samples);
1827 m_audioCallback->OnAudioData((float*)(buf->pkt->data[0]), samples);
1829 m_vizBuffers->m_outputSamples.pop_front();
1833 else if (m_vizBuffers)
1834 m_vizBuffers->Flush();
1838 MixSounds(*(out->pkt));
1839 if (!m_sinkHasVolume || m_muted)
1840 Deamplify(*(out->pkt));
1842 if (m_mode == MODE_TRANSCODE && m_encoder)
1844 CSampleBuffer *buf = m_encoderBuffers->GetFreeBuffer();
1845 m_encoder->Encode(out->pkt->data[0], out->pkt->planes*out->pkt->linesize,
1846 buf->pkt->data[0], buf->pkt->planes*buf->pkt->linesize);
1847 buf->pkt->nb_samples = buf->pkt->max_nb_samples;
1857 m_stats.AddSamples(out->pkt->nb_samples, m_streams);
1858 m_sinkBuffers->m_inputSamples.push_back(out);
1864 std::list<CActiveAEStream*>::iterator it;
1865 CSampleBuffer *buffer;
1866 for (it = m_streams.begin(); it != m_streams.end(); ++it)
1868 if (!(*it)->m_resampleBuffers->m_outputSamples.empty())
1870 buffer = (*it)->m_resampleBuffers->m_outputSamples.front();
1871 (*it)->m_resampleBuffers->m_outputSamples.pop_front();
1872 m_stats.AddSamples(buffer->pkt->nb_samples, m_streams);
1873 m_sinkBuffers->m_inputSamples.push_back(buffer);
1878 // serve sink buffers
1879 busy = m_sinkBuffers->ResampleBuffers();
1880 while(!m_sinkBuffers->m_outputSamples.empty())
1882 CSampleBuffer *out = NULL;
1883 out = m_sinkBuffers->m_outputSamples.front();
1884 m_sinkBuffers->m_outputSamples.pop_front();
1885 m_sink.m_dataPort.SendOutMessage(CSinkDataProtocol::SAMPLE,
1886 &out, sizeof(CSampleBuffer*));
1894 bool CActiveAE::HasWork()
1896 if (!m_sounds_playing.empty())
1898 if (!m_sinkBuffers->m_inputSamples.empty())
1900 if (!m_sinkBuffers->m_outputSamples.empty())
1903 std::list<CActiveAEStream*>::iterator it;
1904 for (it = m_streams.begin(); it != m_streams.end(); ++it)
1906 if (!(*it)->m_resampleBuffers->m_inputSamples.empty())
1908 if (!(*it)->m_resampleBuffers->m_outputSamples.empty())
1910 if (!(*it)->m_processingSamples.empty())
1917 void CActiveAE::MixSounds(CSoundPacket &dstSample)
1919 if (m_sounds_playing.empty())
1924 float *sample_buffer;
1925 int max_samples = dstSample.nb_samples;
1927 std::list<SoundState>::iterator it;
1928 for (it = m_sounds_playing.begin(); it != m_sounds_playing.end(); )
1930 if (!it->sound->IsConverted())
1931 ResampleSound(it->sound);
1932 int available_samples = it->sound->GetSound(false)->nb_samples - it->samples_played;
1933 int mix_samples = std::min(max_samples, available_samples);
1934 int start = it->samples_played *
1935 m_dllAvUtil.av_get_bytes_per_sample(it->sound->GetSound(false)->config.fmt) *
1936 it->sound->GetSound(false)->config.channels /
1937 it->sound->GetSound(false)->planes;
1939 for(int j=0; j<dstSample.planes; j++)
1941 volume = it->sound->GetVolume();
1942 out = (float*)dstSample.data[j];
1943 sample_buffer = (float*)(it->sound->GetSound(false)->data[j]+start);
1944 int nb_floats = mix_samples * dstSample.config.channels / dstSample.planes;
1946 CAEUtil::SSEMulAddArray(out, sample_buffer, volume, nb_floats);
1948 for (int k = 0; k < nb_floats; ++k)
1949 *out++ += *sample_buffer++ * volume;
1953 it->samples_played += mix_samples;
1955 // no more frames, so remove it from the list
1956 if (it->samples_played >= it->sound->GetSound(false)->nb_samples)
1958 it = m_sounds_playing.erase(it);
1965 void CActiveAE::Deamplify(CSoundPacket &dstSample)
1967 if (m_volume < 1.0 || m_muted)
1970 int nb_floats = dstSample.nb_samples * dstSample.config.channels / dstSample.planes;
1972 for(int j=0; j<dstSample.planes; j++)
1974 buffer = (float*)dstSample.data[j];
1976 CAEUtil::SSEMulArray(buffer, m_muted ? 0.0 : m_volume, nb_floats);
1978 float *fbuffer = buffer;
1979 for (int i = 0; i < nb_floats; i++)
1980 *fbuffer++ *= m_volume;
1986 //-----------------------------------------------------------------------------
1988 //-----------------------------------------------------------------------------
1990 void CActiveAE::LoadSettings()
1992 m_settings.device = CSettings::Get().GetString("audiooutput.audiodevice");
1993 m_settings.passthoughdevice = CSettings::Get().GetString("audiooutput.passthroughdevice");
1995 m_settings.config = CSettings::Get().GetInt("audiooutput.config");
1996 m_settings.channels = (m_sink.GetDeviceType(m_settings.device) == AE_DEVTYPE_IEC958) ? AE_CH_LAYOUT_2_0 : CSettings::Get().GetInt("audiooutput.channels");
1997 m_settings.samplerate = CSettings::Get().GetInt("audiooutput.samplerate");
1999 m_settings.stereoupmix = IsSettingVisible("audiooutput.stereoupmix") ? CSettings::Get().GetBool("audiooutput.stereoupmix") : false;
2000 m_settings.normalizelevels = CSettings::Get().GetBool("audiooutput.normalizelevels");
2001 m_settings.guisoundmode = CSettings::Get().GetInt("audiooutput.guisoundmode");
2003 m_settings.passthrough = m_settings.config == AE_CONFIG_FIXED ? false : CSettings::Get().GetBool("audiooutput.passthrough");
2004 m_settings.ac3passthrough = CSettings::Get().GetBool("audiooutput.ac3passthrough");
2005 m_settings.eac3passthrough = CSettings::Get().GetBool("audiooutput.eac3passthrough");
2006 m_settings.truehdpassthrough = CSettings::Get().GetBool("audiooutput.truehdpassthrough");
2007 m_settings.dtspassthrough = CSettings::Get().GetBool("audiooutput.dtspassthrough");
2008 m_settings.dtshdpassthrough = CSettings::Get().GetBool("audiooutput.dtshdpassthrough");
2010 m_settings.resampleQuality = static_cast<AEQuality>(CSettings::Get().GetInt("audiooutput.processquality"));
2013 bool CActiveAE::Initialize()
2015 if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllAvFormat.Load())
2017 CLog::Log(LOGERROR,"CActiveAE::Initialize - failed to load ffmpeg libraries");
2020 m_dllAvFormat.av_register_all();
2024 if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::INIT,
2028 bool success = reply->signal == CActiveAEControlProtocol::ACC ? true : false;
2032 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
2039 CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__);
2044 // hook into windowing for receiving display reset events
2045 #if defined(HAS_GLX) || defined(TARGET_DARWIN_OSX)
2046 g_Windowing.Register(this);
2049 m_inMsgEvent.Reset();
2053 void CActiveAE::EnumerateOutputDevices(AEDeviceList &devices, bool passthrough)
2055 m_sink.EnumerateOutputDevices(devices, passthrough);
2058 std::string CActiveAE::GetDefaultDevice(bool passthrough)
2060 return m_sink.GetDefaultDevice(passthrough);
2063 void CActiveAE::OnSettingsChange(const std::string& setting)
2065 if (setting == "audiooutput.passthroughdevice" ||
2066 setting == "audiooutput.audiodevice" ||
2067 setting == "audiooutput.config" ||
2068 setting == "audiooutput.ac3passthrough" ||
2069 setting == "audiooutput.eac3passthrough" ||
2070 setting == "audiooutput.dtspassthrough" ||
2071 setting == "audiooutput.truehdpassthrough" ||
2072 setting == "audiooutput.dtshdpassthrough" ||
2073 setting == "audiooutput.channels" ||
2074 setting == "audiooutput.stereoupmix" ||
2075 setting == "audiooutput.streamsilence" ||
2076 setting == "audiooutput.processquality" ||
2077 setting == "audiooutput.passthrough" ||
2078 setting == "audiooutput.samplerate" ||
2079 setting == "audiooutput.normalizelevels" ||
2080 setting == "audiooutput.guisoundmode")
2082 m_controlPort.SendOutMessage(CActiveAEControlProtocol::RECONFIGURE);
2086 bool CActiveAE::SupportsRaw(AEDataFormat format)
2088 if (!m_sink.HasPassthroughDevice())
2091 // those formats require HDMI
2092 if (format == AE_FMT_DTSHD || format == AE_FMT_TRUEHD)
2094 if(m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.passthroughdevice")) != AE_DEVTYPE_HDMI)
2102 bool CActiveAE::SupportsSilenceTimeout()
2107 bool CActiveAE::SupportsQualityLevel(enum AEQuality level)
2109 if (level == AE_QUALITY_LOW || level == AE_QUALITY_MID || level == AE_QUALITY_HIGH)
2115 bool CActiveAE::IsSettingVisible(const std::string &settingId)
2117 if (settingId == "audiooutput.samplerate")
2119 if (m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) == AE_DEVTYPE_IEC958)
2121 if (CSettings::Get().GetInt("audiooutput.config") == AE_CONFIG_FIXED)
2124 else if (settingId == "audiooutput.channels")
2126 if (m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) != AE_DEVTYPE_IEC958)
2129 else if (settingId == "audiooutput.passthrough")
2131 if (m_sink.HasPassthroughDevice() && CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED)
2134 else if (settingId == "audiooutput.truehdpassthrough")
2136 if (m_sink.HasPassthroughDevice() &&
2137 CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED &&
2138 m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.passthroughdevice")) == AE_DEVTYPE_HDMI)
2141 else if (settingId == "audiooutput.dtshdpassthrough")
2143 if (m_sink.HasPassthroughDevice() &&
2144 CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED &&
2145 m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.passthroughdevice")) == AE_DEVTYPE_HDMI)
2148 else if (settingId == "audiooutput.stereoupmix")
2150 if (m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) != AE_DEVTYPE_IEC958)
2152 if (CSettings::Get().GetInt("audiooutput.channels") > AE_CH_LAYOUT_2_0)
2157 if (m_sink.HasPassthroughDevice() &&
2158 CSettings::Get().GetBool("audiooutput.passthrough") &&
2159 CSettings::Get().GetBool("audiooutput.ac3passthrough"))
2166 void CActiveAE::Shutdown()
2171 bool CActiveAE::Suspend()
2173 return m_controlPort.SendOutMessage(CActiveAEControlProtocol::SUSPEND);
2176 bool CActiveAE::Resume()
2179 if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::INIT,
2183 bool success = reply->signal == CActiveAEControlProtocol::ACC ? true : false;
2187 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
2193 CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__);
2197 m_inMsgEvent.Reset();
2201 bool CActiveAE::IsSuspended()
2203 return m_stats.IsSuspended();
2206 float CActiveAE::GetVolume()
2211 void CActiveAE::SetVolume(const float volume)
2213 m_aeVolume = std::max( 0.0f, std::min(1.0f, volume));
2214 m_controlPort.SendOutMessage(CActiveAEControlProtocol::VOLUME, &m_aeVolume, sizeof(float));
2217 void CActiveAE::SetMute(const bool enabled)
2219 m_aeMuted = enabled;
2220 m_controlPort.SendOutMessage(CActiveAEControlProtocol::MUTE, &m_aeMuted, sizeof(bool));
2223 bool CActiveAE::IsMuted()
2228 void CActiveAE::SetSoundMode(const int mode)
2233 void CActiveAE::KeepConfiguration(unsigned int millis)
2235 unsigned int timeMs = millis;
2236 m_controlPort.SendOutMessage(CActiveAEControlProtocol::KEEPCONFIG, &timeMs, sizeof(unsigned int));
2239 void CActiveAE::OnLostDevice()
2241 // m_controlPort.SendOutMessage(CActiveAEControlProtocol::DISPLAYLOST);
2244 void CActiveAE::OnResetDevice()
2246 // m_controlPort.SendOutMessage(CActiveAEControlProtocol::DISPLAYRESET);
2249 //-----------------------------------------------------------------------------
2251 //-----------------------------------------------------------------------------
2253 uint8_t **CActiveAE::AllocSoundSample(SampleConfig &config, int &samples, int &bytes_per_sample, int &planes, int &linesize)
2256 planes = m_dllAvUtil.av_sample_fmt_is_planar(config.fmt) ? config.channels : 1;
2257 buffer = new uint8_t*[planes];
2259 // align buffer to 16 in order to be compatible with sse in CAEConvert
2260 m_dllAvUtil.av_samples_alloc(buffer, &linesize, config.channels,
2261 samples, config.fmt, 16);
2262 bytes_per_sample = m_dllAvUtil.av_get_bytes_per_sample(config.fmt);
2266 void CActiveAE::FreeSoundSample(uint8_t **data)
2268 m_dllAvUtil.av_freep(data);
2272 bool CActiveAE::CompareFormat(AEAudioFormat &lhs, AEAudioFormat &rhs)
2274 if (lhs.m_channelLayout != rhs.m_channelLayout ||
2275 lhs.m_dataFormat != rhs.m_dataFormat ||
2276 lhs.m_sampleRate != rhs.m_sampleRate ||
2277 lhs.m_frames != rhs.m_frames)
2283 //-----------------------------------------------------------------------------
2285 //-----------------------------------------------------------------------------
2288 * load sound from an audio file and store original format
2289 * register the sound in ActiveAE
2290 * later when the engine is idle it will convert the sound to sink format
2293 #define SOUNDBUFFER_SIZE 20480
2295 IAESound *CActiveAE::MakeSound(const std::string& file)
2297 AVFormatContext *fmt_ctx = NULL;
2298 AVCodecContext *dec_ctx = NULL;
2299 AVIOContext *io_ctx;
2300 AVInputFormat *io_fmt;
2301 AVCodec *dec = NULL;
2302 CActiveAESound *sound = NULL;
2303 SampleConfig config;
2305 sound = new CActiveAESound(file);
2306 if (!sound->Prepare())
2311 int fileSize = sound->GetFileSize();
2313 fmt_ctx = m_dllAvFormat.avformat_alloc_context();
2314 unsigned char* buffer = (unsigned char*)m_dllAvUtil.av_malloc(SOUNDBUFFER_SIZE+FF_INPUT_BUFFER_PADDING_SIZE);
2315 io_ctx = m_dllAvFormat.avio_alloc_context(buffer, SOUNDBUFFER_SIZE, 0,
2316 sound, CActiveAESound::Read, NULL, CActiveAESound::Seek);
2317 io_ctx->max_packet_size = sound->GetChunkSize();
2318 if(io_ctx->max_packet_size)
2319 io_ctx->max_packet_size *= SOUNDBUFFER_SIZE / io_ctx->max_packet_size;
2321 if(!sound->IsSeekPosible())
2322 io_ctx->seekable = 0;
2324 fmt_ctx->pb = io_ctx;
2326 m_dllAvFormat.av_probe_input_buffer(io_ctx, &io_fmt, file.c_str(), NULL, 0, 0);
2329 m_dllAvFormat.avformat_close_input(&fmt_ctx);
2335 if (m_dllAvFormat.avformat_open_input(&fmt_ctx, file.c_str(), NULL, NULL) == 0)
2337 fmt_ctx->flags |= AVFMT_FLAG_NOPARSE;
2338 if (m_dllAvFormat.avformat_find_stream_info(fmt_ctx, NULL) >= 0)
2340 dec_ctx = fmt_ctx->streams[0]->codec;
2341 dec = m_dllAvCodec.avcodec_find_decoder(dec_ctx->codec_id);
2342 config.sample_rate = dec_ctx->sample_rate;
2343 config.channels = dec_ctx->channels;
2344 config.channel_layout = dec_ctx->channel_layout;
2349 m_dllAvFormat.avformat_close_input(&fmt_ctx);
2354 dec_ctx = m_dllAvCodec.avcodec_alloc_context3(dec);
2355 dec_ctx->sample_rate = config.sample_rate;
2356 dec_ctx->channels = config.channels;
2357 if (!config.channel_layout)
2358 config.channel_layout = m_dllAvUtil.av_get_default_channel_layout(config.channels);
2359 dec_ctx->channel_layout = config.channel_layout;
2362 AVFrame *decoded_frame = NULL;
2363 decoded_frame = m_dllAvCodec.avcodec_alloc_frame();
2365 if (m_dllAvCodec.avcodec_open2(dec_ctx, dec, NULL) >= 0)
2370 m_dllAvCodec.av_init_packet(&avpkt);
2372 while (m_dllAvFormat.av_read_frame(fmt_ctx, &avpkt) >= 0)
2375 len = m_dllAvCodec.avcodec_decode_audio4(dec_ctx, decoded_frame, &got_frame, &avpkt);
2378 m_dllAvCodec.avcodec_close(dec_ctx);
2379 m_dllAvUtil.av_free(dec_ctx);
2380 m_dllAvUtil.av_free(&decoded_frame);
2381 m_dllAvFormat.avformat_close_input(&fmt_ctx);
2389 int samples = fileSize / m_dllAvUtil.av_get_bytes_per_sample(dec_ctx->sample_fmt) / config.channels;
2390 config.fmt = dec_ctx->sample_fmt;
2391 config.bits_per_sample = dec_ctx->bits_per_coded_sample;
2392 sound->InitSound(true, config, samples);
2395 sound->StoreSound(true, decoded_frame->extended_data,
2396 decoded_frame->nb_samples, decoded_frame->linesize[0]);
2399 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);
2409 m_dataPort.SendOutMessage(CActiveAEDataProtocol::NEWSOUND, &sound, sizeof(CActiveAESound*));
2414 void CActiveAE::FreeSound(IAESound *sound)
2416 m_dataPort.SendOutMessage(CActiveAEDataProtocol::FREESOUND, &sound, sizeof(CActiveAESound*));
2419 void CActiveAE::PlaySound(CActiveAESound *sound)
2421 m_dataPort.SendOutMessage(CActiveAEDataProtocol::PLAYSOUND, &sound, sizeof(CActiveAESound*));
2424 void CActiveAE::StopSound(CActiveAESound *sound)
2426 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STOPSOUND, &sound, sizeof(CActiveAESound*));
2430 * resample sounds to destination format for mixing
2431 * destination format is either format of stream or
2432 * default sink format when no stream is playing
2434 void CActiveAE::ResampleSounds()
2436 if (m_settings.guisoundmode == AE_SOUND_OFF ||
2437 (m_settings.guisoundmode == AE_SOUND_IDLE && !m_streams.empty()))
2440 std::vector<CActiveAESound*>::iterator it;
2441 for (it = m_sounds.begin(); it != m_sounds.end(); ++it)
2443 if (!(*it)->IsConverted())
2446 // only do one sound, then yield to main loop
2452 bool CActiveAE::ResampleSound(CActiveAESound *sound)
2454 SampleConfig orig_config, dst_config;
2455 uint8_t **dst_buffer;
2458 if (m_mode == MODE_RAW || m_internalFormat.m_dataFormat == AE_FMT_INVALID)
2461 if (!sound->GetSound(true))
2464 orig_config = sound->GetSound(true)->config;
2466 dst_config.channel_layout = CActiveAEResample::GetAVChannelLayout(m_internalFormat.m_channelLayout);
2467 dst_config.channels = m_internalFormat.m_channelLayout.Count();
2468 dst_config.sample_rate = m_internalFormat.m_sampleRate;
2469 dst_config.fmt = CActiveAEResample::GetAVSampleFormat(m_internalFormat.m_dataFormat);
2470 dst_config.bits_per_sample = CAEUtil::DataFormatToUsedBits(m_internalFormat.m_dataFormat);
2472 CActiveAEResample *resampler = new CActiveAEResample();
2473 resampler->Init(dst_config.channel_layout,
2474 dst_config.channels,
2475 dst_config.sample_rate,
2477 dst_config.bits_per_sample,
2478 orig_config.channel_layout,
2479 orig_config.channels,
2480 orig_config.sample_rate,
2482 orig_config.bits_per_sample,
2486 m_settings.resampleQuality);
2488 dst_samples = resampler->CalcDstSampleCount(sound->GetSound(true)->nb_samples,
2489 m_internalFormat.m_sampleRate,
2490 orig_config.sample_rate);
2492 dst_buffer = sound->InitSound(false, dst_config, dst_samples);
2498 int samples = resampler->Resample(dst_buffer, dst_samples,
2499 sound->GetSound(true)->data,
2500 sound->GetSound(true)->nb_samples,
2503 sound->GetSound(false)->nb_samples = samples;
2506 sound->SetConverted(true);
2510 //-----------------------------------------------------------------------------
2512 //-----------------------------------------------------------------------------
2514 IAEStream *CActiveAE::MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSampleRate, CAEChannelInfo channelLayout, unsigned int options)
2516 //TODO: pass number of samples in audio packet
2518 AEAudioFormat format;
2519 format.m_dataFormat = dataFormat;
2520 format.m_sampleRate = sampleRate;
2521 format.m_encodedRate = encodedSampleRate;
2522 format.m_channelLayout = channelLayout;
2523 format.m_frames = format.m_sampleRate / 10;
2524 format.m_frameSize = format.m_channelLayout.Count() *
2525 (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);
2528 msg.format = format;
2529 msg.options = options;
2532 if (m_dataPort.SendOutMessageSync(CActiveAEDataProtocol::NEWSTREAM,
2534 &msg, sizeof(MsgStreamNew)))
2536 bool success = reply->signal == CActiveAEControlProtocol::ACC ? true : false;
2539 CActiveAEStream *stream = *(CActiveAEStream**)reply->data;
2546 CLog::Log(LOGERROR, "ActiveAE::%s - could not create stream", __FUNCTION__);
2550 IAEStream *CActiveAE::FreeStream(IAEStream *stream)
2552 m_dataPort.SendOutMessage(CActiveAEDataProtocol::FREESTREAM, &stream, sizeof(IAEStream*));
2556 void CActiveAE::FlushStream(CActiveAEStream *stream)
2559 if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::FLUSHSTREAM,
2561 &stream, sizeof(CActiveAEStream*)))
2563 bool success = reply->signal == CActiveAEControlProtocol::ACC ? true : false;
2567 CLog::Log(LOGERROR, "CActiveAE::FlushStream - failed");
2572 void CActiveAE::PauseStream(CActiveAEStream *stream, bool pause)
2574 // TODO pause sink, needs api change
2576 m_controlPort.SendOutMessage(CActiveAEControlProtocol::PAUSESTREAM,
2577 &stream, sizeof(CActiveAEStream*));
2579 m_controlPort.SendOutMessage(CActiveAEControlProtocol::RESUMESTREAM,
2580 &stream, sizeof(CActiveAEStream*));
2583 void CActiveAE::SetStreamAmplification(CActiveAEStream *stream, float amplify)
2585 MsgStreamParameter msg;
2586 msg.stream = stream;
2587 msg.parameter.float_par = amplify;
2588 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMAMP,
2589 &msg, sizeof(MsgStreamParameter));
2592 void CActiveAE::SetStreamReplaygain(CActiveAEStream *stream, float rgain)
2594 MsgStreamParameter msg;
2595 msg.stream = stream;
2596 msg.parameter.float_par = rgain;
2597 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMRGAIN,
2598 &msg, sizeof(MsgStreamParameter));
2601 void CActiveAE::SetStreamVolume(CActiveAEStream *stream, float volume)
2603 MsgStreamParameter msg;
2604 msg.stream = stream;
2605 msg.parameter.float_par = volume;
2606 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMVOLUME,
2607 &msg, sizeof(MsgStreamParameter));
2610 void CActiveAE::SetStreamResampleRatio(CActiveAEStream *stream, double ratio)
2612 MsgStreamParameter msg;
2613 msg.stream = stream;
2614 msg.parameter.double_par = ratio;
2615 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMRESAMPLERATIO,
2616 &msg, sizeof(MsgStreamParameter));
2619 void CActiveAE::SetStreamFade(CActiveAEStream *stream, float from, float target, unsigned int millis)
2622 msg.stream = stream;
2624 msg.target = target;
2625 msg.millis = millis;
2626 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMFADE,
2627 &msg, sizeof(MsgStreamFade));
2630 void CActiveAE::RegisterAudioCallback(IAudioCallback* pCallback)
2632 CSingleLock lock(m_vizLock);
2633 m_audioCallback = pCallback;
2634 m_vizInitialized = false;
2637 void CActiveAE::UnregisterAudioCallback()
2639 CSingleLock lock(m_vizLock);
2640 m_audioCallback = NULL;