2 * Copyright (C) 2005-2008 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, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
22 #include "threads/SingleLock.h"
23 #include "utils/log.h"
27 #include "DVDCodecs/DVDCodecs.h"
28 #include "DVDPlayerAudio.h"
29 #include "cores/AudioEngine/AEFactory.h"
30 #include "cores/AudioEngine/Interfaces/AEStream.h"
31 #include "settings/Settings.h"
35 CDVDAudio::CDVDAudio(volatile bool &bStop)
38 m_pAudioStream = NULL;
42 m_bPassthrough = false;
45 m_SecondsPerByte = 0.0;
49 CDVDAudio::~CDVDAudio()
51 CSingleLock lock (m_critSection);
53 CAEFactory::FreeStream(m_pAudioStream);
58 bool CDVDAudio::Create(const DVDAudioFrame &audioframe, CodecID codec, bool needresampler)
61 "Creating audio stream (codec id: %i, channels: %i, sample rate: %i, %s)",
63 audioframe.channel_count,
64 audioframe.sample_rate,
65 audioframe.passthrough ? "pass-through" : "no pass-through"
68 // if passthrough isset do something else
69 CSingleLock lock(m_critSection);
70 unsigned int options = needresampler && !audioframe.passthrough ? AESTREAM_FORCE_RESAMPLE : 0;
71 options |= AESTREAM_AUTOSTART;
73 m_pAudioStream = CAEFactory::MakeStream(
74 audioframe.data_format,
75 audioframe.sample_rate,
76 audioframe.encoded_sample_rate,
77 audioframe.channel_layout,
80 if (!m_pAudioStream) return false;
82 m_iBitrate = audioframe.sample_rate;
83 m_iBitsPerSample = audioframe.bits_per_sample;
84 m_bPassthrough = audioframe.passthrough;
85 m_channelLayout = audioframe.channel_layout;
86 m_dwPacketSize = m_pAudioStream->GetFrameSize();
88 if(m_channelLayout.Count() && m_iBitrate && m_iBitsPerSample)
89 m_SecondsPerByte = 1.0 / (m_channelLayout.Count() * m_iBitrate * (m_iBitsPerSample>>3));
91 m_SecondsPerByte = 0.0;
94 SetDynamicRangeCompression((long)(g_settings.m_currentVideoSettings.m_VolumeAmplification * 100));
99 void CDVDAudio::Destroy()
101 CSingleLock lock (m_critSection);
104 CAEFactory::FreeStream(m_pAudioStream);
109 m_pAudioStream = NULL;
112 m_iBitsPerSample = 0;
113 m_bPassthrough = false;
117 DWORD CDVDAudio::AddPacketsRenderer(unsigned char* data, DWORD len, CSingleLock &lock)
122 DWORD bps = m_channelLayout.Count() * m_iBitrate * (m_iBitsPerSample>>3);
126 //Calculate a timeout when this definitely should be done
128 timeout = DVD_SEC_TO_TIME(m_pAudioStream->GetDelay() + len * m_SecondsPerByte);
129 timeout += DVD_SEC_TO_TIME(1.0);
130 timeout += CDVDClock::GetAbsoluteClock();
136 copied = m_pAudioStream->AddData(data, len);
139 if (len < m_dwPacketSize)
142 if (copied == 0 && timeout < CDVDClock::GetAbsoluteClock())
144 CLog::Log(LOGERROR, "CDVDAudio::AddPacketsRenderer - timeout adding data to renderer");
156 DWORD CDVDAudio::AddPackets(const DVDAudioFrame &audioframe)
158 CSingleLock lock (m_critSection);
160 unsigned char* data = audioframe.data;
161 DWORD len = audioframe.size;
166 if (m_iBufferSize > 0) // See if there are carryover bytes from the last call. need to add them 1st.
168 copied = std::min(m_dwPacketSize - m_iBufferSize % m_dwPacketSize, len); // Smaller of either the data provided or the leftover data
171 m_pBuffer = (BYTE*)realloc(m_pBuffer, m_iBufferSize + copied);
172 memcpy(m_pBuffer + m_iBufferSize, data, copied); // Tack the caller's data onto the end of the buffer
173 data += copied; // Move forward in caller's data
174 len -= copied; // Decrease amount of data available from caller
175 m_iBufferSize += copied; // Increase amount of data available in buffer
178 if(m_iBufferSize < m_dwPacketSize) // If we don't have enough data to give to the renderer, wait until next time
181 if(AddPacketsRenderer(m_pBuffer, m_iBufferSize, lock) != m_iBufferSize)
184 CLog::Log(LOGERROR, "%s - failed to add leftover bytes to render", __FUNCTION__);
190 return copied; // We used up all the caller's data
193 copied = AddPacketsRenderer(data, len, lock);
197 // if we have more data left, save it for the next call to this funtion
198 if (len > 0 && !m_bStop)
200 m_pBuffer = (BYTE*)realloc(m_pBuffer, len);
202 memcpy(m_pBuffer, data, len);
207 void CDVDAudio::Finish()
209 CSingleLock lock (m_critSection);
213 DWORD silence = m_dwPacketSize - m_iBufferSize % m_dwPacketSize;
215 if(silence > 0 && m_iBufferSize > 0)
217 CLog::Log(LOGDEBUG, "CDVDAudio::Drain - adding %d bytes of silence, buffer size: %d, chunk size: %d", silence, m_iBufferSize, m_dwPacketSize);
218 m_pBuffer = (BYTE*)realloc(m_pBuffer, m_iBufferSize + silence);
219 memset(m_pBuffer+m_iBufferSize, 0, silence);
220 m_iBufferSize += silence;
223 if(AddPacketsRenderer(m_pBuffer, m_iBufferSize, lock) != m_iBufferSize)
224 CLog::Log(LOGERROR, "CDVDAudio::Drain - failed to play the final %d bytes", m_iBufferSize);
229 void CDVDAudio::Drain()
232 CSingleLock lock (m_critSection);
234 m_pAudioStream->Drain();
237 void CDVDAudio::SetVolume(float volume)
239 CSingleLock lock (m_critSection);
240 if (m_pAudioStream) m_pAudioStream->SetVolume(volume);
243 void CDVDAudio::SetDynamicRangeCompression(long drc)
248 float CDVDAudio::GetCurrentAttenuation()
250 CSingleLock lock (m_critSection);
252 return m_pAudioStream->GetVolume();
257 void CDVDAudio::Pause()
259 CSingleLock lock (m_critSection);
260 if (m_pAudioStream) m_pAudioStream->Pause();
263 void CDVDAudio::Resume()
265 CSingleLock lock (m_critSection);
266 if (m_pAudioStream) m_pAudioStream->Resume();
269 double CDVDAudio::GetDelay()
271 CSingleLock lock (m_critSection);
275 delay = m_pAudioStream->GetDelay();
277 delay += m_SecondsPerByte * m_iBufferSize;
279 return delay * DVD_TIME_BASE;
282 void CDVDAudio::Flush()
284 CSingleLock lock (m_critSection);
288 m_pAudioStream->Flush();
293 bool CDVDAudio::IsValidFormat(const DVDAudioFrame &audioframe)
298 if(audioframe.passthrough != m_bPassthrough)
301 if(m_iBitrate != audioframe.sample_rate
302 || m_iBitsPerSample != audioframe.bits_per_sample
303 || m_channelLayout != audioframe.channel_layout)
309 void CDVDAudio::SetResampleRatio(double ratio)
311 CSingleLock lock (m_critSection);
314 m_pAudioStream->SetResampleRatio(ratio);
317 double CDVDAudio::GetCacheTime()
319 CSingleLock lock (m_critSection);
325 delay = m_pAudioStream->GetCacheTime();
327 delay += m_SecondsPerByte * m_iBufferSize;
332 double CDVDAudio::GetCacheTotal()
334 CSingleLock lock (m_critSection);
337 return m_pAudioStream->GetCacheTotal();