1 /******************************************************************************
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 2 of the License, or *
6 * (at your option) any later version. *
8 * This library is distributed in the hope that it will be useful, but *
9 * WITHOUT ANY WARRANTY; without even the implied warranty of *
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
11 * Lesser General Public License for more details. *
13 * You should have received a copy of the GNU Lesser General Public *
14 * License along with this library; if not, write to the Free Software *
15 * Foundation, Inc., 51 Franklin St, 5th fl, Boston, MA 02110-1301, *
16 * USA, or check http://www.fsf.org/about/contact.html *
18 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved. *
19 * Portions Copyright (c) 2005 Paul Cifarelli *
21 ******************************************************************************/
27 #include <sys/ioctl.h>
35 #include "config-amarok.h"
48 #include "hspalsadevice.h"
50 #ifdef HX_LOG_SUBSYSTEM
51 #include "hxtlogutil.h"
52 #include "ihxtlogsystem.h"
61 IHXPreferences
* z_pIHXPrefs
= 0;
62 #define RA_AOE_NOERR 0
63 #define RA_AOE_GENERAL -1
64 #define RA_AOE_DEVNOTOPEN -2
65 #define RA_AOE_NOTENABLED -3
66 #define RA_AOE_BADFORMAT -4
67 #define RA_AOE_NOTSUPPORTED -5
68 #define RA_AOE_DEVBUSY -6
69 #define RA_AOE_BADOPEN -7
72 #define PTHREAD_MUTEX_FAST_NP PTHREAD_MUTEX_NORMAL
75 #if !defined(__NetBSD__) && !defined(__OpenBSD__)
76 #include <sys/soundcard.h>
78 #include <soundcard.h>
81 typedef HX_RESULT (HXEXPORT_PTR FPRMSETDLLACCESSPATH
) (const char*);
84 AudioQueue::AudioQueue( const HXAudioData
*buf
) : fwd(0)
90 AudioQueue::~AudioQueue()
97 HSPAudioDevice::QueryInterface(REFIID riid
, void**ppvObj
)
99 if(IsEqualIID(riid
, IID_IUnknown
))
102 *ppvObj
= (IUnknown
*)(IHXAudioDevice
*)this;
105 else if(IsEqualIID(riid
, IID_IHXAudioDevice
))
108 *ppvObj
= (IHXAudioDevice
*)this;
112 return HXR_NOINTERFACE
;
115 STDMETHODIMP_(UINT32
)
116 HSPAudioDevice::AddRef()
118 return InterlockedIncrement(&m_lRefCount
);
121 STDMETHODIMP_(UINT32
)
122 HSPAudioDevice::Release()
124 if (InterlockedDecrement(&m_lRefCount
) > 0)
134 HSPAudioDevice::CheckFormat( const HXAudioFormat
* pAudioFormat
)
136 m_Player
->print2stderr("########## Got to HSPAudioDevice::CheckFormat\n");
138 return (_CheckFormat(pAudioFormat
));
142 HSPAudioDevice::Close( const BOOL bFlush
)
144 m_Player
->print2stderr("########## Got to HSPAudioDevice::Close flush %d\n", bFlush
);
146 pthread_mutex_lock(&m_m
);
160 m_ulCurrentTime
= m_ulQTime
= 0;
162 if (m_pStreamResponse
)
163 m_pStreamResponse
->Release();
166 pthread_mutex_unlock(&m_m
);
172 HSPAudioDevice::Drain()
174 m_Player
->print2stderr("########## Got to HSPAudioDevice::Drain\n");
175 pthread_mutex_lock(&m_m
);
177 LONG32 err
= _Drain();
179 pthread_mutex_unlock(&m_m
);
184 HSPAudioDevice::GetCurrentAudioTime( REF(ULONG32
) ulCurrentTime
)
186 //m_Player->print2stderr("########## Got to HSPAudioDevice::GetCurrentTime = %d\n", m_ulCurrentTime);
189 snd_pcm_sframes_t frame_delay
= 0;
191 pthread_mutex_lock(&m_m
);
194 err
= snd_pcm_delay (m_pAlsaPCMHandle
, &frame_delay
);
197 #ifdef HX_LOG_SUBSYSTEM
198 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_status: %s", snd_strerror(err
));
200 m_Player
->print2stderr("########## HSPAudioDevice::GetCurrentAudioTime error getting frame_delay: %s\n", snd_strerror(err
));
201 pthread_mutex_unlock(&m_m
);
205 ulCurrentTime
= m_ulCurrentTime
- (ULONG32
)(((double)frame_delay
* 1000.0) / (double)m_unSampleRate
);
207 //m_Player->print2stderr("########## HSPAudioDevice::GetCurrentAudioTime %d %d\n", ulCurrentTime, m_ulCurrentTime);
209 pthread_mutex_unlock(&m_m
);
214 STDMETHODIMP_(UINT16
)
215 HSPAudioDevice::GetVolume()
217 m_Player
->print2stderr("########## Got to HSPAudioDevice::GetVolume\n");
222 HSPAudioDevice::InitVolume(const UINT16
/*uMinVolume*/, const UINT16
/*uMaxVolume*/)
224 m_Player
->print2stderr("########## Got to HSPAudioDevice::InitVolume\n");
229 HSPAudioDevice::Open(const HXAudioFormat
* pAudioFormat
, IHXAudioDeviceResponse
* pStreamResponse
)
233 m_Player
->print2stderr("########## Got to HSPAudioDevice::Open\n");
235 pStreamResponse
->AddRef();
237 pthread_mutex_lock(&m_m
);
241 m_ulTotalWritten
= 0;
244 m_pStreamResponse
= pStreamResponse
;
245 if (!m_pAlsaPCMHandle
)
248 if (err
) m_Player
->print2stderr("########## HSPAudioDevice::Open error (device) %d\n", err
);
249 err
= SetDeviceConfig(pAudioFormat
);
250 if (err
) m_Player
->print2stderr("########## HSPAudioDevice::Open error (config) %d\n", err
);
251 m_ulCurrentTime
= m_ulLastTime
= m_ulQTime
= 0;
254 if (m_pAlsaMixerHandle
!= NULL
)
257 if (err
) m_Player
->print2stderr("########## HSPAudioDevice::Open error (mixer) %d\n", err
);
260 pthread_mutex_unlock(&m_m
);
266 HSPAudioDevice::Pause()
268 m_Player
->print2stderr("########## Got to HSPAudioDevice::Pause %d\n", m_bHasHardwarePauseAndResume
);
274 HSPAudioDevice::Reset()
276 m_Player
->print2stderr("########## Got to HSPAudioDevice::Reset\n");
281 HSPAudioDevice::Resume()
283 m_Player
->print2stderr("########## Got to HSPAudioDevice::Resume\n");
290 HSPAudioDevice::SetVolume( const UINT16
/*uVolume*/ )
292 m_Player
->print2stderr("########## Got to HSPAudioDevice::SetVolume\n");
297 HSPAudioDevice::Write( const HXAudioData
* pAudioData
)
299 addBuf( new AudioQueue( pAudioData
) );
303 int HSPAudioDevice::sync()
305 if (m_pStreamResponse
)
308 if (!GetCurrentAudioTime(curtime
) && curtime
)
309 return m_pStreamResponse
->OnTimeSync(curtime
);
312 // probably a seek occurred
321 HX_RESULT
HSPAudioDevice::OnTimeSync()
332 HSPAudioDevice::_Write( const HXAudioData
* pAudioData
)
339 pAudioData
->pData
->Get(data
, len
);
341 // 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
342 if ( pAudioData
->ulAudioTime
< m_ulCurrentTime
||
343 pAudioData
->ulAudioTime
- m_ulCurrentTime
> (1000 * len
) / (m_unNumChannels
* m_unSampleRate
) + 1 )
345 m_Player
->print2stderr("########## seek detected %ld %ld, len = %ld %d\n", m_ulCurrentTime
, pAudioData
->ulAudioTime
, len
,
346 abs(pAudioData
->ulAudioTime
- (m_ulCurrentTime
+ (1000 * len
) / (m_unNumChannels
* m_unSampleRate
))));
353 err
= WriteBytes(data
, len
, bytes
);
354 m_ulCurrentTime
= pAudioData
->ulAudioTime
;
358 //m_Player->print2stderr("########## %d %d\n", m_ulCurrentTime,pAudioData->ulAudioTime);
360 //m_Player->print2stderr("########## Got to HSPAudioDevice::Write len=%d byteswriten=%d err=%d time=%d\n",
361 // len,bytes,err,m_ulCurrentTime);
367 //------------------------------------------
369 //------------------------------------------
370 HSPAudioDevice::HSPAudioDevice(HelixSimplePlayer
*player
, const char *device
) :
371 m_pAlsaPCMHandle (NULL
),
372 m_pAlsaMixerHandle (NULL
),
373 m_pAlsaMixerElem (NULL
),
375 m_pPCMDeviceName (NULL
),
376 m_pMixerDeviceName (NULL
),
377 m_pMixerElementName (NULL
),
379 m_bHasHardwarePauseAndResume (false),
380 m_nBytesPlayedBeforeLastTrigger(0),
382 m_nLastBytesPlayed(0),
384 m_bGotInitialTrigger(false),
385 m_bUseMMAPTStamps(true),
396 pthread_mutexattr_t ma
;
398 pthread_mutexattr_init(&ma
);
399 pthread_mutexattr_settype(&ma
, PTHREAD_MUTEX_FAST_NP
); // note this is not portable outside linux and a few others
400 pthread_mutex_init(&m_m
, &ma
);
402 pthread_cond_init(&m_cv
, NULL
);
404 // create thread that will wait for buffers to appear to send to the device
405 pthread_create(&m_thrid
, 0, writerThread
, this);
409 int len
= strlen( device
);
410 m_Player
->pCommonClassFactory
->CreateInstance(CLSID_IHXBuffer
, (void **) &m_pPCMDeviceName
);
411 if (m_pPCMDeviceName
)
412 m_pPCMDeviceName
->Set( (const unsigned char*) device
, len
+ 1 );
416 HSPAudioDevice::~HSPAudioDevice()
418 pthread_mutex_lock(&m_m
);
420 pthread_mutex_unlock(&m_m
);
421 pthread_cond_signal(&m_cv
);
423 pthread_join(m_thrid
, &tmp
);
428 HX_RELEASE(m_pPCMDeviceName
);
431 if(m_pMixerDeviceName
)
433 HX_RELEASE(m_pMixerDeviceName
);
436 if(m_pMixerElementName
)
438 HX_RELEASE(m_pMixerElementName
);
441 pthread_cond_destroy(&m_cv
);
442 pthread_mutex_destroy(&m_m
);
445 void HSPAudioDevice::addBuf(struct AudioQueue
*item
)
447 pthread_mutex_lock(&m_m
);
449 m_ulQTime
= item
->ad
.ulAudioTime
;
463 pthread_mutex_unlock(&m_m
);
464 pthread_cond_signal(&m_cv
);
467 AudioQueue
*HSPAudioDevice::getBuf()
469 pthread_mutex_lock(&m_m
);
471 AudioQueue
*item
= m_head
;
480 pthread_mutex_unlock(&m_m
);
485 // NOTE THAT THIS IS NOT UNDER LOCK, AND SHOULD ONLY BE CALLED WITH THE MUTEX LOCKED
486 void HSPAudioDevice::clearQueue()
504 void *HSPAudioDevice::writerThread( void *arg
)
506 HSPAudioDevice
*thisObj
= (HSPAudioDevice
*) arg
;
509 pthread_mutex_lock(&thisObj
->m_m
);
510 while (!thisObj
->m_done
)
512 pthread_mutex_unlock(&thisObj
->m_m
);
513 item
= thisObj
->getBuf();
516 thisObj
->_Write(&item
->ad
);
520 pthread_mutex_lock(&thisObj
->m_m
);
521 if (!thisObj
->m_tail
)
522 pthread_cond_wait(&thisObj
->m_cv
, &thisObj
->m_m
);
524 pthread_mutex_unlock(&thisObj
->m_m
);
526 thisObj
->m_Player
->print2stderr("############ writerThread exit\n");
531 // These Device Specific methods must be implemented
532 // by the platform specific sub-classes.
533 INT16
HSPAudioDevice::GetAudioFd(void)
540 //Device specific methods to open/close the mixer and audio devices.
541 HX_RESULT
HSPAudioDevice::_OpenAudio()
544 const char* szDevice
;
546 HX_ASSERT (m_pAlsaPCMHandle
== NULL
);
547 if (m_pAlsaPCMHandle
)
549 m_wLastError
= RA_AOE_BADOPEN
;
555 HX_RELEASE(m_pPCMDeviceName
);
556 z_pIHXPrefs
->ReadPref("AlsaPCMDeviceName", m_pPCMDeviceName
);
559 if(!m_pPCMDeviceName
)
561 const char szDefaultDevice
[] = "default";
563 m_Player
->pCommonClassFactory
->CreateInstance(CLSID_IHXBuffer
, (void **) &m_pPCMDeviceName
);
564 if (m_pPCMDeviceName
)
565 m_pPCMDeviceName
->Set( (const unsigned char*) szDefaultDevice
, sizeof(szDefaultDevice
) );
568 szDevice
= (const char*) m_pPCMDeviceName
->GetBuffer();
569 m_Player
->print2stderr("########### Opening ALSA PCM device %s\n", szDevice
);
571 #ifdef HX_LOG_SUBSYSTEM
572 HXLOGL2 (HXLOG_ADEV
, "Opening ALSA PCM device %s",
576 err
= snd_pcm_open( &m_pAlsaPCMHandle
,
578 SND_PCM_STREAM_PLAYBACK
,
582 m_Player
->print2stderr("########### snd_pcm_open: %s %s\n", szDevice
, snd_strerror (err
));
583 #ifdef HX_LOG_SUBSYSTEM
584 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_open: %s",
585 szDevice
, snd_strerror (err
));
588 m_wLastError
= RA_AOE_BADOPEN
;
593 err
= snd_pcm_nonblock(m_pAlsaPCMHandle
, true);
596 m_Player
->print2stderr("########## snd_pcm_nonblock: %s\n", snd_strerror (err
));
597 #ifdef HX_LOG_SUBSYSTEM
598 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_nonblock: %s",
601 m_wLastError
= RA_AOE_BADOPEN
;
607 m_Player
->print2stderr("########## return from OpenAudio\n");
608 m_wLastError
= RA_AOE_NOERR
;
614 snd_pcm_close(m_pAlsaPCMHandle
);
615 m_pAlsaPCMHandle
= NULL
;
623 HX_RESULT
HSPAudioDevice::_CloseAudio()
625 if (!m_pAlsaPCMHandle
)
627 m_wLastError
= RA_AOE_DEVNOTOPEN
;
631 #ifdef HX_LOG_SUBSYSTEM
632 HXLOGL2 (HXLOG_ADEV
, "Closing ALSA PCM device");
635 snd_pcm_close(m_pAlsaPCMHandle
);
636 m_pAlsaPCMHandle
= NULL
;
637 m_wLastError
= RA_AOE_NOERR
;
643 HX_RESULT
HSPAudioDevice::_OpenMixer()
646 const char* szDeviceName
= NULL
;
647 const char* szElementName
= NULL
;
648 int nElementIndex
= 0;
650 HX_ASSERT (m_pAlsaMixerHandle
== NULL
);
651 if (m_pAlsaMixerHandle
!= NULL
)
653 m_wLastError
= RA_AOE_BADOPEN
;
657 HX_ASSERT(m_pAlsaMixerElem
== NULL
);
658 if (m_pAlsaMixerElem
!= NULL
)
660 m_wLastError
= RA_AOE_BADOPEN
;
666 HX_RELEASE(m_pMixerDeviceName
);
667 z_pIHXPrefs
->ReadPref("AlsaMixerDeviceName", m_pMixerDeviceName
);
670 if(!m_pMixerDeviceName
)
672 const char szDefaultDevice
[] = "default";
674 m_Player
->pCommonClassFactory
->CreateInstance(CLSID_IHXBuffer
, (void **) &m_pMixerDeviceName
);
675 if (m_pMixerDeviceName
)
676 m_pMixerDeviceName
->Set( (const unsigned char*) szDefaultDevice
, sizeof(szDefaultDevice
) );
681 HX_RELEASE(m_pMixerElementName
);
682 z_pIHXPrefs
->ReadPref("AlsaMixerElementName", m_pMixerElementName
);
685 if(!m_pMixerElementName
)
687 const char szDefaultElement
[] = "PCM";
689 m_Player
->pCommonClassFactory
->CreateInstance(CLSID_IHXBuffer
, (void **) &m_pMixerElementName
);
690 if (m_pMixerElementName
)
691 m_pMixerElementName
->Set( (const unsigned char*) szDefaultElement
, sizeof(szDefaultElement
) );
696 IHXBuffer
* pElementIndex
= NULL
;
697 z_pIHXPrefs
->ReadPref("AlsaMixerElementIndex", pElementIndex
);
700 const char* szElementIndex
= (const char*) pElementIndex
->GetBuffer();
701 nElementIndex
= atoi(szElementIndex
);
703 HX_RELEASE(pElementIndex
);
707 szDeviceName
= (const char*) m_pMixerDeviceName
->GetBuffer();;
708 szElementName
= (const char*) m_pMixerElementName
->GetBuffer();
710 #ifdef HX_LOG_SUBSYSTEM
711 HXLOGL2 (HXLOG_ADEV
, "Opening ALSA mixer device %s",
715 err
= snd_mixer_open(&m_pAlsaMixerHandle
, 0);
718 #ifdef HX_LOG_SUBSYSTEM
719 HXLOGL1 ( HXLOG_ADEV
, "snd_mixer_open: %s",
723 m_wLastError
= RA_AOE_BADOPEN
;
728 err
= snd_mixer_attach(m_pAlsaMixerHandle
, szDeviceName
);
731 #ifdef HX_LOG_SUBSYSTEM
732 HXLOGL1 ( HXLOG_ADEV
, "snd_mixer_attach: %s",
736 m_wLastError
= RA_AOE_BADOPEN
;
742 err
= snd_mixer_selem_register(m_pAlsaMixerHandle
, NULL
, NULL
);
745 #ifdef HX_LOG_SUBSYSTEM
746 HXLOGL1 ( HXLOG_ADEV
, "snd_mixer_selem_register: %s",
749 m_wLastError
= RA_AOE_BADOPEN
;
755 err
= snd_mixer_load(m_pAlsaMixerHandle
);
758 #ifdef HX_LOG_SUBSYSTEM
759 HXLOGL1 ( HXLOG_ADEV
, "snd_mixer_load: %s",
763 m_wLastError
= RA_AOE_NOTENABLED
;
769 /* Find the mixer element */
770 snd_mixer_elem_t
* fallback_elem
= NULL
;
771 snd_mixer_elem_t
* elem
= snd_mixer_first_elem (m_pAlsaMixerHandle
);
772 snd_mixer_elem_type_t type
;
773 const char* elem_name
= NULL
;
774 snd_mixer_selem_id_t
*sid
= NULL
;
777 snd_mixer_selem_id_alloca(&sid
);
781 type
= snd_mixer_elem_get_type(elem
);
782 if (type
== SND_MIXER_ELEM_SIMPLE
)
784 snd_mixer_selem_get_id(elem
, sid
);
786 /* We're only interested in playback volume controls */
787 if(snd_mixer_selem_has_playback_volume(elem
) &&
788 !snd_mixer_selem_has_common_volume(elem
))
792 fallback_elem
= elem
;
795 elem_name
= snd_mixer_selem_id_get_name (sid
);
796 index
= snd_mixer_selem_id_get_index(sid
);
797 if (strcmp(elem_name
, szElementName
) == 0 &&
798 index
== nElementIndex
)
805 elem
= snd_mixer_elem_next(elem
);
808 if (!elem
&& fallback_elem
)
810 elem
= fallback_elem
;
812 type
= snd_mixer_elem_get_type(elem
);
814 if (type
== SND_MIXER_ELEM_SIMPLE
)
816 snd_mixer_selem_get_id(elem
, sid
);
817 elem_name
= snd_mixer_selem_id_get_name (sid
);
820 #ifdef HX_LOG_SUBSYSTEM
821 HXLOGL1 ( HXLOG_ADEV
, "Could not find element %s, using element %s instead",
822 m_pMixerElementName
, elem_name
? elem_name
: "unknown");
827 #ifdef HX_LOG_SUBSYSTEM
828 HXLOGL1 ( HXLOG_ADEV
, "Could not find a usable mixer element",
831 m_wLastError
= RA_AOE_BADOPEN
;
835 m_pAlsaMixerElem
= elem
;
840 if (m_pAlsaMixerHandle
)
850 m_wLastError
= RA_AOE_NOERR
;
854 if(m_pAlsaMixerHandle
)
856 snd_mixer_close(m_pAlsaMixerHandle
);
857 m_pAlsaMixerHandle
= NULL
;
864 HX_RESULT
HSPAudioDevice::_CloseMixer()
867 const char* szMixerDeviceName
= NULL
;
869 if (!m_pAlsaMixerHandle
)
871 m_wLastError
= RA_AOE_DEVNOTOPEN
;
875 if (!m_pMixerDeviceName
)
877 m_wLastError
= RA_AOE_DEVNOTOPEN
;
881 szMixerDeviceName
= (const char*) m_pMixerDeviceName
->GetBuffer();
882 err
= snd_mixer_detach(m_pAlsaMixerHandle
, szMixerDeviceName
);
885 #ifdef HX_LOG_SUBSYSTEM
886 HXLOGL1 ( HXLOG_ADEV
, "snd_mixer_detach: %s",
889 m_wLastError
= RA_AOE_GENERAL
;
894 err
= snd_mixer_close(m_pAlsaMixerHandle
);
897 #ifdef HX_LOG_SUBSYSTEM
898 HXLOGL1 ( HXLOG_ADEV
, "snd_mixer_close: %s",
901 m_wLastError
= RA_AOE_GENERAL
;
907 m_pAlsaMixerHandle
= NULL
;
908 m_pAlsaMixerElem
= NULL
;
909 m_wLastError
= RA_AOE_NOERR
;
916 //Device specific method to set the audio device characteristics. Sample rate,
917 //bits-per-sample, etc.
918 //Method *must* set member vars. m_unSampleRate and m_unNumChannels.
919 HX_RESULT
HSPAudioDevice::SetDeviceConfig( const HXAudioFormat
* pFormat
)
921 snd_pcm_state_t state
;
923 HX_ASSERT(m_pAlsaPCMHandle
!= NULL
);
924 if (!m_pAlsaPCMHandle
)
926 m_wLastError
= RA_AOE_DEVNOTOPEN
;
930 state
= snd_pcm_state(m_pAlsaPCMHandle
);
931 if (state
!= SND_PCM_STATE_OPEN
)
933 #ifdef HX_LOG_SUBSYSTEM
934 HXLOGL1 ( HXLOG_ADEV
, "Device is not in open state in HSPAudioDevice::SetDeviceConfig (%d)", (int) state
);
936 m_wLastError
= RA_AOE_DEVNOTOPEN
;
940 /* Translate from HXAudioFormat to ALSA-friendly values */
941 snd_pcm_format_t fmt
;
942 unsigned int sample_rate
= 0;
943 unsigned int channels
= 0;
944 unsigned int buffer_time
= 500000; /* 0.5 seconds */
945 unsigned int period_time
= buffer_time
/ 4; /* 4 interrupts per buffer */
947 switch (pFormat
->uBitsPerSample
)
950 fmt
= SND_PCM_FORMAT_S8
;
954 fmt
= SND_PCM_FORMAT_S16_LE
;
958 fmt
= SND_PCM_FORMAT_S24_LE
;
962 fmt
= SND_PCM_FORMAT_S32_LE
;
966 fmt
= SND_PCM_FORMAT_UNKNOWN
;
970 if (fmt
== SND_PCM_FORMAT_UNKNOWN
)
972 #ifdef HX_LOG_SUBSYSTEM
973 HXLOGL1 ( HXLOG_ADEV
, "Unknown bits per sample: %d", pFormat
->uBitsPerSample
);
975 m_wLastError
= RA_AOE_NOTENABLED
;
978 sample_rate
= pFormat
->ulSamplesPerSec
;
979 channels
= pFormat
->uChannels
;
983 snd_pcm_hw_params_t
*hwparams
;
984 snd_pcm_sw_params_t
*swparams
;
986 snd_pcm_hw_params_alloca(&hwparams
);
987 snd_pcm_sw_params_alloca(&swparams
);
989 /* Hardware parameters */
990 err
= snd_pcm_hw_params_any(m_pAlsaPCMHandle
, hwparams
);
993 #ifdef HX_LOG_SUBSYSTEM
994 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_hw_params_any: %s", snd_strerror(err
));
996 m_wLastError
= RA_AOE_NOTENABLED
;
1001 err
= snd_pcm_hw_params_set_access(m_pAlsaPCMHandle
, hwparams
, SND_PCM_ACCESS_RW_INTERLEAVED
);
1004 #ifdef HX_LOG_SUBSYSTEM
1005 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_hw_params_set_access: %s", snd_strerror(err
));
1007 m_wLastError
= RA_AOE_NOTENABLED
;
1013 err
= snd_pcm_hw_params_set_format(m_pAlsaPCMHandle
, hwparams
, fmt
);
1016 #ifdef HX_LOG_SUBSYSTEM
1017 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_hw_params_set_format: %s", snd_strerror(err
));
1019 m_wLastError
= RA_AOE_NOTENABLED
;
1025 err
= snd_pcm_hw_params_set_channels(m_pAlsaPCMHandle
, hwparams
, channels
);
1028 #ifdef HX_LOG_SUBSYSTEM
1029 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_hw_params_set_channels: %s", snd_strerror(err
));
1031 m_wLastError
= RA_AOE_NOTENABLED
;
1037 unsigned int sample_rate_out
;
1038 sample_rate_out
= sample_rate
;
1040 err
= snd_pcm_hw_params_set_rate_near(m_pAlsaPCMHandle
, hwparams
, &sample_rate_out
, 0);
1043 #ifdef HX_LOG_SUBSYSTEM
1044 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_hw_params_set_channels: %s", snd_strerror(err
));
1046 m_wLastError
= RA_AOE_NOTENABLED
;
1049 if (sample_rate_out
!= sample_rate
)
1051 #ifdef HX_LOG_SUBSYSTEM
1052 HXLOGL2 ( HXLOG_ADEV
, "Requested a sample rate of %d, got a rate of %d",
1053 sample_rate
, sample_rate_out
);
1056 sample_rate
= sample_rate_out
;
1062 unsigned int buffer_time_out
;
1063 buffer_time_out
= buffer_time
;
1065 err
= snd_pcm_hw_params_set_buffer_time_near(m_pAlsaPCMHandle
, hwparams
, &buffer_time_out
, 0);
1068 #ifdef HX_LOG_SUBSYSTEM
1069 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_hw_params_set_buffer_time_near: %s",
1072 m_wLastError
= RA_AOE_NOTENABLED
;
1075 if (buffer_time_out
!= buffer_time
)
1077 #ifdef HX_LOG_SUBSYSTEM
1078 HXLOGL2 ( HXLOG_ADEV
, "Requested a buffering time of %d, got a time of %d",
1079 buffer_time
, buffer_time_out
);
1082 buffer_time
= buffer_time_out
;
1088 unsigned int period_time_out
;
1089 period_time_out
= period_time
;
1091 err
= snd_pcm_hw_params_set_period_time_near(m_pAlsaPCMHandle
, hwparams
, &period_time_out
, 0);
1094 #ifdef HX_LOG_SUBSYSTEM
1095 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_hw_params_set_period_time_near: %s",
1098 m_wLastError
= RA_AOE_NOTENABLED
;
1101 if (period_time_out
!= period_time
)
1103 #ifdef HX_LOG_SUBSYSTEM
1104 HXLOGL2 ( HXLOG_ADEV
, "Requested a period time of %d, got a period of %d",
1105 period_time
, period_time_out
);
1107 period_time
= period_time_out
;
1111 /* Apply parameters */
1112 err
= snd_pcm_hw_params(m_pAlsaPCMHandle
, hwparams
);
1115 #ifdef HX_LOG_SUBSYSTEM
1116 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_hw_params: %s",
1119 m_wLastError
= RA_AOE_NOTENABLED
;
1122 /* read buffer & period sizes */
1123 snd_pcm_uframes_t buffer_size
= 0;
1124 snd_pcm_uframes_t period_size
= 0;
1128 err
= snd_pcm_hw_params_get_buffer_size(hwparams
, &buffer_size
);
1131 #ifdef HX_LOG_SUBSYSTEM
1132 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_hw_params_get_buffer_size: %s",
1135 m_wLastError
= RA_AOE_NOTENABLED
;
1139 HX_ASSERT (buffer_size
> 0);
1145 err
= snd_pcm_hw_params_get_period_size(hwparams
, &period_size
, 0);
1148 #ifdef HX_LOG_SUBSYSTEM
1149 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_hw_params_get_period_size: %s",
1152 m_wLastError
= RA_AOE_NOTENABLED
;
1156 /* Get hardware pause */
1162 can_pause
= snd_pcm_hw_params_can_pause(hwparams
);
1163 can_resume
= snd_pcm_hw_params_can_resume(hwparams
);
1165 // could we really have one without the other?
1166 m_bHasHardwarePauseAndResume
= (can_pause
&& can_resume
);
1167 m_Player
->print2stderr("########## can_pause %d can_resume %d\n", can_pause
, can_resume
);
1170 /* Software parameters */
1173 err
= snd_pcm_sw_params_current(m_pAlsaPCMHandle
, swparams
);
1176 #ifdef HX_LOG_SUBSYSTEM
1177 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_sw_params_current: %s",
1180 m_wLastError
= RA_AOE_NOTENABLED
;
1184 snd_pcm_uframes_t start_threshold
= ((buffer_size
- 1) / period_size
) * period_size
;
1188 err
= snd_pcm_sw_params_set_start_threshold(m_pAlsaPCMHandle
, swparams
, start_threshold
);
1191 #ifdef HX_LOG_SUBSYSTEM
1192 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_sw_params_set_start_threshold: %s",
1195 m_wLastError
= RA_AOE_NOTENABLED
;
1201 err
= snd_pcm_sw_params_set_avail_min(m_pAlsaPCMHandle
, swparams
, period_size
);
1204 #ifdef HX_LOG_SUBSYSTEM
1205 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_sw_params_set_avail_min: %s",
1208 m_wLastError
= RA_AOE_NOTENABLED
;
1214 err
= snd_pcm_sw_params_set_xfer_align(m_pAlsaPCMHandle
, swparams
, 1);
1217 #ifdef HX_LOG_SUBSYSTEM
1218 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_sw_params_set_xfer_align: %s",
1221 m_wLastError
= RA_AOE_NOTENABLED
;
1227 err
= snd_pcm_sw_params_set_tstamp_mode(m_pAlsaPCMHandle
, swparams
, SND_PCM_TSTAMP_MMAP
);
1230 #ifdef HX_LOG_SUBSYSTEM
1231 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_sw_params_set_xfer_align: %s",
1234 m_wLastError
= RA_AOE_NOTENABLED
;
1240 err
= snd_pcm_sw_params_set_stop_threshold(m_pAlsaPCMHandle
, swparams
, ~0U);
1243 #ifdef HX_LOG_SUBSYSTEM
1244 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_sw_params_set_stop_threshold: %s",
1247 m_wLastError
= RA_AOE_NOTENABLED
;
1253 err
= snd_pcm_sw_params(m_pAlsaPCMHandle
, swparams
);
1256 #ifdef HX_LOG_SUBSYSTEM
1257 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_sw_params: %s",
1260 m_wLastError
= RA_AOE_NOTENABLED
;
1264 /* If all the calls to this point have succeeded, move to the PREPARE state.
1265 We will enter the RUNNING state when we've buffered enough for our start theshold. */
1268 err
= snd_pcm_prepare (m_pAlsaPCMHandle
);
1271 #ifdef HX_LOG_SUBSYSTEM
1272 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_prepare: %s",
1275 m_wLastError
= RA_AOE_NOTENABLED
;
1279 /* Sanity check: See if we're now in the PREPARE state */
1282 snd_pcm_state_t state
;
1283 state
= snd_pcm_state (m_pAlsaPCMHandle
);
1284 if (state
!= SND_PCM_STATE_PREPARED
)
1286 #ifdef HX_LOG_SUBSYSTEM
1287 HXLOGL1 ( HXLOG_ADEV
, "Expected to be in PREPARE state, actually in state %d",
1290 m_wLastError
= RA_AOE_NOTENABLED
;
1294 /* Use avail to get the alsa buffer size, which is distinct from the hardware buffer
1295 size. This will match what GetRoomOnDevice uses. */
1296 int alsa_buffer_size
= 0;
1297 err
= snd_pcm_avail_update(m_pAlsaPCMHandle
);
1300 #ifdef HX_LOG_SUBSYSTEM
1301 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_avail_update: %s", snd_strerror(err
));
1306 alsa_buffer_size
= snd_pcm_frames_to_bytes(m_pAlsaPCMHandle
, err
);
1312 m_wLastError
= RA_AOE_NOERR
;
1314 m_unSampleRate
= sample_rate
;
1315 m_unNumChannels
= channels
;
1316 m_wBlockSize
= m_ulBytesPerGran
;
1317 m_ulDeviceBufferSize
= alsa_buffer_size
;
1318 m_uSampFrameSize
= snd_pcm_frames_to_bytes(m_pAlsaPCMHandle
, 1) / channels
;
1320 #ifdef HX_LOG_SUBSYSTEM
1321 HXLOGL2 ( HXLOG_ADEV
, "Device Configured:\n");
1322 HXLOGL2 ( HXLOG_ADEV
, " Sample Rate: %d", m_unSampleRate
);
1323 HXLOGL2 ( HXLOG_ADEV
, " Sample Width: %d", m_uSampFrameSize
);
1324 HXLOGL2 ( HXLOG_ADEV
, " Num channels: %d", m_unNumChannels
);
1325 HXLOGL2 ( HXLOG_ADEV
, " Block size: %d", m_wBlockSize
);
1326 HXLOGL2 ( HXLOG_ADEV
, " Device buffer size: %lu", m_ulDeviceBufferSize
);
1327 HXLOGL2 ( HXLOG_ADEV
, " Supports HW Pause: %d", m_bHasHardwarePauseAndResume
);
1328 HXLOGL2 ( HXLOG_ADEV
, " Start threshold: %d", start_threshold
);
1335 m_unNumChannels
= 0;
1337 if (m_pAlsaPCMHandle
)
1343 return m_wLastError
;
1346 //Device specific method to write bytes out to the audiodevice and return a
1347 //count of bytes written.
1348 HX_RESULT
HSPAudioDevice::WriteBytes( UCHAR
* buffer
, ULONG32 ulBuffLength
, LONG32
& lCount
)
1350 int err
= 0, count
= 0;
1351 unsigned int frames_written
= 0;
1352 snd_pcm_sframes_t num_frames
= 0;
1353 ULONG32 ulBytesToWrite
= ulBuffLength
;
1354 ULONG32 ulBytesWrote
= 0;
1358 HX_ASSERT(m_pAlsaPCMHandle
);
1359 if (!m_pAlsaPCMHandle
)
1361 m_wLastError
= RA_AOE_DEVNOTOPEN
;
1362 return m_wLastError
;
1365 m_wLastError
= RA_AOE_NOERR
;
1367 if (ulBuffLength
== 0)
1369 lCount
= ulBuffLength
;
1370 return m_wLastError
;
1376 pthread_mutex_lock(&m_m
);
1381 num_frames
= snd_pcm_bytes_to_frames(m_pAlsaPCMHandle
, ulBytesToWrite
);
1382 err
= snd_pcm_writei( m_pAlsaPCMHandle
, buffer
, num_frames
);
1389 pthread_mutex_unlock(&m_m
);
1392 pthread_mutex_unlock(&m_m
);
1396 frames_written
= err
;
1398 pthread_mutex_lock(&m_m
);
1400 ulBytesWrote
= snd_pcm_frames_to_bytes (m_pAlsaPCMHandle
, frames_written
);
1401 pthread_mutex_unlock(&m_m
);
1402 buffer
+= ulBytesWrote
;
1403 ulBytesToWrite
-= ulBytesWrote
;
1404 lCount
+= ulBytesWrote
;
1406 m_ulTotalWritten
+= ulBytesWrote
;
1419 lCount
= (LONG32
) ulBuffLength
;
1424 lCount
= (LONG32
) ulBuffLength
;
1428 m_Player
->print2stderr("########### snd_pcm_writei: %s num_frames=%ld\n", snd_strerror(err
), num_frames
);
1429 #ifdef HX_LOG_SUBSYSTEM
1430 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_writei: %s", snd_strerror(err
));
1432 m_wLastError
= RA_AOE_DEVBUSY
;
1435 } while (err
== -EAGAIN
|| (err
>0 && ulBytesToWrite
>0));
1437 //m_Player->print2stderr("############## count = %d\n", count);
1439 return m_wLastError
;
1442 /* Subtract the `struct timeval' values X and Y,
1443 storing the result in RESULT.
1444 Return 1 if the difference is negative, otherwise 0. */
1447 timeval_subtract (struct timeval
*result
,
1448 const struct timeval
*x
,
1449 const struct timeval
*y_orig
)
1451 struct timeval y
= *y_orig
;
1453 /* Perform the carry for the later subtraction by updating Y. */
1454 if (x
->tv_usec
< y
.tv_usec
)
1456 int nsec
= (y
.tv_usec
- x
->tv_usec
) / 1000000 + 1;
1457 y
.tv_usec
-= 1000000 * nsec
;
1460 if ((x
->tv_usec
- y
.tv_usec
) > 1000000)
1462 int nsec
= (x
->tv_usec
- y
.tv_usec
) / 1000000;
1463 y
.tv_usec
+= 1000000 * nsec
;
1467 /* Compute the time remaining to wait.
1468 `tv_usec' is certainly positive. */
1469 result
->tv_sec
= x
->tv_sec
- y
.tv_sec
;
1470 result
->tv_usec
= x
->tv_usec
- y
.tv_usec
;
1472 /* Return 1 if result is negative. */
1473 return x
->tv_sec
< y
.tv_sec
;
1476 HX_RESULT
HSPAudioDevice::GetBytesActuallyPlayedUsingTStamps(UINT64
&nBytesPlayed
) const
1478 HX_RESULT retVal
= HXR_FAIL
;
1482 snd_timestamp_t trigger_tstamp
, now_tstamp
, diff_tstamp
;
1483 snd_pcm_status_t
* status
;
1485 snd_pcm_status_alloca(&status
);
1487 err
= snd_pcm_status(m_pAlsaPCMHandle
, status
);
1490 #ifdef HX_LOG_SUBSYSTEM
1491 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_status: %s", snd_strerror(err
));
1497 snd_pcm_status_get_tstamp(status
, &now_tstamp
);
1498 snd_pcm_status_get_trigger_tstamp(status
, &trigger_tstamp
);
1500 if(!m_bGotInitialTrigger
&& now_tstamp
.tv_sec
== 0 && now_tstamp
.tv_usec
== 0)
1502 /* Our first "now" timestamp appears to be invalid (or the user is very unlucky, and
1503 happened to start playback as the timestamp rolls over). Fall back to using
1506 XXXRGG: Is there a better way to figure out if the driver supports mmap'd
1509 m_bUseMMAPTStamps
= false;
1513 /* Timestamp seems to be valid */
1514 if(!m_bGotInitialTrigger
)
1516 m_bGotInitialTrigger
= true;
1517 memcpy(&m_tstampLastTrigger
, &trigger_tstamp
, sizeof(m_tstampLastTrigger
));
1521 if(memcmp(&m_tstampLastTrigger
, &trigger_tstamp
, sizeof(m_tstampLastTrigger
)) != 0)
1523 /* There's been a trigger since last time -- restart the timestamp counter
1524 XXXRGG: What if there's been multiple triggers? */
1525 m_nBytesPlayedBeforeLastTrigger
= m_nLastBytesPlayed
;
1526 memcpy(&m_tstampLastTrigger
, &trigger_tstamp
, sizeof(m_tstampLastTrigger
));
1528 #ifdef HX_LOG_SUBSYSTEM
1529 HXLOGL1 ( HXLOG_ADEV
, "Retriggered...");
1534 timeval_subtract (&diff_tstamp
, &now_tstamp
, &m_tstampLastTrigger
);
1536 double fTimePlayed
= (double) diff_tstamp
.tv_sec
+
1537 ((double) diff_tstamp
.tv_usec
/ 1e6
);
1539 nBytesPlayed
= (UINT64
) ((fTimePlayed
* (double) m_unSampleRate
* m_uSampFrameSize
* m_unNumChannels
) + m_nBytesPlayedBeforeLastTrigger
);
1547 HX_RESULT
HSPAudioDevice::GetBytesActuallyPlayedUsingDelay (UINT64
&nBytesPlayed
) const
1549 HX_RESULT retVal
= HXR_FAIL
;
1551 snd_pcm_sframes_t frame_delay
= 0;
1553 err
= snd_pcm_delay (m_pAlsaPCMHandle
, &frame_delay
);
1556 #ifdef HX_LOG_SUBSYSTEM
1557 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_status: %s", snd_strerror(err
));
1563 bytes_delay
= snd_pcm_frames_to_bytes (m_pAlsaPCMHandle
, frame_delay
);
1565 nBytesPlayed
= m_ulTotalWritten
- bytes_delay
;
1569 #ifdef HX_LOG_SUBSYSTEM
1570 // HXLOGL4 ( HXLOG_ADEV, "nBytesPlayed: %llu, m_ulTotalWritten: %llu\n", nBytesPlayed, m_ulTotalWritten);
1576 HX_RESULT
HSPAudioDevice::GetBytesActuallyPlayedUsingAvail(UINT64
&nBytesPlayed
) const
1578 /* Try this the hwsync way. This method seems to crash & burn with dmix,
1579 as avail seems to come from the device, and varies depending on what other
1580 dmix clients are writing to the slave device. Currently not used for that reason. */
1582 HX_RESULT retVal
= HXR_FAIL
;
1585 err
= snd_pcm_hwsync(m_pAlsaPCMHandle
);
1588 #ifdef HX_LOG_SUBSYSTEM
1589 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_hwsync: %s", snd_strerror(err
));
1593 err
= snd_pcm_avail_update(m_pAlsaPCMHandle
);
1596 #ifdef HX_LOG_SUBSYSTEM
1597 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_avail_update: %s", snd_strerror(err
));
1602 snd_pcm_sframes_t avail
= err
;
1604 bytes_avail
= snd_pcm_frames_to_bytes (m_pAlsaPCMHandle
, avail
);
1606 nBytesPlayed
= m_ulTotalWritten
- (m_ulDeviceBufferSize
- bytes_avail
);
1613 HX_RESULT
HSPAudioDevice::GetBytesActuallyPlayedUsingTimer(UINT64
&/*nBytesPlayed*/) const
1615 /* Look at the alsa timer api, and how we can lock onto it as a timer source. */
1620 UINT64
HSPAudioDevice::GetBytesActualyPlayed(void) const
1622 HX_ASSERT(m_pAlsaPCMHandle
);
1623 if (!m_pAlsaPCMHandle
)
1628 HX_RESULT retVal
= HXR_OK
;
1629 UINT64 nBytesPlayed
= 0;
1630 snd_pcm_state_t state
;
1634 state
= snd_pcm_state(m_pAlsaPCMHandle
);
1637 case SND_PCM_STATE_OPEN
:
1638 case SND_PCM_STATE_SETUP
:
1639 case SND_PCM_STATE_PREPARED
:
1640 /* If we're in one of these states, written and played should match. */
1641 m_nLastBytesPlayed
= m_ulTotalWritten
;
1642 return m_nLastBytesPlayed
;
1644 case SND_PCM_STATE_XRUN
:
1648 case SND_PCM_STATE_RUNNING
:
1651 case SND_PCM_STATE_PAUSED
:
1652 // return m_nLastBytesPlayed;
1655 case SND_PCM_STATE_DRAINING
:
1656 case SND_PCM_STATE_SUSPENDED
:
1657 case SND_PCM_STATE_DISCONNECTED
:
1658 HX_ASSERT(!"Not reached");
1665 // XXXRGG: Always use the delay method for now.
1666 m_bUseMMAPTStamps
= false;
1668 if (m_bUseMMAPTStamps
)
1670 retVal
= GetBytesActuallyPlayedUsingTStamps(nBytesPlayed
);
1673 if (!m_bUseMMAPTStamps
|| FAILED(retVal
))
1675 /* MMAP'd timestamps are fishy. Try using snd_pcm_delay. */
1676 retVal
= GetBytesActuallyPlayedUsingDelay(nBytesPlayed
);
1679 m_nLastBytesPlayed
= nBytesPlayed
;
1680 return nBytesPlayed
;
1684 //this must return the number of bytes that can be written without blocking.
1685 HX_RESULT
HSPAudioDevice::GetRoomOnDevice(ULONG32
& ulBytes
) const
1689 HX_ASSERT(m_pAlsaPCMHandle
);
1690 if (!m_pAlsaPCMHandle
)
1692 m_wLastError
= RA_AOE_DEVNOTOPEN
;
1693 return m_wLastError
;
1697 err
= snd_pcm_avail_update(m_pAlsaPCMHandle
);
1700 ulBytes
= snd_pcm_frames_to_bytes(m_pAlsaPCMHandle
, err
);
1718 #ifdef HX_LOG_SUBSYSTEM
1719 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_avail_update: %s", snd_strerror(err
));
1721 m_wLastError
= RA_AOE_DEVBUSY
;
1725 #ifdef HX_LOG_SUBSYSTEM
1726 // HXLOGL4 ( HXLOG_ADEV, "RoomOnDevice: %d", ulBytes);
1729 return m_wLastError
;
1733 //Device specific method to get/set the devices current volume.
1734 UINT16
HSPAudioDevice::_GetVolume() const
1736 HX_ASSERT(m_pAlsaMixerElem
);
1737 if (!m_pAlsaMixerElem
)
1742 UINT16 nRetVolume
= 0;
1744 snd_mixer_elem_type_t type
;
1746 type
= snd_mixer_elem_get_type(m_pAlsaMixerElem
);
1748 if (type
== SND_MIXER_ELEM_SIMPLE
)
1750 long volume
, min_volume
, max_volume
;
1752 if(snd_mixer_selem_has_playback_volume(m_pAlsaMixerElem
) ||
1753 snd_mixer_selem_has_playback_volume_joined(m_pAlsaMixerElem
))
1755 err
= snd_mixer_selem_get_playback_volume(m_pAlsaMixerElem
,
1756 SND_MIXER_SCHN_MONO
,
1760 #ifdef HX_LOG_SUBSYSTEM
1761 HXLOGL1 ( HXLOG_ADEV
, "snd_mixer_selem_get_playback_volume: %s",
1762 snd_strerror (err
));
1768 snd_mixer_selem_get_playback_volume_range(m_pAlsaMixerElem
,
1772 if(max_volume
> min_volume
)
1774 nRetVolume
= (UINT16
) (100 * volume
/ (max_volume
- min_volume
));
1784 HX_RESULT
HSPAudioDevice::_SetVolume(UINT16 unVolume
)
1786 m_wLastError
= RA_AOE_NOERR
;
1788 HX_ASSERT(m_pAlsaMixerElem
);
1789 if (!m_pAlsaMixerElem
)
1791 m_wLastError
= RA_AOE_DEVNOTOPEN
;
1792 return m_wLastError
;
1795 snd_mixer_elem_type_t type
;
1797 type
= snd_mixer_elem_get_type(m_pAlsaMixerElem
);
1799 if (type
== SND_MIXER_ELEM_SIMPLE
)
1801 long volume
, min_volume
, max_volume
, range
;
1803 if(snd_mixer_selem_has_playback_volume(m_pAlsaMixerElem
) ||
1804 snd_mixer_selem_has_playback_volume_joined(m_pAlsaMixerElem
))
1806 snd_mixer_selem_get_playback_volume_range(m_pAlsaMixerElem
,
1810 range
= max_volume
- min_volume
;
1811 volume
= (long) ((unVolume
/ 100) * range
+ min_volume
);
1813 err
= snd_mixer_selem_set_playback_volume( m_pAlsaMixerElem
,
1814 SND_MIXER_SCHN_FRONT_LEFT
,
1818 #ifdef HX_LOG_SUBSYSTEM
1819 HXLOGL1 ( HXLOG_ADEV
, "snd_mixer_selem_set_playback_volume: %s",
1820 snd_strerror (err
));
1822 m_wLastError
= RA_AOE_GENERAL
;
1825 if (!snd_mixer_selem_is_playback_mono (m_pAlsaMixerElem
))
1827 /* Set the right channel too */
1828 err
= snd_mixer_selem_set_playback_volume( m_pAlsaMixerElem
,
1829 SND_MIXER_SCHN_FRONT_RIGHT
,
1833 #ifdef HX_LOG_SUBSYSTEM
1834 HXLOGL1 ( HXLOG_ADEV
, "snd_mixer_selem_set_playback_volume: %s",
1835 snd_strerror (err
));
1837 m_wLastError
= RA_AOE_GENERAL
;
1843 return m_wLastError
;
1846 //Device specific method to drain a device. This should play the remaining
1847 //bytes in the devices buffer and then return.
1848 HX_RESULT
HSPAudioDevice::_Drain()
1850 m_wLastError
= RA_AOE_NOERR
;
1852 HX_ASSERT(m_pAlsaPCMHandle
);
1853 if (!m_pAlsaPCMHandle
)
1855 m_wLastError
= RA_AOE_DEVNOTOPEN
;
1856 return m_wLastError
;
1861 err
= snd_pcm_drain(m_pAlsaPCMHandle
);
1864 #ifdef HX_LOG_SUBSYSTEM
1865 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_drain: %s",
1866 snd_strerror (err
));
1868 m_wLastError
= RA_AOE_GENERAL
;
1871 err
= snd_pcm_prepare(m_pAlsaPCMHandle
);
1874 #ifdef HX_LOG_SUBSYSTEM
1875 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_prepare: %s",
1876 snd_strerror (err
));
1878 m_wLastError
= RA_AOE_GENERAL
;
1881 return m_wLastError
;
1885 //Device specific method to reset device and return it to a state that it
1886 //can accept new sample rates, num channels, etc.
1887 HX_RESULT
HSPAudioDevice::_Reset()
1889 if (!m_pAlsaPCMHandle
)
1891 m_wLastError
= RA_AOE_DEVNOTOPEN
;
1892 return m_wLastError
;
1895 m_wLastError
= RA_AOE_NOERR
;
1897 m_nLastBytesPlayed
= 0;
1901 err
= snd_pcm_drop(m_pAlsaPCMHandle
);
1904 #ifdef HX_LOG_SUBSYSTEM
1905 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_drop: %s",
1906 snd_strerror (err
));
1908 m_wLastError
= RA_AOE_GENERAL
;
1911 err
= snd_pcm_prepare(m_pAlsaPCMHandle
);
1914 #ifdef HX_LOG_SUBSYSTEM
1915 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_prepare: %s",
1916 snd_strerror (err
));
1918 m_wLastError
= RA_AOE_GENERAL
;
1921 return m_wLastError
;
1924 HX_RESULT
HSPAudioDevice::_CheckFormat( const HXAudioFormat
* pFormat
)
1926 HX_ASSERT(m_pAlsaPCMHandle
== NULL
);
1928 m_wLastError
= _OpenAudio();
1929 if(m_wLastError
!= RA_AOE_NOERR
)
1931 return m_wLastError
;
1934 m_wLastError
= RA_AOE_NOERR
;
1936 snd_pcm_format_t fmt
;
1937 unsigned int sample_rate
= 0;
1938 unsigned int channels
= 0;
1940 switch (pFormat
->uBitsPerSample
)
1943 fmt
= SND_PCM_FORMAT_S8
;
1947 fmt
= SND_PCM_FORMAT_S16_LE
;
1951 fmt
= SND_PCM_FORMAT_S24_LE
;
1955 fmt
= SND_PCM_FORMAT_S32_LE
;
1959 fmt
= SND_PCM_FORMAT_UNKNOWN
;
1963 if (fmt
== SND_PCM_FORMAT_UNKNOWN
)
1965 #ifdef HX_LOG_SUBSYSTEM
1966 HXLOGL1 ( HXLOG_ADEV
, "Unknown bits per sample: %d", pFormat
->uBitsPerSample
);
1968 m_wLastError
= RA_AOE_NOTENABLED
;
1969 return m_wLastError
;
1971 sample_rate
= pFormat
->ulSamplesPerSec
;
1972 channels
= pFormat
->uChannels
;
1976 snd_pcm_hw_params_t
*hwparams
;
1978 snd_pcm_hw_params_alloca(&hwparams
);
1980 err
= snd_pcm_hw_params_any(m_pAlsaPCMHandle
, hwparams
);
1983 #ifdef HX_LOG_SUBSYSTEM
1984 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_hw_params_any: %s", snd_strerror(err
));
1986 m_wLastError
= RA_AOE_NOTENABLED
;
1991 err
= snd_pcm_hw_params_test_rate (m_pAlsaPCMHandle
, hwparams
, sample_rate
, 0);
1994 m_wLastError
= RA_AOE_BADFORMAT
;
2000 err
= snd_pcm_hw_params_test_channels (m_pAlsaPCMHandle
, hwparams
, channels
);
2003 m_wLastError
= RA_AOE_BADFORMAT
;
2009 err
= snd_pcm_hw_params_test_format (m_pAlsaPCMHandle
, hwparams
, fmt
);
2012 m_wLastError
= RA_AOE_BADFORMAT
;
2018 return m_wLastError
;
2022 HX_RESULT
HSPAudioDevice::CheckSampleRate( ULONG32 ulSampleRate
)
2024 HX_ASSERT(m_pAlsaPCMHandle
== NULL
);
2025 bool shouldclose
= false;
2027 if (!m_pAlsaPCMHandle
)
2029 m_wLastError
= _OpenAudio();
2030 if(m_wLastError
!= RA_AOE_NOERR
)
2032 return m_wLastError
;
2038 snd_pcm_hw_params_t
*hwparams
;
2040 snd_pcm_hw_params_alloca(&hwparams
);
2042 m_wLastError
= RA_AOE_NOERR
;
2044 err
= snd_pcm_hw_params_any(m_pAlsaPCMHandle
, hwparams
);
2047 #ifdef HX_LOG_SUBSYSTEM
2048 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_hw_params_any: %s", snd_strerror(err
));
2050 m_wLastError
= RA_AOE_NOTENABLED
;
2055 err
= snd_pcm_hw_params_test_rate (m_pAlsaPCMHandle
, hwparams
, ulSampleRate
, 0);
2058 m_wLastError
= RA_AOE_BADFORMAT
;
2065 return m_wLastError
;
2069 HX_RESULT
HSPAudioDevice::_Pause()
2071 HX_ASSERT(m_pAlsaPCMHandle
);
2072 if (!m_pAlsaPCMHandle
)
2074 m_wLastError
= RA_AOE_DEVNOTOPEN
;
2075 return m_wLastError
;
2078 if (m_bHasHardwarePauseAndResume
)
2080 snd_pcm_state_t state
;
2082 state
= snd_pcm_state(m_pAlsaPCMHandle
);
2083 if (state
== SND_PCM_STATE_RUNNING
)
2086 err
= snd_pcm_pause(m_pAlsaPCMHandle
, 1);
2089 #ifdef HX_LOG_SUBSYSTEM
2090 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_pause: %s",
2091 snd_strerror (err
));
2094 m_wLastError
= RA_AOE_NOTSUPPORTED
;
2100 pthread_mutex_lock(&m_m
);
2104 pthread_mutex_unlock(&m_m
);
2107 return m_wLastError
;
2110 HX_RESULT
HSPAudioDevice::_Resume()
2112 HX_ASSERT(m_pAlsaPCMHandle
);
2113 if (!m_pAlsaPCMHandle
)
2115 m_wLastError
= RA_AOE_DEVNOTOPEN
;
2116 return m_wLastError
;
2119 if (m_bHasHardwarePauseAndResume
)
2121 snd_pcm_state_t state
;
2123 state
= snd_pcm_state(m_pAlsaPCMHandle
);
2124 if (state
== SND_PCM_STATE_PAUSED
)
2127 err
= snd_pcm_pause(m_pAlsaPCMHandle
, 0);
2131 #ifdef HX_LOG_SUBSYSTEM
2132 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_pause: %s",
2133 snd_strerror (err
));
2136 m_wLastError
= RA_AOE_NOTSUPPORTED
;
2142 pthread_mutex_lock(&m_m
);
2145 pthread_mutex_unlock(&m_m
);
2148 return m_wLastError
;
2151 BOOL
HSPAudioDevice::HardwarePauseSupported() const
2153 HX_ASSERT(m_pAlsaPCMHandle
!= NULL
);
2155 return m_bHasHardwarePauseAndResume
;
2159 void HSPAudioDevice::HandleXRun(void) const
2163 #ifdef HX_LOG_SUBSYSTEM
2164 HXLOGL2 ( HXLOG_ADEV
, "Handling XRun");
2167 err
= snd_pcm_prepare(m_pAlsaPCMHandle
);
2170 #ifdef HX_LOG_SUBSYSTEM
2171 HXLOGL1 ( HXLOG_ADEV
, "snd_pcm_resume: %s (xrun)",
2172 snd_strerror (err
));
2176 /* Catch up to the write position of the audio device so we get new data.
2177 XXXRGG: Is there some way we, the device, can force a rewind? */
2178 m_nLastBytesPlayed
= m_ulTotalWritten
;
2181 void HSPAudioDevice::HandleSuspend(void) const
2187 err
= snd_pcm_resume(m_pAlsaPCMHandle
);
2192 else if (err
== -EAGAIN
)
2196 } while (err
== -EAGAIN
);
2204 #endif // HELIX_USE_ALSA