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