2 * Copyright (C) 2010-2013 Team XBMC
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)
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.
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/>.
22 #include "threads/SingleLock.h"
23 #include "utils/log.h"
24 #include "utils/MathUtils.h"
26 #include "cores/AudioEngine/AEFactory.h"
27 #include "cores/AudioEngine/Utils/AEUtil.h"
30 #include "ActiveAEStream.h"
32 using namespace ActiveAE;
34 /* typecast AE to CActiveAE */
35 #define AE (*((CActiveAE*)CAEFactory::GetEngine()))
38 CActiveAEStream::CActiveAEStream(AEAudioFormat *format)
42 m_currentBuffer = NULL;
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;
56 m_leftoverBuffer = new uint8_t[m_format.m_frameSize];
58 m_forceResampler = false;
63 CActiveAEStream::~CActiveAEStream()
65 delete [] m_leftoverBuffer;
70 void CActiveAEStream::IncFreeBuffers()
72 CSingleLock lock(m_streamLock);
73 m_streamFreeBuffers++;
76 void CActiveAEStream::DecFreeBuffers()
78 CSingleLock lock(m_streamLock);
79 m_streamFreeBuffers--;
82 void CActiveAEStream::ResetFreeBuffers()
84 CSingleLock lock(m_streamLock);
85 m_streamFreeBuffers = 0;
88 void CActiveAEStream::InitRemapper()
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++)
96 avCur = CActiveAEResample::GetAVChannel(m_format.m_channelLayout[i]);
106 CLog::Log(LOGDEBUG, "CActiveAEStream::%s - initialize remapper", __FUNCTION__);
108 m_remapper = new CActiveAEResample();
109 uint64_t avLayout = CActiveAEResample::GetAVChannelLayout(m_format.m_channelLayout);
111 // build layout according to ffmpeg channel order
112 // we need this for reference
113 CAEChannelInfo ffmpegLayout;
114 ffmpegLayout.Reset();
116 for(unsigned int i=0; i<m_format.m_channelLayout.Count(); i++)
118 for(unsigned int j=0; j<m_format.m_channelLayout.Count(); j++)
120 idx = m_remapper->GetAVChannelIndex(m_format.m_channelLayout[j], avLayout);
123 ffmpegLayout += m_format.m_channelLayout[j];
129 // build remap layout we can pass to resampler as destination layout
130 CAEChannelInfo remapLayout;
132 for(unsigned int i=0; i<m_format.m_channelLayout.Count(); i++)
134 for(unsigned int j=0; j<m_format.m_channelLayout.Count(); j++)
136 idx = m_remapper->GetAVChannelIndex(m_format.m_channelLayout[j], avLayout);
139 remapLayout += ffmpegLayout[j];
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),
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),
159 AE_QUALITY_LOW); // not used for remapping
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);
166 void CActiveAEStream::RemapBuffer()
170 int samples = m_remapper->Resample(m_remapBuffer->data, m_remapBuffer->max_nb_samples,
171 m_currentBuffer->pkt->data, m_currentBuffer->pkt->nb_samples,
174 if (samples != m_currentBuffer->pkt->nb_samples)
176 CLog::Log(LOGERROR, "CActiveAEStream::%s - error remapping", __FUNCTION__);
179 // swap sound packets
180 CSoundPacket *tmp = m_remapBuffer;
181 tmp = m_currentBuffer->pkt;
182 m_currentBuffer->pkt = m_remapBuffer;
187 unsigned int CActiveAEStream::GetSpace()
189 CSingleLock lock(m_streamLock);
190 return m_streamFreeBuffers * m_streamSpace;
193 unsigned int CActiveAEStream::AddData(void *data, unsigned int size)
196 unsigned int copied = 0;
197 unsigned int bytesToCopy = size;
198 uint8_t *buf = (uint8_t*)data;
202 buf = ((uint8_t*)data) + copied;
203 bytesToCopy = size - copied;
207 // fill leftover buffer and copy it first
208 if (m_leftoverBytes && bytesToCopy >= (m_format.m_frameSize - m_leftoverBytes))
210 int fillbytes = m_format.m_frameSize - m_leftoverBytes;
211 memcpy(m_leftoverBuffer+m_leftoverBytes, buf, fillbytes);
213 // leftover buffer will be copied on next cycle
214 buf = m_leftoverBuffer;
215 bytesToCopy = m_format.m_frameSize;
219 int start = m_currentBuffer->pkt->nb_samples *
220 m_currentBuffer->pkt->bytes_per_sample *
221 m_currentBuffer->pkt->config.channels /
222 m_currentBuffer->pkt->planes;
224 int freeSamples = m_currentBuffer->pkt->max_nb_samples - m_currentBuffer->pkt->nb_samples;
225 int availableSamples = bytesToCopy / m_format.m_frameSize;
227 // if we don't have a full frame, copy to leftover buffer
228 if (!availableSamples && bytesToCopy)
230 memcpy(m_leftoverBuffer+m_leftoverBytes, buf, bytesToCopy);
231 m_leftoverBytes = bytesToCopy;
232 copied += bytesToCopy;
235 int samples = std::min(freeSamples, availableSamples);
236 int bytes = samples * m_format.m_frameSize;
238 //TODO: handle planar formats
240 m_convertFn(buf, samples*m_currentBuffer->pkt->config.channels, (float*)(m_currentBuffer->pkt->data[0] + start));
242 memcpy(m_currentBuffer->pkt->data[0] + start, buf, bytes);
244 CSingleLock lock(*m_statsLock);
245 m_currentBuffer->pkt->nb_samples += samples;
246 m_bufferedTime += (double)samples / m_currentBuffer->pkt->config.sample_rate;
248 if (buf != m_leftoverBuffer)
250 if (m_currentBuffer->pkt->nb_samples == m_currentBuffer->pkt->max_nb_samples)
252 MsgStreamSample msgData;
253 msgData.buffer = m_currentBuffer;
254 msgData.stream = this;
256 m_streamPort->SendOutMessage(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample));
257 m_currentBuffer = NULL;
261 else if (m_streamPort->ReceiveInMessage(&msg))
263 if (msg->signal == CActiveAEDataProtocol::STREAMBUFFER)
265 m_currentBuffer = *((CSampleBuffer**)msg->data);
272 CLog::Log(LOGERROR, "CActiveAEStream::AddData - unknown signal");
277 if (!m_inMsgEvent.WaitMSec(200))
283 double CActiveAEStream::GetDelay()
285 return AE.GetDelay(this);
288 bool CActiveAEStream::IsBuffering()
290 CSingleLock lock(m_streamLock);
291 return m_streamIsBuffering;
294 double CActiveAEStream::GetCacheTime()
296 return AE.GetCacheTime(this);
299 double CActiveAEStream::GetCacheTotal()
301 return AE.GetCacheTotal(this);
304 void CActiveAEStream::Pause()
306 AE.PauseStream(this, true);
309 void CActiveAEStream::Resume()
311 AE.PauseStream(this, false);
314 void CActiveAEStream::Drain(bool wait)
317 CActiveAEStream *stream = this;
319 m_streamDraining = true;
320 m_streamDrained = false;
323 if (m_streamPort->SendOutMessageSync(CActiveAEDataProtocol::DRAINSTREAM,
325 &stream, sizeof(CActiveAEStream*)))
327 bool success = reply->signal == CActiveAEDataProtocol::ACC ? true : false;
331 CLog::Log(LOGERROR, "CActiveAEStream::Drain - no acc");
337 MsgStreamSample msgData;
338 msgData.buffer = m_currentBuffer;
339 msgData.stream = this;
341 m_streamPort->SendOutMessage(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample));
342 m_currentBuffer = NULL;
345 XbmcThreads::EndTime timer(2000);
346 while (!timer.IsTimePast())
348 if (m_streamPort->ReceiveInMessage(&msg))
350 if (msg->signal == CActiveAEDataProtocol::STREAMBUFFER)
352 MsgStreamSample msgData;
353 msgData.stream = this;
354 msgData.buffer = *((CSampleBuffer**)msg->data);
355 msg->Reply(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample));
359 else if (msg->signal == CActiveAEDataProtocol::STREAMDRAINED)
368 m_inMsgEvent.WaitMSec(timer.MillisLeft());
370 CLog::Log(LOGERROR, "CActiveAEStream::Drain - timeout out");
373 bool CActiveAEStream::IsDraining()
375 CSingleLock lock(m_streamLock);
376 return m_streamDraining;
379 bool CActiveAEStream::IsDrained()
381 CSingleLock lock(m_streamLock);
382 return m_streamDrained;
385 void CActiveAEStream::Flush()
387 m_currentBuffer = NULL;
389 AE.FlushStream(this);
393 float CActiveAEStream::GetAmplification()
395 return m_streamAmplify;
398 void CActiveAEStream::SetAmplification(float amplify)
400 m_streamAmplify = amplify;
401 AE.SetStreamAmplification(this, m_streamAmplify);
404 float CActiveAEStream::GetReplayGain()
406 return m_streamRgain;
409 void CActiveAEStream::SetReplayGain(float factor)
411 m_streamRgain = std::max( 0.0f, factor);
412 AE.SetStreamReplaygain(this, m_streamRgain);
415 float CActiveAEStream::GetVolume()
417 return m_streamVolume;
420 void CActiveAEStream::SetVolume(float volume)
422 m_streamVolume = std::max( 0.0f, std::min(1.0f, volume));
423 AE.SetStreamVolume(this, m_streamVolume);
426 double CActiveAEStream::GetResampleRatio()
428 return m_streamResampleRatio;
431 bool CActiveAEStream::SetResampleRatio(double ratio)
433 m_streamResampleRatio = ratio;
434 AE.SetStreamResampleRatio(this, m_streamResampleRatio);
438 void CActiveAEStream::FadeVolume(float from, float target, unsigned int time)
440 if (time == 0 || AE_IS_RAW(m_format.m_dataFormat))
443 m_streamFading = true;
444 AE.SetStreamFade(this, from, target, time);
447 bool CActiveAEStream::IsFading()
449 CSingleLock lock(m_streamLock);
450 return m_streamFading;
453 const unsigned int CActiveAEStream::GetFrameSize() const
455 return m_format.m_frameSize;
458 const unsigned int CActiveAEStream::GetChannelCount() const
460 return m_format.m_channelLayout.Count();
463 const unsigned int CActiveAEStream::GetSampleRate() const
465 return m_format.m_sampleRate;
468 const unsigned int CActiveAEStream::GetEncodedSampleRate() const
470 return m_format.m_encodedRate;
473 const enum AEDataFormat CActiveAEStream::GetDataFormat() const
475 return m_format.m_dataFormat;
478 void CActiveAEStream::RegisterAudioCallback(IAudioCallback* pCallback)
482 void CActiveAEStream::UnRegisterAudioCallback()
486 void CActiveAEStream::RegisterSlave(IAEStream *slave)
488 CSingleLock lock(m_streamLock);
489 m_streamSlave = slave;