?? hspalsadevice.cpp
字號:
/****************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, 5th fl, Boston, MA 02110-1301, * * USA, or check http://www.fsf.org/about/contact.html * * * * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved. * * Portions Copyright (c) 2005 Paul Cifarelli * * * ******************************************************************************/#include <unistd.h>#include <fcntl.h>#include <stdlib.h>#include <errno.h>#include <sys/ioctl.h>#include <stdio.h> #include <math.h>#include <time.h>#include <sys/time.h>#include <unistd.h>#include <config.h>#include "hxcomm.h"#include "hxcore.h"#include "hxprefs.h"#include "hxstrutl.h"#include "hxvsrc.h"#include "hxresult.h"#include "hxausvc.h"#include "helix-sp.h"#include "ihxpckts.h"#include "hxprefs.h"#include "hspalsadevice.h"#ifdef HX_LOG_SUBSYSTEM#include "hxtlogutil.h"#include "ihxtlogsystem.h"#endif#include "dllpath.h"#include "hxbuffer.h"#ifdef USE_HELIX_ALSAIHXPreferences* z_pIHXPrefs = 0;#define RA_AOE_NOERR 0#define RA_AOE_GENERAL -1#define RA_AOE_DEVNOTOPEN -2#define RA_AOE_NOTENABLED -3#define RA_AOE_BADFORMAT -4#define RA_AOE_NOTSUPPORTED -5#define RA_AOE_DEVBUSY -6#define RA_AOE_BADOPEN -7#ifdef __FreeBSD__#define PTHREAD_MUTEX_FAST_NP PTHREAD_MUTEX_NORMAL#endif#if !defined(__NetBSD__) && !defined(__OpenBSD__) #include <sys/soundcard.h>#else #include <soundcard.h>#endiftypedef HX_RESULT (HXEXPORT_PTR FPRMSETDLLACCESSPATH) (const char*);AudioQueue::AudioQueue( const HXAudioData *buf) : fwd(0){ ad = *buf; ad.pData->AddRef();}AudioQueue::~AudioQueue(){ ad.pData->Release();}STDMETHODIMPHSPAudioDevice::QueryInterface(REFIID riid, void**ppvObj){ if(IsEqualIID(riid, IID_IUnknown)) { AddRef(); *ppvObj = (IUnknown*)(IHXAudioDevice *)this; return HXR_OK; } else if(IsEqualIID(riid, IID_IHXAudioDevice)) { AddRef(); *ppvObj = (IHXAudioDevice *)this; return HXR_OK; } *ppvObj = NULL; return HXR_NOINTERFACE;}STDMETHODIMP_(UINT32)HSPAudioDevice::AddRef(){ return InterlockedIncrement(&m_lRefCount);}STDMETHODIMP_(UINT32)HSPAudioDevice::Release(){ if (InterlockedDecrement(&m_lRefCount) > 0) { return m_lRefCount; } delete this; return 0;}STDMETHODIMPHSPAudioDevice::CheckFormat( const HXAudioFormat* pAudioFormat ){ m_Player->print2stderr("########## Got to HSPAudioDevice::CheckFormat\n"); return (_CheckFormat(pAudioFormat));}STDMETHODIMPHSPAudioDevice::Close( const BOOL bFlush ){ m_Player->print2stderr("########## Got to HSPAudioDevice::Close flush %d\n", bFlush); pthread_mutex_lock(&m_m); if (bFlush) { clearQueue(); _Drain(); } _Reset(); _CloseAudio(); _CloseMixer(); m_closed = true; m_ulCurrentTime = m_ulQTime = 0; if (m_pStreamResponse) m_pStreamResponse->Release(); pthread_mutex_unlock(&m_m); return 0;} STDMETHODIMPHSPAudioDevice::Drain(){ m_Player->print2stderr("########## Got to HSPAudioDevice::Drain\n"); pthread_mutex_lock(&m_m); LONG32 err = _Drain(); clearQueue(); pthread_mutex_unlock(&m_m); return err;}STDMETHODIMPHSPAudioDevice::GetCurrentAudioTime( REF(ULONG32) ulCurrentTime ){ //m_Player->print2stderr("########## Got to HSPAudioDevice::GetCurrentTime = %d\n", m_ulCurrentTime); int err = 0; snd_pcm_sframes_t frame_delay = 0; pthread_mutex_lock(&m_m); if (!m_closed) { err = snd_pcm_delay (m_pAlsaPCMHandle, &frame_delay); if (err < 0) {#ifdef HX_LOG_SUBSYSTEM HXLOGL1 ( HXLOG_ADEV, "snd_pcm_status: %s", snd_strerror(err)); #endif m_Player->print2stderr("########## HSPAudioDevice::GetCurrentAudioTime error getting frame_delay: %s\n", snd_strerror(err)); pthread_mutex_unlock(&m_m); return -1; } ulCurrentTime = m_ulCurrentTime - (ULONG32)(((double)frame_delay * 1000.0) / (double)m_unSampleRate); //m_Player->print2stderr("########## HSPAudioDevice::GetCurrentAudioTime %d %d\n", ulCurrentTime, m_ulCurrentTime); } pthread_mutex_unlock(&m_m); return 0;}STDMETHODIMP_(UINT16)HSPAudioDevice::GetVolume(){ m_Player->print2stderr("########## Got to HSPAudioDevice::GetVolume\n"); return 0;}STDMETHODIMP_(BOOL) HSPAudioDevice::InitVolume(const UINT16 /*uMinVolume*/, const UINT16 /*uMaxVolume*/){ m_Player->print2stderr("########## Got to HSPAudioDevice::InitVolume\n"); return true;}STDMETHODIMPHSPAudioDevice::Open(const HXAudioFormat* pAudioFormat, IHXAudioDeviceResponse* pStreamResponse){ int err; m_Player->print2stderr("########## Got to HSPAudioDevice::Open\n"); if (pStreamResponse) pStreamResponse->AddRef(); pthread_mutex_lock(&m_m); m_drain = false; m_closed = false; m_ulTotalWritten = 0; m_ulCurrentTime = 0; m_SWPause = false; m_pStreamResponse = pStreamResponse; if (!m_pAlsaPCMHandle) { err = _OpenAudio(); if (err) m_Player->print2stderr("########## HSPAudioDevice::Open error (device) %d\n", err); err = SetDeviceConfig(pAudioFormat); if (err) m_Player->print2stderr("########## HSPAudioDevice::Open error (config) %d\n", err); m_ulCurrentTime = m_ulLastTime = m_ulQTime = 0; } if (m_pAlsaMixerHandle != NULL) { err = _OpenMixer(); if (err) m_Player->print2stderr("########## HSPAudioDevice::Open error (mixer) %d\n", err); } pthread_mutex_unlock(&m_m); return 0;}STDMETHODIMPHSPAudioDevice::Pause(){ m_Player->print2stderr("########## Got to HSPAudioDevice::Pause %d\n", m_bHasHardwarePauseAndResume); _Pause(); return 0;}STDMETHODIMPHSPAudioDevice::Reset(){ m_Player->print2stderr("########## Got to HSPAudioDevice::Reset\n"); return (_Reset());}STDMETHODIMPHSPAudioDevice::Resume(){ m_Player->print2stderr("########## Got to HSPAudioDevice::Resume\n"); _Resume(); return 0;}STDMETHODIMPHSPAudioDevice::SetVolume( const UINT16 /*uVolume*/ ){ m_Player->print2stderr("########## Got to HSPAudioDevice::SetVolume\n"); return 0;}STDMETHODIMPHSPAudioDevice::Write( const HXAudioData* pAudioData ){ addBuf( new AudioQueue( pAudioData ) ); return 0;}int HSPAudioDevice::sync(){ if (m_pStreamResponse) { ULONG32 curtime; if (!GetCurrentAudioTime(curtime) && curtime) return m_pStreamResponse->OnTimeSync(curtime); else { // probably a seek occurred //clearQueue(); _Reset(); } } return -1;}HX_RESULT HSPAudioDevice::OnTimeSync(){ HX_RESULT err; if (!(err = sync())) return HXR_OK; return err;}intHSPAudioDevice::_Write( const HXAudioData* pAudioData ){ unsigned long len; long bytes; unsigned char *data; int err = 0; pAudioData->pData->Get(data, len); // if the time of this buf is earlier than the last, or the time between this buf and the last is > 1 buffer's worth, this was a seek if ( pAudioData->ulAudioTime < m_ulCurrentTime || pAudioData->ulAudioTime - m_ulCurrentTime > (1000 * len) / (m_unNumChannels * m_unSampleRate) + 1 ) { m_Player->print2stderr("########## seek detected %ld %ld, len = %ld %d\n", m_ulCurrentTime, pAudioData->ulAudioTime, len, abs(pAudioData->ulAudioTime - (m_ulCurrentTime + (1000 * len) / (m_unNumChannels * m_unSampleRate)))); //_Reset(); //clearQueue(); } if (!err) { err = WriteBytes(data, len, bytes); m_ulCurrentTime = pAudioData->ulAudioTime; } err = sync(); //m_Player->print2stderr("########## %d %d\n", m_ulCurrentTime,pAudioData->ulAudioTime); //m_Player->print2stderr("########## Got to HSPAudioDevice::Write len=%d byteswriten=%d err=%d time=%d\n", // len,bytes,err,m_ulCurrentTime); return err;}//------------------------------------------// Ctors and Dtors.//------------------------------------------HSPAudioDevice::HSPAudioDevice(HelixSimplePlayer *player, const char *device) : m_pAlsaPCMHandle (NULL), m_pAlsaMixerHandle (NULL), m_pAlsaMixerElem (NULL), m_pPCMDeviceName (NULL), m_pMixerDeviceName (NULL), m_pMixerElementName (NULL), m_bHasHardwarePauseAndResume (FALSE), m_nBytesPlayedBeforeLastTrigger(0), m_nLastBytesPlayed(0), m_bGotInitialTrigger(FALSE), m_bUseMMAPTStamps(TRUE), m_lRefCount(0), m_wLastError(0), m_SWPause(false), m_Player(player), m_done(false), m_drain(false), m_closed(true), m_head(0), m_tail(0){ pthread_mutexattr_t ma; pthread_mutexattr_init(&ma); pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_FAST_NP); // note this is not portable outside linux and a few others pthread_mutex_init(&m_m, &ma); pthread_cond_init(&m_cv, NULL); // create thread that will wait for buffers to appear to send to the device pthread_create(&m_thrid, 0, writerThread, this); if (device) { int len = strlen( device ); m_Player->pCommonClassFactory->CreateInstance(CLSID_IHXBuffer, (void **) &m_pPCMDeviceName); if (m_pPCMDeviceName) m_pPCMDeviceName->Set( (const unsigned char*) device, len + 1 ); }}HSPAudioDevice::~HSPAudioDevice(){ pthread_mutex_lock(&m_m); m_done = true; pthread_mutex_unlock(&m_m); pthread_cond_signal(&m_cv); void *tmp; pthread_join(m_thrid, &tmp); if(m_pPCMDeviceName) { HX_RELEASE(m_pPCMDeviceName); } if(m_pMixerDeviceName) { HX_RELEASE(m_pMixerDeviceName); } if(m_pMixerElementName) { HX_RELEASE(m_pMixerElementName); } pthread_cond_destroy(&m_cv); pthread_mutex_destroy(&m_m);}void HSPAudioDevice::addBuf(struct AudioQueue *item){ pthread_mutex_lock(&m_m); m_ulQTime = item->ad.ulAudioTime; if (m_tail) { item->fwd = 0; m_tail->fwd = item; m_tail = item; } else { item->fwd = 0; m_head = item; m_tail = item; } pthread_mutex_unlock(&m_m); pthread_cond_signal(&m_cv);}AudioQueue *HSPAudioDevice::getBuf(){ pthread_mutex_lock(&m_m); AudioQueue *item = m_head; if (item) { m_head = item->fwd; if (!m_head) m_tail = 0; } pthread_mutex_unlock(&m_m); return item;}// NOTE THAT THIS IS NOT UNDER LOCK, AND SHOULD ONLY BE CALLED WITH THE MUTEX LOCKEDvoid HSPAudioDevice::clearQueue(){ AudioQueue *item; if (!m_tail) return; while (m_tail) { item = m_head; m_head = item->fwd; if (!m_head) m_tail = 0; delete item; } }void *HSPAudioDevice::writerThread( void *arg ){ HSPAudioDevice *thisObj = (HSPAudioDevice *) arg; AudioQueue *item; pthread_mutex_lock(&thisObj->m_m); while (!thisObj->m_done) { pthread_mutex_unlock(&thisObj->m_m); item = thisObj->getBuf(); if (item) thisObj->_Write(&item->ad); delete item; pthread_mutex_lock(&thisObj->m_m); if (!thisObj->m_tail) pthread_cond_wait(&thisObj->m_cv, &thisObj->m_m); } pthread_mutex_unlock(&thisObj->m_m); thisObj->m_Player->print2stderr("############ writerThread exit\n"); return 0;}// These Device Specific methods must be implemented// by the platform specific sub-classes.INT16 HSPAudioDevice::GetAudioFd(void){ //Not implemented. return -1;}//Device specific methods to open/close the mixer and audio devices.HX_RESULT HSPAudioDevice::_OpenAudio(){ int err = 0; const char* szDevice; HX_ASSERT (m_pAlsaPCMHandle == NULL); if (m_pAlsaPCMHandle) { m_wLastError = RA_AOE_BADOPEN; return m_wLastError; }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -