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版本的,即使这 ...
随机推荐
- 日常英语---九、冒险岛link技能导读
日常英语---九.冒险岛link技能导读 一.总结 一句话总结:选最值得练的link技能列上来,先熟悉一部分,没必要一开始就全部弄懂,这样压力太大,可以先熟悉比较有意义的一部分啊 学以致用-还不如说成 ...
- 20165303 2017-2018-2 《Java程序设计》结对编程练习_四则运算
需求分析 能生成简单四则运算题目并判断用户回答对错. 能正确统计回答正确的概率. 能正确处理混合四则运算的优先级的问题. 能正确输出负数等结果. 能处理简单的加,减,乘,除运算. 能正确的处理有括号的 ...
- java --> Long和long/Integer和int
java中非一切是对象,因为还有基本数据类型. 基本数据类型有对应的基本数据类型打包器,它们的基本数据类型打包器是对象. j2se 5.0引入装箱和拆箱,它们是基本数据类型和基本数据类型打包器的关系 ...
- Android的组件化和模块化
Android随着业务的增多,而且后续新的需求的增加,代码的修改会变得非常频繁 然后最近在看组件化和模块化 公司的业务没有那么大,所以这种方式我并没有采取 但是还是需要了解下他的使用机制 还有优缺点之 ...
- Confluence 6 自定义你的空间
通过对你的空间进行界面的自定义能够让你的空间更加出类拔萃. 如果你具有空间管理员权限,你可以修改你空间的颜色配色,添加你自己的空间标识,选择是否在你空间中显示边栏.或者你可以进入 Atlassian ...
- 安装redisPHP扩展
1. "predis/predis":"~1.1@dev" 2.composer update 即可,这是给项目添加redis扩展 启动服务端 redis-se ...
- CentOS7.3将网卡命名方式设置为传统方式
CentOS7.3将网卡命名方式设置为传统方式 生产环境可能拥有不同系列的操作系统,比如,既有CentOS6系列,也有CentOS7系列的系统,而CentOS6和CentOS7在网卡命名方面有着较大区 ...
- python基础之列表以及切片等操作
列表 定义: 能装对象的对象,列表能放大量的数据,各种类型,且列表内的数据是可以修改保存的,常用 [ ] 去表示,每一项数据之间用逗号隔开 1.列表的索引与切片 1.1 索引 与字符串的索引几乎一致, ...
- python记录_day33 线程
##进程就像加工厂,线程是里边的流水线##进程是资源单位,线程是运行单位,每个进程至少有一个线程 即进程是资源分配的最小单位,线程是CPU调度的最小单位 一.线程的创建两种方式,和进程类似1.t = ...
- SSM框架中各层作用
SSM是sping+springMVC+mybatis集成的框架. MVC即model view controller. model层=entity层.存放我们的实体类,与数据库中的属性值基本保持一致 ...