audlinux_alsa.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:38k
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: RCSL 1.0/RPSL 1.0
- *
- * Portions Copyright (c) 1995-2003 RealNetworks, Inc. All Rights Reserved.
- *
- * The contents of this file, and the files included with this file, are
- * subject to the current version of the RealNetworks Public Source License
- * Version 1.0 (the "RPSL") available at
- * http://www.helixcommunity.org/content/rpsl unless you have licensed
- * the file under the RealNetworks Community Source License Version 1.0
- * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
- * in which case the RCSL will apply. You may also obtain the license terms
- * directly from RealNetworks. You may not use this file except in
- * compliance with the RPSL or, if you have a valid RCSL with RealNetworks
- * applicable to this file, the RCSL. Please see the applicable RPSL or
- * RCSL for the rights, obligations and limitations governing use of the
- * contents of the file.
- *
- * This file is part of the Helix DNA Technology. RealNetworks is the
- * developer of the Original Code and owns the copyrights in the portions
- * it created.
- *
- * This file, and the files included with this file, is distributed and made
- * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- *
- * Technology Compatibility Kit Test Suite(s) Location:
- * http://www.helixcommunity.org/content/tck
- *
- * Contributor(s): ljp <ljp@llornkcor.com>
- *
- * ***** END LICENSE BLOCK ***** */
- #include <unistd.h>
- #include <fcntl.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <sys/ioctl.h>
- #define ALSA_PCM_NEW_HW_PARAMS_API
- #define ALSA_PCM_NEW_SW_PARAMS_API
- #include <alsa/asoundlib.h>
- #include <stdio.h>
- #include <math.h>
- #include "ihxpckts.h"
- #include "hxtick.h"
- #include "hxprefs.h"
- #include "timeval.h"
- #include "hxthread.h"
- #include "audlinux_alsa.h"
- #include "hxstrutl.h"
- #include "dllacces.h"
- #include "dllpath.h"
- //------------------------------------------
- // Ctors and Dtors.
- //------------------------------------------
- CAudioOutLinuxAlsa::CAudioOutLinuxAlsa() :
- CAudioOutUNIX(),
- m_ulTickCount(0),
- m_ulLastBytesPlayed(0),
- m_ulLastTimeStamp(0),
- m_ulPausePosition(0),
- m_bHasHardwarePause(FALSE),
- m_bHasHardwareResume(FALSE),
- pcm_handle(0),
- mixer_handle(0)
- {
- };
- CAudioOutLinuxAlsa::~CAudioOutLinuxAlsa()
- {
- #ifdef _DEBUG
- printf("d'torn");
- #endif
- //The mixer is opened independently of the audio device. Make sure
- //it is closed.
- _CloseMixer();
- snd_pcm_hw_params_free(hwparams);
- // snd_pcm_status_free(status);
- };
- // These Device Specific methods must be implemented
- // by the platform specific sub-classes.
- INT16 CAudioOutLinuxAlsa::_Imp_GetAudioFd(void)
- {
- return (INT16) pcm_handle;
- }
- //Device specific methods to open/close the mixer and audio devices.
- HX_RESULT CAudioOutLinuxAlsa::_OpenAudio()
- {
- HX_RESULT retCode = RA_AOE_NOERR;
- int err=0;
-
- //Set the tick count to zero
- m_ulTickCount = 0;
- m_ulLastTimeStamp = 0;
- m_ulLastBytesPlayed = 0;
- m_ulPausePosition = 0;
- //Check the environmental variable to let user overide default device.
- char *pszOverrideName = getenv( "AUDIO" );
- char szDevName[MAX_DEV_NAME];
- // Use defaults if no environment variable is set.
- if ( pszOverrideName && strlen(pszOverrideName)>0 )
- {
- SafeStrCpy( szDevName, pszOverrideName, MAX_DEV_NAME );
- }
- else
- {
- SafeStrCpy( szDevName, "default", MAX_DEV_NAME );
- // SafeStrCpy( szDevName, "hw:0,0", MAX_DEV_NAME );
- // SafeStrCpy( szDevName, "plughw:0,0", MAX_DEV_NAME );
- }
- // Open the audio device if it isn't already open
- if ( pcm_handle <= 0 )
- {
- if ( snd_pcm_open( &pcm_handle, szDevName, SND_PCM_STREAM_PLAYBACK /*stream*/, 0) < 0) {
- #ifdef _DEBUG
- fprintf( stderr, "Failed to open audio device %s : %d errno: %dn",
- szDevName, pcm_handle, errno );
- #endif
- retCode = RA_AOE_BADOPEN;
- }
- }
- if((err=snd_pcm_nonblock( pcm_handle, 1)) < 0)
- {
- #ifdef _DEBUG
- fprintf (stderr, "Cannot set nonblock (%s)n",
- snd_strerror (err));
- #endif
- }
- // if((err = snd_pcm_status_malloc( &status)) <0)
- // {
- // fprintf (stderr, "cannot allocate status parameter structure (%s)n",
- // snd_strerror (err));
- // }
- if((err = snd_pcm_hw_params_malloc( &hwparams)) < 0)
- {
- #ifdef _DEBUG
- fprintf (stderr, "HW parameters malloc failed %sn",
- snd_strerror (err));
- #endif
- }
-
- if ((err = snd_pcm_hw_params_any( pcm_handle, hwparams)) < 0) {
- #ifdef _DEBUG
- fprintf (stderr, "HW parameters init failed %sn",
- snd_strerror (err));
- #endif
- }
- m_wLastError = retCode;
- return m_wLastError;
- }
- HX_RESULT CAudioOutLinuxAlsa::_CloseAudio()
- {
- HX_RESULT retCode = RA_AOE_NOERR;
- if( pcm_handle > 0 )
- // if (snd_pcm_state( pcm_handle) == SND_PCM_STATE_OPEN)
- {
- snd_pcm_close( pcm_handle);
- pcm_handle = 0;//NO_FILE_DESCRIPTOR;
- #ifdef _DEBUG
- printf("pcm_handle is now %dn", pcm_handle);
- #endif
- }
- else
- {
- retCode = RA_AOE_DEVNOTOPEN;
- }
- m_wLastError = retCode;
- return m_wLastError;
- }
- HX_RESULT CAudioOutLinuxAlsa::_OpenMixer()
- {
- HX_RESULT retCode = RA_AOE_NOERR;
- int result;
-
- if(!m_bMixerPresent)
- {
- //Let user override default device with environ variable.
- char *pszOverrideName = getenv( "MIXER" );
- char szDevCtlName[MAX_DEV_NAME];
- // could be "hw:0,0", or "plughw:0,0" or similiar
- if (pszOverrideName && strlen(pszOverrideName) > 0 )
- {
- SafeStrCpy( szDevCtlName , pszOverrideName, MAX_DEV_NAME );
- }
- else
- {
- SafeStrCpy( szDevCtlName , "default", MAX_DEV_NAME );
- // default for volume
- }
- if (( result = snd_mixer_open( &mixer_handle, 0)) < 0)
- {
- #ifdef _DEBUG
- printf( "Open audio device failed %d", result);
- #endif
- retCode = RA_AOE_BADOPEN;
- }
-
- if (( result = snd_mixer_attach( mixer_handle, szDevCtlName )) < 0) {
- #ifdef _DEBUG
- printf("Mixer attach %s failed: %s", szDevCtlName, snd_strerror( result));
- #endif
- snd_mixer_close( mixer_handle);
- retCode = RA_AOE_NOTENABLED;
- }
-
- if (( result = snd_mixer_selem_register( mixer_handle, NULL, NULL)) < 0) {
- #ifdef _DEBUG
- printf("Register mixer error: %s", snd_strerror( result));
- #endif
- snd_mixer_close( mixer_handle);
- retCode = RA_AOE_NOTENABLED;
- }
- if((result = snd_mixer_load( mixer_handle)) < 0 )
- {
- retCode = RA_AOE_NOTENABLED;
- }
- if (mixer_handle > 0)
- {
- m_bMixerPresent = 1;
- _Imp_GetVolume();
- }
- else
- {
- mixer_handle = 0;// NO_FILE_DESCRIPTOR;
- m_bMixerPresent = 0;
- }
- }
- m_wLastError = retCode;
- return m_wLastError;
- }
- HX_RESULT CAudioOutLinuxAlsa::_CloseMixer()
- {
- if( mixer_handle > 0 )
- {
- //Let user override default device with environ variable.
- char *pszOverrideName = getenv( "MIXER" );
- char szDevCtlName[MAX_DEV_NAME];
- // could be "hw:0,0", or "plughw:0,0" or similiar
- if (pszOverrideName && strlen(pszOverrideName) > 0 )
- {
- SafeStrCpy( szDevCtlName , pszOverrideName, MAX_DEV_NAME );
- }
- else
- {
- SafeStrCpy( szDevCtlName , "default", MAX_DEV_NAME );
- // default for volume
- }
- if( snd_mixer_detach( mixer_handle, szDevCtlName) < 0)
- {
- #ifdef _DEBUG
- printf("Detach mixer failedn");
- #endif
- }
-
- if(snd_mixer_close ( mixer_handle) < 0)
- {
- #ifdef _DEBUG
- printf("Close mixer failedn");
- #endif
- mixer_handle = 0;//NO_FILE_DESCRIPTOR;
- }
- }
- return m_wLastError;
- }
- //Devic specific method to set the audio device characteristics. Sample rate,
- //bits-per-sample, etc.
- //Method *must* set member vars. m_unSampleRate and m_unNumChannels.
- HX_RESULT CAudioOutLinuxAlsa::_SetDeviceConfig( const HXAudioFormat* pFormat )
- {
- HX_RESULT retCode = RA_AOE_NOERR;
- int err=0;
- if (snd_pcm_state( pcm_handle) != SND_PCM_STATE_OPEN)
- return RA_AOE_DEVNOTOPEN;
- if (snd_pcm_hw_params_any( pcm_handle, hwparams) < 0) {
- #ifdef _DEBUG
- fprintf(stderr, "Configure device failedn");
- #endif
- return retCode = RA_AOE_NOTENABLED;
- }
- // SND_PCM_ACCESS_RW_INTERLEAVED or
- // SND_PCM_ACCESS_RW_NONINTERLEAVED.
- // There are also access types for MMAPed
- if (snd_pcm_hw_params_set_access( pcm_handle, hwparams,
- SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
- #ifdef _DEBUG
- fprintf(stderr, "Set access failedn");
- #endif
- return retCode = RA_AOE_NOTENABLED;
- }
- // Now set the format. Either 8-bit or 16-bit audio is supported.
- // alsa supports up to 64 bit
- int nSampleWidth = pFormat->uBitsPerSample;
- ULONG32 nSampleRate = pFormat->ulSamplesPerSec;
- int numChannels = pFormat->uChannels;
- int nFormat1 = 0;
- int nFormat2 = 0;
- snd_pcm_format_t m_format;
- snd_pcm_uframes_t bufferSz;
- unsigned long buffer_size, period_size;
- if( nSampleWidth == 16)
- {
- m_format = SND_PCM_FORMAT_S16;
- }
- else
- {
- m_format = SND_PCM_FORMAT_U8;
- }
- m_frameBytes = snd_pcm_format_physical_width( m_format);
- if ((err = snd_pcm_hw_params_set_format( pcm_handle, hwparams,
- m_format) < 0)) {
- #ifdef _DEBUG
- fprintf (stderr, "Set sample format failed %s %dn",
- snd_strerror (err), m_format );
- #endif
- return ( m_wLastError = RA_AOE_NOTENABLED );
- }
- //If we went to 8-bit then
- if( m_format == SND_PCM_FORMAT_U8 )
- {
- nSampleWidth = 8;
- }
- m_uSampFrameSize = samplesize =nSampleWidth/8;
- if ( nSampleWidth != pFormat->uBitsPerSample )
- {
- ((HXAudioFormat*)pFormat)->uBitsPerSample = nSampleWidth;
- }
- // Set sample rate. If the exact rate is not supported
- // by the hardware, use nearest possible rate.
- unsigned int rrate = (unsigned int) nSampleRate;
- if(( err = snd_pcm_hw_params_set_rate_near( pcm_handle, hwparams, &rrate, 0) ) < 0 )
- {
- #ifdef _DEBUG
- fprintf(stderr,
- "The rate %d Hz is not supported by your hardware.n==> Using %d Hz instead.n",
- nSampleRate, rrate);
- #endif
- return ( m_wLastError = RA_AOE_NOTENABLED );
- }
- m_unSampleRate = rrate;
- if ( rrate != pFormat->ulSamplesPerSec )
- {
- ((HXAudioFormat*)pFormat)->ulSamplesPerSec = rrate;
- }
- if (snd_pcm_hw_params_set_channels( pcm_handle, hwparams, numChannels) < 0) {
- #ifdef _DEBUG
- fprintf(stderr, "Error setting channels.n");
- #endif
- return ( m_wLastError = RA_AOE_NOTENABLED );
- }
- m_unNumChannels = channels = numChannels;
- if ( numChannels != pFormat->uChannels )
- {
- ((HXAudioFormat*)pFormat)->uChannels = numChannels;
- }
- int periods = 2; // Number of periods
- snd_pcm_uframes_t periodsize = 2048; // FIXME
- int direct=0;
- snd_pcm_uframes_t period = 0;
- // The period size == fragment size.
- // Note that this in frames (frame = nr_channels * sample_width)
- // So a value of 1024 means 4096 bytes (1024 x 2 x 16-bits)
-
- // if((err = snd_pcm_hw_params_get_period_size_max( hwparams, &period,& direct) ) < 0)
- // {
- // #ifdef _DEBUG
- // printf("Unable to get period size %ld : %sn", period, snd_strerror(err));
- // #endif
- // }
- // direct=0;
- if((err = snd_pcm_hw_params_set_period_size_near( pcm_handle, hwparams, &periodsize, &direct) ) < 0)
- {
- #ifdef _DEBUG
- printf("Set period size failed %ld : %sn", periodsize, snd_strerror(err));
- #endif
- }
- //////////////////////////////////// set periods
- // printf("set periodsn");
- // if ((err = snd_pcm_hw_params_set_periods_near( pcm_handle, hwparams, &periods, &direct )) < 0 )
- // {
- // printf("Error setting periods %sn", snd_strerror(err));
- // }
-
- /* if(( err =snd_pcm_hw_params_get_period_size( hwparams, &period_size, NULL)) < 0)
- {
- printf("unable to get peroidsize:n") ;
- }
- */
- // snd_pcm_hw_params_get_period_size( hwparams, &val);
- // if((err = snd_pcm_hw_params_set_buffer_size( pcm_handle, hwparams, bufferSz )) < 0)
- // if((err = snd_pcm_hw_params_set_buffer_size_near( pcm_handle, hwparams, bufferSz )) < 0)
- // {
- // printf("Unable to set buffer size %li : %sn", bufferSz, snd_strerror(err));
- // }
- // printf("get buffer sizen");
- ////////////////////////// Get buffer size in frames
- // m_wBlockSize = m_ulBytesPerGran;
- if((err = snd_pcm_hw_params_get_buffer_size_max( hwparams, &bufferSz)) < 0)
- {
- #ifdef _DEBUG
- printf("Get buffer size failed:n") ;
- #endif
- if( m_ulDeviceBufferSize <= 0)
- blocksize = m_wBlockSize = m_ulDeviceBufferSize = 8192 * 2;
- }
- else
- {
- blocksize = bufferSz;
- m_wBlockSize = blocksize;
- m_ulDeviceBufferSize = blocksize * samplesize * channels;
- }
- // printf("blocksize %d, samplesize %d, channels %dn", blocksize, samplesize, channels );
- // printf("m_ulDeviceBufferSize %ldn", m_ulDeviceBufferSize);
-
- if (snd_pcm_hw_params( pcm_handle, hwparams) < 0) //write device
- {
- #ifdef _DEBUG
- fprintf(stderr, "Error setting HW params.n");
- #endif
- return ( m_wLastError = RA_AOE_NOTENABLED );
- }
- snd_pcm_sw_params_alloca(&swparams);
- if((err = snd_pcm_sw_params_current( pcm_handle, swparams)) <0)
- {
- #ifdef _DEBUG
- printf("Current SW params failed: %sn", snd_strerror(err));
- #endif
- }
- // if ((err = snd_pcm_sw_params_set_avail_min ( pcm_handle, swparams, 2048)) < 0) {
- // fprintf (stderr, "cannot set minimum available count (%s)n",
- // snd_strerror (err));
- // }
- if((err = snd_pcm_sw_params_set_start_threshold( pcm_handle, swparams, bufferSz )) < 0)
- {
- #ifdef _DEBUG
- printf("Set start threshold mode failed: %sn", snd_strerror(err));
- #endif
- }
- if((err = snd_pcm_sw_params_set_xfer_align( pcm_handle, swparams, 1)) < 0)
- {
- #ifdef _DEBUG
- printf("Set transfer align failed: %sn", snd_strerror(err));
- #endif
- }
- if((err = snd_pcm_sw_params_set_tstamp_mode( pcm_handle, swparams,SND_PCM_TSTAMP_MMAP )) < 0 )
- {
- #ifdef _DEBUG
- printf("Set sw params time stamp mode failed: %sn", snd_strerror(err));
- #endif
- }
- if((err = snd_pcm_sw_params( pcm_handle, swparams)) < 0)
- {
- #ifdef _DEBUG
- printf("Set sw params failed: %sn", snd_strerror(err));
- #endif
- }
- if ((err=snd_pcm_prepare ( pcm_handle)) < 0)
- {
- #ifdef _DEBUG
- fprintf (stderr, "Prepare audio interface failed %sn",
- snd_strerror (err));
- #endif
- return retCode = RA_AOE_NOTENABLED;
- }
- #ifdef _DEBUG
- snd_output_t *output = NULL;
- snd_output_stdio_attach(&output, stdout, 0);
- printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<nn");
- snd_pcm_dump( pcm_handle, output);
- printf("n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<nn");
- snd_pcm_hw_params_dump( hwparams, output);
- printf("n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<nn");
- snd_pcm_sw_params_dump( swparams, output);
- printf("n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<nn");
- // snd_pcm_status_dump( status, output);
- // printf("n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<nn");
- fprintf( stdout, "Device Configured:n");
- fprintf( stdout, " Sample Rate: %dn", m_unSampleRate);
- fprintf( stdout, " Sample Width: %dn", nSampleWidth);
- fprintf( stdout , " Num channels: %dn", m_unNumChannels);
- fprintf( stdout, " Block size: %dn", m_wBlockSize);
- fprintf( stdout, " Device buffer size: %lun", m_ulDeviceBufferSize);
- #endif
- // snd_pcm_sw_params_free( swparams);
- return RA_AOE_NOERR;
- }
- void CAudioOutLinuxAlsa::_SyncUpTimeStamps(ULONG32 writeCount)
- {
- snd_pcm_hwsync( pcm_handle);
- int bytes2 = 0;
- int err = 0;
- snd_pcm_sframes_t framedelay;
- if((err = snd_pcm_delay( pcm_handle, &framedelay)) < 0)
- {
- #ifdef _DEBUG
- fprintf (stderr, "cannot get delay %sn", snd_strerror (err));
- #endif
- }
- bytes2 = snd_pcm_frames_to_bytes( pcm_handle, framedelay);
-
- if( bytes2 > 0)
- {
- m_ulLastBytesPlayed = (UINT64)( m_ulTotalWritten + writeCount - bytes2);
- m_ulLastTimeStamp = GetTickCount();
- }
- }
- //Device specific method to write bytes out to the audiodevice and return a
- //count of bytes written.
- HX_RESULT CAudioOutLinuxAlsa::_WriteBytes( UCHAR* buffer, ULONG32 ulBuffLength, LONG32& lCount )
- {
- LONG32 writeCount;
- HX_RESULT retCode = RA_AOE_NOERR;
- int err=0;
- if( m_ulTickCount == 0 )
- m_ulTickCount = GetTickCount();
- snd_pcm_sframes_t num_frames, size;
- lCount = 0;
- num_frames = snd_pcm_bytes_to_frames( pcm_handle, ulBuffLength); //alsa in frames
- // Returns the number of frames actually written.
- size = snd_pcm_writei( pcm_handle, buffer, num_frames );
- if(size < 0)
- {
- switch (size)
- {
- case -EBADFD:
- {
- #ifdef _DEBUG
- printf("EBADFD: Device not in the right state n");
- #endif
- retCode = RA_AOE_DEVBUSY;
- }
- break;
- case -EPIPE: //lets handle underruns
- {
- if(( size = snd_pcm_prepare( pcm_handle) ) < 0 )
- {
- #ifdef _DEBUG
- printf("EPIPE: Recovery from underrun is difficult: %sn", snd_strerror( size));
- #endif
- retCode = RA_AOE_DEVBUSY;
- }
- }
- break;
- case -ESTRPIPE:
- {
- while (( size = snd_pcm_resume( pcm_handle)) == -EAGAIN)
- sleep(1);
- if ( size < 0)
- {
- size = snd_pcm_prepare( pcm_handle);
- if ( size < 0)
- {
- #ifdef _DEBUG
- printf("ESTRPIPE: Recover from suspend is difficult: %sn", snd_strerror( size));
- #endif
- retCode = RA_AOE_DEVBUSY;
- }
- }
- }
- break;
- };
- }
- // printf("frames written = %dn", size);
- writeCount = snd_pcm_frames_to_bytes( pcm_handle, size );
- if( writeCount < 0 )
- {
- if( errno == EAGAIN )
- retCode = RA_AOE_NOERR;
- if( errno == EINTR )
- retCode = RA_AOE_DEVBUSY;
- }
- else
- {
- _SyncUpTimeStamps( writeCount);
- // XXXRGG: Figure out why writeCount != ulBuffLength
- // lCount = writeCount;
- lCount = ulBuffLength;
- }
- return retCode;
- }
- UINT64 CAudioOutLinuxAlsa::_GetBytesActualyPlayed(void) const
- {
- // Get current playback position in device DMA.
- int bytes2 = 0;
- UINT64 ulTheAnswer = 0;
- if( m_ulTotalWritten > 0 )
- {
- HX_ASSERT( m_unSampleRate!=0 && m_uSampFrameSize!=0 );
- ULONG32 ulTick = GetTickCount();
- //We need to update the timestamps every so often.
- //This make sure that if the XServer was blocked, and
- //we ran dry, that we re-sync up.
- if( (ulTick - m_ulLastTimeStamp) > 200 )
- {
- ((CAudioOutLinuxAlsa*)this)->_SyncUpTimeStamps();
- ulTick = GetTickCount();
- }
- ulTheAnswer = (UINT64)(m_ulLastBytesPlayed+
- ((float)(ulTick-m_ulLastTimeStamp)*
- (float)m_unNumChannels/1000.0*
- m_unSampleRate*m_uSampFrameSize) +0.5 );
- }
- // printf("BytesActualyPlayed %ldn", ulTheAnswer);
- return ulTheAnswer;
- }
- //this must return the number of bytes that can be written without blocking.
- HX_RESULT CAudioOutLinuxAlsa::_GetRoomOnDevice(ULONG32& ulBytes) const
- {
- HX_RESULT retCode = RA_AOE_NOERR;
- // FIXME
- ulBytes = m_ulDeviceBufferSize - ( m_ulTotalWritten - _GetBytesActualyPlayed() );
- // printf("RoomOnDevice %ldn", ulBytes);
- m_wLastError = retCode;
- return m_wLastError;
- }
- //Device specific method to get/set the devices current volume.
- UINT16 CAudioOutLinuxAlsa::_GetVolume() const
- {
- UINT16 nRetVolume = 0;
- long pmin = 0, pmax = 0;
- long percentage = 0;
-
- long frontLeftVolume = 0;
- long frontRightVolume = 0;
-
- /* long frontCenterVolume = 0;
- long rearLeftVolume = 0;
- long rearRightVolume = 0;
-
- long wooferVolume = 0;
- snd_mixer_selem_id_t *sid;
- snd_mixer_selem_id_alloca(&sid);
- */
- snd_mixer_elem_t *mixer_elements2;
- mixer_elements2 = snd_mixer_first_elem( mixer_handle);
- // grab first elem of mixer
- if (snd_mixer_selem_has_playback_volume( mixer_elements2)) {
-
- if( snd_mixer_selem_get_playback_volume( mixer_elements2,
- SND_MIXER_SCHN_FRONT_LEFT, &frontLeftVolume) < 0)
- frontLeftVolume = 0;
-
- if( snd_mixer_selem_get_playback_volume( mixer_elements2,
- SND_MIXER_SCHN_FRONT_RIGHT, &frontRightVolume) < 0)
- frontRightVolume = 0;
- }
- /* snd_mixer_selem_get_playback_volume_range( mixer_elements2, &pmin, &pmax);
- int range = pmax - pmin;
- int val = frontLeftVolume;
- frontRightVolume = frontLeftVolume;
- val -= pmin;
- // printf("min %d, max %d, range %d, val %dn", pmin, pmax, range, val );
- percentage = (long)rint((double)val / (double)range * 100);
- */
- // printf("fleft %ld, fright %ld, percent %dn",
- // frontLeftVolume, frontRightVolume, percentage);
- // Save for future use, demonstrates multichannel mixer access.
-
- // for ( mixer_elements2 = snd_mixer_first_elem( mixer_handle);
- // mixer_elements2;
- // mixer_elements2 = snd_mixer_elem_next( mixer_elements2) ) {
-
- // snd_mixer_selem_get_id( mixer_elements2, sid);
-
- // // if ( !snd_mixer_selem_is_active( mixer_elements2))
- // // continue;
-
- // printf("mixer control '%s',%in",
- // snd_mixer_selem_id_get_name( sid),
- // snd_mixer_selem_id_get_index( sid));
-
- // snd_mixer_selem_get_playback_volume_range( mixer_elements2, &pmin, &pmax);
- // // if its got mono mixer
- // if ( snd_mixer_selem_has_common_volume( mixer_elements2)) //mono
- // {
- // // check for playback vol mixer
- // if (snd_mixer_selem_has_playback_volume( mixer_elements2)) {
- // //score!
- // // if( snd_mixer_find_selem( mixer_handle,mixer_elements2) == SND_MIXER_SCHN_MONO)
- // // {
- // snd_mixer_selem_get_playback_volume( mixer_elements2,
- // SND_MIXER_SCHN_MONO, &frontLeftVolume);
- // //for finding percentage
-
- // int range = pmax - pmin;
- // int val = frontLeftVolume;
- // frontRightVolume = frontLeftVolume;
- // val -= pmin;
- // percentage = (long)rint((double)val / (double)range * 100);
- // printf("common min %d, max %d, range %dn", pmin, pmax, range);
-
- // }
- // }
- // else //stereo
- // {
- // // printf("get seperate r and l volumesn");
- // if (snd_mixer_selem_has_playback_volume( mixer_elements2)) {
-
- // if( snd_mixer_selem_get_playback_volume( mixer_elements2,
- // SND_MIXER_SCHN_FRONT_LEFT, &frontLeftVolume) < 0)
- // frontLeftVolume = 0;
-
- // if( snd_mixer_selem_get_playback_volume( mixer_elements2,
- // SND_MIXER_SCHN_FRONT_RIGHT, &frontRightVolume) < 0)
- // frontRightVolume = 0;
-
- // // if( snd_mixer_selem_get_playback_volume( mixer_elements2,
- // // SND_MIXER_SCHN_FRONT_CENTER, &frontCenterVolume) < 0)
- // // frontCenterVolume = 0;
-
- // // if( snd_mixer_selem_get_playback_volume( mixer_elements2,
- // // SND_MIXER_SCHN_REAR_RIGHT, &rearRightVolume) < 0)
- // // rearRightVolume = 0;
-
- // // if( snd_mixer_selem_get_playback_volume( mixer_elements2,
- // // SND_MIXER_SCHN_REAR_LEFT, &rearLeftVolume) < 0)
- // // rearLeftVolume = 0;
-
- // // if( snd_mixer_selem_get_playback_volume( mixer_elements2,
- // // SND_MIXER_SCHN_WOOFER, &wooferVolume) < 0)
- // // wooferVolume = 0;
-
- // long range = pmax - pmin;
- // long val = frontLeftVolume;
- // frontRightVolume = frontLeftVolume;
- // val -= pmin;
- // percentage = (long)rint(val / range * 100);
-
- // // printf("min %d, max %d, range %dn", pmin, pmax, range);
- // printf("fleft %ld, fright %ld, center %ld, rleft %ld, rright %ld, woofer %ld, percent %dn",
- // frontLeftVolume, frontRightVolume, frontCenterVolume, rearLeftVolume,
- // rearRightVolume, percentage);
- // }
- // // snd_mixer_selem_get_playback_volume_range( mixer_elements2, &pmin, &pmax);
- // }
- // }
-
- // nLeftVolume = (nVolume & 0x000000ff);
- // nRightVolume = (nVolume & 0x0000ff00) >> 8;
- nRetVolume = (UINT16)frontLeftVolume;
- // printf("nRetVolume is %ldn",nRetVolume);
- return nRetVolume;
- }
- HX_RESULT CAudioOutLinuxAlsa::_SetVolume(UINT16 unVolume)
- {
- HX_RESULT retCode = RA_AOE_NOERR;
- ///////////////////////// FIXME:
- long pmin = 0, pmax = 0;
- long percentage = 0;
-
- long frontLeftVolume = 0;
- long frontRightVolume = 0;
-
- /* long frontCenterVolume = 0;
- long rearLeftVolume = 0;
- long rearRightVolume = 0;
-
- long wooferVolume = 0;
- snd_mixer_selem_id_t *sid;
- snd_mixer_selem_id_alloca(&sid);
- */
- snd_mixer_elem_t *mixer_elements;
- frontLeftVolume = frontRightVolume = unVolume;
- // nNewVolume = (unVolume & 0xff) | ((unVolume &0xff) << 8);
- mixer_elements = snd_mixer_first_elem( mixer_handle); //just grab first elem for now
- if (snd_mixer_selem_has_playback_volume( mixer_elements)) {
- // do this as the volume range in alsa might be more or less than 100
- // act like its a percentage, the vol range for rmedigi96 is 16383, and my pci128 is 16
- snd_mixer_selem_get_playback_volume_range( mixer_elements, &pmin, &pmax);
- int range = pmax - pmin;
- int val = frontLeftVolume;
- //percent to volume
- frontLeftVolume = rint((double)range * ((double)val*.01)) + pmin;
-
- frontRightVolume = frontLeftVolume;
-
- if( snd_mixer_selem_set_playback_volume( mixer_elements,
- SND_MIXER_SCHN_FRONT_LEFT,
- frontLeftVolume) < 0)
- frontLeftVolume = 0;
- if( snd_mixer_selem_set_playback_volume( mixer_elements,
- SND_MIXER_SCHN_FRONT_RIGHT,
- frontRightVolume) < 0)
- frontRightVolume = 0;
- }
- #ifdef _DEBUG
- printf("setting volume left %ld, right %ld %ld%n", frontLeftVolume, frontRightVolume, unVolume );
- #endif
- // Save for future use, demonstrates multichannel mixer access.
-
- // for ( mixer_elements = snd_mixer_first_elem( mixer_handle); //ramble through elems
- // mixer_elements;
- // mixer_elements = snd_mixer_elem_next( mixer_elements) )
- // {
-
- // snd_mixer_selem_get_id( mixer_elements, sid);
-
- // printf("mixer control '%s',%in",
- // snd_mixer_selem_id_get_name( sid),
- // snd_mixer_selem_id_get_index( sid));
- // if ( snd_mixer_selem_has_common_volume( mixer_elements)) //is mono
- // {
- // // // check for playback vol mixer
- // if (snd_mixer_selem_has_playback_volume( mixer_elements)) {
- // snd_mixer_selem_get_playback_volume_range( mixer_elements, &pmin, &pmax);
- // int range = pmax - pmin;
- // int val = frontLeftVolume;
- // val -= pmin;
- // frontLeftVolume = rint((double)range * ((double)val*.01)) + pmin; //percent to volume
- // //frontLeftVolume = rint((double)val/(double)range * 100);
- // // frontLeftVolume = (long) ( unVolume & 0x000000ff);
- // frontRightVolume = frontLeftVolume;
- // // frontRightVolume = (long) ( unVolume & 0x0000ff00);
- // //score!
- // if( snd_mixer_selem_set_playback_volume( mixer_elements,
- // SND_MIXER_SCHN_MONO,
- // frontLeftVolume) < 0)
- // frontLeftVolume = 0;
- // val -= pmin;
- // percentage = (long)rint((double)val/(double)range * 100);
- // }
- // }
- // else //is stereo
- // {
- // // if (snd_mixer_selem_has_playback_volume( mixer_elements)) {
- // snd_mixer_selem_get_playback_volume_range( mixer_elements, &pmin, &pmax);
- // printf("vol min %d, max %dn", pmin, pmax);
- // int range = pmax - pmin;
- // int tmp;
- // int val = frontLeftVolume;
- // frontLeftVolume = rint((double)range * ((double)val*.01)) + pmin; //percent to volume
- // //rint((double)val/(double)range * 100);
-
- // // frontLeftVolume = (long) ( unVolume & 0x000000ff);
- // frontRightVolume = frontLeftVolume;
- // // frontRightVolume = (long) ( unVolume & 0x0000ff00);
-
- // if( snd_mixer_selem_set_playback_volume( mixer_elements,
- // SND_MIXER_SCHN_FRONT_LEFT,
- // frontLeftVolume) < 0)
- // frontLeftVolume = 0;
- // if( snd_mixer_selem_set_playback_volume( mixer_elements,
- // SND_MIXER_SCHN_FRONT_RIGHT,
- // frontRightVolume) < 0)
- // frontRightVolume = 0;
-
- // // if( snd_mixer_selem_set_playback_volume( mixer_elements,
- // // SND_MIXER_SCHN_FRONT_CENTER, &frontCenterVolume) < 0)
- // // frontCenterVolume = 0;
-
- // // if( snd_mixer_selem_set_playback_volume( mixer_elements,
- // // SND_MIXER_SCHN_REAR_RIGHT, &rearRightVolume) < 0)
- // // rearRightVolume = 0;
-
- // // if( snd_mixer_selem_set_playback_volume( mixer_elements,
- // // SND_MIXER_SCHN_REAR_LEFT, &rearLeftVolume) < 0)
- // // rearLeftVolume = 0;
-
- // // if( snd_mixer_selem_set_playback_volume( mixer_elements,
- // // SND_MIXER_SCHN_WOOFER, &wooferVolume) < 0)
- // // wooferVolume = 0;
- // // }
- // int range2 = pmax - pmin;
- // int val2 = frontLeftVolume;
- // val2 -= pmin;
- // percentage = (long)rint((double)val2/(double)range2 * 100);
-
- // }
- // }
- // printf("fleft %d, fright %d, center %d, rleft %d, rright %d, woofer %d, percent %dn",
- // frontLeftVolume, frontRightVolume, frontCenterVolume, rearLeftVolume,
- // rearRightVolume, percentage);
- m_wLastError = retCode;
- 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 CAudioOutLinuxAlsa::_Drain()
- {
- HX_RESULT retCode = RA_AOE_NOERR;
- if ( pcm_handle < 0 )
- {
- retCode = RA_AOE_DEVNOTOPEN;
- }
- // Stop PCM device after pending frames have been played
- if( snd_pcm_drain( pcm_handle) < 0)
- retCode = RA_AOE_GENERAL;
-
- m_wLastError = retCode;
- 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 CAudioOutLinuxAlsa::_Reset()
- {
- HX_RESULT retCode = RA_AOE_NOERR;
- m_ulPausePosition = 0;
- if( pcm_handle > 0 )
- // if (snd_pcm_state( pcm_handle) == SND_PCM_STATE_OPEN)
- {
- if( snd_pcm_reset( pcm_handle) < 0)
- {
- retCode = RA_AOE_GENERAL;
- }
- }
- else
- {
- retCode = RA_AOE_DEVNOTOPEN;
- }
- m_wLastError = retCode;
- return m_wLastError;
- }
- HX_RESULT CAudioOutLinuxAlsa::_CheckFormat( const HXAudioFormat* pFormat )
- {
- int nBitsPerSample = pFormat->uBitsPerSample;
- int ulTmp = pFormat->ulSamplesPerSec;
- int nNumChannels = pFormat->uChannels;
- float fTmp = 0.0;
- int err=0;
- snd_pcm_format_t m_format;
- HX_RESULT retCode = RA_AOE_NOERR;
- if( nBitsPerSample = 16)
- {
- m_format = SND_PCM_FORMAT_S16;
- }
- else
- {
- m_format = SND_PCM_FORMAT_U8;
- }
- //Is the device already open?
- if( pcm_handle > 0 || RA_AOE_NOERR != _OpenAudio() )
- {
- retCode = RA_AOE_DEVBUSY;
- return retCode;
- }
- //See if the sample rate is supported.
- if( snd_pcm_hw_params_test_rate ( pcm_handle, hwparams, ulTmp ,0) < 0)
- {
- #ifdef _DEBUG
- fprintf (stderr, "cannot set sample rate (%s)n",
- snd_strerror (err));
- #endif
- //Not quite the real error, but it is what we need to return.
- retCode = RA_AOE_BADFORMAT;
- goto donechecking;
- }
- //Check num channels.
- if(snd_pcm_hw_params_test_channels ( pcm_handle, hwparams, nNumChannels) < 0)
- {
- retCode = RA_AOE_BADFORMAT;
- goto donechecking;
- }
- if ( snd_pcm_hw_params_test_format( pcm_handle, hwparams, m_format /*SND_PCM_FORMAT_S16*/ ) < 0)
- {
- retCode = RA_AOE_BADFORMAT;
- goto donechecking;
- }
- //Close the audio device.
- donechecking:
- _CloseAudio();
- m_wLastError = retCode;
- return retCode;
- }
- HX_RESULT CAudioOutLinuxAlsa::_CheckSampleRate( ULONG32 ulSampleRate )
- {
- ULONG32 ulTmp = ulSampleRate;
- m_wLastError = RA_AOE_NOERR;
- //Is the device already open?
- if( pcm_handle > 0 || RA_AOE_NOERR != _OpenAudio() )
- {
- m_wLastError = RA_AOE_DEVBUSY;
- }
- else
- {
- //See if the sample rate is supported.
- if( snd_pcm_hw_params_test_rate ( pcm_handle, hwparams, (uint)ulTmp, 0) != 1)
- {
- //Not quite the real error, but it is what we need to return.
- m_wLastError = RA_AOE_DEVBUSY;
- }
- else if( ulSampleRate != ulTmp )
- {
- //It is NOT supported
- m_wLastError = RA_AOE_BADFORMAT;
- }
- _CloseAudio();
- }
- return m_wLastError;
- }
- HX_RESULT CAudioOutLinuxAlsa::_Pause()
- {
- m_wLastError = HXR_OK;
- m_ulPausePosition = m_ulTotalWritten;
- m_ulTickCount = 0;
- m_ulLastTimeStamp = 0;
- int err=0;
- if( m_bHasHardwarePause)
- {
- if((err = snd_pcm_pause( pcm_handle, 1)) < 0)
- {
- #ifdef _DEBUG
- fprintf(stderr, "Error : cannot pause (%s)n", snd_strerror (err));
- #endif
- m_wLastError = RA_AOE_NOTSUPPORTED;
- }
- }
- else
- {
- m_wLastError = RA_AOE_NOTSUPPORTED;
- }
- return m_wLastError;
- }
- HX_RESULT CAudioOutLinuxAlsa::_Resume()
- {
- m_wLastError = HXR_OK;
- if( m_ulTotalWritten > 0 )
- {
- m_ulTickCount = GetTickCount();
- m_ulLastTimeStamp = m_ulTickCount;
- }
- if( m_bHasHardwarePause && m_bHasHardwareResume)
- {
- int err=0;
- if((err = snd_pcm_resume( pcm_handle)) < 0)
- {
- #ifdef _DEBUG
- fprintf (stderr, "Error: cannot resume (%s)n",
- snd_strerror (err));
- #endif
- m_wLastError = RA_AOE_NOTSUPPORTED;
- }
- }
- else
- {
- m_wLastError = RA_AOE_NOTSUPPORTED;
- }
-
- return m_wLastError;
- }
- BOOL CAudioOutLinuxAlsa::_HardwarePauseSupported() const
- {
-
- if( snd_pcm_hw_params_can_resume( hwparams) == 1)
- {
- m_bHasHardwareResume = true;
- }
- else
- {
- m_bHasHardwareResume = false;
- }
- if( snd_pcm_hw_params_can_pause( hwparams) == 1)
- {
- m_bHasHardwarePause = true;
- return TRUE;
- }
- else
- {
- m_bHasHardwarePause = false;
- }
- return FALSE;
- }