Merge pull request #4128 from jmarshallnz/activeae_fixes
[vuplus_xbmc] / xbmc / cores / AudioEngine / Engines / ActiveAE / ActiveAE.cpp
1 /*
2  *      Copyright (C) 2010-2013 Team XBMC
3  *      http://xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  */
20
21 #include "ActiveAE.h"
22
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"
28
29 #include "settings/Settings.h"
30 #include "settings/AdvancedSettings.h"
31 #include "windowing/WindowingFactory.h"
32
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
36 void CEngineStats::Reset(unsigned int sampleRate)
37 {
38   CSingleLock lock(m_lock);
39   m_sinkUpdate = XbmcThreads::SystemClockMillis();
40   m_sinkDelay = 0;
41   m_sinkSampleRate = sampleRate;
42   m_bufferedSamples = 0;
43   m_suspended = false;
44 }
45
46 void CEngineStats::UpdateSinkDelay(double delay, int samples)
47 {
48   CSingleLock lock(m_lock);
49   m_sinkUpdate = XbmcThreads::SystemClockMillis();
50   m_sinkDelay = delay;
51   if (samples > m_bufferedSamples)
52   {
53     CLog::Log(LOGERROR, "CEngineStats::UpdateSinkDelay - inconsistency in buffer time");
54   }
55   else
56     m_bufferedSamples -= samples;
57 }
58
59 void CEngineStats::AddSamples(int samples, std::list<CActiveAEStream*> &streams)
60 {
61   CSingleLock lock(m_lock);
62   m_bufferedSamples += samples;
63
64   //update buffered time of streams
65   std::list<CActiveAEStream*>::iterator it;
66   for(it=streams.begin(); it!=streams.end(); ++it)
67   {
68     float delay = 0;
69     std::deque<CSampleBuffer*>::iterator itBuf;
70     for(itBuf=(*it)->m_processingSamples.begin(); itBuf!=(*it)->m_processingSamples.end(); ++itBuf)
71     {
72       delay += (float)(*itBuf)->pkt->nb_samples / (*itBuf)->pkt->config.sample_rate;
73     }
74     delay += (*it)->m_resampleBuffers->GetDelay();
75     (*it)->m_bufferedTime = delay;
76   }
77 }
78
79 float CEngineStats::GetDelay()
80 {
81   CSingleLock lock(m_lock);
82   unsigned int now = XbmcThreads::SystemClockMillis();
83   float delay = m_sinkDelay - (double)(now-m_sinkUpdate) / 1000;
84   delay += (float)m_bufferedSamples / m_sinkSampleRate;
85
86   if (delay < 0)
87     delay = 0.0;
88
89   return delay;
90 }
91
92 // this is used to sync a/v so we need to add sink latency here
93 float CEngineStats::GetDelay(CActiveAEStream *stream)
94 {
95   CSingleLock lock(m_lock);
96   unsigned int now = XbmcThreads::SystemClockMillis();
97   float delay = m_sinkDelay - (double)(now-m_sinkUpdate) / 1000;
98   delay += m_sinkLatency;
99   delay += (float)m_bufferedSamples / m_sinkSampleRate;
100
101   if (delay < 0)
102     delay = 0.0;
103
104   delay += stream->m_bufferedTime;
105   return delay;
106 }
107
108 float CEngineStats::GetCacheTime(CActiveAEStream *stream)
109 {
110   CSingleLock lock(m_lock);
111   float delay = (float)m_bufferedSamples / m_sinkSampleRate;
112
113   delay += stream->m_bufferedTime;
114   return delay;
115 }
116
117 float CEngineStats::GetCacheTotal(CActiveAEStream *stream)
118 {
119   return MAX_CACHE_LEVEL + m_sinkCacheTotal;
120 }
121
122 float CEngineStats::GetWaterLevel()
123 {
124   return (float)m_bufferedSamples / m_sinkSampleRate;
125 }
126
127 void CEngineStats::SetSuspended(bool state)
128 {
129   CSingleLock lock(m_lock);
130   m_suspended = state;
131 }
132
133 bool CEngineStats::IsSuspended()
134 {
135   CSingleLock lock(m_lock);
136   return m_suspended;
137 }
138
139 CActiveAE::CActiveAE() :
140   CThread("ActiveAE"),
141   m_controlPort("OutputControlPort", &m_inMsgEvent, &m_outMsgEvent),
142   m_dataPort("OutputDataPort", &m_inMsgEvent, &m_outMsgEvent),
143   m_sink(&m_outMsgEvent)
144 {
145   m_sinkBuffers = NULL;
146   m_silenceBuffers = NULL;
147   m_encoderBuffers = NULL;
148   m_vizBuffers = NULL;
149   m_vizBuffersInput = NULL;
150   m_volume = 1.0;
151   m_aeVolume = 1.0;
152   m_muted = false;
153   m_aeMuted = false;
154   m_mode = MODE_PCM;
155   m_encoder = NULL;
156   m_audioCallback = NULL;
157   m_vizInitialized = false;
158   m_sinkHasVolume = false;
159 }
160
161 CActiveAE::~CActiveAE()
162 {
163   Dispose();
164 }
165
166 void CActiveAE::Dispose()
167 {
168 #if defined(HAS_GLX) || defined(TARGET_DARWIN_OSX)
169   g_Windowing.Unregister(this);
170 #endif
171
172   m_bStop = true;
173   m_outMsgEvent.Set();
174   StopThread();
175   m_controlPort.Purge();
176   m_dataPort.Purge();
177   m_sink.Dispose();
178
179   m_dllAvFormat.Unload();
180   m_dllAvCodec.Unload();
181   m_dllAvUtil.Unload();
182 }
183
184 //-----------------------------------------------------------------------------
185 // Behavior
186 //-----------------------------------------------------------------------------
187
188 enum AE_STATES
189 {
190   AE_TOP = 0,                      // 0
191   AE_TOP_ERROR,                    // 1
192   AE_TOP_UNCONFIGURED,             // 2
193   AE_TOP_RECONFIGURING,            // 3
194   AE_TOP_CONFIGURED,               // 4
195   AE_TOP_CONFIGURED_SUSPEND,       // 5
196   AE_TOP_CONFIGURED_IDLE,          // 6
197   AE_TOP_CONFIGURED_PLAY,          // 7
198 };
199
200 int AE_parentStates[] = {
201     -1,
202     0, //TOP_ERROR
203     0, //TOP_UNCONFIGURED
204     0, //TOP_CONFIGURED
205     0, //TOP_RECONFIGURING
206     4, //TOP_CONFIGURED_SUSPEND
207     4, //TOP_CONFIGURED_IDLE
208     4, //TOP_CONFIGURED_PLAY
209 };
210
211 void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg)
212 {
213   for (int state = m_state; ; state = AE_parentStates[state])
214   {
215     switch (state)
216     {
217     case AE_TOP: // TOP
218       if (port == &m_controlPort)
219       {
220         switch (signal)
221         {
222         case CActiveAEControlProtocol::GETSTATE:
223           msg->Reply(CActiveAEControlProtocol::ACC, &m_state, sizeof(m_state));
224           return;
225         case CActiveAEControlProtocol::VOLUME:
226           m_volume = *(float*)msg->data;
227           if (m_sinkHasVolume)
228             m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::VOLUME, &m_volume, sizeof(float));
229           return;
230         case CActiveAEControlProtocol::MUTE:
231           m_muted = *(bool*)msg->data;
232           return;
233         case CActiveAEControlProtocol::KEEPCONFIG:
234           m_extKeepConfig = *(unsigned int*)msg->data;
235           return;
236         case CActiveAEControlProtocol::DISPLAYRESET:
237           return;
238         default:
239           break;
240         }
241       }
242       else if (port == &m_dataPort)
243       {
244         switch (signal)
245         {
246         case CActiveAEDataProtocol::NEWSOUND:
247           CActiveAESound *sound;
248           sound = *(CActiveAESound**)msg->data;
249           if (sound)
250           {
251             m_sounds.push_back(sound);
252             ResampleSounds();
253           }
254           return;
255         case CActiveAEDataProtocol::FREESTREAM:
256           CActiveAEStream *stream;
257           stream = *(CActiveAEStream**)msg->data;
258           DiscardStream(stream);
259           return;
260         case CActiveAEDataProtocol::FREESOUND:
261           sound = *(CActiveAESound**)msg->data;
262           DiscardSound(sound);
263           return;
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);
270           return;
271         default:
272           break;
273         }
274       }
275       else if (port == &m_sink.m_dataPort)
276       {
277         switch (signal)
278         {
279         case CSinkDataProtocol::RETURNSAMPLE:
280           CSampleBuffer **buffer;
281           buffer = (CSampleBuffer**)msg->data;
282           if (buffer)
283           {
284             (*buffer)->Return();
285           }
286           return;
287         default:
288           break;
289         }
290       }
291       {
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);
294       }
295       return;
296
297     case AE_TOP_ERROR:
298       if (port == NULL) // timeout
299       {
300         switch (signal)
301         {
302         case CActiveAEControlProtocol::TIMEOUT:
303           m_extError = false;
304           LoadSettings();
305           Configure();
306           if (!m_extError)
307           {
308             m_state = AE_TOP_CONFIGURED_IDLE;
309             m_extTimeout = 0;
310           }
311           else
312           {
313             m_state = AE_TOP_ERROR;
314             m_extTimeout = 500;
315           }
316           return;
317         default:
318           break;
319         }
320       }
321       break;
322
323     case AE_TOP_UNCONFIGURED:
324       if (port == &m_controlPort)
325       {
326         switch (signal)
327         {
328         case CActiveAEControlProtocol::INIT:
329           m_extError = false;
330           m_sink.EnumerateSinkList(false);
331           LoadSettings();
332           Configure();
333           msg->Reply(CActiveAEControlProtocol::ACC);
334           if (!m_extError)
335           {
336             m_state = AE_TOP_CONFIGURED_IDLE;
337             m_extTimeout = 0;
338           }
339           else
340           {
341             m_state = AE_TOP_ERROR;
342             m_extTimeout = 500;
343           }
344           return;
345
346         default:
347           break;
348         }
349       }
350       break;
351
352     case AE_TOP_RECONFIGURING:
353       if (port == NULL) // timeout
354       {
355         switch (signal)
356         {
357         case CActiveAEControlProtocol::TIMEOUT:
358           // drain
359           if (RunStages())
360           {
361             m_extTimeout = 0;
362             return;
363           }
364           if (!m_sinkBuffers->m_inputSamples.empty() || !m_sinkBuffers->m_outputSamples.empty())
365           {
366             m_extTimeout = 100;
367             return;
368           }
369           if (NeedReconfigureSink())
370             DrainSink();
371
372           if (!m_extError)
373             Configure();
374           if (!m_extError)
375           {
376             m_state = AE_TOP_CONFIGURED_PLAY;
377             m_extTimeout = 0;
378           }
379           else
380           {
381             m_state = AE_TOP_ERROR;
382             m_extTimeout = 500;
383           }
384           m_extDeferData = false;
385           return;
386         default:
387           break;
388         }
389       }
390       break;
391
392     case AE_TOP_CONFIGURED:
393       if (port == &m_controlPort)
394       {
395         switch (signal)
396         {
397         case CActiveAEControlProtocol::RECONFIGURE:
398           if (m_streams.empty())
399           {
400             bool silence = false;
401             m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::SILENCEMODE, &silence, sizeof(bool));
402           }
403           LoadSettings();
404           ChangeResamplers();
405           if (!NeedReconfigureBuffers() && !NeedReconfigureSink())
406             return;
407           m_state = AE_TOP_RECONFIGURING;
408           m_extTimeout = 0;
409           // don't accept any data until we are reconfigured
410           m_extDeferData = true;
411           return;
412         case CActiveAEControlProtocol::SUSPEND:
413           UnconfigureSink();
414           m_stats.SetSuspended(true);
415           m_state = AE_TOP_CONFIGURED_SUSPEND;
416           m_extDeferData = true;
417           return;
418         case CActiveAEControlProtocol::DISPLAYLOST:
419           if (m_sink.GetDeviceType(m_mode == MODE_PCM ? m_settings.device : m_settings.passthoughdevice) == AE_DEVTYPE_HDMI)
420           {
421             UnconfigureSink();
422             m_stats.SetSuspended(true);
423             m_state = AE_TOP_CONFIGURED_SUSPEND;
424             m_extDeferData = true;
425           }
426           msg->Reply(CActiveAEControlProtocol::ACC);
427           return;
428         case CActiveAEControlProtocol::PAUSESTREAM:
429           CActiveAEStream *stream;
430           stream = *(CActiveAEStream**)msg->data;
431           if (stream->m_paused != true && m_streams.size() == 1)
432             FlushEngine();
433           stream->m_paused = true;
434           return;
435         case CActiveAEControlProtocol::RESUMESTREAM:
436           stream = *(CActiveAEStream**)msg->data;
437           stream->m_paused = false;
438           m_extTimeout = 0;
439           return;
440         case CActiveAEControlProtocol::FLUSHSTREAM:
441           stream = *(CActiveAEStream**)msg->data;
442           SFlushStream(stream);
443           msg->Reply(CActiveAEControlProtocol::ACC);
444           m_extTimeout = 0;
445           return;
446         case CActiveAEControlProtocol::STREAMAMP:
447           MsgStreamParameter *par;
448           par = (MsgStreamParameter*)msg->data;
449           par->stream->m_limiter.SetAmplification(par->parameter.float_par);
450           par->stream->m_amplify = par->parameter.float_par;
451           return;
452         case CActiveAEControlProtocol::STREAMVOLUME:
453           par = (MsgStreamParameter*)msg->data;
454           par->stream->m_volume = par->parameter.float_par;
455           return;
456         case CActiveAEControlProtocol::STREAMRGAIN:
457           par = (MsgStreamParameter*)msg->data;
458           par->stream->m_rgain = par->parameter.float_par;
459           return;
460         case CActiveAEControlProtocol::STREAMRESAMPLERATIO:
461           par = (MsgStreamParameter*)msg->data;
462           if (par->stream->m_resampleBuffers)
463           {
464             par->stream->m_resampleBuffers->m_resampleRatio = par->parameter.double_par;
465           }
466           return;
467         case CActiveAEControlProtocol::STREAMFADE:
468           MsgStreamFade *fade;
469           fade = (MsgStreamFade*)msg->data;
470           fade->stream->m_fadingBase = fade->from;
471           fade->stream->m_fadingTarget = fade->target;
472           fade->stream->m_fadingTime = fade->millis;
473           fade->stream->m_fadingSamples = -1;
474           return;
475         case CActiveAEControlProtocol::STOPSOUND:
476           CActiveAESound *sound;
477           sound = *(CActiveAESound**)msg->data;
478           SStopSound(sound);
479           return;
480         default:
481           break;
482         }
483       }
484       else if (port == &m_dataPort)
485       {
486         switch (signal)
487         {
488         case CActiveAEDataProtocol::PLAYSOUND:
489           CActiveAESound *sound;
490           sound = *(CActiveAESound**)msg->data;
491           if (m_settings.guisoundmode == AE_SOUND_OFF ||
492              (m_settings.guisoundmode == AE_SOUND_IDLE && !m_streams.empty()))
493             return;
494           if (sound)
495           {
496             SoundState st = {sound, 0};
497             m_sounds_playing.push_back(st);
498             m_extTimeout = 0;
499             m_state = AE_TOP_CONFIGURED_PLAY;
500           }
501           return;
502         case CActiveAEDataProtocol::NEWSTREAM:
503           MsgStreamNew *streamMsg;
504           CActiveAEStream *stream;
505           streamMsg = (MsgStreamNew*)msg->data;
506           stream = CreateStream(streamMsg);
507           if(stream)
508           {
509             msg->Reply(CActiveAEDataProtocol::ACC, &stream, sizeof(CActiveAEStream*));
510             LoadSettings();
511             Configure();
512             if (!m_extError)
513             {
514               m_state = AE_TOP_CONFIGURED_PLAY;
515               m_extTimeout = 0;
516             }
517             else
518             {
519               m_state = AE_TOP_ERROR;
520               m_extTimeout = 500;
521             }
522           }
523           else
524             msg->Reply(CActiveAEDataProtocol::ERR);
525           return;
526         case CActiveAEDataProtocol::STREAMSAMPLE:
527           MsgStreamSample *msgData;
528           CSampleBuffer *samples;
529           msgData = (MsgStreamSample*)msg->data;
530           samples = msgData->stream->m_processingSamples.front();
531           msgData->stream->m_processingSamples.pop_front();
532           if (samples != msgData->buffer)
533             CLog::Log(LOGERROR, "CActiveAE - inconsistency in stream sample message");
534           if (msgData->buffer->pkt->nb_samples == 0)
535             msgData->buffer->Return();
536           else
537             msgData->stream->m_resampleBuffers->m_inputSamples.push_back(msgData->buffer);
538           m_extTimeout = 0;
539           m_state = AE_TOP_CONFIGURED_PLAY;
540           return;
541         case CActiveAEDataProtocol::FREESTREAM:
542           stream = *(CActiveAEStream**)msg->data;
543           DiscardStream(stream);
544           if (m_streams.empty())
545           {
546             if (m_extKeepConfig)
547               m_extDrainTimer.Set(m_extKeepConfig);
548             else
549               m_extDrainTimer.Set(m_stats.GetDelay() * 1000);
550             m_extDrain = true;
551           }
552           m_extTimeout = 0;
553           m_state = AE_TOP_CONFIGURED_PLAY;
554           return;
555         case CActiveAEDataProtocol::DRAINSTREAM:
556           stream = *(CActiveAEStream**)msg->data;
557           stream->m_drain = true;
558           stream->m_resampleBuffers->m_drain = true;
559           m_extTimeout = 0;
560           m_state = AE_TOP_CONFIGURED_PLAY;
561           msg->Reply(CActiveAEDataProtocol::ACC);
562           return;
563         default:
564           break;
565         }
566       }
567       else if (port == &m_sink.m_dataPort)
568       {
569         switch (signal)
570         {
571         case CSinkDataProtocol::RETURNSAMPLE:
572           CSampleBuffer **buffer;
573           buffer = (CSampleBuffer**)msg->data;
574           if (buffer)
575           {
576             (*buffer)->Return();
577           }
578           m_extTimeout = 0;
579           m_state = AE_TOP_CONFIGURED_PLAY;
580           return;
581         default:
582           break;
583         }
584       }
585       break;
586
587     case AE_TOP_CONFIGURED_SUSPEND:
588       if (port == &m_controlPort)
589       {
590         bool displayReset = false;
591         switch (signal)
592         {
593         case CActiveAEControlProtocol::DISPLAYRESET:
594           displayReset = true;
595         case CActiveAEControlProtocol::INIT:
596           m_extError = false;
597           if (!displayReset)
598           {
599             m_sink.EnumerateSinkList(true);
600             LoadSettings();
601           }
602           Configure();
603           if (!displayReset)
604             msg->Reply(CActiveAEControlProtocol::ACC);
605           if (!m_extError)
606           {
607             m_state = AE_TOP_CONFIGURED_PLAY;
608             m_extTimeout = 0;
609           }
610           else
611           {
612             m_state = AE_TOP_ERROR;
613             m_extTimeout = 500;
614           }
615           m_stats.SetSuspended(false);
616           m_extDeferData = false;
617           return;
618         default:
619           break;
620         }
621       }
622       else if (port == &m_sink.m_dataPort)
623       {
624         switch (signal)
625         {
626         case CSinkDataProtocol::RETURNSAMPLE:
627           CSampleBuffer **buffer;
628           buffer = (CSampleBuffer**)msg->data;
629           if (buffer)
630           {
631             (*buffer)->Return();
632           }
633           return;
634         default:
635           break;
636         }
637       }
638       else if (port == NULL) // timeout
639       {
640         switch (signal)
641         {
642         case CActiveAEControlProtocol::TIMEOUT:
643           m_extTimeout = 1000;
644           return;
645         default:
646           break;
647         }
648       }
649       break;
650
651     case AE_TOP_CONFIGURED_IDLE:
652       if (port == NULL) // timeout
653       {
654         switch (signal)
655         {
656         case CActiveAEControlProtocol::RESUMESTREAM:
657           CActiveAEStream *stream;
658           stream = *(CActiveAEStream**)msg->data;
659           stream->m_paused = false;
660           m_state = AE_TOP_CONFIGURED_PLAY;
661           m_extTimeout = 0;
662           return;
663         case CActiveAEControlProtocol::FLUSHSTREAM:
664           stream = *(CActiveAEStream**)msg->data;
665           SFlushStream(stream);
666           msg->Reply(CActiveAEControlProtocol::ACC);
667           m_state = AE_TOP_CONFIGURED_PLAY;
668           m_extTimeout = 0;
669           return;
670         case CActiveAEControlProtocol::TIMEOUT:
671           ResampleSounds();
672           ClearDiscardedBuffers();
673           if (m_extDrain)
674           {
675             if (m_extDrainTimer.IsTimePast())
676             {
677               Configure();
678               if (!m_extError)
679               {
680                 m_state = AE_TOP_CONFIGURED_PLAY;
681                 m_extTimeout = 0;
682               }
683               else
684               {
685                 m_state = AE_TOP_ERROR;
686                 m_extTimeout = 500;
687               }
688             }
689             else
690               m_extTimeout = m_extDrainTimer.MillisLeft();
691           }
692           else
693             m_extTimeout = 5000;
694           return;
695         default:
696           break;
697         }
698       }
699       break;
700
701     case AE_TOP_CONFIGURED_PLAY:
702       if (port == NULL) // timeout
703       {
704         switch (signal)
705         {
706         case CActiveAEControlProtocol::TIMEOUT:
707           if (m_extError)
708           {
709             m_state = AE_TOP_ERROR;
710             m_extTimeout = 100;
711             return;
712           }
713           if (RunStages())
714           {
715             m_extTimeout = 0;
716             return;
717           }
718           if (!m_extDrain && HasWork())
719           {
720             ClearDiscardedBuffers();
721             m_extTimeout = 100;
722             return;
723           }
724           m_extTimeout = 0;
725           m_state = AE_TOP_CONFIGURED_IDLE;
726           return;
727         default:
728           break;
729         }
730       }
731       break;
732
733     default: // we are in no state, should not happen
734       CLog::Log(LOGERROR, "CActiveAE::%s - no valid state: %d", __FUNCTION__, m_state);
735       return;
736     }
737   } // for
738 }
739
740 void CActiveAE::Process()
741 {
742   Message *msg = NULL;
743   Protocol *port = NULL;
744   bool gotMsg;
745   XbmcThreads::EndTime timer;
746
747   m_state = AE_TOP_UNCONFIGURED;
748   m_extTimeout = 1000;
749   m_bStateMachineSelfTrigger = false;
750   m_extDrain = false;
751   m_extDeferData = false;
752   m_extKeepConfig = 0;
753
754   // start sink
755   m_sink.Start();
756
757   while (!m_bStop)
758   {
759     gotMsg = false;
760     timer.Set(m_extTimeout);
761
762     if (m_bStateMachineSelfTrigger)
763     {
764       m_bStateMachineSelfTrigger = false;
765       // self trigger state machine
766       StateMachine(msg->signal, port, msg);
767       if (!m_bStateMachineSelfTrigger)
768       {
769         msg->Release();
770         msg = NULL;
771       }
772       continue;
773     }
774     // check control port
775     else if (m_controlPort.ReceiveOutMessage(&msg))
776     {
777       gotMsg = true;
778       port = &m_controlPort;
779     }
780     // check sink data port
781     else if (m_sink.m_dataPort.ReceiveInMessage(&msg))
782     {
783       gotMsg = true;
784       port = &m_sink.m_dataPort;
785     }
786     else if (!m_extDeferData)
787     {
788       // check data port
789       if (m_dataPort.ReceiveOutMessage(&msg))
790       {
791         gotMsg = true;
792         port = &m_dataPort;
793       }
794       // stream data ports
795       else
796       {
797         std::list<CActiveAEStream*>::iterator it;
798         for(it=m_streams.begin(); it!=m_streams.end(); ++it)
799         {
800           if((*it)->m_streamPort->ReceiveOutMessage(&msg))
801           {
802             gotMsg = true;
803             port = &m_dataPort;
804             break;
805           }
806         }
807       }
808     }
809
810     if (gotMsg)
811     {
812       StateMachine(msg->signal, port, msg);
813       if (!m_bStateMachineSelfTrigger)
814       {
815         msg->Release();
816         msg = NULL;
817       }
818       continue;
819     }
820
821     // wait for message
822     else if (m_outMsgEvent.WaitMSec(m_extTimeout))
823     {
824       m_extTimeout = timer.MillisLeft();
825       continue;
826     }
827     // time out
828     else
829     {
830       msg = m_controlPort.GetMessage();
831       msg->signal = CActiveAEControlProtocol::TIMEOUT;
832       port = 0;
833       // signal timeout to state machine
834       StateMachine(msg->signal, port, msg);
835       if (!m_bStateMachineSelfTrigger)
836       {
837         msg->Release();
838         msg = NULL;
839       }
840     }
841   }
842 }
843
844 AEAudioFormat CActiveAE::GetInputFormat(AEAudioFormat *desiredFmt)
845 {
846   AEAudioFormat inputFormat;
847
848   if (m_streams.empty())
849   {
850     inputFormat.m_dataFormat    = AE_FMT_FLOAT;
851     inputFormat.m_sampleRate    = 44100;
852     inputFormat.m_encodedRate   = 0;
853     inputFormat.m_channelLayout = AE_CH_LAYOUT_2_0;
854     inputFormat.m_frames        = 0;
855     inputFormat.m_frameSamples  = 0;
856     inputFormat.m_frameSize     = 0;
857   }
858   // force input format after unpausing slave
859   else if (desiredFmt != NULL)
860   {
861     inputFormat = *desiredFmt;
862   }
863   // keep format when having multiple streams
864   else if (m_streams.size() > 1 && m_silenceBuffers == NULL)
865   {
866     inputFormat = m_inputFormat;
867   }
868   else
869   {
870     inputFormat = m_streams.front()->m_format;
871     m_inputFormat = inputFormat;
872   }
873
874   return inputFormat;
875 }
876
877 void CActiveAE::Configure(AEAudioFormat *desiredFmt)
878 {
879   bool initSink = false;
880
881   AEAudioFormat sinkInputFormat, inputFormat;
882   AEAudioFormat oldInternalFormat = m_internalFormat;
883   AEAudioFormat oldSinkRequestFormat = m_sinkRequestFormat;
884
885   inputFormat = GetInputFormat(desiredFmt);
886
887   m_sinkRequestFormat = inputFormat;
888   ApplySettingsToFormat(m_sinkRequestFormat, m_settings, (int*)&m_mode);
889   m_extKeepConfig = 0;
890
891   std::string device = AE_IS_RAW(m_sinkRequestFormat.m_dataFormat) ? m_settings.passthoughdevice : m_settings.device;
892   std::string driver;
893   CAESinkFactory::ParseDevice(device, driver);
894   if ((!CompareFormat(m_sinkRequestFormat, m_sinkFormat) && !CompareFormat(m_sinkRequestFormat, oldSinkRequestFormat)) ||
895       m_currDevice.compare(device) != 0 ||
896       m_settings.driver.compare(driver) != 0)
897   {
898     if (!InitSink())
899       return;
900     m_settings.driver = driver;
901     m_currDevice = device;
902     initSink = true;
903     m_stats.Reset(m_sinkFormat.m_sampleRate);
904     m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::VOLUME, &m_volume, sizeof(float));
905
906     // limit buffer size in case of sink returns large buffer
907     unsigned int buffertime = (m_sinkFormat.m_frames*1000) / m_sinkFormat.m_sampleRate;
908     if (buffertime > 80)
909     {
910       CLog::Log(LOGWARNING, "ActiveAE::%s - sink returned large buffer of %d ms, reducing to 80 ms", __FUNCTION__, buffertime);
911       m_sinkFormat.m_frames = 80 * m_sinkFormat.m_sampleRate / 1000;
912     }
913   }
914
915   if (m_silenceBuffers)
916   {
917     m_discardBufferPools.push_back(m_silenceBuffers);
918     m_silenceBuffers = NULL;
919   }
920
921   // buffers for driving gui sounds if no streams are active
922   if (m_streams.empty())
923   {
924     inputFormat = m_sinkFormat;
925     inputFormat.m_dataFormat = AE_FMT_FLOAT;
926     inputFormat.m_frameSize = inputFormat.m_channelLayout.Count() *
927                               (CAEUtil::DataFormatToBits(inputFormat.m_dataFormat) >> 3);
928     m_silenceBuffers = new CActiveAEBufferPool(inputFormat);
929     m_silenceBuffers->Create(MAX_WATER_LEVEL*1000);
930     sinkInputFormat = inputFormat;
931     m_internalFormat = inputFormat;
932
933     bool silence = false;
934     m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::SILENCEMODE, &silence, sizeof(bool));
935
936     delete m_encoder;
937     m_encoder = NULL;
938
939     if (m_encoderBuffers)
940     {
941       m_discardBufferPools.push_back(m_encoderBuffers);
942       m_encoderBuffers = NULL;
943     }
944     if (m_vizBuffers)
945     {
946       m_discardBufferPools.push_back(m_vizBuffers);
947       m_vizBuffers = NULL;
948     }
949     if (m_vizBuffersInput)
950     {
951       m_discardBufferPools.push_back(m_vizBuffersInput);
952       m_vizBuffersInput = NULL;
953     }
954   }
955   // resample buffers for streams
956   else
957   {
958     bool silence = true;
959     m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::SILENCEMODE, &silence, sizeof(bool));
960
961     AEAudioFormat outputFormat;
962     if (m_mode == MODE_RAW)
963     {
964       inputFormat.m_frames = m_sinkFormat.m_frames;
965       outputFormat = inputFormat;
966       sinkInputFormat = m_sinkFormat;
967     }
968     // transcode everything with more than 2 channels
969     else if (m_mode == MODE_TRANSCODE)
970     {
971       outputFormat = inputFormat;
972       outputFormat.m_dataFormat = AE_FMT_FLOATP;
973       outputFormat.m_sampleRate = 48000;
974
975       // setup encoder
976       if (!m_encoder)
977       {
978         m_encoder = new CAEEncoderFFmpeg();
979         m_encoder->Initialize(outputFormat, true);
980         m_encoderFormat = outputFormat;
981       }
982       else
983         outputFormat = m_encoderFormat;
984
985       outputFormat.m_channelLayout = m_encoderFormat.m_channelLayout;
986       outputFormat.m_frames = m_encoderFormat.m_frames;
987
988       // encoder buffer
989       if (m_encoder->GetCodecID() == AV_CODEC_ID_AC3)
990       {
991         AEAudioFormat format;
992         format.m_channelLayout = AE_CH_LAYOUT_2_0;
993         format.m_dataFormat = AE_FMT_S16NE;
994         format.m_frameSize = 2* (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);
995         format.m_frames = AC3_FRAME_SIZE;
996         format.m_sampleRate = 48000;
997         format.m_encodedRate = m_encoderFormat.m_sampleRate;
998         if (m_encoderBuffers && initSink)
999         {
1000           m_discardBufferPools.push_back(m_encoderBuffers);
1001           m_encoderBuffers = NULL;
1002         }
1003         if (!m_encoderBuffers)
1004         {
1005           m_encoderBuffers = new CActiveAEBufferPool(format);
1006           m_encoderBuffers->Create(MAX_WATER_LEVEL*1000);
1007         }
1008       }
1009
1010       sinkInputFormat = m_sinkFormat;
1011     }
1012     else
1013     {
1014       outputFormat = m_sinkFormat;
1015       outputFormat.m_dataFormat = AE_FMT_FLOAT;
1016       outputFormat.m_frameSize = outputFormat.m_channelLayout.Count() *
1017                                  (CAEUtil::DataFormatToBits(outputFormat.m_dataFormat) >> 3);
1018       // TODO: adjust to decoder
1019       sinkInputFormat = outputFormat;
1020     }
1021     m_internalFormat = outputFormat;
1022
1023     std::list<CActiveAEStream*>::iterator it;
1024     for(it=m_streams.begin(); it!=m_streams.end(); ++it)
1025     {
1026       // check if we support input format of stream
1027       if (!AE_IS_RAW((*it)->m_format.m_dataFormat) && 
1028           CActiveAEResample::GetAVSampleFormat((*it)->m_format.m_dataFormat) == AV_SAMPLE_FMT_FLT &&
1029           (*it)->m_format.m_dataFormat != AE_FMT_FLOAT)
1030       {
1031         (*it)->m_convertFn = CAEConvert::ToFloat((*it)->m_format.m_dataFormat);
1032         (*it)->m_format.m_dataFormat = AE_FMT_FLOAT;
1033       }
1034
1035       if (!(*it)->m_inputBuffers)
1036       {
1037         // align input buffers with period of sink or encoder
1038         (*it)->m_format.m_frames = m_internalFormat.m_frames * ((float)(*it)->m_format.m_sampleRate / m_internalFormat.m_sampleRate);
1039
1040         // create buffer pool
1041         (*it)->m_inputBuffers = new CActiveAEBufferPool((*it)->m_format);
1042         (*it)->m_inputBuffers->Create(MAX_CACHE_LEVEL*1000);
1043         (*it)->m_streamSpace = (*it)->m_format.m_frameSize * (*it)->m_format.m_frames;
1044
1045         // if input format does not follow ffmpeg channel mask, we may need to remap channels
1046         (*it)->InitRemapper();
1047       }
1048       if (initSink && (*it)->m_resampleBuffers)
1049       {
1050         m_discardBufferPools.push_back((*it)->m_resampleBuffers);
1051         (*it)->m_resampleBuffers = NULL;
1052       }
1053       if (!(*it)->m_resampleBuffers)
1054       {
1055         (*it)->m_resampleBuffers = new CActiveAEBufferPoolResample((*it)->m_inputBuffers->m_format, outputFormat, m_settings.resampleQuality);
1056         (*it)->m_resampleBuffers->m_changeResampler = (*it)->m_forceResampler;
1057         (*it)->m_resampleBuffers->Create(MAX_CACHE_LEVEL*1000, false, m_settings.stereoupmix, m_settings.normalizelevels);
1058       }
1059       if (m_mode == MODE_TRANSCODE || m_streams.size() > 1)
1060         (*it)->m_resampleBuffers->m_fillPackets = true;
1061
1062       // amplification
1063       (*it)->m_limiter.SetSamplerate(outputFormat.m_sampleRate);
1064     }
1065
1066     // update buffered time of streams
1067     m_stats.AddSamples(0, m_streams);
1068
1069     // buffers for viz
1070     if (!AE_IS_RAW(inputFormat.m_dataFormat))
1071     {
1072       if (initSink && m_vizBuffers)
1073       {
1074         m_discardBufferPools.push_back(m_vizBuffers);
1075         m_vizBuffers = NULL;
1076         m_discardBufferPools.push_back(m_vizBuffersInput);
1077         m_vizBuffersInput = NULL;
1078       }
1079       if (!m_vizBuffers)
1080       {
1081         AEAudioFormat vizFormat = m_internalFormat;
1082         vizFormat.m_channelLayout = AE_CH_LAYOUT_2_0;
1083         vizFormat.m_dataFormat = AE_FMT_FLOAT;
1084
1085         // input buffers
1086         m_vizBuffersInput = new CActiveAEBufferPool(m_internalFormat);
1087         m_vizBuffersInput->Create(2000);
1088
1089         // resample buffers
1090         m_vizBuffers = new CActiveAEBufferPoolResample(m_internalFormat, vizFormat, m_settings.resampleQuality);
1091         // TODO use cache of sync + water level
1092         m_vizBuffers->Create(2000, false, false);
1093         m_vizInitialized = false;
1094       }
1095     }
1096   }
1097
1098   // resample buffers for sink
1099   if (m_sinkBuffers && 
1100      (!CompareFormat(m_sinkBuffers->m_format,m_sinkFormat) || !CompareFormat(m_sinkBuffers->m_inputFormat, sinkInputFormat)))
1101   {
1102     m_discardBufferPools.push_back(m_sinkBuffers);
1103     m_sinkBuffers = NULL;
1104   }
1105   if (!m_sinkBuffers)
1106   {
1107     m_sinkBuffers = new CActiveAEBufferPoolResample(sinkInputFormat, m_sinkFormat, m_settings.resampleQuality);
1108     m_sinkBuffers->Create(MAX_WATER_LEVEL*1000, true, false);
1109   }
1110
1111   // reset gui sounds
1112   if (!CompareFormat(oldInternalFormat, m_internalFormat))
1113   {
1114     if (m_settings.guisoundmode == AE_SOUND_ALWAYS ||
1115        (m_settings.guisoundmode == AE_SOUND_IDLE && m_streams.empty()))
1116     {
1117       std::vector<CActiveAESound*>::iterator it;
1118       for (it = m_sounds.begin(); it != m_sounds.end(); ++it)
1119       {
1120         (*it)->SetConverted(false);
1121       }
1122     }
1123     m_sounds_playing.clear();
1124   }
1125
1126   ClearDiscardedBuffers();
1127   m_extDrain = false;
1128 }
1129
1130 CActiveAEStream* CActiveAE::CreateStream(MsgStreamNew *streamMsg)
1131 {
1132   // we only can handle a single pass through stream
1133   bool hasRawStream = false;
1134   bool hasStream = false;
1135   std::list<CActiveAEStream*>::iterator it;
1136   for(it = m_streams.begin(); it != m_streams.end(); ++it)
1137   {
1138     if((*it)->IsDrained())
1139       continue;
1140     if(AE_IS_RAW((*it)->m_format.m_dataFormat))
1141       hasRawStream = true;
1142     hasStream = true;
1143   }
1144   if (hasRawStream || (hasStream && AE_IS_RAW(streamMsg->format.m_dataFormat)))
1145   {
1146     return NULL;
1147   }
1148
1149   // create the stream
1150   CActiveAEStream *stream;
1151   stream = new CActiveAEStream(&streamMsg->format);
1152   stream->m_streamPort = new CActiveAEDataProtocol("stream",
1153                              &stream->m_inMsgEvent, &m_outMsgEvent);
1154
1155   // create buffer pool
1156   stream->m_inputBuffers = NULL; // create in Configure when we know the sink format
1157   stream->m_resampleBuffers = NULL; // create in Configure when we know the sink format
1158   stream->m_statsLock = m_stats.GetLock();
1159   stream->m_fadingSamples = 0;
1160   stream->m_started = false;
1161
1162   if (streamMsg->options & AESTREAM_PAUSED)
1163     stream->m_paused = true;
1164
1165   if (streamMsg->options & AESTREAM_FORCE_RESAMPLE)
1166     stream->m_forceResampler = true;
1167
1168   m_streams.push_back(stream);
1169
1170   return stream;
1171 }
1172
1173 void CActiveAE::DiscardStream(CActiveAEStream *stream)
1174 {
1175   std::list<CActiveAEStream*>::iterator it;
1176   for (it=m_streams.begin(); it!=m_streams.end(); )
1177   {
1178     if (stream == (*it))
1179     {
1180       while (!(*it)->m_processingSamples.empty())
1181       {
1182         (*it)->m_processingSamples.front()->Return();
1183         (*it)->m_processingSamples.pop_front();
1184       }
1185       m_discardBufferPools.push_back((*it)->m_inputBuffers);
1186       m_discardBufferPools.push_back((*it)->m_resampleBuffers);
1187       CLog::Log(LOGDEBUG, "CActiveAE::DiscardStream - audio stream deleted");
1188       delete (*it)->m_streamPort;
1189       delete (*it);
1190       it = m_streams.erase(it);
1191     }
1192     else
1193       ++it;
1194   }
1195
1196   ClearDiscardedBuffers();
1197 }
1198
1199 void CActiveAE::SFlushStream(CActiveAEStream *stream)
1200 {
1201   while (!stream->m_processingSamples.empty())
1202   {
1203     stream->m_processingSamples.front()->Return();
1204     stream->m_processingSamples.pop_front();
1205   }
1206   stream->m_resampleBuffers->Flush();
1207   stream->m_streamPort->Purge();
1208   stream->m_bufferedTime = 0.0;
1209   stream->m_paused = false;
1210
1211   // flush the engine if we only have a single stream
1212   if (m_streams.size() == 1)
1213   {
1214     FlushEngine();
1215   }
1216 }
1217
1218 void CActiveAE::FlushEngine()
1219 {
1220   if (m_sinkBuffers)
1221     m_sinkBuffers->Flush();
1222   if (m_vizBuffers)
1223     m_vizBuffers->Flush();
1224
1225   // send message to sink
1226   Message *reply;
1227   if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::FLUSH,
1228                                            &reply, 2000))
1229   {
1230     bool success = reply->signal == CSinkControlProtocol::ACC;
1231     if (!success)
1232     {
1233       CLog::Log(LOGERROR, "ActiveAE::%s - returned error on flush", __FUNCTION__);
1234       m_extError = true;
1235     }
1236     reply->Release();
1237   }
1238   else
1239   {
1240     CLog::Log(LOGERROR, "ActiveAE::%s - failed to flush", __FUNCTION__);
1241     m_extError = true;
1242   }
1243   m_stats.Reset(m_sinkFormat.m_sampleRate);
1244 }
1245
1246 void CActiveAE::ClearDiscardedBuffers()
1247 {
1248   std::list<CActiveAEBufferPool*>::iterator it;
1249   for (it=m_discardBufferPools.begin(); it!=m_discardBufferPools.end(); ++it)
1250   {
1251     CActiveAEBufferPoolResample *rbuf = dynamic_cast<CActiveAEBufferPoolResample*>(*it);
1252     if (rbuf)
1253     {
1254       rbuf->Flush();
1255     }
1256     // if all buffers have returned, we can delete the buffer pool
1257     if ((*it)->m_allSamples.size() == (*it)->m_freeSamples.size())
1258     {
1259       delete (*it);
1260       CLog::Log(LOGDEBUG, "CActiveAE::ClearDiscardedBuffers - buffer pool deleted");
1261       m_discardBufferPools.erase(it);
1262       return;
1263     }
1264   }
1265 }
1266
1267 void CActiveAE::SStopSound(CActiveAESound *sound)
1268 {
1269   std::list<SoundState>::iterator it;
1270   for (it=m_sounds_playing.begin(); it!=m_sounds_playing.end(); ++it)
1271   {
1272     if (it->sound == sound)
1273     {
1274       m_sounds_playing.erase(it);
1275       return;
1276     }
1277   }
1278 }
1279
1280 void CActiveAE::DiscardSound(CActiveAESound *sound)
1281 {
1282   SStopSound(sound);
1283
1284   std::vector<CActiveAESound*>::iterator it;
1285   for (it=m_sounds.begin(); it!=m_sounds.end(); ++it)
1286   {
1287     if ((*it) == sound)
1288     {
1289       m_sounds.erase(it);
1290       return;
1291     }
1292   }
1293 }
1294
1295 void CActiveAE::ChangeResamplers()
1296 {
1297   std::list<CActiveAEStream*>::iterator it;
1298   for(it=m_streams.begin(); it!=m_streams.end(); ++it)
1299   {
1300     bool normalize = true;
1301     if (((*it)->m_resampleBuffers->m_format.m_channelLayout.Count() <
1302          (*it)->m_resampleBuffers->m_inputFormat.m_channelLayout.Count()) &&
1303          !m_settings.normalizelevels)
1304       normalize = false;
1305
1306     if ((*it)->m_resampleBuffers && (*it)->m_resampleBuffers->m_resampler &&
1307         (((*it)->m_resampleBuffers->m_resampleQuality != m_settings.resampleQuality) ||
1308         (((*it)->m_resampleBuffers->m_stereoUpmix != m_settings.stereoupmix)) ||
1309         ((*it)->m_resampleBuffers->m_normalize != normalize)))
1310     {
1311       (*it)->m_resampleBuffers->m_changeResampler = true;
1312     }
1313     (*it)->m_resampleBuffers->m_resampleQuality = m_settings.resampleQuality;
1314     (*it)->m_resampleBuffers->m_stereoUpmix = m_settings.stereoupmix;
1315     (*it)->m_resampleBuffers->m_normalize = normalize;
1316   }
1317 }
1318
1319 void CActiveAE::ApplySettingsToFormat(AEAudioFormat &format, AudioSettings &settings, int *mode)
1320 {
1321   int oldMode = m_mode;
1322   if (mode)
1323     *mode = MODE_PCM;
1324
1325   // raw pass through
1326   if (AE_IS_RAW(format.m_dataFormat))
1327   {
1328     if ((format.m_dataFormat == AE_FMT_AC3 && !settings.ac3passthrough) ||
1329         (format.m_dataFormat == AE_FMT_EAC3 && !settings.eac3passthrough) ||
1330         (format.m_dataFormat == AE_FMT_TRUEHD && !settings.truehdpassthrough) ||
1331         (format.m_dataFormat == AE_FMT_DTS && !settings.dtspassthrough) ||
1332         (format.m_dataFormat == AE_FMT_DTSHD && !settings.dtshdpassthrough))
1333     {
1334       CLog::Log(LOGERROR, "CActiveAE::ApplySettingsToFormat - input audio format is wrong");
1335     }
1336     if (mode)
1337       *mode = MODE_RAW;
1338   }
1339   // transcode
1340   else if (settings.channels <= AE_CH_LAYOUT_2_0 && // no multichannel pcm
1341            settings.passthrough &&
1342            settings.ac3passthrough &&
1343            settings.ac3transcode &&
1344            !m_streams.empty() &&
1345            (format.m_channelLayout.Count() > 2 || settings.stereoupmix))
1346   {
1347     format.m_dataFormat = AE_FMT_AC3;
1348     format.m_sampleRate = 48000;
1349     format.m_channelLayout = AE_CH_LAYOUT_2_0;
1350     if (mode)
1351       *mode = MODE_TRANSCODE;
1352   }
1353   else
1354   {
1355     format.m_dataFormat = AE_FMT_FLOAT;
1356     // consider user channel layout for those cases
1357     // 1. input stream is multichannel
1358     // 2. stereo upmix is selected
1359     // 3. fixed mode
1360     if ((format.m_channelLayout.Count() > 2) ||
1361          settings.stereoupmix ||
1362          (settings.config == AE_CONFIG_FIXED))
1363     {
1364       CAEChannelInfo stdLayout;
1365       switch (settings.channels)
1366       {
1367         default:
1368         case  0: stdLayout = AE_CH_LAYOUT_2_0; break;
1369         case  1: stdLayout = AE_CH_LAYOUT_2_0; break;
1370         case  2: stdLayout = AE_CH_LAYOUT_2_1; break;
1371         case  3: stdLayout = AE_CH_LAYOUT_3_0; break;
1372         case  4: stdLayout = AE_CH_LAYOUT_3_1; break;
1373         case  5: stdLayout = AE_CH_LAYOUT_4_0; break;
1374         case  6: stdLayout = AE_CH_LAYOUT_4_1; break;
1375         case  7: stdLayout = AE_CH_LAYOUT_5_0; break;
1376         case  8: stdLayout = AE_CH_LAYOUT_5_1; break;
1377         case  9: stdLayout = AE_CH_LAYOUT_7_0; break;
1378         case 10: stdLayout = AE_CH_LAYOUT_7_1; break;
1379       }
1380
1381       if (m_settings.config == AE_CONFIG_FIXED || (settings.stereoupmix && format.m_channelLayout.Count() <= 2))
1382         format.m_channelLayout = stdLayout;
1383       else if (m_extKeepConfig && (settings.config == AE_CONFIG_AUTO) && (oldMode != MODE_RAW))
1384         format.m_channelLayout = m_internalFormat.m_channelLayout;
1385       else
1386         format.m_channelLayout.ResolveChannels(stdLayout);
1387     }
1388     // don't change from multi to stereo in AUTO mode
1389     else if ((settings.config == AE_CONFIG_AUTO) &&
1390               m_stats.GetWaterLevel() > 0 && m_internalFormat.m_channelLayout.Count() > 2)
1391     {
1392       format.m_channelLayout = m_internalFormat.m_channelLayout;
1393     }
1394
1395     if (m_sink.GetDeviceType(m_settings.device) == AE_DEVTYPE_IEC958)
1396     {
1397       if (format.m_sampleRate > m_settings.samplerate)
1398       {
1399         format.m_sampleRate = m_settings.samplerate;
1400         CLog::Log(LOGINFO, "CActiveAE::ApplySettings - limit samplerate for SPDIF to %d", format.m_sampleRate);
1401       }
1402       format.m_channelLayout = AE_CH_LAYOUT_2_0;
1403     }
1404
1405     if (m_settings.config == AE_CONFIG_FIXED)
1406     {
1407       format.m_sampleRate = m_settings.samplerate;
1408       CLog::Log(LOGINFO, "CActiveAE::ApplySettings - Forcing samplerate to %d", format.m_sampleRate);
1409     }
1410
1411     // sinks may not support mono
1412     if (format.m_channelLayout.Count() == 1)
1413     {
1414       format.m_channelLayout = AE_CH_LAYOUT_2_0;
1415     }
1416   }
1417 }
1418
1419 bool CActiveAE::NeedReconfigureBuffers()
1420 {
1421   AEAudioFormat newFormat = GetInputFormat();
1422   ApplySettingsToFormat(newFormat, m_settings);
1423
1424   if (newFormat.m_dataFormat != m_sinkRequestFormat.m_dataFormat ||
1425       newFormat.m_channelLayout != m_sinkRequestFormat.m_channelLayout ||
1426       newFormat.m_sampleRate != m_sinkRequestFormat.m_sampleRate)
1427     return true;
1428
1429   return false;
1430 }
1431
1432 bool CActiveAE::NeedReconfigureSink()
1433 {
1434   AEAudioFormat newFormat = GetInputFormat();
1435   ApplySettingsToFormat(newFormat, m_settings);
1436
1437   std::string device = AE_IS_RAW(newFormat.m_dataFormat) ? m_settings.passthoughdevice : m_settings.device;
1438   std::string driver;
1439   CAESinkFactory::ParseDevice(device, driver);
1440
1441   if (!CompareFormat(newFormat, m_sinkFormat) ||
1442       m_currDevice.compare(device) != 0 ||
1443       m_settings.driver.compare(driver) != 0)
1444     return true;
1445
1446   return false;
1447 }
1448
1449 bool CActiveAE::InitSink()
1450 {
1451   SinkConfig config;
1452   config.format = m_sinkRequestFormat;
1453   config.stats = &m_stats;
1454   config.device = AE_IS_RAW(m_sinkRequestFormat.m_dataFormat) ? &m_settings.passthoughdevice :
1455                                                                 &m_settings.device;
1456
1457   // send message to sink
1458   Message *reply;
1459   if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::CONFIGURE,
1460                                                  &reply,
1461                                                  5000,
1462                                                  &config, sizeof(config)))
1463   {
1464     bool success = reply->signal == CSinkControlProtocol::ACC;
1465     if (!success)
1466     {
1467       reply->Release();
1468       CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
1469       m_extError = true;
1470       return false;
1471     }
1472     SinkReply *data;
1473     data = (SinkReply*)reply->data;
1474     if (data)
1475     {
1476       m_sinkFormat = data->format;
1477       m_sinkHasVolume = data->hasVolume;
1478       m_stats.SetSinkCacheTotal(data->cacheTotal);
1479       m_stats.SetSinkLatency(data->latency);
1480     }
1481     reply->Release();
1482   }
1483   else
1484   {
1485     CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__);
1486     m_stats.SetSinkCacheTotal(0);
1487     m_stats.SetSinkLatency(0);
1488     m_extError = true;
1489     return false;
1490   }
1491
1492   m_inMsgEvent.Reset();
1493   return true;
1494 }
1495
1496 void CActiveAE::DrainSink()
1497 {
1498   // send message to sink
1499   Message *reply;
1500   if (m_sink.m_dataPort.SendOutMessageSync(CSinkDataProtocol::DRAIN,
1501                                                  &reply,
1502                                                  2000))
1503   {
1504     bool success = reply->signal == CSinkDataProtocol::ACC;
1505     if (!success)
1506     {
1507       reply->Release();
1508       CLog::Log(LOGERROR, "ActiveAE::%s - returned error on drain", __FUNCTION__);
1509       m_extError = true;
1510       return;
1511     }
1512     reply->Release();
1513   }
1514   else
1515   {
1516     CLog::Log(LOGERROR, "ActiveAE::%s - failed to drain", __FUNCTION__);
1517     m_extError = true;
1518     return;
1519   }
1520 }
1521
1522 void CActiveAE::UnconfigureSink()
1523 {
1524   // send message to sink
1525   Message *reply;
1526   if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::UNCONFIGURE,
1527                                                  &reply,
1528                                                  2000))
1529   {
1530     bool success = reply->signal == CSinkControlProtocol::ACC;
1531     if (!success)
1532     {
1533       CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
1534       m_extError = true;
1535     }
1536     reply->Release();
1537   }
1538   else
1539   {
1540     CLog::Log(LOGERROR, "ActiveAE::%s - failed to unconfigure", __FUNCTION__);
1541     m_extError = true;
1542   }
1543
1544   // make sure we open sink on next configure
1545   m_currDevice = "";
1546
1547   m_inMsgEvent.Reset();
1548 }
1549
1550
1551 bool CActiveAE::RunStages()
1552 {
1553   bool busy = false;
1554
1555   // serve input streams
1556   std::list<CActiveAEStream*>::iterator it;
1557   for (it = m_streams.begin(); it != m_streams.end(); ++it)
1558   {
1559     if ((*it)->m_resampleBuffers && !(*it)->m_paused)
1560       busy = (*it)->m_resampleBuffers->ResampleBuffers();
1561     else if ((*it)->m_resampleBuffers && 
1562             ((*it)->m_resampleBuffers->m_inputSamples.size() > (*it)->m_resampleBuffers->m_allSamples.size() * 0.5))
1563     {
1564       CSingleLock lock((*it)->m_streamLock);
1565       (*it)->m_streamIsBuffering = false;
1566     }
1567
1568     // provide buffers to stream
1569     float time = m_stats.GetCacheTime((*it));
1570     CSampleBuffer *buffer;
1571     if (!(*it)->m_drain)
1572     {
1573       while (time < MAX_CACHE_LEVEL && !(*it)->m_inputBuffers->m_freeSamples.empty())
1574       {
1575         buffer = (*it)->m_inputBuffers->GetFreeBuffer();
1576         (*it)->m_processingSamples.push_back(buffer);
1577         (*it)->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMBUFFER, &buffer, sizeof(CSampleBuffer*));
1578         (*it)->IncFreeBuffers();
1579         time += (float)buffer->pkt->max_nb_samples / buffer->pkt->config.sample_rate;
1580       }
1581     }
1582     else
1583     {
1584       if ((*it)->m_resampleBuffers->m_inputSamples.empty() &&
1585           (*it)->m_resampleBuffers->m_outputSamples.empty() &&
1586           (*it)->m_processingSamples.empty())
1587       {
1588         (*it)->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMDRAINED);
1589         (*it)->m_drain = false;
1590         (*it)->m_resampleBuffers->m_drain = false;
1591         (*it)->m_started = false;
1592
1593         // set variables being polled via stream interface
1594         CSingleLock lock((*it)->m_streamLock);
1595         if ((*it)->m_streamSlave)
1596         {
1597           CActiveAEStream *slave = (CActiveAEStream*)((*it)->m_streamSlave);
1598           slave->m_paused = false;
1599
1600           // TODO: find better solution for this
1601           // gapless bites audiophile
1602           if (m_settings.config == AE_CONFIG_MATCH)
1603             Configure(&slave->m_format);
1604
1605           (*it)->m_streamSlave = NULL;
1606         }
1607         (*it)->m_streamDrained = true;
1608         (*it)->m_streamDraining = false;
1609         (*it)->m_streamFading = false;
1610       }
1611     }
1612   }
1613
1614   if (m_stats.GetWaterLevel() < MAX_WATER_LEVEL &&
1615      (m_mode != MODE_TRANSCODE || (m_encoderBuffers && !m_encoderBuffers->m_freeSamples.empty())))
1616   {
1617     // mix streams and sounds sounds
1618     if (m_mode != MODE_RAW)
1619     {
1620       CSampleBuffer *out = NULL;
1621       if (!m_sounds_playing.empty() && m_streams.empty())
1622       {
1623         if (m_silenceBuffers && !m_silenceBuffers->m_freeSamples.empty())
1624         {
1625           out = m_silenceBuffers->GetFreeBuffer();
1626           for (int i=0; i<out->pkt->planes; i++)
1627           {
1628             memset(out->pkt->data[i], 0, out->pkt->linesize);
1629           }
1630           out->pkt->nb_samples = out->pkt->max_nb_samples;
1631         }
1632       }
1633
1634       // mix streams
1635       std::list<CActiveAEStream*>::iterator it;
1636
1637       // if we deal with more than a single stream, all streams
1638       // must provide samples for mixing
1639       bool allStreamsReady = true;
1640       for (it = m_streams.begin(); it != m_streams.end(); ++it)
1641       {
1642         if ((*it)->m_paused || !(*it)->m_started || !(*it)->m_resampleBuffers)
1643           continue;
1644
1645         if ((*it)->m_resampleBuffers->m_outputSamples.empty())
1646           allStreamsReady = false;
1647       }
1648
1649       bool needClamp = false;
1650       for (it = m_streams.begin(); it != m_streams.end() && allStreamsReady; ++it)
1651       {
1652         if ((*it)->m_paused || !(*it)->m_resampleBuffers)
1653           continue;
1654
1655         if (!(*it)->m_resampleBuffers->m_outputSamples.empty())
1656         {
1657           (*it)->m_started = true;
1658
1659           if (!out)
1660           {
1661             out = (*it)->m_resampleBuffers->m_outputSamples.front();
1662             (*it)->m_resampleBuffers->m_outputSamples.pop_front();
1663
1664             int nb_floats = out->pkt->nb_samples * out->pkt->config.channels / out->pkt->planes;
1665             int nb_loops = 1;
1666             float fadingStep = 0.0f;
1667
1668             // fading
1669             if ((*it)->m_fadingSamples == -1)
1670             {
1671               (*it)->m_fadingSamples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1672               (*it)->m_volume = (*it)->m_fadingBase;
1673             }
1674             if ((*it)->m_fadingSamples > 0)
1675             {
1676               nb_floats = out->pkt->config.channels / out->pkt->planes;
1677               nb_loops = out->pkt->nb_samples;
1678               float delta = (*it)->m_fadingTarget - (*it)->m_fadingBase;
1679               int samples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1680               fadingStep = delta / samples;
1681             }
1682
1683             // for stream amplification, 
1684             // turned off downmix normalization,
1685             // or if sink format is float (in order to prevent from clipping)
1686             // we need to run on a per sample basis
1687             if ((*it)->m_amplify != 1.0 || !(*it)->m_resampleBuffers->m_normalize || (m_sinkFormat.m_dataFormat == AE_FMT_FLOAT))
1688             {
1689               nb_floats = out->pkt->config.channels / out->pkt->planes;
1690               nb_loops = out->pkt->nb_samples;
1691             }
1692
1693             for(int i=0; i<nb_loops; i++)
1694             {
1695               if ((*it)->m_fadingSamples > 0)
1696               {
1697                 (*it)->m_volume += fadingStep;
1698                 (*it)->m_fadingSamples--;
1699
1700                 if ((*it)->m_fadingSamples == 0)
1701                 {
1702                   // set variables being polled via stream interface
1703                   CSingleLock lock((*it)->m_streamLock);
1704                   (*it)->m_streamFading = false;
1705                 }
1706               }
1707
1708               // volume for stream
1709               float volume = (*it)->m_volume * (*it)->m_rgain;
1710               if(nb_loops > 1)
1711                 volume *= (*it)->m_limiter.Run((float**)out->pkt->data, out->pkt->config.channels, i*nb_floats, out->pkt->planes > 1);
1712
1713               for(int j=0; j<out->pkt->planes; j++)
1714               {
1715 #ifdef __SSE__
1716                 CAEUtil::SSEMulArray((float*)out->pkt->data[j]+i*nb_floats, volume, nb_floats);
1717 #else
1718                 float* fbuffer = (float*) out->pkt->data[j]+i*nb_floats;
1719                 for (int k = 0; k < nb_floats; ++k)
1720                 {
1721                   fbuffer[k] *= volume;
1722                 }
1723 #endif
1724               }
1725             }
1726           }
1727           else
1728           {
1729             CSampleBuffer *mix = NULL;
1730             mix = (*it)->m_resampleBuffers->m_outputSamples.front();
1731             (*it)->m_resampleBuffers->m_outputSamples.pop_front();
1732
1733             int nb_floats = mix->pkt->nb_samples * mix->pkt->config.channels / mix->pkt->planes;
1734             int nb_loops = 1;
1735             float fadingStep = 0.0f;
1736
1737             // fading
1738             if ((*it)->m_fadingSamples == -1)
1739             {
1740               (*it)->m_fadingSamples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1741               (*it)->m_volume = (*it)->m_fadingBase;
1742             }
1743             if ((*it)->m_fadingSamples > 0)
1744             {
1745               nb_floats = mix->pkt->config.channels / mix->pkt->planes;
1746               nb_loops = mix->pkt->nb_samples;
1747               float delta = (*it)->m_fadingTarget - (*it)->m_fadingBase;
1748               int samples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1749               fadingStep = delta / samples;
1750             }
1751
1752             // for streams amplification of turned off downmix normalization
1753             // we need to run on a per sample basis
1754             if ((*it)->m_amplify != 1.0 || !(*it)->m_resampleBuffers->m_normalize)
1755             {
1756               nb_floats = out->pkt->config.channels / out->pkt->planes;
1757               nb_loops = out->pkt->nb_samples;
1758             }
1759
1760             for(int i=0; i<nb_loops; i++)
1761             {
1762               if ((*it)->m_fadingSamples > 0)
1763               {
1764                 (*it)->m_volume += fadingStep;
1765                 (*it)->m_fadingSamples--;
1766
1767                 if ((*it)->m_fadingSamples == 0)
1768                 {
1769                   // set variables being polled via stream interface
1770                   CSingleLock lock((*it)->m_streamLock);
1771                   (*it)->m_streamFading = false;
1772                 }
1773               }
1774
1775               // volume for stream
1776               float volume = (*it)->m_volume * (*it)->m_rgain;
1777               if(nb_loops > 1)
1778                 volume *= (*it)->m_limiter.Run((float**)mix->pkt->data, mix->pkt->config.channels, i*nb_floats, mix->pkt->planes > 1);
1779
1780               for(int j=0; j<out->pkt->planes && j<mix->pkt->planes; j++)
1781               {
1782                 float *dst = (float*)out->pkt->data[j]+i*nb_floats;
1783                 float *src = (float*)mix->pkt->data[j]+i*nb_floats;
1784 #ifdef __SSE__
1785                 CAEUtil::SSEMulAddArray(dst, src, volume, nb_floats);
1786                 for (int k = 0; k < nb_floats; ++k)
1787                 {
1788                   if (fabs(dst[k]) > 1.0f)
1789                   {
1790                     needClamp = true;
1791                     break;
1792                   }
1793                 }
1794 #else
1795                 for (int k = 0; k < nb_floats; ++k)
1796                 {
1797                   dst[k] += src[k] * volume;
1798                   if (fabs(dst[k]) > 1.0f)
1799                     needClamp = true;
1800                 }
1801 #endif
1802               }
1803             }
1804             mix->Return();
1805           }
1806           busy = true;
1807         }
1808       }// for
1809
1810       // finally clamp samples
1811       if(out && needClamp)
1812       {
1813         int nb_floats = out->pkt->nb_samples * out->pkt->config.channels / out->pkt->planes;
1814         for(int i=0; i<out->pkt->planes; i++)
1815         {
1816           CAEUtil::ClampArray((float*)out->pkt->data[i], nb_floats);
1817         }
1818       }
1819
1820       // process output buffer, gui sounds, encode, viz
1821       if (out)
1822       {
1823         // viz
1824         {
1825           CSingleLock lock(m_vizLock);
1826           if (m_audioCallback && m_vizBuffers && !m_streams.empty())
1827           {
1828             if (!m_vizInitialized)
1829             {
1830               m_audioCallback->OnInitialize(2, m_vizBuffers->m_format.m_sampleRate, 32);
1831               m_vizInitialized = true;
1832             }
1833
1834             if (!m_vizBuffersInput->m_freeSamples.empty())
1835             {
1836               // copy the samples into the viz input buffer
1837               CSampleBuffer *viz = m_vizBuffersInput->GetFreeBuffer();
1838               int samples = std::min(512, out->pkt->nb_samples);
1839               int bytes = samples * out->pkt->config.channels / out->pkt->planes * out->pkt->bytes_per_sample;
1840               for(int i= 0; i < out->pkt->planes; i++)
1841               {
1842                 memcpy(viz->pkt->data[i], out->pkt->data[i], bytes);
1843               }
1844               viz->pkt->nb_samples = samples;
1845               m_vizBuffers->m_inputSamples.push_back(viz);
1846             }
1847             else
1848               CLog::Log(LOGWARNING,"ActiveAE::%s - viz ran out of free buffers", __FUNCTION__);
1849             unsigned int now = XbmcThreads::SystemClockMillis();
1850             unsigned int timestamp = now + m_stats.GetDelay() * 1000;
1851             busy |= m_vizBuffers->ResampleBuffers(timestamp);
1852             while(!m_vizBuffers->m_outputSamples.empty())
1853             {
1854               CSampleBuffer *buf = m_vizBuffers->m_outputSamples.front();
1855               if ((now - buf->timestamp) & 0x80000000)
1856                 break;
1857               else
1858               {
1859                 int samples;
1860                 samples = std::min(512, buf->pkt->nb_samples);
1861                 m_audioCallback->OnAudioData((float*)(buf->pkt->data[0]), samples);
1862                 buf->Return();
1863                 m_vizBuffers->m_outputSamples.pop_front();
1864               }
1865             }
1866           }
1867           else if (m_vizBuffers)
1868             m_vizBuffers->Flush();
1869         }
1870
1871         // mix gui sounds
1872         MixSounds(*(out->pkt));
1873         if (!m_sinkHasVolume || m_muted)
1874           Deamplify(*(out->pkt));
1875
1876         if (m_mode == MODE_TRANSCODE && m_encoder)
1877         {
1878           CSampleBuffer *buf = m_encoderBuffers->GetFreeBuffer();
1879           m_encoder->Encode(out->pkt->data[0], out->pkt->planes*out->pkt->linesize,
1880                             buf->pkt->data[0], buf->pkt->planes*buf->pkt->linesize);
1881           buf->pkt->nb_samples = buf->pkt->max_nb_samples;
1882           out->Return();
1883           out = buf;
1884         }
1885         busy = true;
1886       }
1887
1888       // update stats
1889       if(out)
1890       {
1891         m_stats.AddSamples(out->pkt->nb_samples, m_streams);
1892         m_sinkBuffers->m_inputSamples.push_back(out);
1893       }
1894     }
1895     // pass through
1896     else
1897     {
1898       std::list<CActiveAEStream*>::iterator it;
1899       CSampleBuffer *buffer;
1900       for (it = m_streams.begin(); it != m_streams.end(); ++it)
1901       {
1902         if (!(*it)->m_resampleBuffers->m_outputSamples.empty())
1903         {
1904           buffer =  (*it)->m_resampleBuffers->m_outputSamples.front();
1905           (*it)->m_resampleBuffers->m_outputSamples.pop_front();
1906           m_stats.AddSamples(buffer->pkt->nb_samples, m_streams);
1907           m_sinkBuffers->m_inputSamples.push_back(buffer);
1908         }
1909       }
1910     }
1911
1912     // serve sink buffers
1913     busy = m_sinkBuffers->ResampleBuffers();
1914     while(!m_sinkBuffers->m_outputSamples.empty())
1915     {
1916       CSampleBuffer *out = NULL;
1917       out = m_sinkBuffers->m_outputSamples.front();
1918       m_sinkBuffers->m_outputSamples.pop_front();
1919       m_sink.m_dataPort.SendOutMessage(CSinkDataProtocol::SAMPLE,
1920           &out, sizeof(CSampleBuffer*));
1921       busy = true;
1922     }
1923   }
1924
1925   return busy;
1926 }
1927
1928 bool CActiveAE::HasWork()
1929 {
1930   if (!m_sounds_playing.empty())
1931     return true;
1932   if (!m_sinkBuffers->m_inputSamples.empty())
1933     return true;
1934   if (!m_sinkBuffers->m_outputSamples.empty())
1935     return true;
1936
1937   std::list<CActiveAEStream*>::iterator it;
1938   for (it = m_streams.begin(); it != m_streams.end(); ++it)
1939   {
1940     if (!(*it)->m_resampleBuffers->m_inputSamples.empty())
1941       return true;
1942     if (!(*it)->m_resampleBuffers->m_outputSamples.empty())
1943       return true;
1944     if (!(*it)->m_processingSamples.empty())
1945       return true;
1946   }
1947
1948   return false;
1949 }
1950
1951 void CActiveAE::MixSounds(CSoundPacket &dstSample)
1952 {
1953   if (m_sounds_playing.empty())
1954     return;
1955
1956   float volume;
1957   float *out;
1958   float *sample_buffer;
1959   int max_samples = dstSample.nb_samples;
1960
1961   std::list<SoundState>::iterator it;
1962   for (it = m_sounds_playing.begin(); it != m_sounds_playing.end(); )
1963   {
1964     if (!it->sound->IsConverted())
1965       ResampleSound(it->sound);
1966     int available_samples = it->sound->GetSound(false)->nb_samples - it->samples_played;
1967     int mix_samples = std::min(max_samples, available_samples);
1968     int start = it->samples_played *
1969                 m_dllAvUtil.av_get_bytes_per_sample(it->sound->GetSound(false)->config.fmt) *
1970                 it->sound->GetSound(false)->config.channels /
1971                 it->sound->GetSound(false)->planes;
1972
1973     for(int j=0; j<dstSample.planes; j++)
1974     {
1975       volume = it->sound->GetVolume();
1976       out = (float*)dstSample.data[j];
1977       sample_buffer = (float*)(it->sound->GetSound(false)->data[j]+start);
1978       int nb_floats = mix_samples * dstSample.config.channels / dstSample.planes;
1979 #ifdef __SSE__
1980       CAEUtil::SSEMulAddArray(out, sample_buffer, volume, nb_floats);
1981 #else
1982       for (int k = 0; k < nb_floats; ++k)
1983         *out++ += *sample_buffer++ * volume;
1984 #endif
1985     }
1986
1987     it->samples_played += mix_samples;
1988
1989     // no more frames, so remove it from the list
1990     if (it->samples_played >= it->sound->GetSound(false)->nb_samples)
1991     {
1992       it = m_sounds_playing.erase(it);
1993       continue;
1994     }
1995     ++it;
1996   }
1997 }
1998
1999 void CActiveAE::Deamplify(CSoundPacket &dstSample)
2000 {
2001   if (m_volume < 1.0 || m_muted)
2002   {
2003     float *buffer;
2004     int nb_floats = dstSample.nb_samples * dstSample.config.channels / dstSample.planes;
2005
2006     for(int j=0; j<dstSample.planes; j++)
2007     {
2008       buffer = (float*)dstSample.data[j];
2009 #ifdef __SSE__
2010       CAEUtil::SSEMulArray(buffer, m_muted ? 0.0 : m_volume, nb_floats);
2011 #else
2012       float *fbuffer = buffer;
2013       for (int i = 0; i < nb_floats; i++)
2014         *fbuffer++ *= m_volume;
2015 #endif
2016     }
2017   }
2018 }
2019
2020 //-----------------------------------------------------------------------------
2021 // Configuration
2022 //-----------------------------------------------------------------------------
2023
2024 void CActiveAE::LoadSettings()
2025 {
2026   m_settings.device = CSettings::Get().GetString("audiooutput.audiodevice");
2027   m_settings.passthoughdevice = CSettings::Get().GetString("audiooutput.passthroughdevice");
2028
2029   m_settings.config = CSettings::Get().GetInt("audiooutput.config");
2030   m_settings.channels = (m_sink.GetDeviceType(m_settings.device) == AE_DEVTYPE_IEC958) ? AE_CH_LAYOUT_2_0 : CSettings::Get().GetInt("audiooutput.channels");
2031   m_settings.samplerate = CSettings::Get().GetInt("audiooutput.samplerate");
2032
2033   m_settings.stereoupmix = IsSettingVisible("audiooutput.stereoupmix") ? CSettings::Get().GetBool("audiooutput.stereoupmix") : false;
2034   m_settings.normalizelevels = CSettings::Get().GetBool("audiooutput.normalizelevels");
2035   m_settings.guisoundmode = CSettings::Get().GetInt("audiooutput.guisoundmode");
2036
2037   m_settings.passthrough = m_settings.config == AE_CONFIG_FIXED ? false : CSettings::Get().GetBool("audiooutput.passthrough");
2038   if (!m_sink.HasPassthroughDevice())
2039     m_settings.passthrough = false;
2040   m_settings.ac3passthrough = CSettings::Get().GetBool("audiooutput.ac3passthrough");
2041   m_settings.ac3transcode = CSettings::Get().GetBool("audiooutput.ac3transcode");
2042   m_settings.eac3passthrough = CSettings::Get().GetBool("audiooutput.eac3passthrough");
2043   m_settings.truehdpassthrough = CSettings::Get().GetBool("audiooutput.truehdpassthrough");
2044   m_settings.dtspassthrough = CSettings::Get().GetBool("audiooutput.dtspassthrough");
2045   m_settings.dtshdpassthrough = CSettings::Get().GetBool("audiooutput.dtshdpassthrough");
2046
2047   m_settings.resampleQuality = static_cast<AEQuality>(CSettings::Get().GetInt("audiooutput.processquality"));
2048 }
2049
2050 bool CActiveAE::Initialize()
2051 {
2052   if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllAvFormat.Load())
2053   {
2054     CLog::Log(LOGERROR,"CActiveAE::Initialize - failed to load ffmpeg libraries");
2055     return false;
2056   }
2057   m_dllAvFormat.av_register_all();
2058
2059   Create();
2060   Message *reply;
2061   if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::INIT,
2062                                                  &reply,
2063                                                  5000))
2064   {
2065     bool success = reply->signal == CActiveAEControlProtocol::ACC;
2066     reply->Release();
2067     if (!success)
2068     {
2069       CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
2070       Dispose();
2071       return false;
2072     }
2073   }
2074   else
2075   {
2076     CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__);
2077     Dispose();
2078     return false;
2079   }
2080
2081   // hook into windowing for receiving display reset events
2082 #if defined(HAS_GLX) || defined(TARGET_DARWIN_OSX)
2083   g_Windowing.Register(this);
2084 #endif
2085
2086   m_inMsgEvent.Reset();
2087   return true;
2088 }
2089
2090 void CActiveAE::EnumerateOutputDevices(AEDeviceList &devices, bool passthrough)
2091 {
2092   m_sink.EnumerateOutputDevices(devices, passthrough);
2093 }
2094
2095 std::string CActiveAE::GetDefaultDevice(bool passthrough)
2096 {
2097   return m_sink.GetDefaultDevice(passthrough);
2098 }
2099
2100 void CActiveAE::OnSettingsChange(const std::string& setting)
2101 {
2102   if (setting == "audiooutput.passthroughdevice" ||
2103       setting == "audiooutput.audiodevice"       ||
2104       setting == "audiooutput.config"            ||
2105       setting == "audiooutput.ac3passthrough"    ||
2106       setting == "audiooutput.ac3transcode"      ||
2107       setting == "audiooutput.eac3passthrough"   ||
2108       setting == "audiooutput.dtspassthrough"    ||
2109       setting == "audiooutput.truehdpassthrough" ||
2110       setting == "audiooutput.dtshdpassthrough"  ||
2111       setting == "audiooutput.channels"          ||
2112       setting == "audiooutput.stereoupmix"       ||
2113       setting == "audiooutput.streamsilence"     ||
2114       setting == "audiooutput.processquality"    ||
2115       setting == "audiooutput.passthrough"       ||
2116       setting == "audiooutput.samplerate"        ||
2117       setting == "audiooutput.normalizelevels"   ||
2118       setting == "audiooutput.guisoundmode")
2119   {
2120     m_controlPort.SendOutMessage(CActiveAEControlProtocol::RECONFIGURE);
2121   }
2122 }
2123
2124 bool CActiveAE::SupportsRaw(AEDataFormat format)
2125 {
2126   if (!m_sink.HasPassthroughDevice())
2127     return false;
2128
2129   // those formats require HDMI
2130   if (format == AE_FMT_DTSHD || format == AE_FMT_TRUEHD)
2131   {
2132     if(m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.passthroughdevice")) != AE_DEVTYPE_HDMI)
2133       return false;
2134   }
2135
2136   // TODO: check ELD?
2137   return true;
2138 }
2139
2140 bool CActiveAE::SupportsSilenceTimeout()
2141 {
2142   return true;
2143 }
2144
2145 bool CActiveAE::SupportsQualityLevel(enum AEQuality level)
2146 {
2147   if (level == AE_QUALITY_LOW || level == AE_QUALITY_MID || level == AE_QUALITY_HIGH)
2148     return true;
2149
2150   return false;
2151 }
2152
2153 bool CActiveAE::IsSettingVisible(const std::string &settingId)
2154 {
2155   if (settingId == "audiooutput.samplerate")
2156   {
2157     if (m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) == AE_DEVTYPE_IEC958)
2158       return true;
2159     if (CSettings::Get().GetInt("audiooutput.config") == AE_CONFIG_FIXED)
2160       return true;
2161   }
2162   else if (settingId == "audiooutput.channels")
2163   {
2164     if (m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) != AE_DEVTYPE_IEC958)
2165       return true;
2166   }
2167   else if (settingId == "audiooutput.passthrough")
2168   {
2169     if (m_sink.HasPassthroughDevice() && CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED)
2170       return true;
2171   }
2172   else if (settingId == "audiooutput.truehdpassthrough")
2173   {
2174     if (m_sink.HasPassthroughDevice() &&
2175         CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED &&
2176         m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.passthroughdevice")) == AE_DEVTYPE_HDMI)
2177       return true;
2178   }
2179   else if (settingId == "audiooutput.dtshdpassthrough")
2180   {
2181     if (m_sink.HasPassthroughDevice() &&
2182         CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED &&
2183         m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.passthroughdevice")) == AE_DEVTYPE_HDMI)
2184       return true;
2185   }
2186   else if (settingId == "audiooutput.stereoupmix")
2187   {
2188     if (m_sink.HasPassthroughDevice() ||
2189         CSettings::Get().GetInt("audiooutput.channels") > AE_CH_LAYOUT_2_0)
2190     return true;
2191   }
2192   else if (settingId == "audiooutput.ac3transcode")
2193   {
2194     if (m_sink.HasPassthroughDevice() &&
2195         CSettings::Get().GetBool("audiooutput.ac3passthrough") &&
2196         CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED &&
2197         (CSettings::Get().GetInt("audiooutput.channels") <= AE_CH_LAYOUT_2_0 || m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) == AE_DEVTYPE_IEC958))
2198       return true;
2199   }
2200   return false;
2201 }
2202
2203 void CActiveAE::Shutdown()
2204 {
2205   Dispose();
2206 }
2207
2208 bool CActiveAE::Suspend()
2209 {
2210   return m_controlPort.SendOutMessage(CActiveAEControlProtocol::SUSPEND);
2211 }
2212
2213 bool CActiveAE::Resume()
2214 {
2215   Message *reply;
2216   if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::INIT,
2217                                                  &reply,
2218                                                  5000))
2219   {
2220     bool success = reply->signal == CActiveAEControlProtocol::ACC;
2221     reply->Release();
2222     if (!success)
2223     {
2224       CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
2225       return false;
2226     }
2227   }
2228   else
2229   {
2230     CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__);
2231     return false;
2232   }
2233
2234   m_inMsgEvent.Reset();
2235   return true;
2236 }
2237
2238 bool CActiveAE::IsSuspended()
2239 {
2240   return m_stats.IsSuspended();
2241 }
2242
2243 float CActiveAE::GetVolume()
2244 {
2245   return m_aeVolume;
2246 }
2247
2248 void CActiveAE::SetVolume(const float volume)
2249 {
2250   m_aeVolume = std::max( 0.0f, std::min(1.0f, volume));
2251   m_controlPort.SendOutMessage(CActiveAEControlProtocol::VOLUME, &m_aeVolume, sizeof(float));
2252 }
2253
2254 void CActiveAE::SetMute(const bool enabled)
2255 {
2256   m_aeMuted = enabled;
2257   m_controlPort.SendOutMessage(CActiveAEControlProtocol::MUTE, &m_aeMuted, sizeof(bool));
2258 }
2259
2260 bool CActiveAE::IsMuted()
2261 {
2262   return m_aeMuted;
2263 }
2264
2265 void CActiveAE::SetSoundMode(const int mode)
2266 {
2267   return;
2268 }
2269
2270 void CActiveAE::KeepConfiguration(unsigned int millis)
2271 {
2272   unsigned int timeMs = millis;
2273   m_controlPort.SendOutMessage(CActiveAEControlProtocol::KEEPCONFIG, &timeMs, sizeof(unsigned int));
2274 }
2275
2276 void CActiveAE::OnLostDevice()
2277 {
2278   Message *reply;
2279   if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::DISPLAYLOST,
2280                                                  &reply,
2281                                                  5000))
2282   {
2283     bool success = reply->signal == CActiveAEControlProtocol::ACC;
2284     reply->Release();
2285     if (!success)
2286     {
2287       CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
2288     }
2289   }
2290   else
2291   {
2292     CLog::Log(LOGERROR, "ActiveAE::%s - timed out", __FUNCTION__);
2293   }
2294 }
2295
2296 void CActiveAE::OnResetDevice()
2297 {
2298   m_controlPort.SendOutMessage(CActiveAEControlProtocol::DISPLAYRESET);
2299 }
2300
2301 //-----------------------------------------------------------------------------
2302 // Utils
2303 //-----------------------------------------------------------------------------
2304
2305 uint8_t **CActiveAE::AllocSoundSample(SampleConfig &config, int &samples, int &bytes_per_sample, int &planes, int &linesize)
2306 {
2307   uint8_t **buffer;
2308   planes = m_dllAvUtil.av_sample_fmt_is_planar(config.fmt) ? config.channels : 1;
2309   buffer = new uint8_t*[planes];
2310
2311   // align buffer to 16 in order to be compatible with sse in CAEConvert
2312   m_dllAvUtil.av_samples_alloc(buffer, &linesize, config.channels,
2313                                  samples, config.fmt, 16);
2314   bytes_per_sample = m_dllAvUtil.av_get_bytes_per_sample(config.fmt);
2315   return buffer;
2316 }
2317
2318 void CActiveAE::FreeSoundSample(uint8_t **data)
2319 {
2320   m_dllAvUtil.av_freep(data);
2321   delete [] data;
2322 }
2323
2324 bool CActiveAE::CompareFormat(AEAudioFormat &lhs, AEAudioFormat &rhs)
2325 {
2326   if (lhs.m_channelLayout != rhs.m_channelLayout ||
2327       lhs.m_dataFormat != rhs.m_dataFormat ||
2328       lhs.m_sampleRate != rhs.m_sampleRate)
2329     return false;
2330   else
2331     return true;
2332 }
2333
2334 //-----------------------------------------------------------------------------
2335 // GUI Sounds
2336 //-----------------------------------------------------------------------------
2337
2338 /**
2339  * load sound from an audio file and store original format
2340  * register the sound in ActiveAE
2341  * later when the engine is idle it will convert the sound to sink format
2342  */
2343
2344 #define SOUNDBUFFER_SIZE 20480
2345
2346 IAESound *CActiveAE::MakeSound(const std::string& file)
2347 {
2348   AVFormatContext *fmt_ctx = NULL;
2349   AVCodecContext *dec_ctx = NULL;
2350   AVIOContext *io_ctx;
2351   AVInputFormat *io_fmt;
2352   AVCodec *dec = NULL;
2353   CActiveAESound *sound = NULL;
2354   SampleConfig config;
2355
2356   sound = new CActiveAESound(file);
2357   if (!sound->Prepare())
2358   {
2359     delete sound;
2360     return NULL;
2361   }
2362   int fileSize = sound->GetFileSize();
2363
2364   fmt_ctx = m_dllAvFormat.avformat_alloc_context();
2365   unsigned char* buffer = (unsigned char*)m_dllAvUtil.av_malloc(SOUNDBUFFER_SIZE+FF_INPUT_BUFFER_PADDING_SIZE);
2366   io_ctx = m_dllAvFormat.avio_alloc_context(buffer, SOUNDBUFFER_SIZE, 0,
2367                                             sound, CActiveAESound::Read, NULL, CActiveAESound::Seek);
2368   io_ctx->max_packet_size = sound->GetChunkSize();
2369   if(io_ctx->max_packet_size)
2370     io_ctx->max_packet_size *= SOUNDBUFFER_SIZE / io_ctx->max_packet_size;
2371
2372   if(!sound->IsSeekPosible())
2373     io_ctx->seekable = 0;
2374
2375   fmt_ctx->pb = io_ctx;
2376
2377   m_dllAvFormat.av_probe_input_buffer(io_ctx, &io_fmt, file.c_str(), NULL, 0, 0);
2378   if (!io_fmt)
2379   {
2380     m_dllAvFormat.avformat_close_input(&fmt_ctx);
2381     delete sound;
2382     return NULL;
2383   }
2384
2385   // find decoder
2386   if (m_dllAvFormat.avformat_open_input(&fmt_ctx, file.c_str(), NULL, NULL) == 0)
2387   {
2388     fmt_ctx->flags |= AVFMT_FLAG_NOPARSE;
2389     if (m_dllAvFormat.avformat_find_stream_info(fmt_ctx, NULL) >= 0)
2390     {
2391       dec_ctx = fmt_ctx->streams[0]->codec;
2392       dec = m_dllAvCodec.avcodec_find_decoder(dec_ctx->codec_id);
2393       config.sample_rate = dec_ctx->sample_rate;
2394       config.channels = dec_ctx->channels;
2395       config.channel_layout = dec_ctx->channel_layout;
2396     }
2397   }
2398   if (dec == NULL)
2399   {
2400     m_dllAvFormat.avformat_close_input(&fmt_ctx);
2401     delete sound;
2402     return NULL;
2403   }
2404
2405   dec_ctx = m_dllAvCodec.avcodec_alloc_context3(dec);
2406   dec_ctx->sample_rate = config.sample_rate;
2407   dec_ctx->channels = config.channels;
2408   if (!config.channel_layout)
2409     config.channel_layout = m_dllAvUtil.av_get_default_channel_layout(config.channels);
2410   dec_ctx->channel_layout = config.channel_layout;
2411
2412   AVPacket avpkt;
2413   AVFrame *decoded_frame = NULL;
2414   decoded_frame = m_dllAvCodec.avcodec_alloc_frame();
2415
2416   if (m_dllAvCodec.avcodec_open2(dec_ctx, dec, NULL) >= 0)
2417   {
2418     bool init = false;
2419
2420     // decode until eof
2421     m_dllAvCodec.av_init_packet(&avpkt);
2422     int len;
2423     while (m_dllAvFormat.av_read_frame(fmt_ctx, &avpkt) >= 0)
2424     {
2425       int got_frame = 0;
2426       len = m_dllAvCodec.avcodec_decode_audio4(dec_ctx, decoded_frame, &got_frame, &avpkt);
2427       if (len < 0)
2428       {
2429         m_dllAvCodec.avcodec_close(dec_ctx);
2430         m_dllAvUtil.av_free(dec_ctx);
2431         m_dllAvUtil.av_free(&decoded_frame);
2432         m_dllAvFormat.avformat_close_input(&fmt_ctx);
2433         delete sound;
2434         return NULL;
2435       }
2436       if (got_frame)
2437       {
2438         if (!init)
2439         {
2440           int samples = fileSize / m_dllAvUtil.av_get_bytes_per_sample(dec_ctx->sample_fmt) / config.channels;
2441           config.fmt = dec_ctx->sample_fmt;
2442           config.bits_per_sample = dec_ctx->bits_per_coded_sample;
2443           sound->InitSound(true, config, samples);
2444           init = true;
2445         }
2446         sound->StoreSound(true, decoded_frame->extended_data,
2447                           decoded_frame->nb_samples, decoded_frame->linesize[0]);
2448       }
2449     }
2450     m_dllAvCodec.avcodec_close(dec_ctx);
2451   }
2452
2453   m_dllAvUtil.av_free(dec_ctx);
2454   m_dllAvUtil.av_free(decoded_frame);
2455   m_dllAvFormat.avformat_close_input(&fmt_ctx);
2456
2457   sound->Finish();
2458
2459   // register sound
2460   m_dataPort.SendOutMessage(CActiveAEDataProtocol::NEWSOUND, &sound, sizeof(CActiveAESound*));
2461
2462   return sound;
2463 }
2464
2465 void CActiveAE::FreeSound(IAESound *sound)
2466 {
2467   m_dataPort.SendOutMessage(CActiveAEDataProtocol::FREESOUND, &sound, sizeof(CActiveAESound*));
2468 }
2469
2470 void CActiveAE::PlaySound(CActiveAESound *sound)
2471 {
2472   m_dataPort.SendOutMessage(CActiveAEDataProtocol::PLAYSOUND, &sound, sizeof(CActiveAESound*));
2473 }
2474
2475 void CActiveAE::StopSound(CActiveAESound *sound)
2476 {
2477   m_controlPort.SendOutMessage(CActiveAEControlProtocol::STOPSOUND, &sound, sizeof(CActiveAESound*));
2478 }
2479
2480 /**
2481  * resample sounds to destination format for mixing
2482  * destination format is either format of stream or
2483  * default sink format when no stream is playing
2484  */
2485 void CActiveAE::ResampleSounds()
2486 {
2487   if (m_settings.guisoundmode == AE_SOUND_OFF ||
2488      (m_settings.guisoundmode == AE_SOUND_IDLE && !m_streams.empty()))
2489     return;
2490
2491   std::vector<CActiveAESound*>::iterator it;
2492   for (it = m_sounds.begin(); it != m_sounds.end(); ++it)
2493   {
2494     if (!(*it)->IsConverted())
2495     {
2496       ResampleSound(*it);
2497       // only do one sound, then yield to main loop
2498       break;
2499     }
2500   }
2501 }
2502
2503 bool CActiveAE::ResampleSound(CActiveAESound *sound)
2504 {
2505   SampleConfig orig_config, dst_config;
2506   uint8_t **dst_buffer;
2507   int dst_samples;
2508
2509   if (m_mode == MODE_RAW || m_internalFormat.m_dataFormat == AE_FMT_INVALID)
2510     return false;
2511
2512   if (!sound->GetSound(true))
2513     return false;
2514
2515   orig_config = sound->GetSound(true)->config;
2516
2517   dst_config.channel_layout = CActiveAEResample::GetAVChannelLayout(m_internalFormat.m_channelLayout);
2518   dst_config.channels = m_internalFormat.m_channelLayout.Count();
2519   dst_config.sample_rate = m_internalFormat.m_sampleRate;
2520   dst_config.fmt = CActiveAEResample::GetAVSampleFormat(m_internalFormat.m_dataFormat);
2521   dst_config.bits_per_sample = CAEUtil::DataFormatToUsedBits(m_internalFormat.m_dataFormat);
2522
2523   CActiveAEResample *resampler = new CActiveAEResample();
2524   resampler->Init(dst_config.channel_layout,
2525                   dst_config.channels,
2526                   dst_config.sample_rate,
2527                   dst_config.fmt,
2528                   dst_config.bits_per_sample,
2529                   orig_config.channel_layout,
2530                   orig_config.channels,
2531                   orig_config.sample_rate,
2532                   orig_config.fmt,
2533                   orig_config.bits_per_sample,
2534                   false,
2535                   true,
2536                   NULL,
2537                   m_settings.resampleQuality);
2538
2539   dst_samples = resampler->CalcDstSampleCount(sound->GetSound(true)->nb_samples,
2540                                               m_internalFormat.m_sampleRate,
2541                                               orig_config.sample_rate);
2542
2543   dst_buffer = sound->InitSound(false, dst_config, dst_samples);
2544   if (!dst_buffer)
2545   {
2546     delete resampler;
2547     return false;
2548   }
2549   int samples = resampler->Resample(dst_buffer, dst_samples,
2550                                     sound->GetSound(true)->data,
2551                                     sound->GetSound(true)->nb_samples,
2552                                     1.0);
2553
2554   sound->GetSound(false)->nb_samples = samples;
2555
2556   delete resampler;
2557   sound->SetConverted(true);
2558   return true;
2559 }
2560
2561 //-----------------------------------------------------------------------------
2562 // Streams
2563 //-----------------------------------------------------------------------------
2564
2565 IAEStream *CActiveAE::MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSampleRate, CAEChannelInfo channelLayout, unsigned int options)
2566 {
2567   //TODO: pass number of samples in audio packet
2568
2569   AEAudioFormat format;
2570   format.m_dataFormat = dataFormat;
2571   format.m_sampleRate = sampleRate;
2572   format.m_encodedRate = encodedSampleRate;
2573   format.m_channelLayout = channelLayout;
2574   format.m_frames = format.m_sampleRate / 10;
2575   format.m_frameSize = format.m_channelLayout.Count() *
2576                        (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);
2577
2578   MsgStreamNew msg;
2579   msg.format = format;
2580   msg.options = options;
2581
2582   Message *reply;
2583   if (m_dataPort.SendOutMessageSync(CActiveAEDataProtocol::NEWSTREAM,
2584                                     &reply,10000,
2585                                     &msg, sizeof(MsgStreamNew)))
2586   {
2587     bool success = reply->signal == CActiveAEControlProtocol::ACC;
2588     if (success)
2589     {
2590       CActiveAEStream *stream = *(CActiveAEStream**)reply->data;
2591       reply->Release();
2592       return stream;
2593     }
2594     reply->Release();
2595   }
2596
2597   CLog::Log(LOGERROR, "ActiveAE::%s - could not create stream", __FUNCTION__);
2598   return NULL;
2599 }
2600
2601 IAEStream *CActiveAE::FreeStream(IAEStream *stream)
2602 {
2603   m_dataPort.SendOutMessage(CActiveAEDataProtocol::FREESTREAM, &stream, sizeof(IAEStream*));
2604   return NULL;
2605 }
2606
2607 void CActiveAE::FlushStream(CActiveAEStream *stream)
2608 {
2609   Message *reply;
2610   if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::FLUSHSTREAM,
2611                                        &reply,1000,
2612                                        &stream, sizeof(CActiveAEStream*)))
2613   {
2614     bool success = reply->signal == CActiveAEControlProtocol::ACC;
2615     reply->Release();
2616     if (!success)
2617     {
2618       CLog::Log(LOGERROR, "CActiveAE::FlushStream - failed");
2619     }
2620   }
2621 }
2622
2623 void CActiveAE::PauseStream(CActiveAEStream *stream, bool pause)
2624 {
2625   // TODO pause sink, needs api change
2626   if (pause)
2627     m_controlPort.SendOutMessage(CActiveAEControlProtocol::PAUSESTREAM,
2628                                    &stream, sizeof(CActiveAEStream*));
2629   else
2630     m_controlPort.SendOutMessage(CActiveAEControlProtocol::RESUMESTREAM,
2631                                    &stream, sizeof(CActiveAEStream*));
2632 }
2633
2634 void CActiveAE::SetStreamAmplification(CActiveAEStream *stream, float amplify)
2635 {
2636   MsgStreamParameter msg;
2637   msg.stream = stream;
2638   msg.parameter.float_par = amplify;
2639   m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMAMP,
2640                                      &msg, sizeof(MsgStreamParameter));
2641 }
2642
2643 void CActiveAE::SetStreamReplaygain(CActiveAEStream *stream, float rgain)
2644 {
2645   MsgStreamParameter msg;
2646   msg.stream = stream;
2647   msg.parameter.float_par = rgain;
2648   m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMRGAIN,
2649                                      &msg, sizeof(MsgStreamParameter));
2650 }
2651
2652 void CActiveAE::SetStreamVolume(CActiveAEStream *stream, float volume)
2653 {
2654   MsgStreamParameter msg;
2655   msg.stream = stream;
2656   msg.parameter.float_par = volume;
2657   m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMVOLUME,
2658                                      &msg, sizeof(MsgStreamParameter));
2659 }
2660
2661 void CActiveAE::SetStreamResampleRatio(CActiveAEStream *stream, double ratio)
2662 {
2663   MsgStreamParameter msg;
2664   msg.stream = stream;
2665   msg.parameter.double_par = ratio;
2666   m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMRESAMPLERATIO,
2667                                      &msg, sizeof(MsgStreamParameter));
2668 }
2669
2670 void CActiveAE::SetStreamFade(CActiveAEStream *stream, float from, float target, unsigned int millis)
2671 {
2672   MsgStreamFade msg;
2673   msg.stream = stream;
2674   msg.from = from;
2675   msg.target = target;
2676   msg.millis = millis;
2677   m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMFADE,
2678                                      &msg, sizeof(MsgStreamFade));
2679 }
2680
2681 void CActiveAE::RegisterAudioCallback(IAudioCallback* pCallback)
2682 {
2683   CSingleLock lock(m_vizLock);
2684   m_audioCallback = pCallback;
2685   m_vizInitialized = false;
2686 }
2687
2688 void CActiveAE::UnregisterAudioCallback()
2689 {
2690   CSingleLock lock(m_vizLock);
2691   m_audioCallback = NULL;
2692 }