• Android : 基于alsa库的音乐播放


    继上篇:Android : alsa-lib 移植 ,这篇随笔实现一个demo基于移植好的alsa库在Android平台上播放wav文件:

    一、利用ffmeg将一个mp3文件转换成wav文件

     (1)ubuntu安装ffmeg工具:

         sudo add-apt-repository ppa:djcj/hybrid

         sudo apt-get update

         sudo apt-get install ffmpeg

     (2)mp3转wav:

       ffmpeg -i duandian.mp3 -f wav duandian.wav

    二、demo代码:

    /*
     *  This small demo sends a wave to your speakers.
     */
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sched.h>
    #include <errno.h>
    #include <getopt.h>
    #include "../include/asoundlib.h"
    #include <sys/time.h>
    #include <math.h>
    
    static char *device = "hw:0,0";                     /* playback device */
    int blockMode = 0;                  /* block mode */
    
    /*
     * RIFF WAVE file struct. 
     * For details see WAVE file format documentation  
     * (for example at http://www.wotsit.org). 
     */  
    struct WAV_HEADER_S
    {  
        char            riffType[4];    //4byte,资源交换文件标志:RIFF     
        unsigned int    riffSize;       //4byte,从下个地址到文件结尾的总字节数   
        char            waveType[4];    //4byte,wav文件标志:WAVE      
        char            formatType[4];  //4byte,波形文件标志:FMT(最后一位空格符)   
        unsigned int    formatSize;     //4byte,音频属性(compressionCode,numChannels,sampleRate,bytesPerSecond,blockAlign,bitsPerSample)所占字节数  
        unsigned short  compressionCode;//2byte,编码格式种类(1-线性pcm-WAVE_FORMAT_PCM,WAVEFORMAT_ADPCM)  
        unsigned short  numChannels;    //2byte,通道数  
        unsigned int    sampleRate;     //4byte,采样率  
        unsigned int    bytesPerSecond; //4byte,传输速率  
        unsigned short  blockAlign;     //2byte,数据块的对齐,即DATA数据块长度  
        unsigned short  bitsPerSample;  //2byte,采样精度-PCM位宽  
        char            dataType[4];    //4byte,数据标志:data  
        unsigned int    dataSize;       //4byte,从下个地址到文件结尾的总字节数,即除了wav header以外的pcm data length  
    } wav_header;  
    
    /*
     *   Underrun and suspend recovery
     */
    static int xrun_recovery(snd_pcm_t *handle, int err)
    {
            int wait_cnt=0;
            if (err == -EPIPE) {    /* under-run */
            //重新准备设备进行读写
                    err = snd_pcm_prepare(handle);
                    if (err < 0)
                            printf("Can't recovery from underrun, prepare failed: %s
    ", snd_strerror(err));
            else
                printf("underrun occurred
    ");  
                    return 0;
            } else if (err == -ESTRPIPE) {
                    while ((err = snd_pcm_resume(handle)) == -EAGAIN){
                 sleep(1);       /* wait until the suspend flag is released */
                 wait_cnt++;
                 if(wait_cnt >= 3){
                     printf("suspend flag  released fail after retry %d times!
    ", wait_cnt);
                    break;
                 }
            }
                          
                    if (err < 0) {
                            err = snd_pcm_prepare(handle);
                            if (err < 0)
                                    printf("Can't recovery from suspend, prepare failed: %s
    ", snd_strerror(err));
                    }
                    return 0;
            }
            return err;
    }
      
    int set_pcm_play(FILE *fp)  
    {  
            int    rc;  
            int    ret;  
            int    size;  
            snd_pcm_t*       handle;        //PCI设备句柄  
            snd_pcm_hw_params_t*      params;//硬件信息和PCM流配置  
            unsigned int    val;  
            int    dir=0;  
            snd_pcm_uframes_t  frames;  
            char   *buffer;  
            int channels=wav_header.numChannels;  
            int frequency=wav_header.sampleRate;  
            int bit=wav_header.bitsPerSample;  
            int datablock=wav_header.blockAlign;  
          
            rc=snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, blockMode ? 0 : SND_PCM_NONBLOCK);  
            if(rc<0)  
            {  
                    perror("open PCM device failed:");  
                    exit(1);  
            }  
      
            snd_pcm_hw_params_alloca(&params); //分配params结构体
            if(rc<0)  
            {  
                    perror("snd_pcm_hw_params_alloca:");  
                    exit(1);  
            }  
            
            rc=snd_pcm_hw_params_any(handle, params);//初始化params  
            if(rc<0)  
            {  
                    perror("snd_pcm_hw_params_any:");  
                    exit(1);  
            }  
            
            rc=snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);                                 //初始化访问权限  
            if(rc<0)  
            {  
                    perror("sed_pcm_hw_set_access:");  
                    exit(1);  
            }  
      
            //采样位数  
            switch(bit/8)  {  
                case 1:snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_U8);  
                        break ;  
                case 2:snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);  
                        break ;  
                case 3:snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S24_LE);  
                        break ;  
        }  
            
            rc=snd_pcm_hw_params_set_channels(handle, params, channels);  //设置声道,1表示单声>道,2表示立体声  
            if(rc<0)  
            {  
                    perror("
    snd_pcm_hw_params_set_channels:");  
                    exit(1);  
            }  
            
            val = frequency;  
            rc=snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);  //设置>频率  
            if(rc<0)  
            {  
                    perror("
    snd_pcm_hw_params_set_rate_near:");  
                    exit(1);  
            }  
      
            rc = snd_pcm_hw_params(handle, params);  
            if(rc<0)  
            {  
                perror("
    snd_pcm_hw_params: ");  
                exit(1);  
            }  
      
            rc=snd_pcm_hw_params_get_period_size(params, &frames, &dir);  /*获取周期长度*/  
            if(rc<0)  
            {  
                    perror("
    snd_pcm_hw_params_get_period_size:");  
                    exit(1);  
            }  
      
            size = frames * datablock;   /*4 : 代表数据块长度*/  
      
            buffer =(char*)malloc(size);  
            fseek(fp,sizeof(wav_header),SEEK_SET);  //定位歌曲到数据区  
      
            while (1)  
            {  
                 memset(buffer,0,sizeof(buffer));  
                 ret = fread(buffer, 1, size, fp);  
                 if(ret == 0)  
                 {  
                         printf("music write done!
    ");  
                         break;  
                 }  else if (ret != size)  {  
                          printf("music read out of size !
    ");  
                 }  
             
    /* use poll to wait for next event */           
    write_data:
                
                   if(snd_pcm_wait(handle, 50)){
                ret = snd_pcm_writei(handle,buffer,frames);   // 写音频数据到PCM设备    
                if(ret == -EAGAIN){
                    printf("write EAGAIN
    ");
                    goto write_data;
                }
                else if(ret < 0){
                        if (xrun_recovery(handle, ret) < 0) {
                                            printf("Write error: %s
    ", snd_strerror(ret));
                            break;
                                }
                }    
                   }
           }  
      
            snd_pcm_drain(handle);  
            snd_pcm_close(handle);  
            free(buffer);  
            return 0;  
    }  
      
    int pcm_main(int argc,char *argv[])  
    {  
      
        if(argc!=2)  
        {  
            printf("Usage : ./nanosic_apps  file_name.wav
    ");  
            exit(1);  
        }  
      
        int nread;  
        FILE *fp;  
        fp=fopen(argv[1],"rb");  
        if(fp==NULL)  
        {  
            perror("open file failed:
    ");  
            exit(1);  
        }  
          
        nread=fread(&wav_header,1,sizeof(wav_header),fp);  
        /*example:
        Read wav_header size = 44
        RIFF flag = RIFF?à?WAVEfmt 
        riffSize = 47308956
        waveType = WAVEfmt 
        formatType = fmt 
        formatSize = 16
        compressionCode = 1
        channels = 2
        Sample rate = 44100
        bytesPerSecond = 176400
        blockAlign = 4
        bitsPerSample = 16
        data = LISTp
        dataSize = 112
        */
        printf("Read wav_header size = %d
    ",nread);  
        printf("RIFF flag = %s
    ",wav_header.riffType);  
        printf("riffSize = %d
    ",wav_header.riffSize);  
        printf("waveType = %s
    ",wav_header.waveType);  
        printf("formatType = %s
    ",wav_header.formatType);   
        printf("formatSize = %d
    ",wav_header.formatSize);  
        printf("compressionCode = %d
    ",wav_header.compressionCode);  
        printf("channels = %d
    ",wav_header.numChannels);  
        printf("Sample rate = %d
    ",wav_header.sampleRate);  
        printf("bytesPerSecond = %d
    ",wav_header.bytesPerSecond);  
        printf("blockAlign = %d
    ",wav_header.blockAlign);  
        printf("bitsPerSample = %d
    ",wav_header.bitsPerSample);       
        printf("data = %s
    ",wav_header.dataType);  
        printf("dataSize = %d
    ",wav_header.dataSize);  
          
        set_pcm_play(fp);  //向PCM设备写入数据
        
        return 0;  
    }  
  • 相关阅读:
    使用 udev 高效、动态地管理 Linux 设备文件
    【技术贴】visual stdio 2005下载地址,vs2005下载地址 vs2005正版破解 v
    【转】无法登陆SQL server 服务器的解决办法
    【技术贴】visual stdio 2005下载地址,vs2005下载地址 vs2005正版破解 v
    【技术贴】远程桌面连接 时“由于帐户限制 您无法登陆”的解决办法
    【转】桌面快捷方式打不开的解决办法
    【技术贴】从51下载的网站代码asp源码怎么运行?怎么打开?
    【转】Visual Studio 2005不能调试的错误
    【技术贴】asms文件,安装windows xp原版时,需要“asms”文件,H:\I386\asm
    【技术贴】asms文件,安装windows xp原版时,需要“asms”文件,H:\I386\asm
  • 原文地址:https://www.cnblogs.com/blogs-of-lxl/p/6857347.html
Copyright © 2020-2023  润新知