Merge pull request #3831 from xhaggi/epg-past-data
[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 (initSink && (*it)->m_resampleBuffers)
1012       {
1013         m_discardBufferPools.push_back((*it)->m_resampleBuffers);
1014         (*it)->m_resampleBuffers = NULL;
1015       }
1016       if (!(*it)->m_resampleBuffers)
1017       {
1018         (*it)->m_resampleBuffers = new CActiveAEBufferPoolResample((*it)->m_inputBuffers->m_format, outputFormat, m_settings.resampleQuality);
1019         (*it)->m_resampleBuffers->m_changeResampler = (*it)->m_forceResampler;
1020         (*it)->m_resampleBuffers->Create(MAX_CACHE_LEVEL*1000, false, m_settings.stereoupmix, m_settings.normalizelevels);
1021       }
1022       if (m_mode == MODE_TRANSCODE || m_streams.size() > 1)
1023         (*it)->m_resampleBuffers->m_fillPackets = true;
1024
1025       // amplification
1026       (*it)->m_limiter.SetSamplerate(outputFormat.m_sampleRate);
1027     }
1028
1029     // buffers for viz
1030     if (!AE_IS_RAW(inputFormat.m_dataFormat))
1031     {
1032       if (initSink && m_vizBuffers)
1033       {
1034         m_discardBufferPools.push_back(m_vizBuffers);
1035         m_vizBuffers = NULL;
1036         m_discardBufferPools.push_back(m_vizBuffersInput);
1037         m_vizBuffersInput = NULL;
1038       }
1039       if (!m_vizBuffers)
1040       {
1041         AEAudioFormat vizFormat = m_internalFormat;
1042         vizFormat.m_channelLayout = AE_CH_LAYOUT_2_0;
1043         vizFormat.m_dataFormat = AE_FMT_FLOAT;
1044
1045         // input buffers
1046         m_vizBuffersInput = new CActiveAEBufferPool(m_internalFormat);
1047         m_vizBuffersInput->Create(2000);
1048
1049         // resample buffers
1050         m_vizBuffers = new CActiveAEBufferPoolResample(m_internalFormat, vizFormat, m_settings.resampleQuality);
1051         // TODO use cache of sync + water level
1052         m_vizBuffers->Create(2000, false, false);
1053         m_vizInitialized = false;
1054       }
1055     }
1056   }
1057
1058   // resample buffers for sink
1059   if (m_sinkBuffers && 
1060      (!CompareFormat(m_sinkBuffers->m_format,m_sinkFormat) || !CompareFormat(m_sinkBuffers->m_inputFormat, sinkInputFormat)))
1061   {
1062     m_discardBufferPools.push_back(m_sinkBuffers);
1063     m_sinkBuffers = NULL;
1064   }
1065   if (!m_sinkBuffers)
1066   {
1067     m_sinkBuffers = new CActiveAEBufferPoolResample(sinkInputFormat, m_sinkFormat, m_settings.resampleQuality);
1068     m_sinkBuffers->Create(MAX_WATER_LEVEL*1000, true, false);
1069   }
1070
1071   // reset gui sounds
1072   if (!CompareFormat(oldInternalFormat, m_internalFormat))
1073   {
1074     if (m_settings.guisoundmode == AE_SOUND_ALWAYS ||
1075        (m_settings.guisoundmode == AE_SOUND_IDLE && m_streams.empty()))
1076     {
1077       std::vector<CActiveAESound*>::iterator it;
1078       for (it = m_sounds.begin(); it != m_sounds.end(); ++it)
1079       {
1080         (*it)->SetConverted(false);
1081       }
1082     }
1083     m_sounds_playing.clear();
1084   }
1085
1086   ClearDiscardedBuffers();
1087   m_extDrain = false;
1088 }
1089
1090 CActiveAEStream* CActiveAE::CreateStream(MsgStreamNew *streamMsg)
1091 {
1092   // we only can handle a single pass through stream
1093   bool hasRawStream = false;
1094   bool hasStream = false;
1095   std::list<CActiveAEStream*>::iterator it;
1096   for(it = m_streams.begin(); it != m_streams.end(); ++it)
1097   {
1098     if((*it)->IsDrained())
1099       continue;
1100     if(AE_IS_RAW((*it)->m_format.m_dataFormat))
1101       hasRawStream = true;
1102     hasStream = true;
1103   }
1104   if (hasRawStream || (hasStream && AE_IS_RAW(streamMsg->format.m_dataFormat)))
1105   {
1106     return NULL;
1107   }
1108
1109   // create the stream
1110   CActiveAEStream *stream;
1111   stream = new CActiveAEStream(&streamMsg->format);
1112   stream->m_streamPort = new CActiveAEDataProtocol("stream",
1113                              &stream->m_inMsgEvent, &m_outMsgEvent);
1114
1115   // create buffer pool
1116   stream->m_inputBuffers = NULL; // create in Configure when we know the sink format
1117   stream->m_resampleBuffers = NULL; // create in Configure when we know the sink format
1118   stream->m_statsLock = m_stats.GetLock();
1119   stream->m_fadingSamples = 0;
1120   stream->m_started = false;
1121
1122   if (streamMsg->options & AESTREAM_PAUSED)
1123     stream->m_paused = true;
1124
1125   if (streamMsg->options & AESTREAM_FORCE_RESAMPLE)
1126     stream->m_forceResampler = true;
1127
1128   m_streams.push_back(stream);
1129
1130   return stream;
1131 }
1132
1133 void CActiveAE::DiscardStream(CActiveAEStream *stream)
1134 {
1135   std::list<CActiveAEStream*>::iterator it;
1136   for (it=m_streams.begin(); it!=m_streams.end(); )
1137   {
1138     if (stream == (*it))
1139     {
1140       while (!(*it)->m_processingSamples.empty())
1141       {
1142         (*it)->m_processingSamples.front()->Return();
1143         (*it)->m_processingSamples.pop_front();
1144       }
1145       m_discardBufferPools.push_back((*it)->m_inputBuffers);
1146       m_discardBufferPools.push_back((*it)->m_resampleBuffers);
1147       CLog::Log(LOGDEBUG, "CActiveAE::DiscardStream - audio stream deleted");
1148       delete (*it)->m_streamPort;
1149       delete (*it);
1150       it = m_streams.erase(it);
1151     }
1152     else
1153       ++it;
1154   }
1155
1156   ClearDiscardedBuffers();
1157 }
1158
1159 void CActiveAE::SFlushStream(CActiveAEStream *stream)
1160 {
1161   while (!stream->m_processingSamples.empty())
1162   {
1163     stream->m_processingSamples.front()->Return();
1164     stream->m_processingSamples.pop_front();
1165   }
1166   stream->m_resampleBuffers->Flush();
1167   stream->m_streamPort->Purge();
1168   stream->m_bufferedTime = 0.0;
1169   stream->m_paused = false;
1170
1171   // flush the engine if we only have a single stream
1172   if (m_streams.size() == 1)
1173   {
1174     FlushEngine();
1175   }
1176 }
1177
1178 void CActiveAE::FlushEngine()
1179 {
1180   if (m_sinkBuffers)
1181     m_sinkBuffers->Flush();
1182   if (m_vizBuffers)
1183     m_vizBuffers->Flush();
1184
1185   // send message to sink
1186   Message *reply;
1187   if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::FLUSH,
1188                                            &reply, 2000))
1189   {
1190     bool success = reply->signal == CSinkControlProtocol::ACC ? true : false;
1191     if (!success)
1192     {
1193       CLog::Log(LOGERROR, "ActiveAE::%s - returned error on flush", __FUNCTION__);
1194       m_extError = true;
1195     }
1196     reply->Release();
1197   }
1198   else
1199   {
1200     CLog::Log(LOGERROR, "ActiveAE::%s - failed to flush", __FUNCTION__);
1201     m_extError = true;
1202   }
1203   m_stats.Reset(m_sinkFormat.m_sampleRate);
1204 }
1205
1206 void CActiveAE::ClearDiscardedBuffers()
1207 {
1208   std::list<CActiveAEBufferPool*>::iterator it;
1209   for (it=m_discardBufferPools.begin(); it!=m_discardBufferPools.end(); ++it)
1210   {
1211     CActiveAEBufferPoolResample *rbuf = dynamic_cast<CActiveAEBufferPoolResample*>(*it);
1212     if (rbuf)
1213     {
1214       rbuf->Flush();
1215     }
1216     // if all buffers have returned, we can delete the buffer pool
1217     if ((*it)->m_allSamples.size() == (*it)->m_freeSamples.size())
1218     {
1219       delete (*it);
1220       CLog::Log(LOGDEBUG, "CActiveAE::ClearDiscardedBuffers - buffer pool deleted");
1221       m_discardBufferPools.erase(it);
1222       return;
1223     }
1224   }
1225 }
1226
1227 void CActiveAE::SStopSound(CActiveAESound *sound)
1228 {
1229   std::list<SoundState>::iterator it;
1230   for (it=m_sounds_playing.begin(); it!=m_sounds_playing.end(); ++it)
1231   {
1232     if (it->sound == sound)
1233     {
1234       m_sounds_playing.erase(it);
1235       return;
1236     }
1237   }
1238 }
1239
1240 void CActiveAE::DiscardSound(CActiveAESound *sound)
1241 {
1242   SStopSound(sound);
1243
1244   std::vector<CActiveAESound*>::iterator it;
1245   for (it=m_sounds.begin(); it!=m_sounds.end(); ++it)
1246   {
1247     if ((*it) == sound)
1248     {
1249       m_sounds.erase(it);
1250       return;
1251     }
1252   }
1253 }
1254
1255 void CActiveAE::ChangeResamplers()
1256 {
1257   std::list<CActiveAEStream*>::iterator it;
1258   for(it=m_streams.begin(); it!=m_streams.end(); ++it)
1259   {
1260     bool normalize = true;
1261     if (((*it)->m_resampleBuffers->m_format.m_channelLayout.Count() <
1262          (*it)->m_resampleBuffers->m_inputFormat.m_channelLayout.Count()) &&
1263          !m_settings.normalizelevels)
1264       normalize = false;
1265
1266     if ((*it)->m_resampleBuffers && (*it)->m_resampleBuffers->m_resampler &&
1267         (((*it)->m_resampleBuffers->m_resampleQuality != m_settings.resampleQuality) ||
1268         (((*it)->m_resampleBuffers->m_stereoUpmix != m_settings.stereoupmix)) ||
1269         ((*it)->m_resampleBuffers->m_normalize != normalize)))
1270     {
1271       (*it)->m_resampleBuffers->m_changeResampler = true;
1272     }
1273     (*it)->m_resampleBuffers->m_resampleQuality = m_settings.resampleQuality;
1274     (*it)->m_resampleBuffers->m_stereoUpmix = m_settings.stereoupmix;
1275     (*it)->m_resampleBuffers->m_normalize = normalize;
1276   }
1277 }
1278
1279 void CActiveAE::ApplySettingsToFormat(AEAudioFormat &format, AudioSettings &settings, int *mode)
1280 {
1281   int oldMode = m_mode;
1282   if (mode)
1283     *mode = MODE_PCM;
1284
1285   // raw pass through
1286   if (AE_IS_RAW(format.m_dataFormat))
1287   {
1288     if ((format.m_dataFormat == AE_FMT_AC3 && !settings.ac3passthrough) ||
1289         (format.m_dataFormat == AE_FMT_EAC3 && !settings.eac3passthrough) ||
1290         (format.m_dataFormat == AE_FMT_TRUEHD && !settings.truehdpassthrough) ||
1291         (format.m_dataFormat == AE_FMT_DTS && !settings.dtspassthrough) ||
1292         (format.m_dataFormat == AE_FMT_DTSHD && !settings.dtshdpassthrough))
1293     {
1294       CLog::Log(LOGERROR, "CActiveAE::ApplySettingsToFormat - input audio format is wrong");
1295     }
1296     if (mode)
1297       *mode = MODE_RAW;
1298   }
1299   // transcode
1300   else if (settings.channels <= AE_CH_LAYOUT_2_0 && // no multichannel pcm
1301            settings.passthrough &&
1302            settings.ac3passthrough &&
1303            !m_streams.empty() &&
1304            (format.m_channelLayout.Count() > 2 || settings.stereoupmix))
1305   {
1306     format.m_dataFormat = AE_FMT_AC3;
1307     format.m_sampleRate = 48000;
1308     format.m_channelLayout = AE_CH_LAYOUT_2_0;
1309     if (mode)
1310       *mode = MODE_TRANSCODE;
1311   }
1312   else
1313   {
1314     format.m_dataFormat = AE_FMT_FLOAT;
1315     // consider user channel layout for those cases
1316     // 1. input stream is multichannel
1317     // 2. stereo upmix is selected
1318     // 3. fixed mode
1319     if ((format.m_channelLayout.Count() > 2) ||
1320          settings.stereoupmix ||
1321          (settings.config == AE_CONFIG_FIXED))
1322     {
1323       CAEChannelInfo stdLayout;
1324       switch (settings.channels)
1325       {
1326         default:
1327         case  0: stdLayout = AE_CH_LAYOUT_2_0; break;
1328         case  1: stdLayout = AE_CH_LAYOUT_2_0; break;
1329         case  2: stdLayout = AE_CH_LAYOUT_2_1; break;
1330         case  3: stdLayout = AE_CH_LAYOUT_3_0; break;
1331         case  4: stdLayout = AE_CH_LAYOUT_3_1; break;
1332         case  5: stdLayout = AE_CH_LAYOUT_4_0; break;
1333         case  6: stdLayout = AE_CH_LAYOUT_4_1; break;
1334         case  7: stdLayout = AE_CH_LAYOUT_5_0; break;
1335         case  8: stdLayout = AE_CH_LAYOUT_5_1; break;
1336         case  9: stdLayout = AE_CH_LAYOUT_7_0; break;
1337         case 10: stdLayout = AE_CH_LAYOUT_7_1; break;
1338       }
1339
1340       if (m_settings.config == AE_CONFIG_FIXED || (settings.stereoupmix && format.m_channelLayout.Count() <= 2))
1341         format.m_channelLayout = stdLayout;
1342       else if (m_extKeepConfig && (settings.config == AE_CONFIG_AUTO) && (oldMode != MODE_RAW))
1343         format.m_channelLayout = m_internalFormat.m_channelLayout;
1344       else
1345         format.m_channelLayout.ResolveChannels(stdLayout);
1346     }
1347     // don't change from multi to stereo in AUTO mode
1348     else if ((settings.config == AE_CONFIG_AUTO) &&
1349               m_stats.GetWaterLevel() > 0 && m_internalFormat.m_channelLayout.Count() > 2)
1350     {
1351       format.m_channelLayout = m_internalFormat.m_channelLayout;
1352     }
1353
1354     if (m_sink.GetDeviceType(m_settings.device) == AE_DEVTYPE_IEC958)
1355     {
1356       if (format.m_sampleRate > m_settings.samplerate)
1357       {
1358         format.m_sampleRate = m_settings.samplerate;
1359         CLog::Log(LOGINFO, "CActiveAE::ApplySettings - limit samplerate for SPDIF to %d", format.m_sampleRate);
1360       }
1361       format.m_channelLayout = AE_CH_LAYOUT_2_0;
1362     }
1363
1364     if (m_settings.config == AE_CONFIG_FIXED)
1365     {
1366       format.m_sampleRate = m_settings.samplerate;
1367       CLog::Log(LOGINFO, "CActiveAE::ApplySettings - Forcing samplerate to %d", format.m_sampleRate);
1368     }
1369
1370     // sinks may not support mono
1371     if (format.m_channelLayout.Count() == 1)
1372     {
1373       format.m_channelLayout = AE_CH_LAYOUT_2_0;
1374     }
1375   }
1376 }
1377
1378 bool CActiveAE::NeedReconfigureBuffers()
1379 {
1380   AEAudioFormat newFormat = GetInputFormat();
1381   ApplySettingsToFormat(newFormat, m_settings);
1382
1383   if (newFormat.m_dataFormat != m_sinkRequestFormat.m_dataFormat ||
1384       newFormat.m_channelLayout != m_sinkRequestFormat.m_channelLayout ||
1385       newFormat.m_sampleRate != m_sinkRequestFormat.m_sampleRate)
1386     return true;
1387
1388   return false;
1389 }
1390
1391 bool CActiveAE::NeedReconfigureSink()
1392 {
1393   AEAudioFormat newFormat = GetInputFormat();
1394   ApplySettingsToFormat(newFormat, m_settings);
1395
1396   std::string device = AE_IS_RAW(newFormat.m_dataFormat) ? m_settings.passthoughdevice : m_settings.device;
1397   std::string driver;
1398   CAESinkFactory::ParseDevice(device, driver);
1399   if (m_settings.driver.compare(driver) != 0)
1400     return true;
1401
1402   if (!IsSinkCompatible(newFormat, device))
1403     return true;
1404
1405   return false;
1406 }
1407
1408 bool CActiveAE::InitSink()
1409 {
1410   SinkConfig config;
1411   config.format = m_sinkRequestFormat;
1412   config.stats = &m_stats;
1413   config.device = AE_IS_RAW(m_sinkRequestFormat.m_dataFormat) ? &m_settings.passthoughdevice :
1414                                                                 &m_settings.device;
1415
1416   // send message to sink
1417   Message *reply;
1418   if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::CONFIGURE,
1419                                                  &reply,
1420                                                  5000,
1421                                                  &config, sizeof(config)))
1422   {
1423     bool success = reply->signal == CSinkControlProtocol::ACC ? true : false;
1424     if (!success)
1425     {
1426       reply->Release();
1427       CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
1428       m_extError = true;
1429       return false;
1430     }
1431     AEAudioFormat *data;
1432     data = (AEAudioFormat*)reply->data;
1433     if (data)
1434     {
1435       m_sinkFormat = *data;
1436     }
1437     m_sinkHasVolume = m_sink.HasVolume();
1438     reply->Release();
1439   }
1440   else
1441   {
1442     CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__);
1443     m_extError = true;
1444     return false;
1445   }
1446
1447   m_inMsgEvent.Reset();
1448   return true;
1449 }
1450
1451 void CActiveAE::DrainSink()
1452 {
1453   // send message to sink
1454   Message *reply;
1455   if (m_sink.m_dataPort.SendOutMessageSync(CSinkDataProtocol::DRAIN,
1456                                                  &reply,
1457                                                  2000))
1458   {
1459     bool success = reply->signal == CSinkDataProtocol::ACC ? true : false;
1460     if (!success)
1461     {
1462       reply->Release();
1463       CLog::Log(LOGERROR, "ActiveAE::%s - returned error on drain", __FUNCTION__);
1464       m_extError = true;
1465       return;
1466     }
1467     reply->Release();
1468   }
1469   else
1470   {
1471     CLog::Log(LOGERROR, "ActiveAE::%s - failed to drain", __FUNCTION__);
1472     m_extError = true;
1473     return;
1474   }
1475 }
1476
1477 bool CActiveAE::IsSinkCompatible(const AEAudioFormat &format, const std::string &device)
1478 {
1479   bool compatible = false;
1480   SinkConfig config;
1481   config.format = format;
1482   config.device = &device;
1483
1484   // send message to sink
1485   Message *reply;
1486   if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::ISCOMPATIBLE,
1487                                                  &reply,
1488                                                  1000,
1489                                                  &config, sizeof(config)))
1490   {
1491     bool success = reply->signal == CSinkControlProtocol::ACC ? true : false;
1492     if (!success)
1493     {
1494       reply->Release();
1495       CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
1496       m_extError = true;
1497       return false;
1498     }
1499     compatible = *(bool*)reply->data;
1500     reply->Release();
1501   }
1502   else
1503   {
1504     CLog::Log(LOGERROR, "ActiveAE::%s - failed to query compatibility", __FUNCTION__);
1505     m_extError = true;
1506     return false;
1507   }
1508   return compatible;
1509 }
1510
1511 void CActiveAE::UnconfigureSink()
1512 {
1513   // send message to sink
1514   Message *reply;
1515   if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::UNCONFIGURE,
1516                                                  &reply,
1517                                                  2000))
1518   {
1519     bool success = reply->signal == CSinkControlProtocol::ACC ? true : false;
1520     if (!success)
1521     {
1522       CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
1523       m_extError = true;
1524     }
1525     reply->Release();
1526   }
1527   else
1528   {
1529     CLog::Log(LOGERROR, "ActiveAE::%s - failed to unconfigure", __FUNCTION__);
1530     m_extError = true;
1531   }
1532
1533   m_inMsgEvent.Reset();
1534 }
1535
1536
1537 bool CActiveAE::RunStages()
1538 {
1539   bool busy = false;
1540
1541   // serve input streams
1542   std::list<CActiveAEStream*>::iterator it;
1543   for (it = m_streams.begin(); it != m_streams.end(); ++it)
1544   {
1545     if ((*it)->m_resampleBuffers && !(*it)->m_paused)
1546       busy = (*it)->m_resampleBuffers->ResampleBuffers();
1547     else if ((*it)->m_resampleBuffers && 
1548             ((*it)->m_resampleBuffers->m_inputSamples.size() > (*it)->m_resampleBuffers->m_allSamples.size() * 0.5))
1549     {
1550       CSingleLock lock((*it)->m_streamLock);
1551       (*it)->m_streamIsBuffering = false;
1552     }
1553
1554     // provide buffers to stream
1555     float time = m_stats.GetCacheTime((*it));
1556     CSampleBuffer *buffer;
1557     if (!(*it)->m_drain)
1558     {
1559       while (time < MAX_CACHE_LEVEL && !(*it)->m_inputBuffers->m_freeSamples.empty())
1560       {
1561         buffer = (*it)->m_inputBuffers->GetFreeBuffer();
1562         (*it)->m_processingSamples.push_back(buffer);
1563         (*it)->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMBUFFER, &buffer, sizeof(CSampleBuffer*));
1564         (*it)->IncFreeBuffers();
1565         time += (float)buffer->pkt->max_nb_samples / buffer->pkt->config.sample_rate;
1566       }
1567     }
1568     else
1569     {
1570       if ((*it)->m_resampleBuffers->m_inputSamples.empty() &&
1571           (*it)->m_resampleBuffers->m_outputSamples.empty() &&
1572           (*it)->m_processingSamples.empty())
1573       {
1574         (*it)->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMDRAINED);
1575         (*it)->m_drain = false;
1576         (*it)->m_resampleBuffers->m_drain = false;
1577         (*it)->m_started = false;
1578
1579         // set variables being polled via stream interface
1580         CSingleLock lock((*it)->m_streamLock);
1581         if ((*it)->m_streamSlave)
1582         {
1583           CActiveAEStream *slave = (CActiveAEStream*)((*it)->m_streamSlave);
1584           slave->m_paused = false;
1585
1586           // TODO: find better solution for this
1587           // gapless bites audiophile
1588           if (m_settings.config == AE_CONFIG_MATCH)
1589             Configure(&slave->m_format);
1590
1591           (*it)->m_streamSlave = NULL;
1592         }
1593         (*it)->m_streamDrained = true;
1594         (*it)->m_streamDraining = false;
1595         (*it)->m_streamFading = false;
1596       }
1597     }
1598   }
1599
1600   if (m_stats.GetWaterLevel() < MAX_WATER_LEVEL &&
1601      (m_mode != MODE_TRANSCODE || (m_encoderBuffers && !m_encoderBuffers->m_freeSamples.empty())))
1602   {
1603     // mix streams and sounds sounds
1604     if (m_mode != MODE_RAW)
1605     {
1606       CSampleBuffer *out = NULL;
1607       if (!m_sounds_playing.empty() && m_streams.empty())
1608       {
1609         if (m_silenceBuffers && !m_silenceBuffers->m_freeSamples.empty())
1610         {
1611           out = m_silenceBuffers->GetFreeBuffer();
1612           for (int i=0; i<out->pkt->planes; i++)
1613           {
1614             memset(out->pkt->data[i], 0, out->pkt->linesize);
1615           }
1616           out->pkt->nb_samples = out->pkt->max_nb_samples;
1617         }
1618       }
1619
1620       // mix streams
1621       std::list<CActiveAEStream*>::iterator it;
1622
1623       // if we deal with more than a single stream, all streams
1624       // must provide samples for mixing
1625       bool allStreamsReady = true;
1626       for (it = m_streams.begin(); it != m_streams.end(); ++it)
1627       {
1628         if ((*it)->m_paused || !(*it)->m_started || !(*it)->m_resampleBuffers)
1629           continue;
1630
1631         if ((*it)->m_resampleBuffers->m_outputSamples.empty())
1632           allStreamsReady = false;
1633       }
1634
1635       bool needClamp = false;
1636       for (it = m_streams.begin(); it != m_streams.end() && allStreamsReady; ++it)
1637       {
1638         if ((*it)->m_paused || !(*it)->m_resampleBuffers)
1639           continue;
1640
1641         if (!(*it)->m_resampleBuffers->m_outputSamples.empty())
1642         {
1643           (*it)->m_started = true;
1644
1645           if (!out)
1646           {
1647             out = (*it)->m_resampleBuffers->m_outputSamples.front();
1648             (*it)->m_resampleBuffers->m_outputSamples.pop_front();
1649
1650             int nb_floats = out->pkt->nb_samples * out->pkt->config.channels / out->pkt->planes;
1651             int nb_loops = 1;
1652             float fadingStep = 0.0f;
1653
1654             // fading
1655             if ((*it)->m_fadingSamples == -1)
1656             {
1657               (*it)->m_fadingSamples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1658               (*it)->m_volume = (*it)->m_fadingBase;
1659             }
1660             if ((*it)->m_fadingSamples > 0)
1661             {
1662               nb_floats = out->pkt->config.channels / out->pkt->planes;
1663               nb_loops = out->pkt->nb_samples;
1664               float delta = (*it)->m_fadingTarget - (*it)->m_fadingBase;
1665               int samples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1666               fadingStep = delta / samples;
1667             }
1668
1669             // for stream amplification, 
1670             // turned off downmix normalization,
1671             // or if sink format is float (in order to prevent from clipping)
1672             // we need to run on a per sample basis
1673             if ((*it)->m_amplify != 1.0 || !(*it)->m_resampleBuffers->m_normalize || (m_sinkFormat.m_dataFormat == AE_FMT_FLOAT))
1674             {
1675               nb_floats = out->pkt->config.channels / out->pkt->planes;
1676               nb_loops = out->pkt->nb_samples;
1677             }
1678
1679             for(int i=0; i<nb_loops; i++)
1680             {
1681               if ((*it)->m_fadingSamples > 0)
1682               {
1683                 (*it)->m_volume += fadingStep;
1684                 (*it)->m_fadingSamples--;
1685
1686                 if ((*it)->m_fadingSamples == 0)
1687                 {
1688                   // set variables being polled via stream interface
1689                   CSingleLock lock((*it)->m_streamLock);
1690                   (*it)->m_streamFading = false;
1691                 }
1692               }
1693
1694               // volume for stream
1695               float volume = (*it)->m_volume * (*it)->m_rgain;
1696               if(nb_loops > 1)
1697                 volume *= (*it)->m_limiter.Run((float**)out->pkt->data, out->pkt->config.channels, i*nb_floats, out->pkt->planes > 1);
1698
1699               for(int j=0; j<out->pkt->planes; j++)
1700               {
1701 #ifdef __SSE__
1702                 CAEUtil::SSEMulArray((float*)out->pkt->data[j]+i*nb_floats, volume, nb_floats);
1703 #else
1704                 float* fbuffer = (float*) out->pkt->data[j]+i*nb_floats;
1705                 for (int k = 0; k < nb_floats; ++k)
1706                 {
1707                   fbuffer[k] *= volume;
1708                 }
1709 #endif
1710               }
1711             }
1712           }
1713           else
1714           {
1715             CSampleBuffer *mix = NULL;
1716             mix = (*it)->m_resampleBuffers->m_outputSamples.front();
1717             (*it)->m_resampleBuffers->m_outputSamples.pop_front();
1718
1719             int nb_floats = mix->pkt->nb_samples * mix->pkt->config.channels / mix->pkt->planes;
1720             int nb_loops = 1;
1721             float fadingStep = 0.0f;
1722
1723             // fading
1724             if ((*it)->m_fadingSamples == -1)
1725             {
1726               (*it)->m_fadingSamples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1727               (*it)->m_volume = (*it)->m_fadingBase;
1728             }
1729             if ((*it)->m_fadingSamples > 0)
1730             {
1731               nb_floats = mix->pkt->config.channels / mix->pkt->planes;
1732               nb_loops = mix->pkt->nb_samples;
1733               float delta = (*it)->m_fadingTarget - (*it)->m_fadingBase;
1734               int samples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f;
1735               fadingStep = delta / samples;
1736             }
1737
1738             // for streams amplification of turned off downmix normalization
1739             // we need to run on a per sample basis
1740             if ((*it)->m_amplify != 1.0 || !(*it)->m_resampleBuffers->m_normalize)
1741             {
1742               nb_floats = out->pkt->config.channels / out->pkt->planes;
1743               nb_loops = out->pkt->nb_samples;
1744             }
1745
1746             for(int i=0; i<nb_loops; i++)
1747             {
1748               if ((*it)->m_fadingSamples > 0)
1749               {
1750                 (*it)->m_volume += fadingStep;
1751                 (*it)->m_fadingSamples--;
1752
1753                 if ((*it)->m_fadingSamples == 0)
1754                 {
1755                   // set variables being polled via stream interface
1756                   CSingleLock lock((*it)->m_streamLock);
1757                   (*it)->m_streamFading = false;
1758                 }
1759               }
1760
1761               // volume for stream
1762               float volume = (*it)->m_volume * (*it)->m_rgain;
1763               if(nb_loops > 1)
1764                 volume *= (*it)->m_limiter.Run((float**)mix->pkt->data, mix->pkt->config.channels, i*nb_floats, mix->pkt->planes > 1);
1765
1766               for(int j=0; j<out->pkt->planes && j<mix->pkt->planes; j++)
1767               {
1768                 float *dst = (float*)out->pkt->data[j]+i*nb_floats;
1769                 float *src = (float*)mix->pkt->data[j]+i*nb_floats;
1770 #ifdef __SSE__
1771                 CAEUtil::SSEMulAddArray(dst, src, volume, nb_floats);
1772                 for (int k = 0; k < nb_floats; ++k)
1773                 {
1774                   if (fabs(dst[k]) > 1.0f)
1775                   {
1776                     needClamp = true;
1777                     break;
1778                   }
1779                 }
1780 #else
1781                 for (int k = 0; k < nb_floats; ++k)
1782                 {
1783                   dst[k] += src[k] * volume;
1784                   if (fabs(dst[k]) > 1.0f)
1785                     needClamp = true;
1786                 }
1787 #endif
1788               }
1789             }
1790             mix->Return();
1791           }
1792           busy = true;
1793         }
1794       }// for
1795
1796       // finally clamp samples
1797       if(out && needClamp)
1798       {
1799         int nb_floats = out->pkt->nb_samples * out->pkt->config.channels / out->pkt->planes;
1800         for(int i=0; i<out->pkt->planes; i++)
1801         {
1802           CAEUtil::ClampArray((float*)out->pkt->data[i], nb_floats);
1803         }
1804       }
1805
1806       // process output buffer, gui sounds, encode, viz
1807       if (out)
1808       {
1809         // viz
1810         {
1811           CSingleLock lock(m_vizLock);
1812           if (m_audioCallback && m_vizBuffers && !m_streams.empty())
1813           {
1814             if (!m_vizInitialized)
1815             {
1816               m_audioCallback->OnInitialize(2, m_vizBuffers->m_format.m_sampleRate, 32);
1817               m_vizInitialized = true;
1818             }
1819
1820             if (!m_vizBuffersInput->m_freeSamples.empty())
1821             {
1822               // copy the samples into the viz input buffer
1823               CSampleBuffer *viz = m_vizBuffersInput->GetFreeBuffer();
1824               int samples = std::min(512, out->pkt->nb_samples);
1825               int bytes = samples * out->pkt->config.channels / out->pkt->planes * out->pkt->bytes_per_sample;
1826               for(int i= 0; i < out->pkt->planes; i++)
1827               {
1828                 memcpy(viz->pkt->data[i], out->pkt->data[i], bytes);
1829               }
1830               viz->pkt->nb_samples = samples;
1831               m_vizBuffers->m_inputSamples.push_back(viz);
1832             }
1833             else
1834               CLog::Log(LOGWARNING,"ActiveAE::%s - viz ran out of free buffers", __FUNCTION__);
1835             unsigned int now = XbmcThreads::SystemClockMillis();
1836             unsigned int timestamp = now + m_stats.GetDelay() * 1000;
1837             busy |= m_vizBuffers->ResampleBuffers(timestamp);
1838             while(!m_vizBuffers->m_outputSamples.empty())
1839             {
1840               CSampleBuffer *buf = m_vizBuffers->m_outputSamples.front();
1841               if ((now - buf->timestamp) & 0x80000000)
1842                 break;
1843               else
1844               {
1845                 int samples;
1846                 samples = std::min(512, buf->pkt->nb_samples);
1847                 m_audioCallback->OnAudioData((float*)(buf->pkt->data[0]), samples);
1848                 buf->Return();
1849                 m_vizBuffers->m_outputSamples.pop_front();
1850               }
1851             }
1852           }
1853           else if (m_vizBuffers)
1854             m_vizBuffers->Flush();
1855         }
1856
1857         // mix gui sounds
1858         MixSounds(*(out->pkt));
1859         if (!m_sinkHasVolume || m_muted)
1860           Deamplify(*(out->pkt));
1861
1862         if (m_mode == MODE_TRANSCODE && m_encoder)
1863         {
1864           CSampleBuffer *buf = m_encoderBuffers->GetFreeBuffer();
1865           m_encoder->Encode(out->pkt->data[0], out->pkt->planes*out->pkt->linesize,
1866                             buf->pkt->data[0], buf->pkt->planes*buf->pkt->linesize);
1867           buf->pkt->nb_samples = buf->pkt->max_nb_samples;
1868           out->Return();
1869           out = buf;
1870         }
1871         busy = true;
1872       }
1873
1874       // update stats
1875       if(out)
1876       {
1877         m_stats.AddSamples(out->pkt->nb_samples, m_streams);
1878         m_sinkBuffers->m_inputSamples.push_back(out);
1879       }
1880     }
1881     // pass through
1882     else
1883     {
1884       std::list<CActiveAEStream*>::iterator it;
1885       CSampleBuffer *buffer;
1886       for (it = m_streams.begin(); it != m_streams.end(); ++it)
1887       {
1888         if (!(*it)->m_resampleBuffers->m_outputSamples.empty())
1889         {
1890           buffer =  (*it)->m_resampleBuffers->m_outputSamples.front();
1891           (*it)->m_resampleBuffers->m_outputSamples.pop_front();
1892           m_stats.AddSamples(buffer->pkt->nb_samples, m_streams);
1893           m_sinkBuffers->m_inputSamples.push_back(buffer);
1894         }
1895       }
1896     }
1897
1898     // serve sink buffers
1899     busy = m_sinkBuffers->ResampleBuffers();
1900     while(!m_sinkBuffers->m_outputSamples.empty())
1901     {
1902       CSampleBuffer *out = NULL;
1903       out = m_sinkBuffers->m_outputSamples.front();
1904       m_sinkBuffers->m_outputSamples.pop_front();
1905       m_sink.m_dataPort.SendOutMessage(CSinkDataProtocol::SAMPLE,
1906           &out, sizeof(CSampleBuffer*));
1907       busy = true;
1908     }
1909   }
1910
1911   return busy;
1912 }
1913
1914 bool CActiveAE::HasWork()
1915 {
1916   if (!m_sounds_playing.empty())
1917     return true;
1918   if (!m_sinkBuffers->m_inputSamples.empty())
1919     return true;
1920   if (!m_sinkBuffers->m_outputSamples.empty())
1921     return true;
1922
1923   std::list<CActiveAEStream*>::iterator it;
1924   for (it = m_streams.begin(); it != m_streams.end(); ++it)
1925   {
1926     if (!(*it)->m_resampleBuffers->m_inputSamples.empty())
1927       return true;
1928     if (!(*it)->m_resampleBuffers->m_outputSamples.empty())
1929       return true;
1930     if (!(*it)->m_processingSamples.empty())
1931       return true;
1932   }
1933
1934   return false;
1935 }
1936
1937 void CActiveAE::MixSounds(CSoundPacket &dstSample)
1938 {
1939   if (m_sounds_playing.empty())
1940     return;
1941
1942   float volume;
1943   float *out;
1944   float *sample_buffer;
1945   int max_samples = dstSample.nb_samples;
1946
1947   std::list<SoundState>::iterator it;
1948   for (it = m_sounds_playing.begin(); it != m_sounds_playing.end(); )
1949   {
1950     if (!it->sound->IsConverted())
1951       ResampleSound(it->sound);
1952     int available_samples = it->sound->GetSound(false)->nb_samples - it->samples_played;
1953     int mix_samples = std::min(max_samples, available_samples);
1954     int start = it->samples_played *
1955                 m_dllAvUtil.av_get_bytes_per_sample(it->sound->GetSound(false)->config.fmt) *
1956                 it->sound->GetSound(false)->config.channels /
1957                 it->sound->GetSound(false)->planes;
1958
1959     for(int j=0; j<dstSample.planes; j++)
1960     {
1961       volume = it->sound->GetVolume();
1962       out = (float*)dstSample.data[j];
1963       sample_buffer = (float*)(it->sound->GetSound(false)->data[j]+start);
1964       int nb_floats = mix_samples * dstSample.config.channels / dstSample.planes;
1965 #ifdef __SSE__
1966       CAEUtil::SSEMulAddArray(out, sample_buffer, volume, nb_floats);
1967 #else
1968       for (int k = 0; k < nb_floats; ++k)
1969         *out++ += *sample_buffer++ * volume;
1970 #endif
1971     }
1972
1973     it->samples_played += mix_samples;
1974
1975     // no more frames, so remove it from the list
1976     if (it->samples_played >= it->sound->GetSound(false)->nb_samples)
1977     {
1978       it = m_sounds_playing.erase(it);
1979       continue;
1980     }
1981     ++it;
1982   }
1983 }
1984
1985 void CActiveAE::Deamplify(CSoundPacket &dstSample)
1986 {
1987   if (m_volume < 1.0 || m_muted)
1988   {
1989     float *buffer;
1990     int nb_floats = dstSample.nb_samples * dstSample.config.channels / dstSample.planes;
1991
1992     for(int j=0; j<dstSample.planes; j++)
1993     {
1994       buffer = (float*)dstSample.data[j];
1995 #ifdef __SSE__
1996       CAEUtil::SSEMulArray(buffer, m_muted ? 0.0 : m_volume, nb_floats);
1997 #else
1998       float *fbuffer = buffer;
1999       for (int i = 0; i < nb_floats; i++)
2000         *fbuffer++ *= m_volume;
2001 #endif
2002     }
2003   }
2004 }
2005
2006 //-----------------------------------------------------------------------------
2007 // Configuration
2008 //-----------------------------------------------------------------------------
2009
2010 void CActiveAE::LoadSettings()
2011 {
2012   m_settings.device = CSettings::Get().GetString("audiooutput.audiodevice");
2013   m_settings.passthoughdevice = CSettings::Get().GetString("audiooutput.passthroughdevice");
2014
2015   m_settings.config = CSettings::Get().GetInt("audiooutput.config");
2016   m_settings.channels = (m_sink.GetDeviceType(m_settings.device) == AE_DEVTYPE_IEC958) ? AE_CH_LAYOUT_2_0 : CSettings::Get().GetInt("audiooutput.channels");
2017   m_settings.samplerate = CSettings::Get().GetInt("audiooutput.samplerate");
2018
2019   m_settings.stereoupmix = IsSettingVisible("audiooutput.stereoupmix") ? CSettings::Get().GetBool("audiooutput.stereoupmix") : false;
2020   m_settings.normalizelevels = CSettings::Get().GetBool("audiooutput.normalizelevels");
2021   m_settings.guisoundmode = CSettings::Get().GetInt("audiooutput.guisoundmode");
2022
2023   m_settings.passthrough = m_settings.config == AE_CONFIG_FIXED ? false : CSettings::Get().GetBool("audiooutput.passthrough");
2024   m_settings.ac3passthrough = CSettings::Get().GetBool("audiooutput.ac3passthrough");
2025   m_settings.eac3passthrough = CSettings::Get().GetBool("audiooutput.eac3passthrough");
2026   m_settings.truehdpassthrough = CSettings::Get().GetBool("audiooutput.truehdpassthrough");
2027   m_settings.dtspassthrough = CSettings::Get().GetBool("audiooutput.dtspassthrough");
2028   m_settings.dtshdpassthrough = CSettings::Get().GetBool("audiooutput.dtshdpassthrough");
2029
2030   m_settings.resampleQuality = static_cast<AEQuality>(CSettings::Get().GetInt("audiooutput.processquality"));
2031 }
2032
2033 bool CActiveAE::Initialize()
2034 {
2035   if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllAvFormat.Load())
2036   {
2037     CLog::Log(LOGERROR,"CActiveAE::Initialize - failed to load ffmpeg libraries");
2038     return false;
2039   }
2040   m_dllAvFormat.av_register_all();
2041
2042   Create();
2043   Message *reply;
2044   if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::INIT,
2045                                                  &reply,
2046                                                  5000))
2047   {
2048     bool success = reply->signal == CActiveAEControlProtocol::ACC ? true : false;
2049     reply->Release();
2050     if (!success)
2051     {
2052       CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
2053       Dispose();
2054       return false;
2055     }
2056   }
2057   else
2058   {
2059     CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__);
2060     Dispose();
2061     return false;
2062   }
2063
2064   // hook into windowing for receiving display reset events
2065 #if defined(HAS_GLX) || defined(TARGET_DARWIN_OSX)
2066   g_Windowing.Register(this);
2067 #endif
2068
2069   m_inMsgEvent.Reset();
2070   return true;
2071 }
2072
2073 void CActiveAE::EnumerateOutputDevices(AEDeviceList &devices, bool passthrough)
2074 {
2075   m_sink.EnumerateOutputDevices(devices, passthrough);
2076 }
2077
2078 std::string CActiveAE::GetDefaultDevice(bool passthrough)
2079 {
2080   return m_sink.GetDefaultDevice(passthrough);
2081 }
2082
2083 void CActiveAE::OnSettingsChange(const std::string& setting)
2084 {
2085   if (setting == "audiooutput.passthroughdevice" ||
2086       setting == "audiooutput.audiodevice"       ||
2087       setting == "audiooutput.config"            ||
2088       setting == "audiooutput.ac3passthrough"    ||
2089       setting == "audiooutput.eac3passthrough"   ||
2090       setting == "audiooutput.dtspassthrough"    ||
2091       setting == "audiooutput.truehdpassthrough" ||
2092       setting == "audiooutput.dtshdpassthrough"  ||
2093       setting == "audiooutput.channels"          ||
2094       setting == "audiooutput.stereoupmix"       ||
2095       setting == "audiooutput.streamsilence"     ||
2096       setting == "audiooutput.processquality"    ||
2097       setting == "audiooutput.passthrough"       ||
2098       setting == "audiooutput.samplerate"        ||
2099       setting == "audiooutput.normalizelevels"   ||
2100       setting == "audiooutput.guisoundmode")
2101   {
2102     m_controlPort.SendOutMessage(CActiveAEControlProtocol::RECONFIGURE);
2103   }
2104 }
2105
2106 bool CActiveAE::SupportsRaw(AEDataFormat format)
2107 {
2108   if (!m_sink.HasPassthroughDevice())
2109     return false;
2110
2111   // those formats require HDMI
2112   if (format == AE_FMT_DTSHD || format == AE_FMT_TRUEHD)
2113   {
2114     if(m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.passthroughdevice")) != AE_DEVTYPE_HDMI)
2115       return false;
2116   }
2117
2118   // TODO: check ELD?
2119   return true;
2120 }
2121
2122 bool CActiveAE::SupportsSilenceTimeout()
2123 {
2124   return true;
2125 }
2126
2127 bool CActiveAE::SupportsQualityLevel(enum AEQuality level)
2128 {
2129   if (level == AE_QUALITY_LOW || level == AE_QUALITY_MID || level == AE_QUALITY_HIGH)
2130     return true;
2131
2132   return false;
2133 }
2134
2135 bool CActiveAE::IsSettingVisible(const std::string &settingId)
2136 {
2137   if (settingId == "audiooutput.samplerate")
2138   {
2139     if (m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) == AE_DEVTYPE_IEC958)
2140       return true;
2141     if (CSettings::Get().GetInt("audiooutput.config") == AE_CONFIG_FIXED)
2142       return true;
2143   }
2144   else if (settingId == "audiooutput.channels")
2145   {
2146     if (m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) != AE_DEVTYPE_IEC958)
2147       return true;
2148   }
2149   else if (settingId == "audiooutput.passthrough")
2150   {
2151     if (m_sink.HasPassthroughDevice() && CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED)
2152       return true;
2153   }
2154   else if (settingId == "audiooutput.truehdpassthrough")
2155   {
2156     if (m_sink.HasPassthroughDevice() &&
2157         CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED &&
2158         m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.passthroughdevice")) == AE_DEVTYPE_HDMI)
2159       return true;
2160   }
2161   else if (settingId == "audiooutput.dtshdpassthrough")
2162   {
2163     if (m_sink.HasPassthroughDevice() &&
2164         CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED &&
2165         m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.passthroughdevice")) == AE_DEVTYPE_HDMI)
2166       return true;
2167   }
2168   else if (settingId == "audiooutput.stereoupmix")
2169   {
2170     if (m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) != AE_DEVTYPE_IEC958)
2171     {
2172       if (CSettings::Get().GetInt("audiooutput.channels") > AE_CH_LAYOUT_2_0)
2173         return true;
2174     }
2175     else
2176     {
2177       if (m_sink.HasPassthroughDevice() &&
2178           CSettings::Get().GetBool("audiooutput.passthrough") &&
2179           CSettings::Get().GetBool("audiooutput.ac3passthrough"))
2180         return true;
2181     }
2182   }
2183   return false;
2184 }
2185
2186 void CActiveAE::Shutdown()
2187 {
2188   Dispose();
2189 }
2190
2191 bool CActiveAE::Suspend()
2192 {
2193   return m_controlPort.SendOutMessage(CActiveAEControlProtocol::SUSPEND);
2194 }
2195
2196 bool CActiveAE::Resume()
2197 {
2198   Message *reply;
2199   if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::INIT,
2200                                                  &reply,
2201                                                  5000))
2202   {
2203     bool success = reply->signal == CActiveAEControlProtocol::ACC ? true : false;
2204     reply->Release();
2205     if (!success)
2206     {
2207       CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__);
2208       return false;
2209     }
2210   }
2211   else
2212   {
2213     CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__);
2214     return false;
2215   }
2216
2217   m_inMsgEvent.Reset();
2218   return true;
2219 }
2220
2221 bool CActiveAE::IsSuspended()
2222 {
2223   return m_stats.IsSuspended();
2224 }
2225
2226 float CActiveAE::GetVolume()
2227 {
2228   return m_aeVolume;
2229 }
2230
2231 void CActiveAE::SetVolume(const float volume)
2232 {
2233   m_aeVolume = std::max( 0.0f, std::min(1.0f, volume));
2234   m_controlPort.SendOutMessage(CActiveAEControlProtocol::VOLUME, &m_aeVolume, sizeof(float));
2235 }
2236
2237 void CActiveAE::SetMute(const bool enabled)
2238 {
2239   m_aeMuted = enabled;
2240   m_controlPort.SendOutMessage(CActiveAEControlProtocol::MUTE, &m_aeMuted, sizeof(bool));
2241 }
2242
2243 bool CActiveAE::IsMuted()
2244 {
2245   return m_aeMuted;
2246 }
2247
2248 void CActiveAE::SetSoundMode(const int mode)
2249 {
2250   return;
2251 }
2252
2253 void CActiveAE::KeepConfiguration(unsigned int millis)
2254 {
2255   unsigned int timeMs = millis;
2256   m_controlPort.SendOutMessage(CActiveAEControlProtocol::KEEPCONFIG, &timeMs, sizeof(unsigned int));
2257 }
2258
2259 void CActiveAE::OnLostDevice()
2260 {
2261 //  m_controlPort.SendOutMessage(CActiveAEControlProtocol::DISPLAYLOST);
2262 }
2263
2264 void CActiveAE::OnResetDevice()
2265 {
2266 //  m_controlPort.SendOutMessage(CActiveAEControlProtocol::DISPLAYRESET);
2267 }
2268
2269 //-----------------------------------------------------------------------------
2270 // Utils
2271 //-----------------------------------------------------------------------------
2272
2273 uint8_t **CActiveAE::AllocSoundSample(SampleConfig &config, int &samples, int &bytes_per_sample, int &planes, int &linesize)
2274 {
2275   uint8_t **buffer;
2276   planes = m_dllAvUtil.av_sample_fmt_is_planar(config.fmt) ? config.channels : 1;
2277   buffer = new uint8_t*[planes];
2278
2279   // align buffer to 16 in order to be compatible with sse in CAEConvert
2280   m_dllAvUtil.av_samples_alloc(buffer, &linesize, config.channels,
2281                                  samples, config.fmt, 16);
2282   bytes_per_sample = m_dllAvUtil.av_get_bytes_per_sample(config.fmt);
2283   return buffer;
2284 }
2285
2286 void CActiveAE::FreeSoundSample(uint8_t **data)
2287 {
2288   m_dllAvUtil.av_freep(data);
2289   delete [] data;
2290 }
2291
2292 bool CActiveAE::CompareFormat(AEAudioFormat &lhs, AEAudioFormat &rhs)
2293 {
2294   if (lhs.m_channelLayout != rhs.m_channelLayout ||
2295       lhs.m_dataFormat != rhs.m_dataFormat ||
2296       lhs.m_sampleRate != rhs.m_sampleRate ||
2297       lhs.m_frames != rhs.m_frames)
2298     return false;
2299   else
2300     return true;
2301 }
2302
2303 //-----------------------------------------------------------------------------
2304 // GUI Sounds
2305 //-----------------------------------------------------------------------------
2306
2307 /**
2308  * load sound from an audio file and store original format
2309  * register the sound in ActiveAE
2310  * later when the engine is idle it will convert the sound to sink format
2311  */
2312
2313 #define SOUNDBUFFER_SIZE 20480
2314
2315 IAESound *CActiveAE::MakeSound(const std::string& file)
2316 {
2317   AVFormatContext *fmt_ctx = NULL;
2318   AVCodecContext *dec_ctx = NULL;
2319   AVIOContext *io_ctx;
2320   AVInputFormat *io_fmt;
2321   AVCodec *dec = NULL;
2322   CActiveAESound *sound = NULL;
2323   SampleConfig config;
2324
2325   sound = new CActiveAESound(file);
2326   if (!sound->Prepare())
2327   {
2328     delete sound;
2329     return NULL;
2330   }
2331   int fileSize = sound->GetFileSize();
2332
2333   fmt_ctx = m_dllAvFormat.avformat_alloc_context();
2334   unsigned char* buffer = (unsigned char*)m_dllAvUtil.av_malloc(SOUNDBUFFER_SIZE+FF_INPUT_BUFFER_PADDING_SIZE);
2335   io_ctx = m_dllAvFormat.avio_alloc_context(buffer, SOUNDBUFFER_SIZE, 0,
2336                                             sound, CActiveAESound::Read, NULL, CActiveAESound::Seek);
2337   io_ctx->max_packet_size = sound->GetChunkSize();
2338   if(io_ctx->max_packet_size)
2339     io_ctx->max_packet_size *= SOUNDBUFFER_SIZE / io_ctx->max_packet_size;
2340
2341   if(!sound->IsSeekPosible())
2342     io_ctx->seekable = 0;
2343
2344   fmt_ctx->pb = io_ctx;
2345
2346   m_dllAvFormat.av_probe_input_buffer(io_ctx, &io_fmt, file.c_str(), NULL, 0, 0);
2347   if (!io_fmt)
2348   {
2349     m_dllAvFormat.avformat_close_input(&fmt_ctx);
2350     delete sound;
2351     return NULL;
2352   }
2353
2354   // find decoder
2355   if (m_dllAvFormat.avformat_open_input(&fmt_ctx, file.c_str(), NULL, NULL) == 0)
2356   {
2357     fmt_ctx->flags |= AVFMT_FLAG_NOPARSE;
2358     if (m_dllAvFormat.avformat_find_stream_info(fmt_ctx, NULL) >= 0)
2359     {
2360       dec_ctx = fmt_ctx->streams[0]->codec;
2361       dec = m_dllAvCodec.avcodec_find_decoder(dec_ctx->codec_id);
2362       config.sample_rate = dec_ctx->sample_rate;
2363       config.channels = dec_ctx->channels;
2364       config.channel_layout = dec_ctx->channel_layout;
2365     }
2366   }
2367   if (dec == NULL)
2368   {
2369     m_dllAvFormat.avformat_close_input(&fmt_ctx);
2370     delete sound;
2371     return NULL;
2372   }
2373
2374   dec_ctx = m_dllAvCodec.avcodec_alloc_context3(dec);
2375   dec_ctx->sample_rate = config.sample_rate;
2376   dec_ctx->channels = config.channels;
2377   if (!config.channel_layout)
2378     config.channel_layout = m_dllAvUtil.av_get_default_channel_layout(config.channels);
2379   dec_ctx->channel_layout = config.channel_layout;
2380
2381   AVPacket avpkt;
2382   AVFrame *decoded_frame = NULL;
2383   decoded_frame = m_dllAvCodec.avcodec_alloc_frame();
2384
2385   if (m_dllAvCodec.avcodec_open2(dec_ctx, dec, NULL) >= 0)
2386   {
2387     bool init = false;
2388
2389     // decode until eof
2390     m_dllAvCodec.av_init_packet(&avpkt);
2391     int len;
2392     while (m_dllAvFormat.av_read_frame(fmt_ctx, &avpkt) >= 0)
2393     {
2394       int got_frame = 0;
2395       len = m_dllAvCodec.avcodec_decode_audio4(dec_ctx, decoded_frame, &got_frame, &avpkt);
2396       if (len < 0)
2397       {
2398         m_dllAvCodec.avcodec_close(dec_ctx);
2399         m_dllAvUtil.av_free(dec_ctx);
2400         m_dllAvUtil.av_free(&decoded_frame);
2401         m_dllAvFormat.avformat_close_input(&fmt_ctx);
2402         delete sound;
2403         return NULL;
2404       }
2405       if (got_frame)
2406       {
2407         if (!init)
2408         {
2409           int samples = fileSize / m_dllAvUtil.av_get_bytes_per_sample(dec_ctx->sample_fmt) / config.channels;
2410           config.fmt = dec_ctx->sample_fmt;
2411           config.bits_per_sample = dec_ctx->bits_per_coded_sample;
2412           sound->InitSound(true, config, samples);
2413           init = true;
2414         }
2415         sound->StoreSound(true, decoded_frame->extended_data,
2416                           decoded_frame->nb_samples, decoded_frame->linesize[0]);
2417       }
2418     }
2419     m_dllAvCodec.avcodec_close(dec_ctx);
2420   }
2421
2422   m_dllAvUtil.av_free(dec_ctx);
2423   m_dllAvUtil.av_free(decoded_frame);
2424   m_dllAvFormat.avformat_close_input(&fmt_ctx);
2425
2426   sound->Finish();
2427
2428   // register sound
2429   m_dataPort.SendOutMessage(CActiveAEDataProtocol::NEWSOUND, &sound, sizeof(CActiveAESound*));
2430
2431   return sound;
2432 }
2433
2434 void CActiveAE::FreeSound(IAESound *sound)
2435 {
2436   m_dataPort.SendOutMessage(CActiveAEDataProtocol::FREESOUND, &sound, sizeof(CActiveAESound*));
2437 }
2438
2439 void CActiveAE::PlaySound(CActiveAESound *sound)
2440 {
2441   m_dataPort.SendOutMessage(CActiveAEDataProtocol::PLAYSOUND, &sound, sizeof(CActiveAESound*));
2442 }
2443
2444 void CActiveAE::StopSound(CActiveAESound *sound)
2445 {
2446   m_controlPort.SendOutMessage(CActiveAEControlProtocol::STOPSOUND, &sound, sizeof(CActiveAESound*));
2447 }
2448
2449 /**
2450  * resample sounds to destination format for mixing
2451  * destination format is either format of stream or
2452  * default sink format when no stream is playing
2453  */
2454 void CActiveAE::ResampleSounds()
2455 {
2456   if (m_settings.guisoundmode == AE_SOUND_OFF ||
2457      (m_settings.guisoundmode == AE_SOUND_IDLE && !m_streams.empty()))
2458     return;
2459
2460   std::vector<CActiveAESound*>::iterator it;
2461   for (it = m_sounds.begin(); it != m_sounds.end(); ++it)
2462   {
2463     if (!(*it)->IsConverted())
2464     {
2465       ResampleSound(*it);
2466       // only do one sound, then yield to main loop
2467       break;
2468     }
2469   }
2470 }
2471
2472 bool CActiveAE::ResampleSound(CActiveAESound *sound)
2473 {
2474   SampleConfig orig_config, dst_config;
2475   uint8_t **dst_buffer;
2476   int dst_samples;
2477
2478   if (m_mode == MODE_RAW || m_internalFormat.m_dataFormat == AE_FMT_INVALID)
2479     return false;
2480
2481   if (!sound->GetSound(true))
2482     return false;
2483
2484   orig_config = sound->GetSound(true)->config;
2485
2486   dst_config.channel_layout = CActiveAEResample::GetAVChannelLayout(m_internalFormat.m_channelLayout);
2487   dst_config.channels = m_internalFormat.m_channelLayout.Count();
2488   dst_config.sample_rate = m_internalFormat.m_sampleRate;
2489   dst_config.fmt = CActiveAEResample::GetAVSampleFormat(m_internalFormat.m_dataFormat);
2490   dst_config.bits_per_sample = CAEUtil::DataFormatToUsedBits(m_internalFormat.m_dataFormat);
2491
2492   CActiveAEResample *resampler = new CActiveAEResample();
2493   resampler->Init(dst_config.channel_layout,
2494                   dst_config.channels,
2495                   dst_config.sample_rate,
2496                   dst_config.fmt,
2497                   dst_config.bits_per_sample,
2498                   orig_config.channel_layout,
2499                   orig_config.channels,
2500                   orig_config.sample_rate,
2501                   orig_config.fmt,
2502                   orig_config.bits_per_sample,
2503                   false,
2504                   true,
2505                   NULL,
2506                   m_settings.resampleQuality);
2507
2508   dst_samples = resampler->CalcDstSampleCount(sound->GetSound(true)->nb_samples,
2509                                               m_internalFormat.m_sampleRate,
2510                                               orig_config.sample_rate);
2511
2512   dst_buffer = sound->InitSound(false, dst_config, dst_samples);
2513   if (!dst_buffer)
2514   {
2515     delete resampler;
2516     return false;
2517   }
2518   int samples = resampler->Resample(dst_buffer, dst_samples,
2519                                     sound->GetSound(true)->data,
2520                                     sound->GetSound(true)->nb_samples,
2521                                     1.0);
2522
2523   sound->GetSound(false)->nb_samples = samples;
2524
2525   delete resampler;
2526   sound->SetConverted(true);
2527   return true;
2528 }
2529
2530 //-----------------------------------------------------------------------------
2531 // Streams
2532 //-----------------------------------------------------------------------------
2533
2534 IAEStream *CActiveAE::MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSampleRate, CAEChannelInfo channelLayout, unsigned int options)
2535 {
2536   //TODO: pass number of samples in audio packet
2537
2538   AEAudioFormat format;
2539   format.m_dataFormat = dataFormat;
2540   format.m_sampleRate = sampleRate;
2541   format.m_encodedRate = encodedSampleRate;
2542   format.m_channelLayout = channelLayout;
2543   format.m_frames = format.m_sampleRate / 10;
2544   format.m_frameSize = format.m_channelLayout.Count() *
2545                        (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);
2546
2547   MsgStreamNew msg;
2548   msg.format = format;
2549   msg.options = options;
2550
2551   Message *reply;
2552   if (m_dataPort.SendOutMessageSync(CActiveAEDataProtocol::NEWSTREAM,
2553                                     &reply,10000,
2554                                     &msg, sizeof(MsgStreamNew)))
2555   {
2556     bool success = reply->signal == CActiveAEControlProtocol::ACC ? true : false;
2557     if (success)
2558     {
2559       CActiveAEStream *stream = *(CActiveAEStream**)reply->data;
2560       reply->Release();
2561       return stream;
2562     }
2563     reply->Release();
2564   }
2565
2566   CLog::Log(LOGERROR, "ActiveAE::%s - could not create stream", __FUNCTION__);
2567   return NULL;
2568 }
2569
2570 IAEStream *CActiveAE::FreeStream(IAEStream *stream)
2571 {
2572   m_dataPort.SendOutMessage(CActiveAEDataProtocol::FREESTREAM, &stream, sizeof(IAEStream*));
2573   return NULL;
2574 }
2575
2576 void CActiveAE::FlushStream(CActiveAEStream *stream)
2577 {
2578   Message *reply;
2579   if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::FLUSHSTREAM,
2580                                        &reply,1000,
2581                                        &stream, sizeof(CActiveAEStream*)))
2582   {
2583     bool success = reply->signal == CActiveAEControlProtocol::ACC ? true : false;
2584     reply->Release();
2585     if (!success)
2586     {
2587       CLog::Log(LOGERROR, "CActiveAE::FlushStream - failed");
2588     }
2589   }
2590 }
2591
2592 void CActiveAE::PauseStream(CActiveAEStream *stream, bool pause)
2593 {
2594   // TODO pause sink, needs api change
2595   if (pause)
2596     m_controlPort.SendOutMessage(CActiveAEControlProtocol::PAUSESTREAM,
2597                                    &stream, sizeof(CActiveAEStream*));
2598   else
2599     m_controlPort.SendOutMessage(CActiveAEControlProtocol::RESUMESTREAM,
2600                                    &stream, sizeof(CActiveAEStream*));
2601 }
2602
2603 void CActiveAE::SetStreamAmplification(CActiveAEStream *stream, float amplify)
2604 {
2605   MsgStreamParameter msg;
2606   msg.stream = stream;
2607   msg.parameter.float_par = amplify;
2608   m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMAMP,
2609                                      &msg, sizeof(MsgStreamParameter));
2610 }
2611
2612 void CActiveAE::SetStreamReplaygain(CActiveAEStream *stream, float rgain)
2613 {
2614   MsgStreamParameter msg;
2615   msg.stream = stream;
2616   msg.parameter.float_par = rgain;
2617   m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMRGAIN,
2618                                      &msg, sizeof(MsgStreamParameter));
2619 }
2620
2621 void CActiveAE::SetStreamVolume(CActiveAEStream *stream, float volume)
2622 {
2623   MsgStreamParameter msg;
2624   msg.stream = stream;
2625   msg.parameter.float_par = volume;
2626   m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMVOLUME,
2627                                      &msg, sizeof(MsgStreamParameter));
2628 }
2629
2630 void CActiveAE::SetStreamResampleRatio(CActiveAEStream *stream, double ratio)
2631 {
2632   MsgStreamParameter msg;
2633   msg.stream = stream;
2634   msg.parameter.double_par = ratio;
2635   m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMRESAMPLERATIO,
2636                                      &msg, sizeof(MsgStreamParameter));
2637 }
2638
2639 void CActiveAE::SetStreamFade(CActiveAEStream *stream, float from, float target, unsigned int millis)
2640 {
2641   MsgStreamFade msg;
2642   msg.stream = stream;
2643   msg.from = from;
2644   msg.target = target;
2645   msg.millis = millis;
2646   m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMFADE,
2647                                      &msg, sizeof(MsgStreamFade));
2648 }
2649
2650 void CActiveAE::RegisterAudioCallback(IAudioCallback* pCallback)
2651 {
2652   CSingleLock lock(m_vizLock);
2653   m_audioCallback = pCallback;
2654   m_vizInitialized = false;
2655 }
2656
2657 void CActiveAE::UnregisterAudioCallback()
2658 {
2659   CSingleLock lock(m_vizLock);
2660   m_audioCallback = NULL;
2661 }