zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

OpenAL播放pcm或wav数据流-windows/ios/android(一)

AndroidiosWindows 播放 数据流 PCM wav
2023-09-27 14:29:30 时间
* Function    * OpenAL through the buffer queuing mechanism to support the streaming playback of sound. The buffer queue is a buffer associated with a single source contact mechanism.  * when audio playback, continuous rendering of each buffer, as if the buffer is composed of a continuous sound. This can be controlled by some special functions.  * flow is generally the source of the work. In a number of audio buffer by alSourceQueueBuffers () function to queue, and then play the sound source,  * next with property AL_BUFFERS_PROCESSED to query. This property obtains the number of buffers that have been processed,  * allows applications to use the alSourceUnqueueBuffers () function to delete the buffers that have been processed.  * alSourceUnqueueBuffers () function will start from the queue header will be processed in order to remove the buffer. Finally, the rest of the buffer queue in gear.  * Opanal for audio rendering related implementation and definition, etc.  * OpenAL通过缓冲器排队机制支持声音的流式播放。缓冲器排队是多个缓冲器与单一音源相关联的一种机制。  * 当音源播放时,连续对各个缓冲器进行渲染,就好象这些缓冲器组成了一个连续的声音。这可以通过一些特殊函数来控制。  * 流音源的工作一般是这样的。音源里的一批缓冲器通过alSourceQueueBuffers()函数进行排队,然后播放音源,  * 接下来用属性AL_BUFFERS_PROCESSED来查询。该属性得出已经处理好的缓冲器的数量,  * 从而允许应用程序使用alSourceUnqueueBuffers()函数删除那些已经处理好的缓冲器。  * alSourceUnqueueBuffers()函数将从队列头部开始依次将处理好的缓冲器删除。最后,其余的缓冲器在音源上排队。  * OpanAl 用于音频渲染相关实现及定义,等  #ifndef __LVS_OPENAL_INTERFACE_H__   #define __LVS_OPENAL_INTERFACE_H__   #include  stdio.h    #include  stdlib.h    #include  string    //windows   #ifdef WIN32   #include  Windows.h    //openAl库   #include "alut.h"   #pragma comment(lib,"alut.lib")   #pragma comment(lib,"OpenAL32.lib")   //ios   #elif __APPLE__   #include "alut.h"   //ANDROID平台     #elif __ANDROID__     #include "alut.h"   //linux   #else   #include "alut.h"   #endif   //到处宏定义   //windows   #ifdef WIN32   #define LVS_DLLEXPORT __declspec(dllexport)   //ios   #elif __APPLE__   #define LVS_DLLEXPORT   //linux   #else   #define LVS_DLLEXPORT   #endif   using namespace std;   //接口初始化   int lvs_openal_interface_init();   //接口释放   void lvs_openal_interface_uninit();   //接口开始播放   void lvs_openal_interface_playsound();   //接口停止播放   void lvs_openal_interface_stopsound();   //接口设置音量   void lvs_openal_interface_setvolume(float volume);//volume取值范围(0~1)   //接口获取音量   float lvs_openal_interface_getvolume();   //接口传入pcm数据用于播放   int lvs_openal_interface_openaudiofromqueue(char* data,int dataSize,int aSampleRate,int aBit ,int aChannel);   //更新队列数据,删除已经播放的buffer,这个在队列满的时候用   int lvs_openal_interface_updataQueueBuffer();   //获取当前时间戳   long long lvs_openal_interface_getrealpts();   //获取已经播放了多少个数据块   long long lvs_openal_interface_getIsplayBufferSize();   //获取缓存队列长度   int lvs_openal_getnumqueuedsize();   class cclass_openal_interface;   class cclass_openal_interface   public:       cclass_openal_interface();       virtual ~cclass_openal_interface();       //开始播放       void playSound();       //停止播放       void stopSound();       //设置音量       void SetVolume(float volume);//volume取值范围(0~1)       //获取音量       float GetVolume();       //传入pcm数据用于播放       int openAudioFromQueue(char* data,int dataSize,int aSampleRate,int aBit ,int aChannel);       //更新队列数据,删除已经播放的buffer       int updataQueueBuffer();   private:       //初始化openal       int initOpenAL();       //释放openal       void cleanUpOpenAL();   public:       int m_numprocessed;             //队列中已经播放过的数量       int m_numqueued;                //队列中缓冲队列数量       long long m_IsplayBufferSize;   //已经播放了多少个音频缓存数目       double m_oneframeduration;      //一帧音频数据持续时间(ms)       float m_volume;                 //当前音量volume取值范围(0~1)       int m_samplerate;               //采样率       int m_bit;                      //样本值       int m_channel;                  //声道数       int m_datasize;                 //一帧音频数据量   private:       ALCdevice * m_Devicde;          //device句柄       ALCcontext * m_Context;         //device context       ALuint m_outSourceId;           //source id 负责播放   #endif  
int lvs_openal_interface_openaudiofromqueue(char* data,int dataSize,int aSampleRate,int aBit ,int aChannel)       return copenal_interface- openAudioFromQueue(data,dataSize,aSampleRate,aBit,aChannel);   long long lvs_openal_interface_getrealpts()       long long time = (long long )((copenal_interface- m_IsplayBufferSize * copenal_interface- m_oneframeduration) + 0.5);       printf("*****m_IsplayBufferSize : %ld",copenal_interface- m_IsplayBufferSize);       printf("****************time : %lld(ms)\n",time);       return time;   long long lvs_openal_interface_getIsplayBufferSize()       return copenal_interface- m_IsplayBufferSize;   int lvs_openal_getnumqueuedsize()       return copenal_interface- m_numqueued;   int lvs_openal_interface_updataQueueBuffer()       return copenal_interface- updataQueueBuffer();   cclass_openal_interface::cclass_openal_interface()       m_Devicde = NULL;         m_Context = NULL;             m_outSourceId = 0;             m_numprocessed = 0;                 m_numqueued = 0;       m_IsplayBufferSize = 0;       m_oneframeduration = 0.0;       m_volume = 1.0;       m_samplerate = 0;       m_bit = 0;       m_channel = 0;       m_datasize = 0;       //init       initOpenAL();   cclass_openal_interface::~cclass_openal_interface()       cleanUpOpenAL();       m_Devicde = NULL;         m_Context = NULL;             m_outSourceId = 0;             m_numprocessed = 0;                 m_numqueued = 0;       m_IsplayBufferSize = 0;       m_oneframeduration = 0.0;       m_volume = 1.0;       m_samplerate = 0;       m_bit = 0;       m_channel = 0;       m_datasize = 0;   int cclass_openal_interface::initOpenAL()       int ret = 0;       printf("=======initOpenAl===\n");   #ifdef WIN32       //初始化 ALUT openal函数库       int zwg_argc=1;       //添加函数库名称       char* zwg_argv[]={"ZWG_ALUT"};         ret= alutInit( zwg_argc, zwg_argv);    #else   #endif       //打开device       m_Devicde = alcOpenDevice(NULL);       if (m_Devicde)       {   #ifdef WIN32           //windows 用这个context 声音不正常,以后处理   #else           //建立声音文本描述           m_Context = alcCreateContext(m_Devicde, NULL);           //设置行为文本描述           alcMakeContextCurrent(m_Context);   #endif       }       //创建一个source并设置一些属性       alGenSources(1,  m_outSourceId);       alSpeedOfSound(1.0);       alDopplerVelocity(1.0);       alDopplerFactor(1.0);       alSourcef(m_outSourceId, AL_PITCH, 1.0f);       alSourcef(m_outSourceId, AL_GAIN, 1.0f);       alSourcei(m_outSourceId, AL_LOOPING, AL_FALSE);       alSourcef(m_outSourceId, AL_SOURCE_TYPE, AL_STREAMING);       return ret;   void cclass_openal_interface::cleanUpOpenAL()       printf("=======cleanUpOpenAL===\n");       alDeleteSources(1,  m_outSourceId);   #ifdef WIN32       alcCloseDevice(m_Devicde);       m_Devicde = NULL;       alutExit();   #else       ALCcontext * Context = alcGetCurrentContext();       ALCdevice * Devicde = alcGetContextsDevice(Context);       if (Context)       {           alcMakeContextCurrent(NULL);           alcDestroyContext(Context);           m_Context = NULL;       }       alcCloseDevice(m_Devicde);       m_Devicde = NULL;   #endif   void cclass_openal_interface::playSound()       int ret = 0;       alSourcePlay(m_outSourceId);       if((ret = alGetError()) != AL_NO_ERROR)       {           printf("error alcMakeContextCurrent %x : %s\n", ret,alutGetErrorString (ret));       }   void cclass_openal_interface::stopSound()       alSourceStop(m_outSourceId);   void cclass_openal_interface::SetVolume(float volume)//volume取值范围(0~1)       m_volume = volume;       alSourcef(m_outSourceId,AL_GAIN,volume);   float cclass_openal_interface::GetVolume()       return m_volume;   int cclass_openal_interface::updataQueueBuffer()       //播放状态字段       ALint stateVaue = 0;       //获取处理队列,得出已经播放过的缓冲器的数量       alGetSourcei(m_outSourceId, AL_BUFFERS_PROCESSED,  m_numprocessed);       //获取缓存队列,缓存的队列数量       alGetSourcei(m_outSourceId, AL_BUFFERS_QUEUED,  m_numqueued);       //获取播放状态,是不是正在播放       alGetSourcei(m_outSourceId, AL_SOURCE_STATE,  stateVaue);       //printf("===statevaue ========================%x\n",stateVaue);       if (stateVaue == AL_STOPPED ||           stateVaue == AL_PAUSED ||            stateVaue == AL_INITIAL)        {           //如果没有数据,或数据播放完了           if (m_numqueued   m_numprocessed || m_numqueued == 0 ||(m_numqueued == 1   m_numprocessed ==1))           {               //停止播放               printf("...Audio Stop\n");               stopSound();               cleanUpOpenAL();               return 0;           }           if (stateVaue != AL_PLAYING)           {               playSound();           }       }       //将已经播放过的的数据删除掉       while(m_numprocessed --)       {           ALuint buff;           //更新缓存buffer中的数据到source中           alSourceUnqueueBuffers(m_outSourceId, 1,  buff);           //删除缓存buff中的数据           alDeleteBuffers(1,  buff);           //得到已经播放的音频队列多少块           m_IsplayBufferSize ++;       }       long long time = (long long )((m_IsplayBufferSize * m_oneframeduration) + 0.5);       //printf("*****m_IsplayBufferSize : %ld",m_IsplayBufferSize);       //printf("****************time : %ld(ms)\n",time);       return 1;   int cclass_openal_interface::openAudioFromQueue(char* data,int dataSize,int aSampleRate,int aBit ,int aChannel)       int ret = 0;       //样本数openal的表示方法       ALenum format = 0;       //buffer id 负责缓存,要用局部变量每次数据都是新的地址       ALuint bufferID = 0;       if (m_datasize == 0             m_samplerate == 0             m_bit == 0             m_channel == 0)       {           if (dataSize != 0                 aSampleRate != 0                 aBit != 0                 aChannel != 0)           {               m_datasize = dataSize;               m_samplerate = aSampleRate;               m_bit = aBit;               m_channel = aChannel;               m_oneframeduration = m_datasize * 1.0 /(m_bit/8) /m_channel /m_samplerate * 1000 ;   //计算一帧数据持续时间           }       }       //创建一个buffer       alGenBuffers(1,  bufferID);       if((ret = alGetError()) != AL_NO_ERROR)       {           printf("error alGenBuffers %x : %s\n", ret,alutGetErrorString (ret));           //AL_ILLEGAL_ENUM            //AL_INVALID_VALUE           //#define AL_ILLEGAL_COMMAND                        0xA004           //#define AL_INVALID_OPERATION                      0xA004       }       if (aBit == 8)        {           if (aChannel == 1)            {               format = AL_FORMAT_MONO8;           }           else if(aChannel == 2)           {               format = AL_FORMAT_STEREO8;           }       }       if( aBit == 16 )       {           if( aChannel == 1 )            {                format = AL_FORMAT_MONO16;           }           if( aChannel == 2 )            {               format = AL_FORMAT_STEREO16;           }       }       //指定要将数据复制到缓冲区中的数据       alBufferData(bufferID, format, data, dataSize,aSampleRate);       if((ret = alGetError()) != AL_NO_ERROR)       {           printf("error alBufferData %x : %s\n", ret,alutGetErrorString (ret));           //AL_ILLEGAL_ENUM            //AL_INVALID_VALUE           //#define AL_ILLEGAL_COMMAND                        0xA004           //#define AL_INVALID_OPERATION                      0xA004       }       //附加一个或一组buffer到一个source上       alSourceQueueBuffers(m_outSourceId, 1,  bufferID);       if((ret = alGetError()) != AL_NO_ERROR)       {           printf("error alSourceQueueBuffers %x : %s\n", ret,alutGetErrorString (ret));       }       //更新队列数据       ret = updataQueueBuffer();       //删除一个缓冲 这里不应该删除缓冲,在source里面播放完毕删除       //alDeleteBuffers(1,  bufferID);       bufferID = 0;       return 1;  
//要显示的pcm/wav文件路径及名称   #define PCM_STREAM_PATH_NAME  "../pcm_stream/44100_2_16.pcm"   int main()       int ret = 0;       int nSampleRate = 44100;                   //采样率       int nBit = 16;                             //样本数       int nChannel = 2;                          //声道       int ndatasize = 1024 * (nBit/8) *nChannel; //每次读取的数据大小        char ndata[4096 + 1] = {0};                //读取的数据                FILE * pFile_pcm = NULL;                   //读取pcm数据的文件句柄         //打开pcm文件       if((pFile_pcm = fopen(PCM_STREAM_PATH_NAME, "rb")) == NULL)       {           printf("filed open file : %s\n",PCM_STREAM_PATH_NAME);           return getchar();       }       else       {           printf("success open file : %s\n",PCM_STREAM_PATH_NAME);       }       //init       lvs_openal_interface_init();       //设置音量volume取值范围(0~1)       lvs_openal_interface_setvolume(1.0);       for(;;)       {           Sleep(23);           //循环读取文件           ret = fread(ndata, 1,ndatasize, pFile_pcm);           if (ret != ndatasize)           {               //seek到文件开头               fseek(pFile_pcm, 0, SEEK_SET);               fread(ndata, 1,ndatasize, pFile_pcm);           }           //具体的处理在这里           ret = lvs_openal_interface_openaudiofromqueue((char *)ndata,ndatasize,nSampleRate,nBit,nChannel);           long long time = lvs_openal_interface_getrealpts();       }       //uinit       lvs_openal_interface_uninit();       //关闭pcm文件       if (pFile_pcm != NULL)       {           fclose(pFile_pcm);           pFile_pcm = NULL;       }       return 1;  
程序运行效果并能听到声音:

 

本demo还需完善。

 

from:http://blog.csdn.net/zhuweigangzwg/article/details/53286945


Application Loader及Transporter App上传ipa外、可以在Windows上架iOS APP工具 随着xcode的更新,苹果公司已经不直接提供Application Loader这个工具上传IPA了,导致上传ipa比较难搞了。 这里分享介绍一个可以在Windows、跨平台申请iOS证书上传ipa的工具Appuploader,方面跨平台开发没有苹果电脑,或者还不熟悉iOS上架流程的开发者使用。 双重验证码登录,安全放心,已帮助上万开发者提交苹果APP!
windows电脑在线创建ios证书的教程 目前苹果官网提供的,生成ios打包证书的方法,只能使用mac电脑,通过钥匙串访问的功能,生成证书,这种方法的缺点是你必须要有苹果mac电脑才能生成证书,而一个mac电脑,少则8000多元,成本比较高。 所以我们这篇文章,在这里教会大家如何在没有mac电脑的情况下,创建ios证书
Uni开发的app,使用Windows S10,放在ios上,全程跟着一个马平川。 其实在我写这篇文章的时候,很多版本的app都已经更新了,但是突然有一天我觉得如果我不把它们记录下来,它们就会被遗忘,现在越来越多的人在用uniapp开发app。