Merge pull request #4619 from fritsch/aefixes
[vuplus_xbmc] / xbmc / cores / AudioEngine / Engines / ActiveAE / ActiveAEStream.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 "system.h"
22 #include "threads/SingleLock.h"
23 #include "utils/log.h"
24 #include "utils/MathUtils.h"
25
26 #include "cores/AudioEngine/AEFactory.h"
27 #include "cores/AudioEngine/Utils/AEUtil.h"
28
29 #include "ActiveAE.h"
30 #include "ActiveAEStream.h"
31
32 using namespace ActiveAE;
33
34 /* typecast AE to CActiveAE */
35 #define AE (*((CActiveAE*)CAEFactory::GetEngine()))
36
37
38 CActiveAEStream::CActiveAEStream(AEAudioFormat *format)
39 {
40   m_format = *format;
41   m_bufferedTime = 0;
42   m_currentBuffer = NULL;
43   m_drain = false;
44   m_paused = false;
45   m_rgain = 1.0;
46   m_volume = 1.0;
47   m_amplify = 1.0;
48   m_streamSpace = m_format.m_frameSize * m_format.m_frames;
49   m_streamDraining = false;
50   m_streamDrained = false;
51   m_streamFading = false;
52   m_streamFreeBuffers = 0;
53   m_streamIsBuffering = true;
54   m_streamSlave = NULL;
55   m_convertFn = NULL;
56   m_leftoverBuffer = new uint8_t[m_format.m_frameSize];
57   m_leftoverBytes = 0;
58   m_forceResampler = false;
59   m_remapper = NULL;
60   m_remapBuffer = NULL;
61   m_streamResampleRatio = 1.0;
62 }
63
64 CActiveAEStream::~CActiveAEStream()
65 {
66   delete [] m_leftoverBuffer;
67   delete m_remapper;
68   delete m_remapBuffer;
69 }
70
71 void CActiveAEStream::IncFreeBuffers()
72 {
73   CSingleLock lock(m_streamLock);
74   m_streamFreeBuffers++;
75 }
76
77 void CActiveAEStream::DecFreeBuffers()
78 {
79   CSingleLock lock(m_streamLock);
80   m_streamFreeBuffers--;
81 }
82
83 void CActiveAEStream::ResetFreeBuffers()
84 {
85   CSingleLock lock(m_streamLock);
86   m_streamFreeBuffers = 0;
87 }
88
89 void CActiveAEStream::InitRemapper()
90 {
91   // check if input format follows ffmpeg channel mask
92   bool needRemap = false;
93   unsigned int avLast, avCur = 0;
94   for(unsigned int i=0; i<m_format.m_channelLayout.Count(); i++)
95   {
96     avLast = avCur;
97     avCur = CActiveAEResample::GetAVChannel(m_format.m_channelLayout[i]);
98     if(avCur < avLast)
99     {
100       needRemap = true;
101       break;
102     }
103   }
104
105   if(needRemap)
106   {
107     CLog::Log(LOGDEBUG, "CActiveAEStream::%s - initialize remapper", __FUNCTION__);
108
109     m_remapper = new CActiveAEResample();
110     uint64_t avLayout = CActiveAEResample::GetAVChannelLayout(m_format.m_channelLayout);
111
112     // build layout according to ffmpeg channel order
113     // we need this for reference
114     CAEChannelInfo ffmpegLayout;
115     ffmpegLayout.Reset();
116     int idx = 0;
117     for(unsigned int i=0; i<m_format.m_channelLayout.Count(); i++)
118     {
119       for(unsigned int j=0; j<m_format.m_channelLayout.Count(); j++)
120       {
121         idx = m_remapper->GetAVChannelIndex(m_format.m_channelLayout[j], avLayout);
122         if (idx == (int)i)
123         {
124           ffmpegLayout += m_format.m_channelLayout[j];
125           break;
126         }
127       }
128     }
129
130     // build remap layout we can pass to resampler as destination layout
131     CAEChannelInfo remapLayout;
132     remapLayout.Reset();
133     for(unsigned int i=0; i<m_format.m_channelLayout.Count(); i++)
134     {
135       for(unsigned int j=0; j<m_format.m_channelLayout.Count(); j++)
136       {
137         idx = m_remapper->GetAVChannelIndex(m_format.m_channelLayout[j], avLayout);
138         if (idx == (int)i)
139         {
140           remapLayout += ffmpegLayout[j];
141           break;
142         }
143       }
144     }
145
146     // initialize resampler for only doing remapping
147     m_remapper->Init(avLayout,
148                      m_format.m_channelLayout.Count(),
149                      m_format.m_sampleRate,
150                      CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat),
151                      CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat),
152                      avLayout,
153                      m_format.m_channelLayout.Count(),
154                      m_format.m_sampleRate,
155                      CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat),
156                      CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat),
157                      false,
158                      false,
159                      &remapLayout,
160                      AE_QUALITY_LOW); // not used for remapping
161
162     // extra sound packet, we can't resample to the same buffer
163     m_remapBuffer = new CSoundPacket(m_inputBuffers->m_allSamples[0]->pkt->config, m_inputBuffers->m_allSamples[0]->pkt->max_nb_samples);
164   }
165 }
166
167 void CActiveAEStream::RemapBuffer()
168 {
169   if(m_remapper)
170   {
171     int samples = m_remapper->Resample(m_remapBuffer->data, m_remapBuffer->max_nb_samples,
172                                        m_currentBuffer->pkt->data, m_currentBuffer->pkt->nb_samples,
173                                        1.0);
174
175     if (samples != m_currentBuffer->pkt->nb_samples)
176     {
177       CLog::Log(LOGERROR, "CActiveAEStream::%s - error remapping", __FUNCTION__);
178     }
179
180     // swap sound packets
181     CSoundPacket *tmp = m_remapBuffer;
182     tmp = m_currentBuffer->pkt;
183     m_currentBuffer->pkt = m_remapBuffer;
184     m_remapBuffer = tmp;
185   }
186 }
187
188 unsigned int CActiveAEStream::GetSpace()
189 {
190   CSingleLock lock(m_streamLock);
191   return m_streamFreeBuffers * m_streamSpace;
192 }
193
194 unsigned int CActiveAEStream::AddData(void *data, unsigned int size)
195 {
196   Message *msg;
197   unsigned int copied = 0;
198   unsigned int bytesToCopy = size;
199   uint8_t *buf = (uint8_t*)data;
200
201   while(copied < size)
202   {
203     buf = ((uint8_t*)data) + copied;
204     bytesToCopy = size - copied;
205
206     if (m_currentBuffer)
207     {
208       // fill leftover buffer and copy it first
209       if (m_leftoverBytes && bytesToCopy >= (m_format.m_frameSize - m_leftoverBytes))
210       {
211         int fillbytes = m_format.m_frameSize - m_leftoverBytes;
212         memcpy(m_leftoverBuffer+m_leftoverBytes, buf, fillbytes);
213         copied += fillbytes;
214         // leftover buffer will be copied on next cycle
215         buf = m_leftoverBuffer;
216         bytesToCopy = m_format.m_frameSize;
217         m_leftoverBytes = 0;
218       }
219
220       int start = m_currentBuffer->pkt->nb_samples *
221                   m_currentBuffer->pkt->bytes_per_sample *
222                   m_currentBuffer->pkt->config.channels /
223                   m_currentBuffer->pkt->planes;
224
225       int freeSamples = m_currentBuffer->pkt->max_nb_samples - m_currentBuffer->pkt->nb_samples;
226       int availableSamples = bytesToCopy / m_format.m_frameSize;
227
228       // if we don't have a full frame, copy to leftover buffer
229       if (!availableSamples && bytesToCopy)
230       {
231         memcpy(m_leftoverBuffer+m_leftoverBytes, buf, bytesToCopy);
232         m_leftoverBytes = bytesToCopy;
233         copied += bytesToCopy;
234       }
235
236       int samples = std::min(freeSamples, availableSamples);
237       int bytes = samples * m_format.m_frameSize;
238
239       //TODO: handle planar formats
240       if (m_convertFn)
241         m_convertFn(buf, samples*m_currentBuffer->pkt->config.channels, (float*)(m_currentBuffer->pkt->data[0] + start));
242       else
243         memcpy(m_currentBuffer->pkt->data[0] + start, buf, bytes);
244       {
245         CSingleLock lock(*m_statsLock);
246         m_currentBuffer->pkt->nb_samples += samples;
247         m_bufferedTime += (double)samples / m_currentBuffer->pkt->config.sample_rate;
248       }
249       if (buf != m_leftoverBuffer)
250         copied += bytes;
251       if (m_currentBuffer->pkt->nb_samples == m_currentBuffer->pkt->max_nb_samples)
252       {
253         MsgStreamSample msgData;
254         msgData.buffer = m_currentBuffer;
255         msgData.stream = this;
256         RemapBuffer();
257         m_streamPort->SendOutMessage(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample));
258         m_currentBuffer = NULL;
259       }
260       continue;
261     }
262     else if (m_streamPort->ReceiveInMessage(&msg))
263     {
264       if (msg->signal == CActiveAEDataProtocol::STREAMBUFFER)
265       {
266         m_currentBuffer = *((CSampleBuffer**)msg->data);
267         msg->Release();
268         DecFreeBuffers();
269         continue;
270       }
271       else
272       {
273         CLog::Log(LOGERROR, "CActiveAEStream::AddData - unknown signal");
274         msg->Release();
275         break;
276       }
277     }
278     if (!m_inMsgEvent.WaitMSec(200))
279       break;
280   }
281   return copied;
282 }
283
284 double CActiveAEStream::GetDelay()
285 {
286   return AE.GetDelay(this);
287 }
288
289 bool CActiveAEStream::IsBuffering()
290 {
291   CSingleLock lock(m_streamLock);
292   return m_streamIsBuffering;
293 }
294
295 double CActiveAEStream::GetCacheTime()
296 {
297   return AE.GetCacheTime(this);
298 }
299
300 double CActiveAEStream::GetCacheTotal()
301 {
302   return AE.GetCacheTotal(this);
303 }
304
305 void CActiveAEStream::Pause()
306 {
307   AE.PauseStream(this, true);
308 }
309
310 void CActiveAEStream::Resume()
311 {
312   AE.PauseStream(this, false);
313 }
314
315 void CActiveAEStream::Drain(bool wait)
316 {
317   Message *msg;
318   CActiveAEStream *stream = this;
319
320   m_streamDraining = true;
321   m_streamDrained = false;
322
323   Message *reply;
324   if (m_streamPort->SendOutMessageSync(CActiveAEDataProtocol::DRAINSTREAM,
325                                        &reply,2000,
326                                        &stream, sizeof(CActiveAEStream*)))
327   {
328     bool success = reply->signal == CActiveAEDataProtocol::ACC ? true : false;
329     reply->Release();
330     if (!success)
331     {
332       CLog::Log(LOGERROR, "CActiveAEStream::Drain - no acc");
333     }
334   }
335
336   if (m_currentBuffer)
337   {
338     MsgStreamSample msgData;
339     msgData.buffer = m_currentBuffer;
340     msgData.stream = this;
341     RemapBuffer();
342     m_streamPort->SendOutMessage(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample));
343     m_currentBuffer = NULL;
344   }
345
346   XbmcThreads::EndTime timer(2000);
347   while (!timer.IsTimePast())
348   {
349     if (m_streamPort->ReceiveInMessage(&msg))
350     {
351       if (msg->signal == CActiveAEDataProtocol::STREAMBUFFER)
352       {
353         MsgStreamSample msgData;
354         msgData.stream = this;
355         msgData.buffer = *((CSampleBuffer**)msg->data);
356         msg->Reply(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample));
357         DecFreeBuffers();
358         continue;
359       }
360       else if (msg->signal == CActiveAEDataProtocol::STREAMDRAINED)
361       {
362         msg->Release();
363         return;
364       }
365     }
366     else if (!wait)
367       return;
368
369     m_inMsgEvent.WaitMSec(timer.MillisLeft());
370   }
371   CLog::Log(LOGERROR, "CActiveAEStream::Drain - timeout out");
372 }
373
374 bool CActiveAEStream::IsDraining()
375 {
376   CSingleLock lock(m_streamLock);
377   return m_streamDraining;
378 }
379
380 bool CActiveAEStream::IsDrained()
381 {
382   CSingleLock lock(m_streamLock);
383   return m_streamDrained;
384 }
385
386 void CActiveAEStream::Flush()
387 {
388   m_currentBuffer = NULL;
389   m_leftoverBytes = 0;
390   AE.FlushStream(this);
391   ResetFreeBuffers();
392 }
393
394 float CActiveAEStream::GetAmplification()
395 {
396   return m_streamAmplify;
397 }
398
399 void CActiveAEStream::SetAmplification(float amplify)
400 {
401   m_streamAmplify = amplify;
402   AE.SetStreamAmplification(this, m_streamAmplify);
403 }
404
405 float CActiveAEStream::GetReplayGain()
406 {
407   return m_streamRgain;
408 }
409
410 void CActiveAEStream::SetReplayGain(float factor)
411 {
412   m_streamRgain = std::max( 0.0f, factor);
413   AE.SetStreamReplaygain(this, m_streamRgain);
414 }
415
416 float CActiveAEStream::GetVolume()
417 {
418   return m_streamVolume;
419 }
420
421 void CActiveAEStream::SetVolume(float volume)
422 {
423   m_streamVolume = std::max( 0.0f, std::min(1.0f, volume));
424   AE.SetStreamVolume(this, m_streamVolume);
425 }
426
427 double CActiveAEStream::GetResampleRatio()
428 {
429   return m_streamResampleRatio;
430 }
431
432 bool CActiveAEStream::SetResampleRatio(double ratio)
433 {
434   m_streamResampleRatio = ratio;
435   AE.SetStreamResampleRatio(this, m_streamResampleRatio);
436   return true;
437 }
438
439 void CActiveAEStream::FadeVolume(float from, float target, unsigned int time)
440 {
441   if (time == 0 || AE_IS_RAW(m_format.m_dataFormat))
442     return;
443
444   m_streamFading = true;
445   AE.SetStreamFade(this, from, target, time);
446 }
447
448 bool CActiveAEStream::IsFading()
449 {
450   CSingleLock lock(m_streamLock);
451   return m_streamFading;
452 }
453
454 const unsigned int CActiveAEStream::GetFrameSize() const
455 {
456   return m_format.m_frameSize;
457 }
458
459 const unsigned int CActiveAEStream::GetChannelCount() const
460 {
461   return m_format.m_channelLayout.Count();
462 }
463
464 const unsigned int CActiveAEStream::GetSampleRate() const
465 {
466   return m_format.m_sampleRate;
467 }
468
469 const unsigned int CActiveAEStream::GetEncodedSampleRate() const
470 {
471   return m_format.m_encodedRate;
472 }
473
474 const enum AEDataFormat CActiveAEStream::GetDataFormat() const
475 {
476   return m_format.m_dataFormat;
477 }
478
479 void CActiveAEStream::RegisterAudioCallback(IAudioCallback* pCallback)
480 {
481 }
482
483 void CActiveAEStream::UnRegisterAudioCallback()
484 {
485 }
486
487 void CActiveAEStream::RegisterSlave(IAEStream *slave)
488 {
489   CSingleLock lock(m_streamLock);
490   m_streamSlave = slave;
491 }
492