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 = ; /* 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[]; //4byte,资源交换文件标志:RIFF
unsigned int riffSize; //4byte,从下个地址到文件结尾的总字节数
char waveType[]; //4byte,wav文件标志:WAVE
char formatType[]; //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[]; //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=;
if (err == -EPIPE) { /* under-run */
//重新准备设备进行读写
err = snd_pcm_prepare(handle);
if (err < )
printf("Can't recovery from underrun, prepare failed: %s\n", snd_strerror(err));
else
printf("underrun occurred\n");
return ;
} else if (err == -ESTRPIPE) {
while ((err = snd_pcm_resume(handle)) == -EAGAIN){
sleep(); /* wait until the suspend flag is released */
wait_cnt++;
if(wait_cnt >= ){
printf("suspend flag released fail after retry %d times!\n", wait_cnt);
break;
}
} if (err < ) {
err = snd_pcm_prepare(handle);
if (err < )
printf("Can't recovery from suspend, prepare failed: %s\n", snd_strerror(err));
}
return ;
}
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=;
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 ? : SND_PCM_NONBLOCK);
if(rc<)
{
perror("\open PCM device failed:");
exit();
} snd_pcm_hw_params_alloca(¶ms); //分配params结构体
if(rc<)
{
perror("\snd_pcm_hw_params_alloca:");
exit();
} rc=snd_pcm_hw_params_any(handle, params);//初始化params
if(rc<)
{
perror("\snd_pcm_hw_params_any:");
exit();
} rc=snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); //初始化访问权限
if(rc<)
{
perror("\sed_pcm_hw_set_access:");
exit();
} //采样位数
switch(bit/) {
case :snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_U8);
break ;
case :snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
break ;
case :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<)
{
perror("\nsnd_pcm_hw_params_set_channels:");
exit();
} val = frequency;
rc=snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); //设置>频率
if(rc<)
{
perror("\nsnd_pcm_hw_params_set_rate_near:");
exit();
} rc = snd_pcm_hw_params(handle, params);
if(rc<)
{
perror("\nsnd_pcm_hw_params: ");
exit();
} rc=snd_pcm_hw_params_get_period_size(params, &frames, &dir); /*获取周期长度*/
if(rc<)
{
perror("\nsnd_pcm_hw_params_get_period_size:");
exit();
} size = frames * datablock; /*4 : 代表数据块长度*/ buffer =(char*)malloc(size);
fseek(fp,sizeof(wav_header),SEEK_SET); //定位歌曲到数据区 while ()
{
memset(buffer,,sizeof(buffer));
ret = fread(buffer, , size, fp);
if(ret == )
{
printf("music write done!\n");
break;
} else if (ret != size) {
printf("music read out of size !\n");
} /* use poll to wait for next event */
write_data: if(snd_pcm_wait(handle, )){
ret = snd_pcm_writei(handle,buffer,frames); // 写音频数据到PCM设备
if(ret == -EAGAIN){
printf("write EAGAIN\n");
goto write_data;
}
else if(ret < ){
if (xrun_recovery(handle, ret) < ) {
printf("Write error: %s\n", snd_strerror(ret));
break;
}
}
}
} snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
return ;
} int pcm_main(int argc,char *argv[])
{ if(argc!=)
{
printf("Usage : ./nanosic_apps file_name.wav\n");
exit();
} int nread;
FILE *fp;
fp=fopen(argv[],"rb");
if(fp==NULL)
{
perror("open file failed:\n");
exit();
} nread=fread(&wav_header,,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\n",nread);
printf("RIFF flag = %s\n",wav_header.riffType);
printf("riffSize = %d\n",wav_header.riffSize);
printf("waveType = %s\n",wav_header.waveType);
printf("formatType = %s\n",wav_header.formatType);
printf("formatSize = %d\n",wav_header.formatSize);
printf("compressionCode = %d\n",wav_header.compressionCode);
printf("channels = %d\n",wav_header.numChannels);
printf("Sample rate = %d\n",wav_header.sampleRate);
printf("bytesPerSecond = %d\n",wav_header.bytesPerSecond);
printf("blockAlign = %d\n",wav_header.blockAlign);
printf("bitsPerSample = %d\n",wav_header.bitsPerSample);
printf("data = %s\n",wav_header.dataType);
printf("dataSize = %d\n",wav_header.dataSize); set_pcm_play(fp); //向PCM设备写入数据 return ;
}
Android : 基于alsa库的音乐播放的更多相关文章
- 基于jQuery仿QQ音乐播放器网页版代码
基于jQuery仿QQ音乐播放器网页版代码是一款黑色样式风格的网页QQ音乐播放器样式代码.效果图如下: 在线预览 源码下载 实现的代码. html代码: <div class="m ...
- iOS之基于FreeStreamer的简单音乐播放器(模仿QQ音乐)
代码地址如下:http://www.demodashi.com/demo/11944.html 天道酬勤 前言 作为一名iOS开发者,每当使用APP的时候,总难免会情不自禁的去想想,这个怎么做的?该怎 ...
- Android应用--简、美音乐播放器增加音量控制
Android应用--简.美音乐播放器增加音量控制 2013年6月26日简.美音乐播放器继续完善中.. 题外话:上一篇博客是在6月11号发的,那篇博客似乎有点问题,可能是因为代码结构有点乱的原因,很难 ...
- Android应用--简、美音乐播放器获取专辑图片(自定义列表适配器)
Android应用--简.美音乐播放器获取专辑图片(自定义列表适配器) 2013年7月3日简.美音乐播放器开发 第二阶段已增加功能: 1.歌词滚动显示 2.来电监听 3.音量控制 4.左右滑动切换歌词 ...
- 基于Qt的开源音乐播放器(CZPlayer)
CZPlayer CZPlayer是基于Qt开发的一款功能强大的音乐播放器,该播放器的论坛地址请点击here,目前CZPlayer已经是第四个版本了,历史版本也分别在我的github上, github ...
- android快捷简单的实现音乐播放器
自己做了一个相对完整的音乐播放器,现在把播放模块提取出来,分享给大家.音乐播放器基本功能都实现了的,可能有些BUG,希望谅解. 播放器功能如下: 1.暂停,播放 2.拖动条实现,快进,快退 3.歌词同 ...
- Android开发实战之简单音乐播放器
最近开始学习音频相关.所以,很想自己做一个音乐播放器,于是,花了一天学习,将播放器的基本功能实现了出来.我觉得学习知识点还是蛮多的,所以写篇博客总结一下关于一个音乐播放器实现的逻辑.希望这篇博文对你的 ...
- Swift 3 :基于 AVAudioPlayer 的简单音乐播放器
2017.05.22 17:46* 字数 1585 阅读 5095评论 0喜欢 8赞赏 2 https://www.jianshu.com/p/4d5c257428a1 学习ios以来差不多接近两个月 ...
- 基于JavaFX实现的音乐播放器
前言 这个是本科四年的毕业设计,我个人自命题的一个音乐播放器的设计与实现,其实也存在一些功能还没完全开发完成,但粗略的答辩也就过去了,还让我拿了个优秀,好开心.界面UI是参考网易云UWP版本的,即使这 ...
随机推荐
- Axure 第一个原型 简单的登录页面
设置所有元件的尺寸和位置的时候都是借助截图软件来调整位置的
- 数组方法map(映射),reduce(规约),foreach(遍历),filter(过滤)
数组方法map(映射),reduce(规约),foreach(遍历),filter(过滤) map()方法返回一个由原数组中每一个元素调用一个指定方法后返回的新数组 reduce()方法接受一个函数作 ...
- SSRF漏洞
概念:服务端在获取攻击者输入的url时,如果这个过程中,服务端并没有对这个url做任何的限制和过滤,那么就很有可能存在ssrf漏洞. 漏洞利用:SSRF攻击的目标一般是外网无法访问的内部系统.攻击者可 ...
- bzoj3876: [Ahoi2014&Jsoi2014]支线剧情
题意:给一幅图,从1开始,每条边有边权最少走一遍,可以在任意点退出,问最小花费 题解:上下界费用流,每个边都流一遍,然后为了保证流量平衡,新建源点汇点,跑费用流把流量平衡 /************* ...
- react中直接调用子组件的方法(非props方式)
我们都知道在 react中,若要在父组件调用子组件的方法,通常我们会采用在父组件定义一个方法,作为props转给子组件,然后执行该方法,可以获取到子组件传回的参数以得到我们的目的. 显而易见,这个执行 ...
- python中eval()和json.dumps的使用
在python中通过requests.get(url)获取json数据,此时可能需要eval进行解析. # -*- coding: utf-8 -*- import requests r = requ ...
- rpc框架实现(持续更新)
网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,rpc基于长连接的远程过程调用应用而生. 一:A服务调用B服务,整个调用过程,主要经历如下几个步骤:(摘自 ...
- [vjudge contest15(xjoi)] C - Berzerk
CodeForces - 787C Rick and Morty are playing their own version of Berzerk (which has nothing in comm ...
- 数据库恢复(database restore)之兵不血刃——半小时恢复客户数据库
昨天,一个客户打打来电话,说他们的数据库坏了,不能用了,需要我帮助恢复下,这马上要放假了,居然出了这事儿,自己也不太喜欢恢复数据库这类,尤其是他们的数据库是个win上的库,但心里很清楚,客户比咱着急, ...
- Django之路由分配系统
前言: Django大致工作流程 1.客户端发送请求(get/post)经过web服务器.Django中间件. 到达路由分配系统 2.路由分配系统根据提取 request中携带的的url路径(path ...