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