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