?? hspalsadevice.cpp
字號:
case SND_PCM_STATE_DISCONNECTED: HX_ASSERT(!"Not reached"); break; } break; } // XXXRGG: Always use the delay method for now. m_bUseMMAPTStamps = FALSE; if (m_bUseMMAPTStamps) { retVal = GetBytesActuallyPlayedUsingTStamps(nBytesPlayed); } if (!m_bUseMMAPTStamps || FAILED(retVal)) { /* MMAP'd timestamps are fishy. Try using snd_pcm_delay. */ retVal = GetBytesActuallyPlayedUsingDelay(nBytesPlayed); } m_nLastBytesPlayed = nBytesPlayed; return nBytesPlayed;}//this must return the number of bytes that can be written without blocking.HX_RESULT HSPAudioDevice::GetRoomOnDevice(ULONG32& ulBytes) const{ ulBytes = 0; HX_ASSERT(m_pAlsaPCMHandle); if (!m_pAlsaPCMHandle) { m_wLastError = RA_AOE_DEVNOTOPEN; return m_wLastError; } int err = 0; err = snd_pcm_avail_update(m_pAlsaPCMHandle); if(err > 0) { ulBytes = snd_pcm_frames_to_bytes(m_pAlsaPCMHandle, err); } else { switch (err) { case -EAGAIN: break; case -EPIPE: HandleXRun(); break; case -ESTRPIPE: HandleSuspend(); break; default:#ifdef HX_LOG_SUBSYSTEM HXLOGL1 ( HXLOG_ADEV, "snd_pcm_avail_update: %s", snd_strerror(err));#endif m_wLastError = RA_AOE_DEVBUSY; } }#ifdef HX_LOG_SUBSYSTEM// HXLOGL4 ( HXLOG_ADEV, "RoomOnDevice: %d", ulBytes); #endif return m_wLastError;}//Device specific method to get/set the devices current volume.UINT16 HSPAudioDevice::_GetVolume() const{ HX_ASSERT(m_pAlsaMixerElem); if (!m_pAlsaMixerElem) { return 0; } UINT16 nRetVolume = 0; snd_mixer_elem_type_t type; int err = 0; type = snd_mixer_elem_get_type(m_pAlsaMixerElem); if (type == SND_MIXER_ELEM_SIMPLE) { long volume, min_volume, max_volume; if(snd_mixer_selem_has_playback_volume(m_pAlsaMixerElem) || snd_mixer_selem_has_playback_volume_joined(m_pAlsaMixerElem)) { err = snd_mixer_selem_get_playback_volume(m_pAlsaMixerElem, SND_MIXER_SCHN_MONO, &volume); if (err < 0) {#ifdef HX_LOG_SUBSYSTEM HXLOGL1 ( HXLOG_ADEV, "snd_mixer_selem_get_playback_volume: %s", snd_strerror (err));#endif } if (err == 0) { snd_mixer_selem_get_playback_volume_range(m_pAlsaMixerElem, &min_volume, &max_volume); if(max_volume > min_volume) { nRetVolume = (UINT16) (100 * volume / (max_volume - min_volume)); } } } } return nRetVolume;}HX_RESULT HSPAudioDevice::_SetVolume(UINT16 unVolume){ m_wLastError = RA_AOE_NOERR; HX_ASSERT(m_pAlsaMixerElem); if (!m_pAlsaMixerElem) { m_wLastError = RA_AOE_DEVNOTOPEN; return m_wLastError; } snd_mixer_elem_type_t type; int err = 0; type = snd_mixer_elem_get_type(m_pAlsaMixerElem); if (type == SND_MIXER_ELEM_SIMPLE) { long volume, min_volume, max_volume, range; if(snd_mixer_selem_has_playback_volume(m_pAlsaMixerElem) || snd_mixer_selem_has_playback_volume_joined(m_pAlsaMixerElem)) { snd_mixer_selem_get_playback_volume_range(m_pAlsaMixerElem, &min_volume, &max_volume); range = max_volume - min_volume; volume = (long) ((unVolume / 100) * range + min_volume); err = snd_mixer_selem_set_playback_volume( m_pAlsaMixerElem, SND_MIXER_SCHN_FRONT_LEFT, volume); if (err < 0) {#ifdef HX_LOG_SUBSYSTEM HXLOGL1 ( HXLOG_ADEV, "snd_mixer_selem_set_playback_volume: %s", snd_strerror (err));#endif m_wLastError = RA_AOE_GENERAL; } if (!snd_mixer_selem_is_playback_mono (m_pAlsaMixerElem)) { /* Set the right channel too */ err = snd_mixer_selem_set_playback_volume( m_pAlsaMixerElem, SND_MIXER_SCHN_FRONT_RIGHT, volume); if (err < 0) {#ifdef HX_LOG_SUBSYSTEM HXLOGL1 ( HXLOG_ADEV, "snd_mixer_selem_set_playback_volume: %s", snd_strerror (err));#endif m_wLastError = RA_AOE_GENERAL; } } } } return m_wLastError;}//Device specific method to drain a device. This should play the remaining//bytes in the devices buffer and then return.HX_RESULT HSPAudioDevice::_Drain(){ m_wLastError = RA_AOE_NOERR; HX_ASSERT(m_pAlsaPCMHandle); if (!m_pAlsaPCMHandle) { m_wLastError = RA_AOE_DEVNOTOPEN; return m_wLastError; } int err = 0; err = snd_pcm_drain(m_pAlsaPCMHandle); if (err < 0) {#ifdef HX_LOG_SUBSYSTEM HXLOGL1 ( HXLOG_ADEV, "snd_pcm_drain: %s", snd_strerror (err));#endif m_wLastError = RA_AOE_GENERAL; } err = snd_pcm_prepare(m_pAlsaPCMHandle); if (err < 0) {#ifdef HX_LOG_SUBSYSTEM HXLOGL1 ( HXLOG_ADEV, "snd_pcm_prepare: %s", snd_strerror (err));#endif m_wLastError = RA_AOE_GENERAL; } return m_wLastError;}//Device specific method to reset device and return it to a state that it//can accept new sample rates, num channels, etc.HX_RESULT HSPAudioDevice::_Reset(){ if (!m_pAlsaPCMHandle) { m_wLastError = RA_AOE_DEVNOTOPEN; return m_wLastError; } m_wLastError = RA_AOE_NOERR; m_nLastBytesPlayed = 0; int err = 0; err = snd_pcm_drop(m_pAlsaPCMHandle); if (err < 0) {#ifdef HX_LOG_SUBSYSTEM HXLOGL1 ( HXLOG_ADEV, "snd_pcm_drop: %s", snd_strerror (err));#endif m_wLastError = RA_AOE_GENERAL; } err = snd_pcm_prepare(m_pAlsaPCMHandle); if (err < 0) {#ifdef HX_LOG_SUBSYSTEM HXLOGL1 ( HXLOG_ADEV, "snd_pcm_prepare: %s", snd_strerror (err));#endif m_wLastError = RA_AOE_GENERAL; } return m_wLastError;}HX_RESULT HSPAudioDevice::_CheckFormat( const HXAudioFormat* pFormat ){ HX_ASSERT(m_pAlsaPCMHandle == NULL); m_wLastError = _OpenAudio(); if(m_wLastError != RA_AOE_NOERR) { return m_wLastError; } m_wLastError = RA_AOE_NOERR; snd_pcm_format_t fmt; unsigned int sample_rate = 0; unsigned int channels = 0; switch (pFormat->uBitsPerSample) { case 8: fmt = SND_PCM_FORMAT_S8; break; case 16: fmt = SND_PCM_FORMAT_S16_LE; break; case 24: fmt = SND_PCM_FORMAT_S24_LE; break; case 32: fmt = SND_PCM_FORMAT_S32_LE; break; default: fmt = SND_PCM_FORMAT_UNKNOWN; break; } if (fmt == SND_PCM_FORMAT_UNKNOWN) {#ifdef HX_LOG_SUBSYSTEM HXLOGL1 ( HXLOG_ADEV, "Unknown bits per sample: %d", pFormat->uBitsPerSample);#endif m_wLastError = RA_AOE_NOTENABLED; return m_wLastError; } sample_rate = pFormat->ulSamplesPerSec; channels = pFormat->uChannels; /* Apply to ALSA */ int err = 0; snd_pcm_hw_params_t *hwparams; snd_pcm_hw_params_alloca(&hwparams); err = snd_pcm_hw_params_any(m_pAlsaPCMHandle, hwparams); if (err < 0) {#ifdef HX_LOG_SUBSYSTEM HXLOGL1 ( HXLOG_ADEV, "snd_pcm_hw_params_any: %s", snd_strerror(err));#endif m_wLastError = RA_AOE_NOTENABLED; } if (err == 0) { err = snd_pcm_hw_params_test_rate (m_pAlsaPCMHandle, hwparams, sample_rate, 0); if (err < 0) { m_wLastError = RA_AOE_BADFORMAT; } } if (err == 0) { err = snd_pcm_hw_params_test_channels (m_pAlsaPCMHandle, hwparams, channels); if (err < 0) { m_wLastError = RA_AOE_BADFORMAT; } } if (err == 0) { err = snd_pcm_hw_params_test_format (m_pAlsaPCMHandle, hwparams, fmt); if (err < 0) { m_wLastError = RA_AOE_BADFORMAT; } } _CloseAudio(); return m_wLastError;}HX_RESULT HSPAudioDevice::CheckSampleRate( ULONG32 ulSampleRate ){ HX_ASSERT(m_pAlsaPCMHandle == NULL); bool shouldclose = false; if (!m_pAlsaPCMHandle) { m_wLastError = _OpenAudio(); if(m_wLastError != RA_AOE_NOERR) { return m_wLastError; } shouldclose = true; } int err = 0; snd_pcm_hw_params_t *hwparams; snd_pcm_hw_params_alloca(&hwparams); m_wLastError = RA_AOE_NOERR; err = snd_pcm_hw_params_any(m_pAlsaPCMHandle, hwparams); if (err < 0) {#ifdef HX_LOG_SUBSYSTEM HXLOGL1 ( HXLOG_ADEV, "snd_pcm_hw_params_any: %s", snd_strerror(err));#endif m_wLastError = RA_AOE_NOTENABLED; } if (err == 0) { err = snd_pcm_hw_params_test_rate (m_pAlsaPCMHandle, hwparams, ulSampleRate, 0); if (err < 0) { m_wLastError = RA_AOE_BADFORMAT; } } if (shouldclose) _CloseAudio(); return m_wLastError;}HX_RESULT HSPAudioDevice::_Pause(){ HX_ASSERT(m_pAlsaPCMHandle); if (!m_pAlsaPCMHandle) { m_wLastError = RA_AOE_DEVNOTOPEN; return m_wLastError; } if (m_bHasHardwarePauseAndResume) { snd_pcm_state_t state; state = snd_pcm_state(m_pAlsaPCMHandle); if (state == SND_PCM_STATE_RUNNING) { int err = 0; err = snd_pcm_pause(m_pAlsaPCMHandle, 1); if (err < 0) {#ifdef HX_LOG_SUBSYSTEM HXLOGL1 ( HXLOG_ADEV, "snd_pcm_pause: %s", snd_strerror (err));#endif m_wLastError = RA_AOE_NOTSUPPORTED; } } } else { pthread_mutex_lock(&m_m); m_SWPause = true; _Drain(); _Reset(); pthread_mutex_unlock(&m_m); } return m_wLastError;}HX_RESULT HSPAudioDevice::_Resume(){ HX_ASSERT(m_pAlsaPCMHandle); if (!m_pAlsaPCMHandle) { m_wLastError = RA_AOE_DEVNOTOPEN; return m_wLastError; } if (m_bHasHardwarePauseAndResume) { snd_pcm_state_t state; state = snd_pcm_state(m_pAlsaPCMHandle); if (state == SND_PCM_STATE_PAUSED) { int err = 0; err = snd_pcm_pause(m_pAlsaPCMHandle, 0); if (err < 0) {#ifdef HX_LOG_SUBSYSTEM HXLOGL1 ( HXLOG_ADEV, "snd_pcm_pause: %s", snd_strerror (err));#endif m_wLastError = RA_AOE_NOTSUPPORTED; } } } else { pthread_mutex_lock(&m_m); m_SWPause = false; _Reset(); pthread_mutex_unlock(&m_m); } return m_wLastError;}BOOL HSPAudioDevice::HardwarePauseSupported() const{ HX_ASSERT(m_pAlsaPCMHandle != NULL); return m_bHasHardwarePauseAndResume;}void HSPAudioDevice::HandleXRun(void) const{ int err = 0;#ifdef HX_LOG_SUBSYSTEM HXLOGL2 ( HXLOG_ADEV, "Handling XRun");#endif err = snd_pcm_prepare(m_pAlsaPCMHandle); if (err < 0) {#ifdef HX_LOG_SUBSYSTEM HXLOGL1 ( HXLOG_ADEV, "snd_pcm_resume: %s (xrun)", snd_strerror (err));#endif } /* Catch up to the write position of the audio device so we get new data. XXXRGG: Is there some way we, the device, can force a rewind? */ m_nLastBytesPlayed = m_ulTotalWritten;}void HSPAudioDevice::HandleSuspend(void) const{ int err = 0; do { err = snd_pcm_resume(m_pAlsaPCMHandle); if (err == 0) { break; } else if (err == -EAGAIN) { usleep(1000); } } while (err == -EAGAIN); if (err < 0) { HandleXRun(); }}#endif // HELIX_USE_ALSA
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -