2 * Copyright (C) 2010-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
23 using namespace ActiveAE;
24 #include "ActiveAESound.h"
25 #include "ActiveAEStream.h"
26 #include "cores/AudioEngine/Utils/AEUtil.h"
27 #include "cores/AudioEngine/Encoders/AEEncoderFFmpeg.h"
29 #include "settings/Settings.h"
30 #include "settings/AdvancedSettings.h"
31 #include "windowing/WindowingFactory.h"
33 #define MAX_CACHE_LEVEL 0.5 // total cache time of stream in seconds
34 #define MAX_WATER_LEVEL 0.25 // buffered time after stream stages in seconds
35 #define MAX_BUFFER_TIME 0.1 // max time of a buffer in seconds
37 void CEngineStats::Reset(unsigned int sampleRate)
39 CSingleLock lock(m_lock);
40 m_sinkUpdate = XbmcThreads::SystemClockMillis();
42 m_sinkSampleRate = sampleRate;
43 m_bufferedSamples = 0;
47 void CEngineStats::UpdateSinkDelay(double delay, int samples)
49 CSingleLock lock(m_lock);
50 m_sinkUpdate = XbmcThreads::SystemClockMillis();
52 if (samples > m_bufferedSamples)
54 CLog::Log(LOGERROR, "CEngineStats::UpdateSinkDelay - inconsistency in buffer time");
57 m_bufferedSamples -= samples;
60 void CEngineStats::AddSamples(int samples, std::list<CActiveAEStream*> &streams)
62 CSingleLock lock(m_lock);
63 m_bufferedSamples += samples;
65 //update buffered time of streams
66 std::list<CActiveAEStream*>::iterator it;
67 for(it=streams.begin(); it!=streams.end(); ++it)
70 std::deque<CSampleBuffer*>::iterator itBuf;
71 for(itBuf=(*it)->m_processingSamples.begin(); itBuf!=(*it)->m_processingSamples.end(); ++itBuf)
73 delay += (float)(*itBuf)->pkt->nb_samples / (*itBuf)->pkt->config.sample_rate;
75 delay += (*it)->m_resampleBuffers->GetDelay();
76 (*it)->m_bufferedTime = delay;
80 float CEngineStats::GetDelay()
82 CSingleLock lock(m_lock);
83 unsigned int now = XbmcThreads::SystemClockMillis();
84 float delay = m_sinkDelay - (double)(now-m_sinkUpdate) / 1000;
85 delay += (float)m_bufferedSamples / m_sinkSampleRate;
93 // this is used to sync a/v so we need to add sink latency here
94 float CEngineStats::GetDelay(CActiveAEStream *stream)
96 CSingleLock lock(m_lock);
97 unsigned int now = XbmcThreads::SystemClockMillis();
98 float delay = m_sinkDelay - (double)(now-m_sinkUpdate) / 1000;
99 delay += m_sinkLatency;
100 delay += (float)m_bufferedSamples / m_sinkSampleRate;
105 delay += stream->m_bufferedTime / stream->m_streamResampleRatio;
109 float CEngineStats::GetCacheTime(CActiveAEStream *stream)
111 CSingleLock lock(m_lock);
112 float delay = (float)m_bufferedSamples / m_sinkSampleRate;
114 delay += stream->m_bufferedTime;
118 float CEngineStats::GetCacheTotal(CActiveAEStream *stream)
120 return MAX_CACHE_LEVEL + m_sinkCacheTotal;
123 float CEngineStats::GetWaterLevel()
125 CSingleLock lock(m_lock);
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;
153 m_volumeScaled = 1.0;
159 m_audioCallback = NULL;
160 m_vizInitialized = false;
161 m_sinkHasVolume = false;
164 CActiveAE::~CActiveAE()
169 void CActiveAE::Dispose()
171 #if defined(HAS_GLX) || defined(TARGET_DARWIN)
172 g_Windowing.Unregister(this);
178 m_controlPort.Purge();
182 m_dllAvFormat.Unload();
183 m_dllAvCodec.Unload();
184 m_dllAvUtil.Unload();
187 //-----------------------------------------------------------------------------
189 //-----------------------------------------------------------------------------
195 AE_TOP_UNCONFIGURED, // 2
196 AE_TOP_RECONFIGURING, // 3
197 AE_TOP_CONFIGURED, // 4
198 AE_TOP_CONFIGURED_SUSPEND, // 5
199 AE_TOP_CONFIGURED_IDLE, // 6
200 AE_TOP_CONFIGURED_PLAY, // 7
203 int AE_parentStates[] = {
206 0, //TOP_UNCONFIGURED
208 0, //TOP_RECONFIGURING
209 4, //TOP_CONFIGURED_SUSPEND
210 4, //TOP_CONFIGURED_IDLE
211 4, //TOP_CONFIGURED_PLAY
214 void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg)
216 for (int state = m_state; ; state = AE_parentStates[state])
221 if (port == &m_controlPort)
225 case CActiveAEControlProtocol::GETSTATE:
226 msg->Reply(CActiveAEControlProtocol::ACC, &m_state, sizeof(m_state));
228 case CActiveAEControlProtocol::VOLUME:
229 m_volume = *(float*)msg->data;
230 m_volumeScaled = CAEUtil::GainToScale(CAEUtil::PercentToGain(m_volume));
232 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::VOLUME, &m_volume, sizeof(float));
234 case CActiveAEControlProtocol::MUTE:
235 m_muted = *(bool*)msg->data;
237 case CActiveAEControlProtocol::KEEPCONFIG:
238 m_extKeepConfig = *(unsigned int*)msg->data;
240 case CActiveAEControlProtocol::DISPLAYRESET:
242 case CActiveAEControlProtocol::APPFOCUSED:
243 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::APPFOCUSED, msg->data, sizeof(bool));
249 else if (port == &m_dataPort)
253 case CActiveAEDataProtocol::NEWSOUND:
254 CActiveAESound *sound;
255 sound = *(CActiveAESound**)msg->data;
258 m_sounds.push_back(sound);
262 case CActiveAEDataProtocol::FREESTREAM:
263 CActiveAEStream *stream;
264 stream = *(CActiveAEStream**)msg->data;
265 DiscardStream(stream);
267 case CActiveAEDataProtocol::FREESOUND:
268 sound = *(CActiveAESound**)msg->data;
271 case CActiveAEDataProtocol::DRAINSTREAM:
272 stream = *(CActiveAEStream**)msg->data;
273 stream->m_drain = true;
274 stream->m_resampleBuffers->m_drain = true;
275 msg->Reply(CActiveAEDataProtocol::ACC);
276 stream->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMDRAINED);
282 else if (port == &m_sink.m_dataPort)
286 case CSinkDataProtocol::RETURNSAMPLE:
287 CSampleBuffer **buffer;
288 buffer = (CSampleBuffer**)msg->data;
299 std::string portName = port == NULL ? "timer" : port->portName;
300 CLog::Log(LOGWARNING, "CActiveAE::%s - signal: %d from port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state);
305 if (port == NULL) // timeout
309 case CActiveAEControlProtocol::TIMEOUT:
315 m_state = AE_TOP_CONFIGURED_IDLE;
320 m_state = AE_TOP_ERROR;
330 case AE_TOP_UNCONFIGURED:
331 if (port == &m_controlPort)
335 case CActiveAEControlProtocol::INIT:
337 m_sink.EnumerateSinkList(false);
340 msg->Reply(CActiveAEControlProtocol::ACC);
343 m_state = AE_TOP_CONFIGURED_IDLE;
348 m_state = AE_TOP_ERROR;
359 case AE_TOP_RECONFIGURING:
360 if (port == NULL) // timeout
364 case CActiveAEControlProtocol::TIMEOUT:
371 if (!m_sinkBuffers->m_inputSamples.empty() || !m_sinkBuffers->m_outputSamples.empty())
376 if (NeedReconfigureSink())
383 m_state = AE_TOP_CONFIGURED_PLAY;
388 m_state = AE_TOP_ERROR;
391 m_extDeferData = false;
399 case AE_TOP_CONFIGURED:
400 if (port == &m_controlPort)
405 case CActiveAEControlProtocol::RECONFIGURE:
406 if (m_streams.empty())
409 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::STREAMING, &streaming, sizeof(bool));
413 if (!NeedReconfigureBuffers() && !NeedReconfigureSink())
415 m_state = AE_TOP_RECONFIGURING;
417 // don't accept any data until we are reconfigured
418 m_extDeferData = true;
420 case CActiveAEControlProtocol::SUSPEND:
422 m_stats.SetSuspended(true);
423 m_state = AE_TOP_CONFIGURED_SUSPEND;
424 m_extDeferData = true;
426 case CActiveAEControlProtocol::DISPLAYLOST:
427 if (m_sink.GetDeviceType(m_mode == MODE_PCM ? m_settings.device : m_settings.passthoughdevice) == AE_DEVTYPE_HDMI)
430 m_stats.SetSuspended(true);
431 m_state = AE_TOP_CONFIGURED_SUSPEND;
432 m_extDeferData = true;
434 msg->Reply(CActiveAEControlProtocol::ACC);
436 case CActiveAEControlProtocol::DEVICECHANGE:
439 CLog::Log(LOGDEBUG,"CActiveAE - device change event");
440 while (!m_extLastDeviceChange.empty() && (now - m_extLastDeviceChange.front() > 0))
442 m_extLastDeviceChange.pop();
444 if (m_extLastDeviceChange.size() > 2)
446 CLog::Log(LOGWARNING,"CActiveAE - received %ld device change events within one second", m_extLastDeviceChange.size());
449 m_extLastDeviceChange.push(now);
451 m_controlPort.PurgeOut(CActiveAEControlProtocol::DEVICECHANGE);
452 m_sink.EnumerateSinkList(true);
458 m_state = AE_TOP_CONFIGURED_PLAY;
463 m_state = AE_TOP_ERROR;
467 case CActiveAEControlProtocol::PAUSESTREAM:
468 CActiveAEStream *stream;
469 stream = *(CActiveAEStream**)msg->data;
470 if (stream->m_paused != true && m_streams.size() == 1)
474 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::STREAMING, &streaming, sizeof(bool));
476 stream->m_paused = true;
478 case CActiveAEControlProtocol::RESUMESTREAM:
479 stream = *(CActiveAEStream**)msg->data;
480 stream->m_paused = false;
482 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::STREAMING, &streaming, sizeof(bool));
485 case CActiveAEControlProtocol::FLUSHSTREAM:
486 stream = *(CActiveAEStream**)msg->data;
487 SFlushStream(stream);
488 msg->Reply(CActiveAEControlProtocol::ACC);
491 case CActiveAEControlProtocol::STREAMAMP:
492 MsgStreamParameter *par;
493 par = (MsgStreamParameter*)msg->data;
494 par->stream->m_limiter.SetAmplification(par->parameter.float_par);
495 par->stream->m_amplify = par->parameter.float_par;
497 case CActiveAEControlProtocol::STREAMVOLUME:
498 par = (MsgStreamParameter*)msg->data;
499 par->stream->m_volume = par->parameter.float_par;
501 case CActiveAEControlProtocol::STREAMRGAIN:
502 par = (MsgStreamParameter*)msg->data;
503 par->stream->m_rgain = par->parameter.float_par;
505 case CActiveAEControlProtocol::STREAMRESAMPLERATIO:
506 par = (MsgStreamParameter*)msg->data;
507 if (par->stream->m_resampleBuffers)
509 par->stream->m_resampleBuffers->m_resampleRatio = par->parameter.double_par;
512 case CActiveAEControlProtocol::STREAMFADE:
514 fade = (MsgStreamFade*)msg->data;
515 fade->stream->m_fadingBase = fade->from;
516 fade->stream->m_fadingTarget = fade->target;
517 fade->stream->m_fadingTime = fade->millis;
518 fade->stream->m_fadingSamples = -1;
520 case CActiveAEControlProtocol::STOPSOUND:
521 CActiveAESound *sound;
522 sound = *(CActiveAESound**)msg->data;
529 else if (port == &m_dataPort)
533 case CActiveAEDataProtocol::PLAYSOUND:
534 CActiveAESound *sound;
535 sound = *(CActiveAESound**)msg->data;
536 if (m_settings.guisoundmode == AE_SOUND_OFF ||
537 (m_settings.guisoundmode == AE_SOUND_IDLE && !m_streams.empty()))
541 SoundState st = {sound, 0};
542 m_sounds_playing.push_back(st);
544 m_state = AE_TOP_CONFIGURED_PLAY;
547 case CActiveAEDataProtocol::NEWSTREAM:
548 MsgStreamNew *streamMsg;
549 CActiveAEStream *stream;
550 streamMsg = (MsgStreamNew*)msg->data;
551 stream = CreateStream(streamMsg);
554 msg->Reply(CActiveAEDataProtocol::ACC, &stream, sizeof(CActiveAEStream*));
559 m_state = AE_TOP_CONFIGURED_PLAY;
564 m_state = AE_TOP_ERROR;
569 msg->Reply(CActiveAEDataProtocol::ERR);
571 case CActiveAEDataProtocol::STREAMSAMPLE:
572 MsgStreamSample *msgData;
573 CSampleBuffer *samples;
574 msgData = (MsgStreamSample*)msg->data;
575 samples = msgData->stream->m_processingSamples.front();
576 msgData->stream->m_processingSamples.pop_front();
577 if (samples != msgData->buffer)
578 CLog::Log(LOGERROR, "CActiveAE - inconsistency in stream sample message");
579 if (msgData->buffer->pkt->nb_samples == 0)
580 msgData->buffer->Return();
582 msgData->stream->m_resampleBuffers->m_inputSamples.push_back(msgData->buffer);
584 m_state = AE_TOP_CONFIGURED_PLAY;
586 case CActiveAEDataProtocol::FREESTREAM:
587 stream = *(CActiveAEStream**)msg->data;
588 DiscardStream(stream);
589 if (m_streams.empty())
592 m_extDrainTimer.Set(m_extKeepConfig);
594 m_extDrainTimer.Set(m_stats.GetDelay() * 1000);
598 m_state = AE_TOP_CONFIGURED_PLAY;
600 case CActiveAEDataProtocol::DRAINSTREAM:
601 stream = *(CActiveAEStream**)msg->data;
602 stream->m_drain = true;
603 stream->m_resampleBuffers->m_drain = true;
605 m_state = AE_TOP_CONFIGURED_PLAY;
606 msg->Reply(CActiveAEDataProtocol::ACC);
612 else if (port == &m_sink.m_dataPort)
616 case CSinkDataProtocol::RETURNSAMPLE:
617 CSampleBuffer **buffer;
618 buffer = (CSampleBuffer**)msg->data;
624 m_state = AE_TOP_CONFIGURED_PLAY;
632 case AE_TOP_CONFIGURED_SUSPEND:
633 if (port == &m_controlPort)
635 bool displayReset = false;
638 case CActiveAEControlProtocol::DISPLAYRESET:
639 CLog::Log(LOGDEBUG,"CActiveAE - display reset event");
641 case CActiveAEControlProtocol::INIT:
645 m_controlPort.PurgeOut(CActiveAEControlProtocol::DEVICECHANGE);
646 m_sink.EnumerateSinkList(true);
651 msg->Reply(CActiveAEControlProtocol::ACC);
654 m_state = AE_TOP_CONFIGURED_PLAY;
659 m_state = AE_TOP_ERROR;
662 m_stats.SetSuspended(false);
663 m_extDeferData = false;
665 case CActiveAEControlProtocol::DEVICECHANGE:
671 else if (port == &m_sink.m_dataPort)
675 case CSinkDataProtocol::RETURNSAMPLE:
676 CSampleBuffer **buffer;
677 buffer = (CSampleBuffer**)msg->data;
687 else if (port == NULL) // timeout
691 case CActiveAEControlProtocol::TIMEOUT:
700 case AE_TOP_CONFIGURED_IDLE:
701 if (port == &m_controlPort)
705 case CActiveAEControlProtocol::RESUMESTREAM:
706 CActiveAEStream *stream;
707 stream = *(CActiveAEStream**)msg->data;
708 stream->m_paused = false;
709 m_state = AE_TOP_CONFIGURED_PLAY;
712 case CActiveAEControlProtocol::FLUSHSTREAM:
713 stream = *(CActiveAEStream**)msg->data;
714 SFlushStream(stream);
715 msg->Reply(CActiveAEControlProtocol::ACC);
716 m_state = AE_TOP_CONFIGURED_PLAY;
723 else if (port == NULL) // timeout
727 case CActiveAEControlProtocol::TIMEOUT:
729 ClearDiscardedBuffers();
732 if (m_extDrainTimer.IsTimePast())
737 m_state = AE_TOP_CONFIGURED_PLAY;
742 m_state = AE_TOP_ERROR;
747 m_extTimeout = m_extDrainTimer.MillisLeft();
758 case AE_TOP_CONFIGURED_PLAY:
759 if (port == NULL) // timeout
763 case CActiveAEControlProtocol::TIMEOUT:
766 m_state = AE_TOP_ERROR;
775 if (!m_extDrain && HasWork())
777 ClearDiscardedBuffers();
782 m_state = AE_TOP_CONFIGURED_IDLE;
790 default: // we are in no state, should not happen
791 CLog::Log(LOGERROR, "CActiveAE::%s - no valid state: %d", __FUNCTION__, m_state);
797 void CActiveAE::Process()
800 Protocol *port = NULL;
802 XbmcThreads::EndTime timer;
804 m_state = AE_TOP_UNCONFIGURED;
806 m_bStateMachineSelfTrigger = false;
808 m_extDeferData = false;
817 timer.Set(m_extTimeout);
819 if (m_bStateMachineSelfTrigger)
821 m_bStateMachineSelfTrigger = false;
822 // self trigger state machine
823 StateMachine(msg->signal, port, msg);
824 if (!m_bStateMachineSelfTrigger)
831 // check control port
832 else if (m_controlPort.ReceiveOutMessage(&msg))
835 port = &m_controlPort;
837 // check sink data port
838 else if (m_sink.m_dataPort.ReceiveInMessage(&msg))
841 port = &m_sink.m_dataPort;
843 else if (!m_extDeferData)
846 if (m_dataPort.ReceiveOutMessage(&msg))
854 std::list<CActiveAEStream*>::iterator it;
855 for(it=m_streams.begin(); it!=m_streams.end(); ++it)
857 if((*it)->m_streamPort->ReceiveOutMessage(&msg))
869 StateMachine(msg->signal, port, msg);
870 if (!m_bStateMachineSelfTrigger)
879 else if (m_outMsgEvent.WaitMSec(m_extTimeout))
881 m_extTimeout = timer.MillisLeft();
887 msg = m_controlPort.GetMessage();
888 msg->signal = CActiveAEControlProtocol::TIMEOUT;
890 // signal timeout to state machine
891 StateMachine(msg->signal, port, msg);
892 if (!m_bStateMachineSelfTrigger)
901 AEAudioFormat CActiveAE::GetInputFormat(AEAudioFormat *desiredFmt)
903 AEAudioFormat inputFormat;
905 if (m_streams.empty())
907 inputFormat.m_dataFormat = AE_FMT_FLOAT;
908 inputFormat.m_sampleRate = 44100;
909 inputFormat.m_encodedRate = 0;
910 inputFormat.m_channelLayout = AE_CH_LAYOUT_2_0;
911 inputFormat.m_frames = 0;
912 inputFormat.m_frameSamples = 0;
913 inputFormat.m_frameSize = 0;
915 // force input format after unpausing slave
916 else if (desiredFmt != NULL)
918 inputFormat = *desiredFmt;
920 // keep format when having multiple streams
921 else if (m_streams.size() > 1 && m_silenceBuffers == NULL)
923 inputFormat = m_inputFormat;
927 inputFormat = m_streams.front()->m_format;
928 m_inputFormat = inputFormat;
934 void CActiveAE::Configure(AEAudioFormat *desiredFmt)
936 bool initSink = false;
938 AEAudioFormat sinkInputFormat, inputFormat;
939 AEAudioFormat oldInternalFormat = m_internalFormat;
940 AEAudioFormat oldSinkRequestFormat = m_sinkRequestFormat;
942 inputFormat = GetInputFormat(desiredFmt);
944 m_sinkRequestFormat = inputFormat;
945 ApplySettingsToFormat(m_sinkRequestFormat, m_settings, (int*)&m_mode);
948 std::string device = AE_IS_RAW(m_sinkRequestFormat.m_dataFormat) ? m_settings.passthoughdevice : m_settings.device;
950 CAESinkFactory::ParseDevice(device, driver);
951 if ((!CompareFormat(m_sinkRequestFormat, m_sinkFormat) && !CompareFormat(m_sinkRequestFormat, oldSinkRequestFormat)) ||
952 m_currDevice.compare(device) != 0 ||
953 m_settings.driver.compare(driver) != 0)
957 m_settings.driver = driver;
958 m_currDevice = device;
960 m_stats.Reset(m_sinkFormat.m_sampleRate);
961 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::VOLUME, &m_volume, sizeof(float));
963 // limit buffer size in case of sink returns large buffer
964 unsigned int buffertime = m_sinkFormat.m_frames / m_sinkFormat.m_sampleRate;
965 if (buffertime > MAX_BUFFER_TIME)
967 CLog::Log(LOGWARNING, "ActiveAE::%s - sink returned large buffer of %d ms, reducing to %d ms", __FUNCTION__, buffertime, (int)(MAX_BUFFER_TIME*1000));
968 m_sinkFormat.m_frames = MAX_BUFFER_TIME * m_sinkFormat.m_sampleRate;
972 if (m_silenceBuffers)
974 m_discardBufferPools.push_back(m_silenceBuffers);
975 m_silenceBuffers = NULL;
978 // buffers for driving gui sounds if no streams are active
979 if (m_streams.empty())
981 inputFormat = m_sinkFormat;
982 if (m_sinkFormat.m_channelLayout.Count() > m_sinkRequestFormat.m_channelLayout.Count())
984 inputFormat.m_channelLayout = m_sinkRequestFormat.m_channelLayout;
985 inputFormat.m_channelLayout.ResolveChannels(m_sinkFormat.m_channelLayout);
987 inputFormat.m_dataFormat = AE_FMT_FLOAT;
988 inputFormat.m_frameSize = inputFormat.m_channelLayout.Count() *
989 (CAEUtil::DataFormatToBits(inputFormat.m_dataFormat) >> 3);
990 m_silenceBuffers = new CActiveAEBufferPool(inputFormat);
991 m_silenceBuffers->Create(MAX_WATER_LEVEL*1000);
992 sinkInputFormat = inputFormat;
993 m_internalFormat = inputFormat;
995 bool streaming = false;
996 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::STREAMING, &streaming, sizeof(bool));
1001 if (m_encoderBuffers)
1003 m_discardBufferPools.push_back(m_encoderBuffers);
1004 m_encoderBuffers = NULL;
1008 m_discardBufferPools.push_back(m_vizBuffers);
1009 m_vizBuffers = NULL;
1011 if (m_vizBuffersInput)
1013 m_discardBufferPools.push_back(m_vizBuffersInput);
1014 m_vizBuffersInput = NULL;
1017 // resample buffers for streams
1020 bool streaming = true;
1021 m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::STREAMING, &streaming, sizeof(bool));
1023 AEAudioFormat outputFormat;
1024 if (m_mode == MODE_RAW)
1026 inputFormat.m_frames = m_sinkFormat.m_frames;
1027 outputFormat = inputFormat;
1028 sinkInputFormat = m_sinkFormat;
1030 // transcode everything with more than 2 channels
1031 else if (m_mode == MODE_TRANSCODE)
1033 outputFormat = inputFormat;
1034 outputFormat.m_dataFormat = AE_FMT_FLOATP;
1035 outputFormat.m_sampleRate = 48000;
1036 outputFormat.m_encodedRate = 48000;
1041 m_encoder = new CAEEncoderFFmpeg();
1042 m_encoder->Initialize(outputFormat, true);
1043 m_encoderFormat = outputFormat;
1046 outputFormat = m_encoderFormat;
1048 outputFormat.m_channelLayout = m_encoderFormat.m_channelLayout;
1049 outputFormat.m_frames = m_encoderFormat.m_frames;
1052 if (m_encoder->GetCodecID() == AV_CODEC_ID_AC3)
1054 AEAudioFormat format;
1055 format.m_channelLayout = AE_CH_LAYOUT_2_0;
1056 format.m_dataFormat = AE_FMT_S16NE;
1057 format.m_frameSize = 2* (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);
1058 format.m_frames = AC3_FRAME_SIZE;
1059 format.m_sampleRate = 48000;
1060 format.m_encodedRate = m_encoderFormat.m_sampleRate;
1061 if (m_encoderBuffers && initSink)
1063 m_discardBufferPools.push_back(m_encoderBuffers);
1064 m_encoderBuffers = NULL;
1066 if (!m_encoderBuffers)
1068 m_encoderBuffers = new CActiveAEBufferPool(format);
1069 m_encoderBuffers->Create(MAX_WATER_LEVEL*1000);
1073 sinkInputFormat = m_sinkFormat;
1077 outputFormat = m_sinkFormat;
1078 outputFormat.m_dataFormat = AE_FMT_FLOAT;
1079 outputFormat.m_frameSize = outputFormat.m_channelLayout.Count() *
1080 (CAEUtil::DataFormatToBits(outputFormat.m_dataFormat) >> 3);
1082 // due to channel ordering of the driver, a sink may return more channels than
1083 // requested, i.e. 2.1 request returns FL,FR,BL,BR,FC,LFE for ALSA
1084 // in this case we need to downmix to requested format
1085 if (m_sinkFormat.m_channelLayout.Count() > m_sinkRequestFormat.m_channelLayout.Count())
1087 outputFormat.m_channelLayout = m_sinkRequestFormat.m_channelLayout;
1088 outputFormat.m_channelLayout.ResolveChannels(m_sinkFormat.m_channelLayout);
1091 // TODO: adjust to decoder
1092 sinkInputFormat = outputFormat;
1094 m_internalFormat = outputFormat;
1096 std::list<CActiveAEStream*>::iterator it;
1097 for(it=m_streams.begin(); it!=m_streams.end(); ++it)
1099 // check if we support input format of stream
1100 if (!AE_IS_RAW((*it)->m_format.m_dataFormat) &&
1101 CActiveAEResample::GetAVSampleFormat((*it)->m_format.m_dataFormat) == AV_SAMPLE_FMT_FLT &&
1102 (*it)->m_format.m_dataFormat != AE_FMT_FLOAT)
1104 (*it)->m_convertFn = CAEConvert::ToFloat((*it)->m_format.m_dataFormat);
1105 (*it)->m_format.m_dataFormat = AE_FMT_FLOAT;
1108 if (!(*it)->m_inputBuffers)
1110 // align input buffers with period of sink or encoder
1111 (*it)->m_format.m_frames = m_internalFormat.m_frames * ((float)(*it)->m_format.m_sampleRate / m_internalFormat.m_sampleRate);
1113 // create buffer pool
1114 (*it)->m_inputBuffers = new CActiveAEBufferPool((*it)->m_format);
1115 (*it)->m_inputBuffers->Create(MAX_CACHE_LEVEL*1000);
1116 (*it)->m_streamSpace = (*it)->m_format.m_frameSize * (*it)->m_format.m_frames;
1118 // if input format does not follow ffmpeg channel mask, we may need to remap channels
1119 (*it)->InitRemapper();
1121 if (initSink && (*it)->m_resampleBuffers)
1123 m_discardBufferPools.push_back((*it)->m_resampleBuffers);
1124 (*it)->m_resampleBuffers = NULL;
1126 if (!(*it)->m_resampleBuffers)
1128 (*it)->m_resampleBuffers = new CActiveAEBufferPoolResample((*it)->m_inputBuffers->m_format, outputFormat, m_settings.resampleQuality);
1129 (*it)->m_resampleBuffers->m_changeResampler = (*it)->m_forceResampler;
1130 (*it)->m_resampleBuffers->Create(MAX_CACHE_LEVEL*1000, false, m_settings.stereoupmix, m_settings.normalizelevels);
1132 if (m_mode == MODE_TRANSCODE || m_streams.size() > 1)
1133 (*it)->m_resampleBuffers->m_fillPackets = true;
1136 (*it)->m_limiter.SetSamplerate(outputFormat.m_sampleRate);
1139 // update buffered time of streams
1140 m_stats.AddSamples(0, m_streams);
1143 if (!AE_IS_RAW(inputFormat.m_dataFormat))
1145 if (initSink && m_vizBuffers)
1147 m_discardBufferPools.push_back(m_vizBuffers);
1148 m_vizBuffers = NULL;
1149 m_discardBufferPools.push_back(m_vizBuffersInput);
1150 m_vizBuffersInput = NULL;
1154 AEAudioFormat vizFormat = m_internalFormat;
1155 vizFormat.m_channelLayout = AE_CH_LAYOUT_2_0;
1156 vizFormat.m_dataFormat = AE_FMT_FLOAT;
1159 m_vizBuffersInput = new CActiveAEBufferPool(m_internalFormat);
1160 m_vizBuffersInput->Create(2000);
1163 m_vizBuffers = new CActiveAEBufferPoolResample(m_internalFormat, vizFormat, m_settings.resampleQuality);
1164 // TODO use cache of sync + water level
1165 m_vizBuffers->Create(2000, false, false);
1166 m_vizInitialized = false;
1171 // resample buffers for sink
1172 if (m_sinkBuffers &&
1173 (!CompareFormat(m_sinkBuffers->m_format,m_sinkFormat) ||
1174 !CompareFormat(m_sinkBuffers->m_inputFormat, sinkInputFormat) ||
1175 m_sinkBuffers->m_format.m_frames != m_sinkFormat.m_frames))
1177 m_discardBufferPools.push_back(m_sinkBuffers);
1178 m_sinkBuffers = NULL;
1182 m_sinkBuffers = new CActiveAEBufferPoolResample(sinkInputFormat, m_sinkFormat, m_settings.resampleQuality);
1183 m_sinkBuffers->Create(MAX_WATER_LEVEL*1000, true, false);
1187 if (!CompareFormat(oldInternalFormat, m_internalFormat))
1189 if (m_settings.guisoundmode == AE_SOUND_ALWAYS ||
1190 (m_settings.guisoundmode == AE_SOUND_IDLE && m_streams.empty()))
1192 std::vector<CActiveAESound*>::iterator it;
1193 for (it = m_sounds.begin(); it != m_sounds.end(); ++it)
1195 (*it)->SetConverted(false);
1198 m_sounds_playing.clear();
1201 ClearDiscardedBuffers();
1205 CActiveAEStream* CActiveAE::CreateStream(MsgStreamNew *streamMsg)
1207 // we only can handle a single pass through stream
1208 bool hasRawStream = false;
1209 bool hasStream = false;
1210 std::list<CActiveAEStream*>::iterator it;
1211 for(it = m_streams.begin(); it != m_streams.end(); ++it)
1213 if((*it)->IsDrained())
1215 if(AE_IS_RAW((*it)->m_format.m_dataFormat))
1216 hasRawStream = true;
1219 if (hasRawStream || (hasStream && AE_IS_RAW(streamMsg->format.m_dataFormat)))
1224 // create the stream
1225 CActiveAEStream *stream;
1226 stream = new CActiveAEStream(&streamMsg->format);
1227 stream->m_streamPort = new CActiveAEDataProtocol("stream",
1228 &stream->m_inMsgEvent, &m_outMsgEvent);
1230 // create buffer pool
1231 stream->m_inputBuffers = NULL; // create in Configure when we know the sink format
1232 stream->m_resampleBuffers = NULL; // create in Configure when we know the sink format
1233 stream->m_statsLock = m_stats.GetLock();
1234 stream->m_fadingSamples = 0;
1235 stream->m_started = false;
1237 if (streamMsg->options & AESTREAM_PAUSED)
1238 stream->m_paused = true;
1240 if (streamMsg->options & AESTREAM_FORCE_RESAMPLE)
1241 stream->m_forceResampler = true;
1243 m_streams.push_back(stream);
1248 void CActiveAE::DiscardStream(CActiveAEStream *stream)
1250 std::list<CActiveAEStream*>::iterator it;
1251 for (it=m_streams.begin(); it!=m_streams.end(); )
1253 if (stream == (*it))
1255 while (!(*it)->m_processingSamples.empty())
1257 (*it)->m_processingSamples.front()->Return();
1258 (*it)->m_processingSamples.pop_front();
1260 m_discardBufferPools.push_back((*it)->m_inputBuffers);
1261 m_discardBufferPools.push_back((*it)->m_resampleBuffers);
1262 CLog::Log(LOGDEBUG, "CActiveAE::DiscardStream - audio stream deleted");
1263 delete (*it)->m_streamPort;
1265 it = m_streams.erase(it);
1271 ClearDiscardedBuffers();
1274 void CActiveAE::SFlushStream(CActiveAEStream *stream)
1276 while (!stream->m_processingSamples.empty())
1278 stream->m_processingSamples.front()->Return();
1279 stream->m_processingSamples.pop_front();
1281 stream->m_resampleBuffers->Flush();
1282 stream->m_streamPort->Purge();
1283 stream->m_bufferedTime = 0.0;
1284 stream->m_paused = false;
1286 // flush the engine if we only have a single stream
1287 if (m_streams.size() == 1)
1293 void CActiveAE::FlushEngine()
1296 m_sinkBuffers->Flush();
1298 m_vizBuffers->Flush();
1300 // send message to sink
1302 if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::FLUSH,
1305 bool success = reply->signal == CSinkControlProtocol::ACC;
1308 CLog::Log(LOGERROR, "ActiveAE::%s - returned error on flush", __FUNCTION__);
1315 CLog::Log(LOGERROR, "ActiveAE::%s - failed to flush", __FUNCTION__);
1318 m_stats.Reset(m_sinkFormat.m_sampleRate);
1321 void CActiveAE::ClearDiscardedBuffers()
1323 std::list<CActiveAEBufferPool*>::iterator it;
1324 for (it=m_discardBufferPools.begin(); it!=m_discardBufferPools.end(); ++it)
1326 CActiveAEBufferPoolResample *rbuf = dynamic_cast<CActiveAEBufferPoolResample*>(*it);
1331 // if all buffers have returned, we can delete the buffer pool
1332 if ((*it)->m_allSamples.size() == (*it)->m_freeSamples.size())
1335 CLog::Log(LOGDEBUG, "CActiveAE::ClearDiscardedBuffers - buffer pool deleted");
1336 m_discardBufferPools.erase(it);
1342 void CActiveAE::SStopSound(CActiveAESound *sound)
1344 std::list<SoundState>::iterator it;
1345 for (it=m_sounds_playing.begin(); it!=m_sounds_playing.end(); ++it)
1347 if (it->sound == sound)
1349 m_sounds_playing.erase(it);
1355 void CActiveAE::DiscardSound(CActiveAESound *sound)
1359 std::vector<CActiveAESound*>::iterator it;
1360 for (it=m_sounds.begin(); it!=m_sounds.end(); ++it)
1370 void CActiveAE::ChangeResamplers()
1372 std::list<CActiveAEStream*>::iterator it;
1373 for(it=m_streams.begin(); it!=m_streams.end(); ++it)
1375 bool normalize = true;
1376 if (((*it)->m_resampleBuffers->m_format.m_channelLayout.Count() <
1377 (*it)->m_resampleBuffers->m_inputFormat.m_channelLayout.Count()) &&
1378 !m_settings.normalizelevels)
1381 if ((*it)->m_resampleBuffers && (*it)->m_resampleBuffers->m_resampler &&
1382 (((*it)->m_resampleBuffers->m_resampleQuality != m_settings.resampleQuality) ||
1383 (((*it)->m_resampleBuffers->m_stereoUpmix != m_settings.stereoupmix)) ||
1384 ((*it)->m_resampleBuffers->m_normalize != normalize)))
1386 (*it)->m_resampleBuffers->m_changeResampler = true;
1388 (*it)->m_resampleBuffers->m_resampleQuality = m_settings.resampleQuality;
1389 (*it)->m_resampleBuffers->m_stereoUpmix = m_settings.stereoupmix;
1390 (*it)->m_resampleBuffers->m_normalize = normalize;
1394 void CActiveAE::ApplySettingsToFormat(AEAudioFormat &format, AudioSettings &settings, int *mode)
1396 int oldMode = m_mode;
1401 if (AE_IS_RAW(format.m_dataFormat))
1403 if ((format.m_dataFormat == AE_FMT_AC3 && !settings.ac3passthrough) ||
1404 (format.m_dataFormat == AE_FMT_EAC3 && !settings.eac3passthrough) ||
1405 (format.m_dataFormat == AE_FMT_TRUEHD && !settings.truehdpassthrough) ||
1406 (format.m_dataFormat == AE_FMT_DTS && !settings.dtspassthrough) ||
1407 (format.m_dataFormat == AE_FMT_DTSHD && !settings.dtshdpassthrough))
1409 CLog::Log(LOGERROR, "CActiveAE::ApplySettingsToFormat - input audio format is wrong");
1415 else if (settings.channels <= AE_CH_LAYOUT_2_0 && // no multichannel pcm
1416 settings.passthrough &&
1417 settings.ac3passthrough &&
1418 settings.ac3transcode &&
1419 !m_streams.empty() &&
1420 (format.m_channelLayout.Count() > 2 || settings.stereoupmix))
1422 format.m_dataFormat = AE_FMT_AC3;
1423 format.m_sampleRate = 48000;
1424 format.m_encodedRate = 48000;
1425 format.m_channelLayout = AE_CH_LAYOUT_2_0;
1427 *mode = MODE_TRANSCODE;
1431 format.m_dataFormat = AE_FMT_FLOAT;
1432 // consider user channel layout for those cases
1433 // 1. input stream is multichannel
1434 // 2. stereo upmix is selected
1436 if ((format.m_channelLayout.Count() > 2) ||
1437 settings.stereoupmix ||
1438 (settings.config == AE_CONFIG_FIXED))
1440 CAEChannelInfo stdLayout;
1441 switch (settings.channels)
1444 case 0: stdLayout = AE_CH_LAYOUT_2_0; break;
1445 case 1: stdLayout = AE_CH_LAYOUT_2_0; break;
1446 case 2: stdLayout = AE_CH_LAYOUT_2_1; break;
1447 case 3: stdLayout = AE_CH_LAYOUT_3_0; break;
1448 case 4: stdLayout = AE_CH_LAYOUT_3_1; break;
1449 case 5: stdLayout = AE_CH_LAYOUT_4_0; break;
1450 case 6: stdLayout = AE_CH_LAYOUT_4_1; break;
1451 case 7: stdLayout = AE_CH_LAYOUT_5_0; break;
1452 case 8: stdLayout = AE_CH_LAYOUT_5_1; break;
1453 case 9: stdLayout = AE_CH_LAYOUT_7_0; break;
1454 case 10: stdLayout = AE_CH_LAYOUT_7_1; break;
1457 if (m_settings.config == AE_CONFIG_FIXED || (settings.stereoupmix && format.m_channelLayout.Count() <= 2))
1458 format.m_channelLayout = stdLayout;
1459 else if (m_extKeepConfig && (settings.config == AE_CONFIG_AUTO) && (oldMode != MODE_RAW))
1460 format.m_channelLayout = m_internalFormat.m_channelLayout;
1462 format.m_channelLayout.ResolveChannels(stdLayout);
1464 // don't change from multi to stereo in AUTO mode
1465 else if ((settings.config == AE_CONFIG_AUTO) &&
1466 m_stats.GetWaterLevel() > 0 && m_internalFormat.m_channelLayout.Count() > 2)
1468 format.m_channelLayout = m_internalFormat.m_channelLayout;
1471 if (m_sink.GetDeviceType(m_settings.device) == AE_DEVTYPE_IEC958)
1473 if (format.m_sampleRate > m_settings.samplerate)
1475 format.m_sampleRate = m_settings.samplerate;
1476 CLog::Log(LOGINFO, "CActiveAE::ApplySettings - limit samplerate for SPDIF to %d", format.m_sampleRate);
1478 format.m_channelLayout = AE_CH_LAYOUT_2_0;
1481 if (m_settings.config == AE_CONFIG_FIXED)
1483 format.m_sampleRate = m_settings.samplerate;
1484 CLog::Log(LOGINFO, "CActiveAE::ApplySettings - Forcing samplerate to %d", format.m_sampleRate);
1487 // sinks may not support mono
1488 if (format.m_channelLayout.Count() == 1)
1490 format.m_channelLayout = AE_CH_LAYOUT_2_0;
1495 bool CActiveAE::NeedReconfigureBuffers()
1497 AEAudioFormat newFormat = GetInputFormat();
1498 ApplySettingsToFormat(newFormat, m_settings);
1500 if (newFormat.m_dataFormat != m_sinkRequestFormat.m_dataFormat ||
1501 newFormat.m_channelLayout != m_sinkRequestFormat.m_channelLayout ||
1502 newFormat.m_sampleRate != m_sinkRequestFormat.m_sampleRate)
1508 bool CActiveAE::NeedReconfigureSink()
1510 AEAudioFormat newFormat = GetInputFormat();
1511 ApplySettingsToFormat(newFormat, m_settings);
1513 std::string device = AE_IS_RAW(newFormat.m_dataFormat) ? m_settings.passthoughdevice : m_settings.device;
1515 CAESinkFactory::ParseDevice(device, driver);
1517 if (!CompareFormat(newFormat, m_sinkFormat) ||
1518 m_currDevice.compare(device) != 0 ||
1519 m_settings.driver.compare(driver) != 0)
1525 bool CActiveAE::InitSink()
1528 config.format = m_sinkRequestFormat;
1529 config.stats = &m_stats;
1530 config.device = AE_IS_RAW(m_sinkRequestFormat.m_dataFormat) ? &m_settings.passthoughdevice :
1533 // send message to sink
1535 if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::CONFIGURE,
1538 &config, sizeof(config)))
1540 bool success = reply->signal == CSinkControlProtocol::ACC;
1544 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
1549 data = (SinkReply*)reply->data;
1552 m_sinkFormat = data->format;
1553 m_sinkHasVolume = data->hasVolume;
1554 m_stats.SetSinkCacheTotal(data->cacheTotal);
1555 m_stats.SetSinkLatency(data->latency);
1561 CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__);
1562 m_stats.SetSinkCacheTotal(0);
1563 m_stats.SetSinkLatency(0);
1568 m_inMsgEvent.Reset();
1572 void CActiveAE::DrainSink()
1574 // send message to sink
1576 if (m_sink.m_dataPort.SendOutMessageSync(CSinkDataProtocol::DRAIN,
1580 bool success = reply->signal == CSinkDataProtocol::ACC;
1584 CLog::Log(LOGERROR, "ActiveAE::%s - returned error on drain", __FUNCTION__);
1592 CLog::Log(LOGERROR, "ActiveAE::%s - failed to drain", __FUNCTION__);
1598 void CActiveAE::UnconfigureSink()
1600 // send message to sink
1602 if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::UNCONFIGURE,
1606 bool success = reply->signal == CSinkControlProtocol::ACC;
1609 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
1616 CLog::Log(LOGERROR, "ActiveAE::%s - failed to unconfigure", __FUNCTION__);
1620 // make sure we open sink on next configure
1623 m_inMsgEvent.Reset();
1627 bool CActiveAE::RunStages()
1631 // serve input streams
1632 std::list<CActiveAEStream*>::iterator it;
1633 for (it = m_streams.begin(); it != m_streams.end(); ++it)
1635 if ((*it)->m_resampleBuffers && !(*it)->m_paused)
1636 busy = (*it)->m_resampleBuffers->ResampleBuffers();
1637 else if ((*it)->m_resampleBuffers &&
1638 ((*it)->m_resampleBuffers->m_inputSamples.size() > (*it)->m_resampleBuffers->m_allSamples.size() * 0.5))
1640 CSingleLock lock((*it)->m_streamLock);
1641 (*it)->m_streamIsBuffering = false;
1644 // provide buffers to stream
1645 float time = m_stats.GetCacheTime((*it));
1646 CSampleBuffer *buffer;
1647 if (!(*it)->m_drain)
1649 while (time < MAX_CACHE_LEVEL && !(*it)->m_inputBuffers->m_freeSamples.empty())
1651 buffer = (*it)->m_inputBuffers->GetFreeBuffer();
1652 (*it)->m_processingSamples.push_back(buffer);
1653 (*it)->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMBUFFER, &buffer, sizeof(CSampleBuffer*));
1654 (*it)->IncFreeBuffers();
1655 time += (float)buffer->pkt->max_nb_samples / buffer->pkt->config.sample_rate;
1660 if ((*it)->m_resampleBuffers->m_inputSamples.empty() &&
1661 (*it)->m_resampleBuffers->m_outputSamples.empty() &&
1662 (*it)->m_processingSamples.empty())
1664 (*it)->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMDRAINED);
1665 (*it)->m_drain = false;
1666 (*it)->m_resampleBuffers->m_drain = false;
1667 (*it)->m_started = false;
1669 // set variables being polled via stream interface
1670 CSingleLock lock((*it)->m_streamLock);
1671 if ((*it)->m_streamSlave)
1673 CActiveAEStream *slave = (CActiveAEStream*)((*it)->m_streamSlave);
1674 slave->m_paused = false;
1676 // TODO: find better solution for this
1677 // gapless bites audiophile
1678 if (m_settings.config == AE_CONFIG_MATCH)
1679 Configure(&slave->m_format);
1681 (*it)->m_streamSlave = NULL;
1683 (*it)->m_streamDrained = true;
1684 (*it)->m_streamDraining = false;
1685 (*it)->m_streamFading = false;
1690 if (m_stats.GetWaterLevel() < MAX_WATER_LEVEL &&
1691 (m_mode != MODE_TRANSCODE || (m_encoderBuffers && !m_encoderBuffers->m_freeSamples.empty())))
1693 // mix streams and sounds sounds
1694 if (m_mode != MODE_RAW)
1696 CSampleBuffer *out = NULL;
1697 if (!m_sounds_playing.empty() && m_streams.empty())
1699 if (m_silenceBuffers && !m_silenceBuffers->m_freeSamples.empty())
1701 out = m_silenceBuffers->GetFreeBuffer();
1702 for (int i=0; i<out->pkt->planes; i++)
1704 memset(out->pkt->data[i], 0, out->pkt->linesize);
1706 out->pkt->nb_samples = out->pkt->max_nb_samples;
1711 std::list<CActiveAEStream*>::iterator it;
1713 // if we deal with more than a single stream, all streams
1714 // must provide samples for mixing
1715 bool allStreamsReady = true;
1716 for (it = m_streams.begin(); it != m_streams.end(); ++it)
1718 if ((*it)->m_paused || !(*it)->m_started || !(*it)->m_resampleBuffers)
1721 if ((*it)->m_resampleBuffers->m_outputSamples.empty())
1722 allStreamsReady = false;
1725 bool needClamp = false;
1726 for (it = m_streams.begin(); it != m_streams.end() && allStreamsReady; ++it)
1728 if ((*it)->m_paused || !(*it)->m_resampleBuffers)
1731 if (!(*it)->m_resampleBuffers->m_outputSamples.empty())
1733 (*it)->m_started = true;
1737 out = (*it)->m_resampleBuffers->m_outputSamples.front();
1738 (*it)->m_resampleBuffers->m_outputSamples.pop_front();
1740 int nb_floats = out->pkt->nb_samples * out->pkt->config.channels / out->pkt->planes;
1742 float fadingStep = 0.0f;
1745 if ((*it)->m_fadingSamples == -1)
1747 (*it)->m_fadingSamples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1748 (*it)->m_volume = (*it)->m_fadingBase;
1750 if ((*it)->m_fadingSamples > 0)
1752 nb_floats = out->pkt->config.channels / out->pkt->planes;
1753 nb_loops = out->pkt->nb_samples;
1754 float delta = (*it)->m_fadingTarget - (*it)->m_fadingBase;
1755 int samples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1756 fadingStep = delta / samples;
1759 // for stream amplification,
1760 // turned off downmix normalization,
1761 // or if sink format is float (in order to prevent from clipping)
1762 // we need to run on a per sample basis
1763 if ((*it)->m_amplify != 1.0 || !(*it)->m_resampleBuffers->m_normalize || (m_sinkFormat.m_dataFormat == AE_FMT_FLOAT))
1765 nb_floats = out->pkt->config.channels / out->pkt->planes;
1766 nb_loops = out->pkt->nb_samples;
1769 for(int i=0; i<nb_loops; i++)
1771 if ((*it)->m_fadingSamples > 0)
1773 (*it)->m_volume += fadingStep;
1774 (*it)->m_fadingSamples--;
1776 if ((*it)->m_fadingSamples == 0)
1778 // set variables being polled via stream interface
1779 CSingleLock lock((*it)->m_streamLock);
1780 (*it)->m_streamFading = false;
1784 // volume for stream
1785 float volume = (*it)->m_volume * (*it)->m_rgain;
1787 volume *= (*it)->m_limiter.Run((float**)out->pkt->data, out->pkt->config.channels, i*nb_floats, out->pkt->planes > 1);
1789 for(int j=0; j<out->pkt->planes; j++)
1792 CAEUtil::SSEMulArray((float*)out->pkt->data[j]+i*nb_floats, volume, nb_floats);
1794 float* fbuffer = (float*) out->pkt->data[j]+i*nb_floats;
1795 for (int k = 0; k < nb_floats; ++k)
1797 fbuffer[k] *= volume;
1805 CSampleBuffer *mix = NULL;
1806 mix = (*it)->m_resampleBuffers->m_outputSamples.front();
1807 (*it)->m_resampleBuffers->m_outputSamples.pop_front();
1809 int nb_floats = mix->pkt->nb_samples * mix->pkt->config.channels / mix->pkt->planes;
1811 float fadingStep = 0.0f;
1814 if ((*it)->m_fadingSamples == -1)
1816 (*it)->m_fadingSamples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1817 (*it)->m_volume = (*it)->m_fadingBase;
1819 if ((*it)->m_fadingSamples > 0)
1821 nb_floats = mix->pkt->config.channels / mix->pkt->planes;
1822 nb_loops = mix->pkt->nb_samples;
1823 float delta = (*it)->m_fadingTarget - (*it)->m_fadingBase;
1824 int samples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1825 fadingStep = delta / samples;
1828 // for streams amplification of turned off downmix normalization
1829 // we need to run on a per sample basis
1830 if ((*it)->m_amplify != 1.0 || !(*it)->m_resampleBuffers->m_normalize)
1832 nb_floats = out->pkt->config.channels / out->pkt->planes;
1833 nb_loops = out->pkt->nb_samples;
1836 for(int i=0; i<nb_loops; i++)
1838 if ((*it)->m_fadingSamples > 0)
1840 (*it)->m_volume += fadingStep;
1841 (*it)->m_fadingSamples--;
1843 if ((*it)->m_fadingSamples == 0)
1845 // set variables being polled via stream interface
1846 CSingleLock lock((*it)->m_streamLock);
1847 (*it)->m_streamFading = false;
1851 // volume for stream
1852 float volume = (*it)->m_volume * (*it)->m_rgain;
1854 volume *= (*it)->m_limiter.Run((float**)mix->pkt->data, mix->pkt->config.channels, i*nb_floats, mix->pkt->planes > 1);
1856 for(int j=0; j<out->pkt->planes && j<mix->pkt->planes; j++)
1858 float *dst = (float*)out->pkt->data[j]+i*nb_floats;
1859 float *src = (float*)mix->pkt->data[j]+i*nb_floats;
1861 CAEUtil::SSEMulAddArray(dst, src, volume, nb_floats);
1862 for (int k = 0; k < nb_floats; ++k)
1864 if (fabs(dst[k]) > 1.0f)
1871 for (int k = 0; k < nb_floats; ++k)
1873 dst[k] += src[k] * volume;
1874 if (fabs(dst[k]) > 1.0f)
1886 // finally clamp samples
1887 if(out && needClamp)
1889 int nb_floats = out->pkt->nb_samples * out->pkt->config.channels / out->pkt->planes;
1890 for(int i=0; i<out->pkt->planes; i++)
1892 CAEUtil::ClampArray((float*)out->pkt->data[i], nb_floats);
1896 // process output buffer, gui sounds, encode, viz
1901 CSingleLock lock(m_vizLock);
1902 if (m_audioCallback && m_vizBuffers && !m_streams.empty())
1904 if (!m_vizInitialized)
1906 m_audioCallback->OnInitialize(2, m_vizBuffers->m_format.m_sampleRate, 32);
1907 m_vizInitialized = true;
1910 if (!m_vizBuffersInput->m_freeSamples.empty())
1912 // copy the samples into the viz input buffer
1913 CSampleBuffer *viz = m_vizBuffersInput->GetFreeBuffer();
1914 int samples = std::min(512, out->pkt->nb_samples);
1915 int bytes = samples * out->pkt->config.channels / out->pkt->planes * out->pkt->bytes_per_sample;
1916 for(int i= 0; i < out->pkt->planes; i++)
1918 memcpy(viz->pkt->data[i], out->pkt->data[i], bytes);
1920 viz->pkt->nb_samples = samples;
1921 m_vizBuffers->m_inputSamples.push_back(viz);
1924 CLog::Log(LOGWARNING,"ActiveAE::%s - viz ran out of free buffers", __FUNCTION__);
1925 unsigned int now = XbmcThreads::SystemClockMillis();
1926 unsigned int timestamp = now + m_stats.GetDelay() * 1000;
1927 busy |= m_vizBuffers->ResampleBuffers(timestamp);
1928 while(!m_vizBuffers->m_outputSamples.empty())
1930 CSampleBuffer *buf = m_vizBuffers->m_outputSamples.front();
1931 if ((now - buf->timestamp) & 0x80000000)
1936 samples = std::min(512, buf->pkt->nb_samples);
1937 m_audioCallback->OnAudioData((float*)(buf->pkt->data[0]), samples);
1939 m_vizBuffers->m_outputSamples.pop_front();
1943 else if (m_vizBuffers)
1944 m_vizBuffers->Flush();
1948 MixSounds(*(out->pkt));
1949 if (!m_sinkHasVolume || m_muted)
1950 Deamplify(*(out->pkt));
1952 if (m_mode == MODE_TRANSCODE && m_encoder)
1954 CSampleBuffer *buf = m_encoderBuffers->GetFreeBuffer();
1955 m_encoder->Encode(out->pkt->data[0], out->pkt->planes*out->pkt->linesize,
1956 buf->pkt->data[0], buf->pkt->planes*buf->pkt->linesize);
1957 buf->pkt->nb_samples = buf->pkt->max_nb_samples;
1967 m_stats.AddSamples(out->pkt->nb_samples, m_streams);
1968 m_sinkBuffers->m_inputSamples.push_back(out);
1974 std::list<CActiveAEStream*>::iterator it;
1975 CSampleBuffer *buffer;
1976 for (it = m_streams.begin(); it != m_streams.end(); ++it)
1978 if (!(*it)->m_resampleBuffers->m_outputSamples.empty() && !(*it)->m_paused)
1980 buffer = (*it)->m_resampleBuffers->m_outputSamples.front();
1981 (*it)->m_resampleBuffers->m_outputSamples.pop_front();
1982 m_stats.AddSamples(buffer->pkt->nb_samples, m_streams);
1983 m_sinkBuffers->m_inputSamples.push_back(buffer);
1989 // serve sink buffers
1990 busy |= m_sinkBuffers->ResampleBuffers();
1991 while(!m_sinkBuffers->m_outputSamples.empty())
1993 CSampleBuffer *out = NULL;
1994 out = m_sinkBuffers->m_outputSamples.front();
1995 m_sinkBuffers->m_outputSamples.pop_front();
1996 m_sink.m_dataPort.SendOutMessage(CSinkDataProtocol::SAMPLE,
1997 &out, sizeof(CSampleBuffer*));
2004 bool CActiveAE::HasWork()
2006 if (!m_sounds_playing.empty())
2008 if (!m_sinkBuffers->m_inputSamples.empty())
2010 if (!m_sinkBuffers->m_outputSamples.empty())
2013 std::list<CActiveAEStream*>::iterator it;
2014 for (it = m_streams.begin(); it != m_streams.end(); ++it)
2016 if (!(*it)->m_resampleBuffers->m_inputSamples.empty())
2018 if (!(*it)->m_resampleBuffers->m_outputSamples.empty())
2020 if (!(*it)->m_processingSamples.empty())
2027 void CActiveAE::MixSounds(CSoundPacket &dstSample)
2029 if (m_sounds_playing.empty())
2034 float *sample_buffer;
2035 int max_samples = dstSample.nb_samples;
2037 std::list<SoundState>::iterator it;
2038 for (it = m_sounds_playing.begin(); it != m_sounds_playing.end(); )
2040 if (!it->sound->IsConverted())
2041 ResampleSound(it->sound);
2042 int available_samples = it->sound->GetSound(false)->nb_samples - it->samples_played;
2043 int mix_samples = std::min(max_samples, available_samples);
2044 int start = it->samples_played *
2045 m_dllAvUtil.av_get_bytes_per_sample(it->sound->GetSound(false)->config.fmt) *
2046 it->sound->GetSound(false)->config.channels /
2047 it->sound->GetSound(false)->planes;
2049 for(int j=0; j<dstSample.planes; j++)
2051 volume = it->sound->GetVolume();
2052 out = (float*)dstSample.data[j];
2053 sample_buffer = (float*)(it->sound->GetSound(false)->data[j]+start);
2054 int nb_floats = mix_samples * dstSample.config.channels / dstSample.planes;
2056 CAEUtil::SSEMulAddArray(out, sample_buffer, volume, nb_floats);
2058 for (int k = 0; k < nb_floats; ++k)
2059 *out++ += *sample_buffer++ * volume;
2063 it->samples_played += mix_samples;
2065 // no more frames, so remove it from the list
2066 if (it->samples_played >= it->sound->GetSound(false)->nb_samples)
2068 it = m_sounds_playing.erase(it);
2075 void CActiveAE::Deamplify(CSoundPacket &dstSample)
2077 if (m_volumeScaled < 1.0 || m_muted)
2080 int nb_floats = dstSample.nb_samples * dstSample.config.channels / dstSample.planes;
2081 float volume = m_muted ? 0.0f : m_volumeScaled;
2083 for(int j=0; j<dstSample.planes; j++)
2085 buffer = (float*)dstSample.data[j];
2087 CAEUtil::SSEMulArray(buffer, volume, nb_floats);
2089 float *fbuffer = buffer;
2090 for (int i = 0; i < nb_floats; i++)
2091 *fbuffer++ *= volume;
2097 //-----------------------------------------------------------------------------
2099 //-----------------------------------------------------------------------------
2101 void CActiveAE::LoadSettings()
2103 m_settings.device = CSettings::Get().GetString("audiooutput.audiodevice");
2104 m_settings.passthoughdevice = CSettings::Get().GetString("audiooutput.passthroughdevice");
2106 m_settings.config = CSettings::Get().GetInt("audiooutput.config");
2107 m_settings.channels = (m_sink.GetDeviceType(m_settings.device) == AE_DEVTYPE_IEC958) ? AE_CH_LAYOUT_2_0 : CSettings::Get().GetInt("audiooutput.channels");
2108 m_settings.samplerate = CSettings::Get().GetInt("audiooutput.samplerate");
2110 m_settings.stereoupmix = IsSettingVisible("audiooutput.stereoupmix") ? CSettings::Get().GetBool("audiooutput.stereoupmix") : false;
2111 m_settings.normalizelevels = CSettings::Get().GetBool("audiooutput.normalizelevels");
2112 m_settings.guisoundmode = CSettings::Get().GetInt("audiooutput.guisoundmode");
2114 m_settings.passthrough = m_settings.config == AE_CONFIG_FIXED ? false : CSettings::Get().GetBool("audiooutput.passthrough");
2115 if (!m_sink.HasPassthroughDevice())
2116 m_settings.passthrough = false;
2117 m_settings.ac3passthrough = CSettings::Get().GetBool("audiooutput.ac3passthrough");
2118 m_settings.ac3transcode = CSettings::Get().GetBool("audiooutput.ac3transcode");
2119 m_settings.eac3passthrough = CSettings::Get().GetBool("audiooutput.eac3passthrough");
2120 m_settings.truehdpassthrough = CSettings::Get().GetBool("audiooutput.truehdpassthrough");
2121 m_settings.dtspassthrough = CSettings::Get().GetBool("audiooutput.dtspassthrough");
2122 m_settings.dtshdpassthrough = CSettings::Get().GetBool("audiooutput.dtshdpassthrough");
2124 m_settings.resampleQuality = static_cast<AEQuality>(CSettings::Get().GetInt("audiooutput.processquality"));
2127 bool CActiveAE::Initialize()
2129 if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllAvFormat.Load())
2131 CLog::Log(LOGERROR,"CActiveAE::Initialize - failed to load ffmpeg libraries");
2134 m_dllAvFormat.av_register_all();
2138 if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::INIT,
2142 bool success = reply->signal == CActiveAEControlProtocol::ACC;
2146 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
2153 CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__);
2158 // hook into windowing for receiving display reset events
2159 #if defined(HAS_GLX) || defined(TARGET_DARWIN)
2160 g_Windowing.Register(this);
2163 m_inMsgEvent.Reset();
2167 void CActiveAE::EnumerateOutputDevices(AEDeviceList &devices, bool passthrough)
2169 m_sink.EnumerateOutputDevices(devices, passthrough);
2172 std::string CActiveAE::GetDefaultDevice(bool passthrough)
2174 return m_sink.GetDefaultDevice(passthrough);
2177 void CActiveAE::OnSettingsChange(const std::string& setting)
2179 if (setting == "audiooutput.passthroughdevice" ||
2180 setting == "audiooutput.audiodevice" ||
2181 setting == "audiooutput.config" ||
2182 setting == "audiooutput.ac3passthrough" ||
2183 setting == "audiooutput.ac3transcode" ||
2184 setting == "audiooutput.eac3passthrough" ||
2185 setting == "audiooutput.dtspassthrough" ||
2186 setting == "audiooutput.truehdpassthrough" ||
2187 setting == "audiooutput.dtshdpassthrough" ||
2188 setting == "audiooutput.channels" ||
2189 setting == "audiooutput.stereoupmix" ||
2190 setting == "audiooutput.streamsilence" ||
2191 setting == "audiooutput.processquality" ||
2192 setting == "audiooutput.passthrough" ||
2193 setting == "audiooutput.samplerate" ||
2194 setting == "audiooutput.normalizelevels" ||
2195 setting == "audiooutput.guisoundmode")
2197 m_controlPort.SendOutMessage(CActiveAEControlProtocol::RECONFIGURE);
2201 bool CActiveAE::SupportsRaw(AEDataFormat format, int samplerate)
2203 if (!m_sink.SupportsFormat(CSettings::Get().GetString("audiooutput.passthroughdevice"), format, samplerate))
2209 bool CActiveAE::SupportsSilenceTimeout()
2214 bool CActiveAE::SupportsQualityLevel(enum AEQuality level)
2216 if (level == AE_QUALITY_LOW || level == AE_QUALITY_MID || level == AE_QUALITY_HIGH)
2222 bool CActiveAE::IsSettingVisible(const std::string &settingId)
2224 if (settingId == "audiooutput.samplerate")
2226 if (m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) == AE_DEVTYPE_IEC958)
2228 if (CSettings::Get().GetInt("audiooutput.config") == AE_CONFIG_FIXED)
2231 else if (settingId == "audiooutput.channels")
2233 if (m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) != AE_DEVTYPE_IEC958)
2236 else if (settingId == "audiooutput.passthrough")
2238 if (m_sink.HasPassthroughDevice() && CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED)
2241 else if (settingId == "audiooutput.truehdpassthrough")
2243 if (m_sink.SupportsFormat(CSettings::Get().GetString("audiooutput.passthroughdevice"), AE_FMT_TRUEHD, 192000) &&
2244 CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED)
2247 else if (settingId == "audiooutput.dtshdpassthrough")
2249 if (m_sink.SupportsFormat(CSettings::Get().GetString("audiooutput.passthroughdevice"), AE_FMT_DTSHD, 192000) &&
2250 CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED)
2253 else if (settingId == "audiooutput.eac3passthrough")
2255 if (m_sink.SupportsFormat(CSettings::Get().GetString("audiooutput.passthroughdevice"), AE_FMT_EAC3, 192000) &&
2256 CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED)
2259 else if (settingId == "audiooutput.stereoupmix")
2261 if (m_sink.HasPassthroughDevice() ||
2262 CSettings::Get().GetInt("audiooutput.channels") > AE_CH_LAYOUT_2_0)
2265 else if (settingId == "audiooutput.ac3transcode")
2267 if (m_sink.HasPassthroughDevice() &&
2268 CSettings::Get().GetBool("audiooutput.ac3passthrough") &&
2269 CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED &&
2270 (CSettings::Get().GetInt("audiooutput.channels") <= AE_CH_LAYOUT_2_0 || m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) == AE_DEVTYPE_IEC958))
2276 void CActiveAE::Shutdown()
2281 bool CActiveAE::Suspend()
2283 return m_controlPort.SendOutMessage(CActiveAEControlProtocol::SUSPEND);
2286 bool CActiveAE::Resume()
2289 if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::INIT,
2293 bool success = reply->signal == CActiveAEControlProtocol::ACC;
2297 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
2303 CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__);
2307 m_inMsgEvent.Reset();
2311 bool CActiveAE::IsSuspended()
2313 return m_stats.IsSuspended();
2316 float CActiveAE::GetVolume()
2321 void CActiveAE::SetVolume(const float volume)
2323 m_aeVolume = std::max( 0.0f, std::min(1.0f, volume));
2324 m_controlPort.SendOutMessage(CActiveAEControlProtocol::VOLUME, &m_aeVolume, sizeof(float));
2327 void CActiveAE::SetMute(const bool enabled)
2329 m_aeMuted = enabled;
2330 m_controlPort.SendOutMessage(CActiveAEControlProtocol::MUTE, &m_aeMuted, sizeof(bool));
2333 bool CActiveAE::IsMuted()
2338 void CActiveAE::SetSoundMode(const int mode)
2343 void CActiveAE::KeepConfiguration(unsigned int millis)
2345 unsigned int timeMs = millis;
2346 m_controlPort.SendOutMessage(CActiveAEControlProtocol::KEEPCONFIG, &timeMs, sizeof(unsigned int));
2349 void CActiveAE::DeviceChange()
2351 m_controlPort.SendOutMessage(CActiveAEControlProtocol::DEVICECHANGE);
2354 void CActiveAE::OnLostDevice()
2357 if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::DISPLAYLOST,
2361 bool success = reply->signal == CActiveAEControlProtocol::ACC;
2365 CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
2370 CLog::Log(LOGERROR, "ActiveAE::%s - timed out", __FUNCTION__);
2374 void CActiveAE::OnResetDevice()
2376 m_controlPort.SendOutMessage(CActiveAEControlProtocol::DISPLAYRESET);
2379 void CActiveAE::OnAppFocusChange(bool focus)
2381 m_controlPort.SendOutMessage(CActiveAEControlProtocol::APPFOCUSED, &focus, sizeof(focus));
2384 //-----------------------------------------------------------------------------
2386 //-----------------------------------------------------------------------------
2388 uint8_t **CActiveAE::AllocSoundSample(SampleConfig &config, int &samples, int &bytes_per_sample, int &planes, int &linesize)
2391 planes = m_dllAvUtil.av_sample_fmt_is_planar(config.fmt) ? config.channels : 1;
2392 buffer = new uint8_t*[planes];
2394 // align buffer to 16 in order to be compatible with sse in CAEConvert
2395 m_dllAvUtil.av_samples_alloc(buffer, &linesize, config.channels,
2396 samples, config.fmt, 16);
2397 bytes_per_sample = m_dllAvUtil.av_get_bytes_per_sample(config.fmt);
2401 void CActiveAE::FreeSoundSample(uint8_t **data)
2403 m_dllAvUtil.av_freep(data);
2407 bool CActiveAE::CompareFormat(AEAudioFormat &lhs, AEAudioFormat &rhs)
2409 if (lhs.m_channelLayout != rhs.m_channelLayout ||
2410 lhs.m_dataFormat != rhs.m_dataFormat ||
2411 lhs.m_sampleRate != rhs.m_sampleRate)
2417 //-----------------------------------------------------------------------------
2419 //-----------------------------------------------------------------------------
2422 * load sound from an audio file and store original format
2423 * register the sound in ActiveAE
2424 * later when the engine is idle it will convert the sound to sink format
2427 #define SOUNDBUFFER_SIZE 20480
2429 IAESound *CActiveAE::MakeSound(const std::string& file)
2431 AVFormatContext *fmt_ctx = NULL;
2432 AVCodecContext *dec_ctx = NULL;
2433 AVIOContext *io_ctx;
2434 AVInputFormat *io_fmt;
2435 AVCodec *dec = NULL;
2436 CActiveAESound *sound = NULL;
2437 SampleConfig config;
2439 sound = new CActiveAESound(file);
2440 if (!sound->Prepare())
2445 int fileSize = sound->GetFileSize();
2447 fmt_ctx = m_dllAvFormat.avformat_alloc_context();
2448 unsigned char* buffer = (unsigned char*)m_dllAvUtil.av_malloc(SOUNDBUFFER_SIZE+FF_INPUT_BUFFER_PADDING_SIZE);
2449 io_ctx = m_dllAvFormat.avio_alloc_context(buffer, SOUNDBUFFER_SIZE, 0,
2450 sound, CActiveAESound::Read, NULL, CActiveAESound::Seek);
2451 io_ctx->max_packet_size = sound->GetChunkSize();
2452 if(io_ctx->max_packet_size)
2453 io_ctx->max_packet_size *= SOUNDBUFFER_SIZE / io_ctx->max_packet_size;
2455 if(!sound->IsSeekPosible())
2456 io_ctx->seekable = 0;
2458 fmt_ctx->pb = io_ctx;
2460 m_dllAvFormat.av_probe_input_buffer(io_ctx, &io_fmt, file.c_str(), NULL, 0, 0);
2463 m_dllAvFormat.avformat_close_input(&fmt_ctx);
2469 if (m_dllAvFormat.avformat_open_input(&fmt_ctx, file.c_str(), NULL, NULL) == 0)
2471 fmt_ctx->flags |= AVFMT_FLAG_NOPARSE;
2472 if (m_dllAvFormat.avformat_find_stream_info(fmt_ctx, NULL) >= 0)
2474 dec_ctx = fmt_ctx->streams[0]->codec;
2475 dec = m_dllAvCodec.avcodec_find_decoder(dec_ctx->codec_id);
2476 config.sample_rate = dec_ctx->sample_rate;
2477 config.channels = dec_ctx->channels;
2478 config.channel_layout = dec_ctx->channel_layout;
2483 m_dllAvFormat.avformat_close_input(&fmt_ctx);
2488 dec_ctx = m_dllAvCodec.avcodec_alloc_context3(dec);
2489 dec_ctx->sample_rate = config.sample_rate;
2490 dec_ctx->channels = config.channels;
2491 if (!config.channel_layout)
2492 config.channel_layout = m_dllAvUtil.av_get_default_channel_layout(config.channels);
2493 dec_ctx->channel_layout = config.channel_layout;
2496 AVFrame *decoded_frame = NULL;
2497 decoded_frame = m_dllAvCodec.avcodec_alloc_frame();
2499 if (m_dllAvCodec.avcodec_open2(dec_ctx, dec, NULL) >= 0)
2504 m_dllAvCodec.av_init_packet(&avpkt);
2506 while (m_dllAvFormat.av_read_frame(fmt_ctx, &avpkt) >= 0)
2509 len = m_dllAvCodec.avcodec_decode_audio4(dec_ctx, decoded_frame, &got_frame, &avpkt);
2512 m_dllAvCodec.avcodec_close(dec_ctx);
2513 m_dllAvUtil.av_free(dec_ctx);
2514 m_dllAvUtil.av_free(&decoded_frame);
2515 m_dllAvFormat.avformat_close_input(&fmt_ctx);
2523 int samples = fileSize / m_dllAvUtil.av_get_bytes_per_sample(dec_ctx->sample_fmt) / config.channels;
2524 config.fmt = dec_ctx->sample_fmt;
2525 config.bits_per_sample = dec_ctx->bits_per_coded_sample;
2526 sound->InitSound(true, config, samples);
2529 sound->StoreSound(true, decoded_frame->extended_data,
2530 decoded_frame->nb_samples, decoded_frame->linesize[0]);
2533 m_dllAvCodec.avcodec_close(dec_ctx);
2536 m_dllAvUtil.av_free(dec_ctx);
2537 m_dllAvUtil.av_free(decoded_frame);
2538 m_dllAvFormat.avformat_close_input(&fmt_ctx);
2543 m_dataPort.SendOutMessage(CActiveAEDataProtocol::NEWSOUND, &sound, sizeof(CActiveAESound*));
2548 void CActiveAE::FreeSound(IAESound *sound)
2550 m_dataPort.SendOutMessage(CActiveAEDataProtocol::FREESOUND, &sound, sizeof(CActiveAESound*));
2553 void CActiveAE::PlaySound(CActiveAESound *sound)
2555 m_dataPort.SendOutMessage(CActiveAEDataProtocol::PLAYSOUND, &sound, sizeof(CActiveAESound*));
2558 void CActiveAE::StopSound(CActiveAESound *sound)
2560 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STOPSOUND, &sound, sizeof(CActiveAESound*));
2564 * resample sounds to destination format for mixing
2565 * destination format is either format of stream or
2566 * default sink format when no stream is playing
2568 void CActiveAE::ResampleSounds()
2570 if (m_settings.guisoundmode == AE_SOUND_OFF ||
2571 (m_settings.guisoundmode == AE_SOUND_IDLE && !m_streams.empty()))
2574 std::vector<CActiveAESound*>::iterator it;
2575 for (it = m_sounds.begin(); it != m_sounds.end(); ++it)
2577 if (!(*it)->IsConverted())
2580 // only do one sound, then yield to main loop
2586 bool CActiveAE::ResampleSound(CActiveAESound *sound)
2588 SampleConfig orig_config, dst_config;
2589 uint8_t **dst_buffer;
2592 if (m_mode == MODE_RAW || m_internalFormat.m_dataFormat == AE_FMT_INVALID)
2595 if (!sound->GetSound(true))
2598 orig_config = sound->GetSound(true)->config;
2600 dst_config.channel_layout = CActiveAEResample::GetAVChannelLayout(m_internalFormat.m_channelLayout);
2601 dst_config.channels = m_internalFormat.m_channelLayout.Count();
2602 dst_config.sample_rate = m_internalFormat.m_sampleRate;
2603 dst_config.fmt = CActiveAEResample::GetAVSampleFormat(m_internalFormat.m_dataFormat);
2604 dst_config.bits_per_sample = CAEUtil::DataFormatToUsedBits(m_internalFormat.m_dataFormat);
2606 CActiveAEResample *resampler = new CActiveAEResample();
2607 resampler->Init(dst_config.channel_layout,
2608 dst_config.channels,
2609 dst_config.sample_rate,
2611 dst_config.bits_per_sample,
2612 orig_config.channel_layout,
2613 orig_config.channels,
2614 orig_config.sample_rate,
2616 orig_config.bits_per_sample,
2620 m_settings.resampleQuality);
2622 dst_samples = resampler->CalcDstSampleCount(sound->GetSound(true)->nb_samples,
2623 m_internalFormat.m_sampleRate,
2624 orig_config.sample_rate);
2626 dst_buffer = sound->InitSound(false, dst_config, dst_samples);
2632 int samples = resampler->Resample(dst_buffer, dst_samples,
2633 sound->GetSound(true)->data,
2634 sound->GetSound(true)->nb_samples,
2637 sound->GetSound(false)->nb_samples = samples;
2640 sound->SetConverted(true);
2644 //-----------------------------------------------------------------------------
2646 //-----------------------------------------------------------------------------
2648 IAEStream *CActiveAE::MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSampleRate, CAEChannelInfo channelLayout, unsigned int options)
2653 //TODO: pass number of samples in audio packet
2655 AEAudioFormat format;
2656 format.m_dataFormat = dataFormat;
2657 format.m_sampleRate = sampleRate;
2658 format.m_encodedRate = encodedSampleRate;
2659 format.m_channelLayout = channelLayout;
2660 format.m_frames = format.m_sampleRate / 10;
2661 format.m_frameSize = format.m_channelLayout.Count() *
2662 (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);
2665 msg.format = format;
2666 msg.options = options;
2669 if (m_dataPort.SendOutMessageSync(CActiveAEDataProtocol::NEWSTREAM,
2671 &msg, sizeof(MsgStreamNew)))
2673 bool success = reply->signal == CActiveAEControlProtocol::ACC;
2676 CActiveAEStream *stream = *(CActiveAEStream**)reply->data;
2683 CLog::Log(LOGERROR, "ActiveAE::%s - could not create stream", __FUNCTION__);
2687 IAEStream *CActiveAE::FreeStream(IAEStream *stream)
2689 m_dataPort.SendOutMessage(CActiveAEDataProtocol::FREESTREAM, &stream, sizeof(IAEStream*));
2693 void CActiveAE::FlushStream(CActiveAEStream *stream)
2696 if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::FLUSHSTREAM,
2698 &stream, sizeof(CActiveAEStream*)))
2700 bool success = reply->signal == CActiveAEControlProtocol::ACC;
2704 CLog::Log(LOGERROR, "CActiveAE::FlushStream - failed");
2709 void CActiveAE::PauseStream(CActiveAEStream *stream, bool pause)
2711 // TODO pause sink, needs api change
2713 m_controlPort.SendOutMessage(CActiveAEControlProtocol::PAUSESTREAM,
2714 &stream, sizeof(CActiveAEStream*));
2716 m_controlPort.SendOutMessage(CActiveAEControlProtocol::RESUMESTREAM,
2717 &stream, sizeof(CActiveAEStream*));
2720 void CActiveAE::SetStreamAmplification(CActiveAEStream *stream, float amplify)
2722 MsgStreamParameter msg;
2723 msg.stream = stream;
2724 msg.parameter.float_par = amplify;
2725 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMAMP,
2726 &msg, sizeof(MsgStreamParameter));
2729 void CActiveAE::SetStreamReplaygain(CActiveAEStream *stream, float rgain)
2731 MsgStreamParameter msg;
2732 msg.stream = stream;
2733 msg.parameter.float_par = rgain;
2734 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMRGAIN,
2735 &msg, sizeof(MsgStreamParameter));
2738 void CActiveAE::SetStreamVolume(CActiveAEStream *stream, float volume)
2740 MsgStreamParameter msg;
2741 msg.stream = stream;
2742 msg.parameter.float_par = volume;
2743 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMVOLUME,
2744 &msg, sizeof(MsgStreamParameter));
2747 void CActiveAE::SetStreamResampleRatio(CActiveAEStream *stream, double ratio)
2749 MsgStreamParameter msg;
2750 msg.stream = stream;
2751 msg.parameter.double_par = ratio;
2752 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMRESAMPLERATIO,
2753 &msg, sizeof(MsgStreamParameter));
2756 void CActiveAE::SetStreamFade(CActiveAEStream *stream, float from, float target, unsigned int millis)
2759 msg.stream = stream;
2761 msg.target = target;
2762 msg.millis = millis;
2763 m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMFADE,
2764 &msg, sizeof(MsgStreamFade));
2767 void CActiveAE::RegisterAudioCallback(IAudioCallback* pCallback)
2769 CSingleLock lock(m_vizLock);
2770 m_audioCallback = pCallback;
2771 m_vizInitialized = false;
2774 void CActiveAE::UnregisterAudioCallback()
2776 CSingleLock lock(m_vizLock);
2777 m_audioCallback = NULL;