Merge pull request #3815 from ndogxj/patch-1
[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 "AEFactory.h"
27 #include "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 }
62
63 CActiveAEStream::~CActiveAEStream()
64 {
65   delete [] m_leftoverBuffer;
66   delete m_remapper;
67   delete m_remapBuffer;
68 }
69
70 void CActiveAEStream::IncFreeBuffers()
71 {
72   CSingleLock lock(m_streamLock);
73   m_streamFreeBuffers++;
74 }
75
76 void CActiveAEStream::DecFreeBuffers()
77 {
78   CSingleLock lock(m_streamLock);
79   m_streamFreeBuffers--;
80 }
81
82 void CActiveAEStream::ResetFreeBuffers()
83 {
84   CSingleLock lock(m_streamLock);
85   m_streamFreeBuffers = 0;
86 }
87
88 void CActiveAEStream::InitRemapper()
89 {
90   // check if input format follows ffmpeg channel mask
91   bool needRemap = false;
92   unsigned int avLast, avCur = 0;
93   for(unsigned int i=0; i<m_format.m_channelLayout.Count(); i++)
94   {
95     avLast = avCur;
96     avCur = CActiveAEResample::GetAVChannel(m_format.m_channelLayout[i]);
97     if(avCur < avLast)
98     {
99       needRemap = true;
100       break;
101     }
102   }
103
104   if(needRemap)
105   {
106     CLog::Log(LOGDEBUG, "CActiveAEStream::%s - initialize remapper", __FUNCTION__);
107
108     m_remapper = new CActiveAEResample();
109     uint64_t avLayout = CActiveAEResample::GetAVChannelLayout(m_format.m_channelLayout);
110
111     // build layout according to ffmpeg channel order
112     // we need this for reference
113     CAEChannelInfo ffmpegLayout;
114     ffmpegLayout.Reset();
115     int idx = 0;
116     for(unsigned int i=0; i<m_format.m_channelLayout.Count(); i++)
117     {
118       for(unsigned int j=0; j<m_format.m_channelLayout.Count(); j++)
119       {
120         idx = m_remapper->GetAVChannelIndex(m_format.m_channelLayout[j], avLayout);
121         if (idx == i)
122         {
123           ffmpegLayout += m_format.m_channelLayout[j];
124           break;
125         }
126       }
127     }
128
129     // build remap layout we can pass to resampler as destination layout
130     CAEChannelInfo remapLayout;
131     remapLayout.Reset();
132     for(unsigned int i=0; i<m_format.m_channelLayout.Count(); i++)
133     {
134       for(unsigned int j=0; j<m_format.m_channelLayout.Count(); j++)
135       {
136         idx = m_remapper->GetAVChannelIndex(m_format.m_channelLayout[j], avLayout);
137         if (idx == i)
138         {
139           remapLayout += ffmpegLayout[j];
140           break;
141         }
142       }
143     }
144
145     // initialize resampler for only doing remapping
146     m_remapper->Init(avLayout,
147                      m_format.m_channelLayout.Count(),
148                      m_format.m_sampleRate,
149                      CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat),
150                      CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat),
151                      avLayout,
152                      m_format.m_channelLayout.Count(),
153                      m_format.m_sampleRate,
154                      CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat),
155                      CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat),
156                      false,
157                      false,
158                      &remapLayout,
159                      AE_QUALITY_LOW); // not used for remapping
160
161     // extra sound packet, we can't resample to the same buffer
162     m_remapBuffer = new CSoundPacket(m_inputBuffers->m_allSamples[0]->pkt->config, m_inputBuffers->m_allSamples[0]->pkt->max_nb_samples);
163   }
164 }
165
166 void CActiveAEStream::RemapBuffer()
167 {
168   if(m_remapper)
169   {
170     int samples = m_remapper->Resample(m_remapBuffer->data, m_remapBuffer->max_nb_samples,
171                                        m_currentBuffer->pkt->data, m_currentBuffer->pkt->nb_samples,
172                                        1.0);
173
174     if (samples != m_currentBuffer->pkt->nb_samples)
175     {
176       CLog::Log(LOGERROR, "CActiveAEStream::%s - error remapping", __FUNCTION__);
177     }
178
179     // swap sound packets
180     CSoundPacket *tmp = m_remapBuffer;
181     tmp = m_currentBuffer->pkt;
182     m_currentBuffer->pkt = m_remapBuffer;
183     m_remapBuffer = tmp;
184   }
185 }
186
187 unsigned int CActiveAEStream::GetSpace()
188 {
189   CSingleLock lock(m_streamLock);
190   return m_streamFreeBuffers * m_streamSpace;
191 }
192
193 unsigned int CActiveAEStream::AddData(void *data, unsigned int size)
194 {
195   Message *msg;
196   unsigned int copied = 0;
197   unsigned int bytesToCopy = size;
198   uint8_t *buf = (uint8_t*)data;
199
200   while(copied < size)
201   {
202     buf = (uint8_t*)data;
203     bytesToCopy = size - copied;
204
205     if (m_currentBuffer)
206     {
207       // fill leftover buffer and copy it first
208       if (m_leftoverBytes && bytesToCopy >= (m_format.m_frameSize - m_leftoverBytes))
209       {
210         int fillbytes = m_format.m_frameSize - m_leftoverBytes;
211         memcpy(m_leftoverBuffer+m_leftoverBytes, (uint8_t*)data, fillbytes);
212         data = (uint8_t*)data + fillbytes;
213         size -= 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+copied, 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+copied, samples*m_currentBuffer->pkt->config.channels, (float*)(m_currentBuffer->pkt->data[0] + start));
242       else
243         memcpy(m_currentBuffer->pkt->data[0] + start, buf+copied, 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         RemapBuffer();
357         msg->Reply(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample));
358         DecFreeBuffers();
359         continue;
360       }
361       else if (msg->signal == CActiveAEDataProtocol::STREAMDRAINED)
362       {
363         msg->Release();
364         return;
365       }
366     }
367     else if (!wait)
368       return;
369
370     m_inMsgEvent.WaitMSec(timer.MillisLeft());
371   }
372   CLog::Log(LOGERROR, "CActiveAEStream::Drain - timeout out");
373 }
374
375 bool CActiveAEStream::IsDraining()
376 {
377   CSingleLock lock(m_streamLock);
378   return m_streamDraining;
379 }
380
381 bool CActiveAEStream::IsDrained()
382 {
383   CSingleLock lock(m_streamLock);
384   return m_streamDrained;
385 }
386
387 void CActiveAEStream::Flush()
388 {
389   m_currentBuffer = NULL;
390   m_leftoverBytes = 0;
391   AE.FlushStream(this);
392   ResetFreeBuffers();
393 }
394
395 float CActiveAEStream::GetAmplification()
396 {
397   return m_streamAmplify;
398 }
399
400 void CActiveAEStream::SetAmplification(float amplify)
401 {
402   m_streamAmplify = amplify;
403   AE.SetStreamAmplification(this, m_streamAmplify);
404 }
405
406 float CActiveAEStream::GetReplayGain()
407 {
408   return m_streamRgain;
409 }
410
411 void CActiveAEStream::SetReplayGain(float factor)
412 {
413   m_streamRgain = std::max( 0.0f, factor);
414   AE.SetStreamReplaygain(this, m_streamRgain);
415 }
416
417 float CActiveAEStream::GetVolume()
418 {
419   return m_streamVolume;
420 }
421
422 void CActiveAEStream::SetVolume(float volume)
423 {
424   m_streamVolume = std::max( 0.0f, std::min(1.0f, volume));
425   AE.SetStreamVolume(this, m_streamVolume);
426 }
427
428 double CActiveAEStream::GetResampleRatio()
429 {
430   return m_streamResampleRatio;
431 }
432
433 bool CActiveAEStream::SetResampleRatio(double ratio)
434 {
435   m_streamResampleRatio = ratio;
436   AE.SetStreamResampleRatio(this, m_streamResampleRatio);
437   return true;
438 }
439
440 void CActiveAEStream::FadeVolume(float from, float target, unsigned int time)
441 {
442   if (time == 0 || AE_IS_RAW(m_format.m_dataFormat))
443     return;
444
445   m_streamFading = true;
446   AE.SetStreamFade(this, from, target, time);
447 }
448
449 bool CActiveAEStream::IsFading()
450 {
451   CSingleLock lock(m_streamLock);
452   return m_streamFading;
453 }
454
455 const unsigned int CActiveAEStream::GetFrameSize() const
456 {
457   return m_format.m_frameSize;
458 }
459
460 const unsigned int CActiveAEStream::GetChannelCount() const
461 {
462   return m_format.m_channelLayout.Count();
463 }
464
465 const unsigned int CActiveAEStream::GetSampleRate() const
466 {
467   return m_format.m_sampleRate;
468 }
469
470 const unsigned int CActiveAEStream::GetEncodedSampleRate() const
471 {
472   return m_format.m_encodedRate;
473 }
474
475 const enum AEDataFormat CActiveAEStream::GetDataFormat() const
476 {
477   return m_format.m_dataFormat;
478 }
479
480 void CActiveAEStream::RegisterAudioCallback(IAudioCallback* pCallback)
481 {
482 }
483
484 void CActiveAEStream::UnRegisterAudioCallback()
485 {
486 }
487
488 void CActiveAEStream::RegisterSlave(IAEStream *slave)
489 {
490   CSingleLock lock(m_streamLock);
491   m_streamSlave = slave;
492 }
493