audlinux_alsa.cpp
来自「symbian 下的helix player源代码」· C++ 代码 · 共 1,247 行 · 第 1/3 页
CPP
1,247 行
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: audlinux_alsa.cpp,v 1.1.2.1 2004/07/09 02:01:42 hubbe Exp $
*
* Portions Copyright (c) 1995-2004 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 (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (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.
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL") in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your version of
* this file only under the terms of the GPL, and not to allow others
* to use your version of this file under the terms of either the RPSL
* or RCSL, indicate your decision by deleting the provisions above
* and replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient may
* use your version of this file under the terms of any one of the
* RPSL, the RCSL or the GPL.
*
* 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):
*
* ***** 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\'tor\n");
#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: %d\n",
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 %s\n",
snd_strerror (err));
#endif
}
if ((err = snd_pcm_hw_params_any( pcm_handle, hwparams)) < 0) {
#ifdef _DEBUG
fprintf (stderr, "HW parameters init failed %s\n",
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 %d\n", 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 failed\n");
#endif
}
if(snd_mixer_close ( mixer_handle) < 0)
{
#ifdef _DEBUG
printf("Close mixer failed\n");
#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 failed\n");
#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 failed\n");
#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 %d\n",
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 );
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?