Alsa 读取wave文件,并播放wave 文件
对于一个wave文件,如果需要播放,涉及到几个方面
1.对于wave文件的解析
2.通过解析wave文件,将得到的参数(主要是sampfrequency, bitsperSample,channel)通过alsa api设下去
3.正确找到data的起始点
4.play alsa
1.对于wave文件的解析,需要知道wave文件的格式
注意几点,标准的是44byte的头,但是有些情况下会有additional info, 占据2字节。头信息参见下图,也可以参考wave 文件解析
endian |
field name |
Size |
|
big | ChunkID | 4 | 文件头标识,一般就是" RIFF" 四个字母 |
little | ChunkSize | 4 | 整个数据文件的大小,不包括上面ID和Size本身 |
big | Format | 4 | 一般就是" WAVE" 四个字母 |
big | SubChunk1ID | 4 | 格式说明块,本字段一般就是"fmt " |
little | SubChunk1Size | 4 | 本数据块的大小,不包括ID和Size字段本身 |
little | AudioFormat | 2 | 音频的格式说明 |
little | NumChannels | 2 | 声道数 |
little | SampleRate | 4 | 采样率 |
little | ByteRate | 4 | 比特率,每秒所需要的字节数 |
little | BlockAlign | 2 | 数据块对齐单元 |
little | BitsPerSample | 2 | 采样时模数转换的分辨率 |
big | SubChunk2ID | 4 | 真正的声音数据块,本字段一般是"data" |
little | SubChunk2Size | 4 | 本数据块的大小,不包括ID和Size字段本身 |
little | Data | N | 音频的采样数据 |
2.设置alsa的参数可以详见代码
3.通过解析wave file可以知道我们data的起始位置
4.通过alsa来play,详见代码
/** @file TestAlsaPlayWave.cpp @brief This is a short example to play the audio wave, please define the path in the main func @par author: jlm @par pre env: alsa @todo */ #include <stdio.h> #include <stdlib.h> #include <string> #include <sched.h> #include <errno.h> #include <getopt.h> #include <iostream> #include <asoundlib.h> #include <sys/time.h> #include <math.h> using namespace std; /*********Type definition***********************/ typedef unsigned char uint8; typedef unsigned short uint16; typedef enum EBitsPerSample { BITS_UNKNOWN = , BITS_PER_SAMPLE_8 = , BITS_PER_SAMPLE_16 = , BITS_PER_SAMPLE_32 = }EBitsPerSample_t; typedef enum ENumOfChannels { NUM_OF_CHANNELS_1 = , NUM_OF_CHANNELS_2 = }ENumOfChannels_t; #if 0 /** PCM state */ typedef enum _snd_pcm_state { /** Open */ SND_PCM_STATE_OPEN = , /** Setup installed */ SND_PCM_STATE_SETUP, /** Ready to start */ SND_PCM_STATE_PREPARED, /** Running */ SND_PCM_STATE_RUNNING, /** Stopped: underrun (playback) or overrun (capture) detected */ SND_PCM_STATE_XRUN, /** Draining: running (playback) or stopped (capture) */ SND_PCM_STATE_DRAINING, /** Paused */ SND_PCM_STATE_PAUSED, /** Hardware is suspended */ SND_PCM_STATE_SUSPENDED, /** Hardware is disconnected */ SND_PCM_STATE_DISCONNECTED, SND_PCM_STATE_LAST = SND_PCM_STATE_DISCONNECTED } snd_pcm_state_t; #endif typedef struct ALSA_CONFIGURATION { std::string alsaDevice; std::string friendlyName; /// Read: Buffer size should be large enough to prevent overrun (read / write buffer full) unsigned int alsaBufferSize; /// Chunk size should be smaller to prevent underrun (write buffer empty) unsigned int alsaPeriodFrame; unsigned int samplingFrequency;//48kHz EBitsPerSample bitsPerSample; ENumOfChannels numOfChannels; bool block; // false means nonblock snd_pcm_access_t accessType; snd_pcm_stream_t streamType; // Playback or capture unsigned int alsaCapturePeriod; // Length of each capture period }Alsa_Conf; typedef struct Wave_Header { uint8 ChunkID[]; uint8 ChunkSize[]; uint8 Format[]; uint8 SubChunk1ID[]; uint8 SubChunk1Size[]; uint8 AudioFormat[]; uint8 NumChannels[]; uint8 SampleRate[]; uint8 ByteRate[]; uint8 BlockAlign[]; uint8 BitsPerSample[]; uint8 CombineWaveFileExtra2Bytes[]; uint8 SubChunk2ID[]; uint8 SubChunk2Size[]; }Wave_Header_t; typedef struct Wave_Header_Size_Info { uint8 ChunkID[]; uint8 ChunkSize[]; uint8 Format[]; uint8 SubChunk1ID[]; uint8 SubChunk1Size[]; }Wave_Header_Size_Info_t; typedef struct Wave_Header_Audio_Info { uint8 AudioFormat[]; uint8 NumChannels[]; uint8 SampleRate[]; uint8 ByteRate[]; uint8 BlockAlign[]; uint8 BitsPerSample[]; }Wave_Header_Audio_Info_t; typedef struct Wave_Header_Additional_Info { uint8 AdditionalInfo_2Bytes[]; //this depends on the SubChunk1Size,normal if SubChunk1Size=16 then match the normal wave format, if SubChunk1Size=18 then 2 more additional info bytes }Wave_Header_Additional_Info_t; typedef struct Wave_Header_Data_Info { uint8 SubChunk2ID[]; uint8 SubChunk2Size[]; }Wave_Header_Data_Info_t; /*********Global Variable***********************/ snd_pcm_uframes_t g_frames; //just test purpose /*********Func Declaration***********************/ void TestAlsaDevice(snd_pcm_t** phandler); bool PrepareAlsaDevice(Alsa_Conf* palsaCfg,snd_pcm_t** phandler); bool closeAlsaDevice(snd_pcm_t** phandler); bool ParseWaveFile(const string wavepath,Alsa_Conf* palsaCfg); uint16 HandleLittleEndian(uint8* arr,int size); bool PlayWave(FILE** fp,snd_pcm_t** phandler,Alsa_Conf* palsaCfg); uint16 HandleLittleEndian(uint8* arr,int size) { uint16 value=; ;i<size;i++) { value=value+(arr[i]<<(*i)); } return value; } #if 0 //this is the return value ChunkID = "RIFF" ChunkSize = Format = "WAVE" fmt = "fmt " SubChunk1Size = AudioFormat = NumChannels = SampleRate = ByteRate = BlockAlign = BitsPerSample = SubChunk2ID = "data" SubChunk2Size = #endif //parse the wave file bool ParseWaveFile(const string wavepath,Alsa_Conf* palsaCfg,FILE** fp) { ; //FILE* fp=NULL; *fp=fopen(wavepath.c_str(),"rb"); if(*fp==NULL) { cout<<"Can parse the wave file-->need check the file name"<<endl; } /*********************size info parse begin*************************/ //read size info Wave_Header_Size_Info_t wav_size_info; memset(&wav_size_info,,sizeof(Wave_Header_Size_Info_t)); ret=fread(&wav_size_info,,*fp); ) { cout<<"read error"<<endl; return false; } string ChunkID=""; ;i<;i++) { ChunkID+=wav_size_info.ChunkID[i]; } string riff="RIFF"; !=strcmp(ChunkID.c_str(),riff.c_str())) { cout<<"Invalid the fist Chunk id"<<endl; return false; } uint16 ChunkSize=HandleLittleEndian(wav_size_info.ChunkSize,); cout<<"The ChunSize is "<<ChunkSize<<endl; string Format=""; ;i<;i++) { Format+=wav_size_info.Format[i]; } !=strcmp(Format.c_str(),"WAVE")) { cout<<"Invalid the format"<<endl; return false; } string SubChunk1ID=""; ;i<;i++) { SubChunk1ID+=wav_size_info.SubChunk1ID[i]; } string fmt="fmt "; !=strcmp(SubChunk1ID.c_str(),fmt.c_str())) { cout<<"Invalid the SubChunk1ID "<<endl; return false; } uint16 SubChunk1Size=HandleLittleEndian(wav_size_info.SubChunk1Size,); && SubChunk1Size!=) { cout<<"Invalid the SubChunk1Size"<<endl; return false; } /*********************Audio info parse begin*************************/ Wave_Header_Audio_Info_t wav_audio_info; memset(&wav_audio_info,,sizeof(Wave_Header_Audio_Info_t)); ret=fread(&wav_audio_info,,*fp); ) { cout<<"read error"<<endl; return false; } //fseek(fp,sizeof(Wave_Header_Size_Info_t),0);//文件指针偏移3个字节到'2' because fread will shift the pointer uint16 AudioFormat =HandleLittleEndian(wav_audio_info.AudioFormat,); uint16 NumChannels =HandleLittleEndian(wav_audio_info.NumChannels,); uint16 SampleRate =HandleLittleEndian(wav_audio_info.SampleRate,); uint16 ByteRate =HandleLittleEndian(wav_audio_info.ByteRate,); uint16 BlockAlign =HandleLittleEndian(wav_audio_info.BlockAlign,); uint16 BitsPerSample=HandleLittleEndian(wav_audio_info.BitsPerSample,); palsaCfg->numOfChannels=(ENumOfChannels)NumChannels; palsaCfg->samplingFrequency=SampleRate; palsaCfg->bitsPerSample=(EBitsPerSample)BitsPerSample; /*********************Additional info parse begin if needed*************************/ ) { Wave_Header_Additional_Info_t wav_additional_info; memset(&wav_additional_info,,sizeof(Wave_Header_Additional_Info_t)); fread(&wav_additional_info,,*fp); cout<<"read wav_additional_info"<<endl; ) { cout<<"read error"<<endl; return false; } uint16 AdditionalInfo=HandleLittleEndian(wav_additional_info.AdditionalInfo_2Bytes,); cout<<"read AdditionalInfo value="<<AdditionalInfo<<endl; } /*********************Data info parse begin *************************/ Wave_Header_Data_Info_t wave_data_info; memset(&wave_data_info,,sizeof(Wave_Header_Data_Info_t)); fread(&wave_data_info,,*fp); ) { cout<<"read error"<<endl; return false; } string SubChunk2ID=""; ;i<;i++) { SubChunk2ID+=wave_data_info.SubChunk2ID[i]; } string fact="fact"; string data="data"; ==strcmp(SubChunk2ID.c_str(),fact.c_str())) { cout<<"SubChunk2ID fact"<<endl; } ==strcmp(SubChunk2ID.c_str(),data.c_str())) { cout<<"SubChunk2ID data"<<endl; } else { cout<<"Invalid SubChunk2ID "<<endl; return false; } uint16 SubChunk2Size=HandleLittleEndian(wave_data_info.SubChunk2Size,); cout<<"End Parse"<<endl; return true; } bool PlayWave(FILE** fp,snd_pcm_t** phandler,Alsa_Conf* palsaCfg) { ; bool ret=false; snd_pcm_uframes_t frames=palsaCfg->alsaPeriodFrame; ; //4bytes uint16 audio_data_size=frames*bytesPerFrame;//one period 10ms ,1600*10/1000*(2*16/8)=640bytes one period uint8* buffer=new uint8[audio_data_size]; cout<<"Start play wave"<<endl; if(*fp==NULL || *phandler==NULL || palsaCfg==NULL) { cout<<"End play wave because something is NULL"<<endl; return false; } //fseek(*fp,46,SEEK_SET); //no need to do fseek because already shifted cout<<"available frame "<<snd_pcm_avail(*phandler)<<"my frames is "<<frames<<endl; while(true) { if(feof(*fp)) { cout<<"Reach end of the file"<<endl; break; } else { if(snd_pcm_avail(*phandler)<frames) { continue; } else { memset(reinterpret_cast<,sizeof(uint8)*audio_data_size); err=fread(buffer,,*fp); ) { cout<<"read error"<<endl; } if ( NULL != buffer ) { err = snd_pcm_writei(*phandler, buffer, frames); ) { cout<<"Fail to write the audio data to ALSA. Reason: "<<(snd_strerror(err)); // recover ALSA device err = snd_pcm_recover(*phandler, err, ); ) { cout<<"Fail to recover ALSA device. Reason: "<<(snd_strerror(err)); ret = false; } else { cout<<"ALSA device is recovered from error state"<<endl; } } } else { cout<<"Write buffer is NULL!"<<endl; } } } usleep(palsaCfg->alsaCapturePeriod / ( * )); } delete[] buffer; buffer=NULL; return ret; } bool PrepareAlsaDevice(Alsa_Conf* palsaCfg,snd_pcm_t** phandler) { bool ret=false; bool success=true; ; snd_pcm_format_t format; snd_pcm_hw_params_t *hw_params = NULL; ; if(palsaCfg!=NULL) { // open ALSA device error=snd_pcm_open(phandler,palsaCfg->alsaDevice.c_str(),palsaCfg->streamType,palsaCfg->block? :SND_PCM_NONBLOCK); ) //0 on success otherwise a negative error code { success=false; cout<<"Open Alsadevice error error code="<<snd_strerror(error)<<endl; } if(success) { //allocate hardware parameter structur error=snd_pcm_hw_params_malloc(&hw_params);//alsao can use snd_pcm_hw_params_alloca(&hwparams) ) { success=false; hw_params=NULL; cout<<"Set hw params error error code="<<snd_strerror(error)<<endl; } } if(success) { //Fill params with a full configuration space for a PCM. initialize the hardware parameter error=snd_pcm_hw_params_any(*phandler,hw_params); ) { success=false; cout<<"Broken configuration for PCM: no configurations available: "<<snd_strerror(error)<<endl; } } if(success) { // set the access type error = snd_pcm_hw_params_set_access(*phandler, hw_params, palsaCfg->accessType); ) { cout<<"[SG]Fail to set access type. Reason: "<<snd_strerror(error)<<endl; success = false; } } if(success) { switch (palsaCfg->bitsPerSample) { case BITS_PER_SAMPLE_8: { format = SND_PCM_FORMAT_U8; break; } case BITS_PER_SAMPLE_16: { format = SND_PCM_FORMAT_S16_LE; //indicate this was little endian break; } case BITS_PER_SAMPLE_32: { format = SND_PCM_FORMAT_S32_LE; break; } default: { format = SND_PCM_FORMAT_S16_LE; cout<<"Invalid format"<<endl; success=false; } } if(success) { error=snd_pcm_hw_params_set_format(*phandler,hw_params,format); ) { cout<<"set format not available for "<<snd_strerror(error)<<endl; success=false; } } } if(success) { error=snd_pcm_hw_params_set_rate_near(*phandler,hw_params,&palsaCfg->samplingFrequency,); ) { cout<<"set rate not available for "<<snd_strerror(error)<<endl; success=false; } } if(success) { error=snd_pcm_hw_params_set_channels(*phandler,hw_params,palsaCfg->numOfChannels); ) { cout<<"set_channels not available for "<<snd_strerror(error)<<endl; success=false; } } if (success) { // set period size (period size is also a chunk size for reading from ALSA) snd_pcm_uframes_t alsaPeriodFrame = static_cast<snd_pcm_uframes_t>(palsaCfg->alsaPeriodFrame); // One frame could be 4 bytes at most // set period size error = snd_pcm_hw_params_set_period_size_near(*phandler, hw_params, &alsaPeriodFrame, &dir); ) { cout<<"[SG]Fail to set period size. Reason: "<<snd_strerror(error)<<endl; success = false; } } if (success) { // set hardware parameters error = snd_pcm_hw_params(*phandler, hw_params); ) { cout<<"[SG]Fail to set hardware parameter. Reason: "<<snd_strerror(error)<<endl; success = false; } } if (success) { error=snd_pcm_hw_params_get_period_size(hw_params, &g_frames, &dir); //get frame cout<<"Frame is "<<g_frames<<endl; // free the memory for hardware parameter structure snd_pcm_hw_params_free(hw_params); hw_params = NULL; // Prepare ALSA device error = snd_pcm_prepare(*phandler); ) { cout<<"Fail to prepare ALSA device. Reason: "<<(snd_strerror(error))<<endl; success = false; } } if (success) { cout<<"ALSA device is ready to use"<<endl; } else { // fail to prepare ALSA device ==> un-initialize ALSA device if (hw_params != NULL) { snd_pcm_hw_params_free(hw_params); hw_params = NULL; } closeAlsaDevice(phandler); } } return success; } bool closeAlsaDevice(snd_pcm_t** phandler) { bool ret = true; snd_pcm_state_t state; int snd_ret; if (*phandler != NULL) { // drop the pending audio frame if needed state = snd_pcm_state(*phandler); cout<<"Alsa handler sate: "<<state<<endl; if ((SND_PCM_STATE_RUNNING == state) || (SND_PCM_STATE_XRUN == state) || (SND_PCM_STATE_SUSPENDED == state)) { snd_ret = snd_pcm_drop(*phandler); ) { cout<<"Fail to drop ALSA device. Reason: "<<(snd_strerror(snd_ret))<<endl; } } // close ALSA handler snd_ret = snd_pcm_close(*phandler); ) { cout<<"Fail to close ALSA device. Reason: "<<(snd_strerror(snd_ret))<<endl; ret = false; } *phandler = NULL; cout<<"CLOSE ALSA DEVICE"<<endl; } return ret; } int main() { bool ret=false; snd_pcm_t* m_phandler=NULL; Alsa_Conf* m_palsaCfg=new Alsa_Conf(); m_palsaCfg->alsaDevice = string("sd_out_16k"); //m_palsaCfg->samplingFrequency = 16000; m_palsaCfg->alsaCapturePeriod = ; //m_palsaCfg->numOfChannels = NUM_OF_CHANNELS_1; m_palsaCfg->block = true; //block m_palsaCfg->friendlyName = "AlsaWave"; //m_palsaCfg->bitsPerSample = BITS_PER_SAMPLE_16; m_palsaCfg->alsaPeriodFrame = m_palsaCfg->samplingFrequency * m_palsaCfg->alsaCapturePeriod / ; // calculate the number of frame in one period m_palsaCfg->alsaBufferSize = m_palsaCfg->alsaPeriodFrame * ; //means the whole buffer was perdion*8, e.g. 10ms means every 10ms we will get/send the data m_palsaCfg->accessType = SND_PCM_ACCESS_RW_INTERLEAVED; m_palsaCfg->streamType = SND_PCM_STREAM_PLAYBACK; FILE* fp=NULL; const string wavePath="/mnt/hgfs/0_SharedFolder/0_Local_Test_Folder/01_TestFolder/TestALSA/left_1k_right_400hz.wav"; //parse the wave file ret=ParseWaveFile(wavePath,m_palsaCfg,&fp); //update the value m_palsaCfg->alsaPeriodFrame = m_palsaCfg->samplingFrequency * m_palsaCfg->alsaCapturePeriod / ; // calculate the number of frame in one period if(ret) { //open alsa device ret=PrepareAlsaDevice(m_palsaCfg,&m_phandler); } if(ret) { PlayWave(&fp,&m_phandler,m_palsaCfg); } closeAlsaDevice(&m_phandler); if(fp!=NULL) { fclose(fp); fp=NULL; } delete m_palsaCfg; m_palsaCfg=NULL; ; }
Alsa 读取wave文件,并播放wave 文件的更多相关文章
- 读取SD卡文件夹下的MP3文件和播放MP3文件
首先获取SD卡path路径下的所有的MP3文件,并将文件名和文件大小存入List数组(此代码定义在FileUtils类中): /** * 读取目录中的Mp3文件的名字和大小 */ public Lis ...
- Linux音频编程--使用ALSA库播放wav文件
在UBUNTU系统上使用alsa库完成了对外播放的wav文件的案例. 案例代码: /** *test.c * *注意:这个例子在Ubuntu 12.04.1环境下编译运行成功. * */ #inclu ...
- Opencv 播放mp4文件和读取摄像头图以及可能会发生的一些异常问题解决方法
学习内容 学习Opencv 读取并播放本地视频和打开摄像头图像以及可能会发生的一些异常问题解决方法 代码演示 电脑环境信息: OpenCV版本:4.5.2 ,vs2017 1.视频文件读取与播放 加载 ...
- python 播放 wav 文件
未使用其他库, 只是使用 pywin32 调用系统底层 API 播放 wav 文件. # Our raison d'etre - playing sounds import pywintypes im ...
- 【转】C# 视频监控系列(12):H264播放器——播放录像文件
原文地址:http://www.cnblogs.com/over140/archive/2009/03/23/1419643.html?spm=5176.100239.blogcont51182.16 ...
- VC++中MCI播放音频文件 【转】
MCI播放mp3音频文件例程 源文件中需要包含头文件 Mmsystem.h,在Project->Settings->Link->Object/libray module中加入库 Wi ...
- 如何播放 WAV 文件?
from http://www.vckbase.com/index.php/wv/434 平时,你在多媒体软件的设计中是怎样处理声音文件的呢?使用Windows 提供的API函数 sndPlaySou ...
- ffmpeg和opencv 播放视频文件和显示器
ffmpeg它是基于最新版本,在官网下载http://ffmpeg.zeranoe.com/builds/.编译时VS2010配置相关头文件及库的路径就可以.opencv的搭建參考上一个博客. 首先简 ...
- STM32音乐播放器,文件查找的实现
使用FATFS只是完成了一个基本的文件读写,有时候我们需要扩展一些功能,比如MP3实验,需要上一曲下一曲的切换,扩展的代码如下 //显示目录下所有文件 u8 ShowFileList(u8* dirP ...
- Qt 播放音频文件
Qt播放音频文件的方法有好多中,简单介绍几种 不过一下几种方式都需要在Qt工程文件中添加 QT += multimedia 第一 QMediaPlayer类 可以播放MP3文件,同时使用也 ...
随机推荐
- 在TFS中通过程序动态创建Bug并感知Bug解决状态
为便于跟踪问题解决情况,预警引擎产生的比较严重的预警日志,需要在TFS中登记Bug,通过TFS的状态流转,利用TFS Bug的Web挂钩功能,动态感知Bug解决状态,从而跟踪预警问题的解决状态, 整体 ...
- Omi新成员omi-router正式发布
原文链接-https://github.com/AlloyTeam/omi/blob/master/tutorial omi-router omi-router是Omi框架专属的router插件,文件 ...
- 使用nginx代理kibana并设置身份验证
1.在es-sever上安装nginx #wget http://nginx.org/download/nginx-1.8.1.tar.gz #tar xvf nginx-1.8.1.tar.gz # ...
- JDK中日期和时间的几个常用类浅析(四)
java.time.Instant java.time.Instant类对应的是时间线上的一个时间点.该类通过保存着从格林威治的起始时间(1970年一月一日零点零分)开始计算所经过的纳妙数来表示时 ...
- python之列表作为函数的参数
函数参数为 列表或者字典 传递一个列表,例如 [1, 2, 3] 将此传给函数get_sum() 求出 各个元素之和 传递一个字典,打印出key/value的对应关系表: #!/usr/bin/env ...
- 老李分享:HTTP协议之协议头
老李分享:HTTP协议之协议头 当我们打开一个网页时,浏览器要向网站服务器发送一个HTTP请求头,然后网站服务器根据HTTP请求头的内容生成当次请求的内容发送给浏览器.你明白HTTP请求头的具体含 ...
- 微信小程序省市联动
最近呢刚好做了一个省市联动的功能,今天看到有人问这个怎么做,我就把我做的放上来共享一下: 首先呢,来看看效果,点击文字'点击',弹出选择窗口,点击取消或者确定(取消.确定按钮在选择框上边,截图有些不清 ...
- 基于Spring Security 的JSaaS应用的权限管理
1. 概述 权限管理,一般指根据系统设置的安全规则或者安全策略,用户可以访问而且只能访问自己被授权的资源.资源包括访问的页面,访问的数据等,这在传统的应用系统中比较常见.本文介绍的则是基于Saas系统 ...
- 关于block使用的几点注意事项
1.在使用block前需要对block指针做判空处理. 不判空直接使用,一旦指针为空直接产生崩溃. if (!self.isOnlyNet) { if (succBlock == NULL) { // ...
- Servlet(一)基础总结
一.Servlet概述 1.Java Servlet是基于Java的一种技术和标准,是独立于平台和协议,服务器端的java应用程序.与Applet相比.Applet运行在客户端,而Servlet运行在 ...