这篇文章的app程序是参考国嵌的。
在编写app之前我们要编译好madplay
准备工作一:
编译madplay
首先解压三个压缩文件
[root@localhost ~]# cd /work/projects/sound/
[root@localhost sound]# ls
libid3tag-0.15.1b.tar.gz libmad-0.15.1b.tar.gz madplay-0.15.2b.tar.gz
[root@localhost sound]# tar xzf libid3tag-0.15.1b.tar.gz //从名字上看是个库
[root@localhost sound]# tar xzf libmad-0.15.1b.tar.gz //这个也是库
[root@localhost sound]# tar xzf madplay-0.15.2b.tar.gz //这个是应用程序,它依赖这两个库
[root@localhost sound]#
[root@localhost sound]# cd libid3tag-0.15.1b
[root@localhost libid3tag-0.15.1b]# ./configure--host=arm-linux --prefix=/work/projects/sound/tmp
configure: WARNING: If you wanted to set the --build type, don't use--host.
If a cross compiler isdetected then cross compile mode will be used.
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
然后再
make
make install
再按照上面的方法进入libmad-0.15.1b文件夹编译
./configure --host=arm-linux --prefix=/work/projects/sound/tmpLDFLAGS="-L/work/projects/sound/tmp/lib" CFLAGS="-I/work/projects/sound/tmp/include"
注意: -L/work…..
这个-L与/之间没有空格.
然后再
make
make install
把tmp/bin/* tmp/lib/*so* -d把库文件复制到开发板lib文件夹,bin文件复制到开发板的bin文件夹
# madplay --tty-control /mnt/mp3/beyond.mp3
MPEG Audio Decoder 0.15.2 (beta) - Copyright (C) 2000-2004 RobertLeslie et al.
s3c2410-uda1341-superlp: audio_set_dsp_speed:44100 prescaler:66
Artist: Beyond£¨»Æ¼Ò¾Ô£©
Album:ÒôÀÖµîÌÃMusicPalace
Comment:http://music.zkinfo.ha.cn
s3c2410-uda1341-superlp: audio_set_dsp_speed:44100 prescaler:66
到这里时候测试下自己的开发板能否播放mp3音乐。
注意事项:确保自己的开发板已经有声卡了,想提高播放音乐的音量不能用madplay提供的方法(声音加大会破掉,而且音质会变得很差),如果你的开发板有QT界面直接调整音量滑块。
准备工作二:
编写开发板上的驱动程序。我的开发板是TQ2440。
key_drv_irq.c
#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/irq.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <asm/io.h> #include <asm/arch/regs-gpio.h> #include <asm/hardware.h> static int major; static struct class *key_class; static struct class_device *key_class_dev; volatile unsigned long *gpfcon; volatile unsigned long *gpfdat; static DECLARE_WAIT_QUEUE_HEAD(button_waitq); /* 中断事件标志, 中断服务程序将它置1,third_drv_read将它清0 */ static volatile int ev_press = 0; struct pin_desc{ unsigned int pin; unsigned int key_val; }; /* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */ /* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */ static unsigned char key_val; struct pin_desc pins_desc[4] = { {S3C2410_GPF1, 0x01}, {S3C2410_GPF4, 0x02}, {S3C2410_GPF2, 0x03}, {S3C2410_GPF0, 0x04}, }; /* * 确定按键值 */ static irqreturn_t buttons_irq(int irq, void *dev_id) { struct pin_desc * pindesc = (struct pin_desc *)dev_id; unsigned int pinval; pinval = s3c2410_gpio_getpin(pindesc->pin); if (pinval) { /* 松开 */ key_val = 0x80 | pindesc->key_val; } else { /* 按下 */ key_val = pindesc->key_val; } ev_press = 1; /* 表示中断发生了 */ wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */ return IRQ_RETVAL(IRQ_HANDLED); } static int key_drv_open(struct inode *inode, struct file *file) { /* 配置成输入模式 */ request_irq(IRQ_EINT1, buttons_irq, IRQT_BOTHEDGE, "K1", &pins_desc[0]); request_irq(IRQ_EINT4, buttons_irq, IRQT_BOTHEDGE, "K2", &pins_desc[1]); request_irq(IRQ_EINT2, buttons_irq, IRQT_BOTHEDGE, "K3", &pins_desc[2]); request_irq(IRQ_EINT0, buttons_irq, IRQT_BOTHEDGE, "K4", &pins_desc[3]); return 0; } static ssize_t key_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) { if (size != 1) return -EINVAL; /* 如果没有按键动作, 休眠 */ wait_event_interruptible(button_waitq, ev_press); /* 如果有按键动作, 返回键值 */ copy_to_user(buf, &key_val, 1); ev_press = 0; return 1; } int key_dev_close(struct inode *inode, struct file *file) { free_irq(IRQ_EINT1, &pins_desc[0]); free_irq(IRQ_EINT4, &pins_desc[1]); free_irq(IRQ_EINT2, &pins_desc[2]); free_irq(IRQ_EINT0, &pins_desc[3]); return 0; } static struct file_operations key_drv_fops={ .owner=THIS_MODULE, .open=key_drv_open, .read=key_drv_read, .release=key_dev_close, }; static int key_drv_init(void) { major=register_chrdev(0, "key_drv", &key_drv_fops); key_class=class_create(THIS_MODULE, "keydrv"); key_class_dev=class_device_create(key_class, NULL, MKDEV(major,0), NULL,"buttons"); /* dev/buttons */ gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16); //0x56000010是的GPIOB的 gpfdat = gpfcon + 1; return 0; } static void key_drv_exit(void) { unregister_chrdev(major, "key_drv"); class_device_unregister(key_class_dev); class_destroy(key_class); //class_destory(key_class); iounmap(gpfcon); } module_init(key_drv_init); module_exit(key_drv_exit); MODULE_LICENSE("GPL");
编译成ko文件,然后安装到开发板上。
app-mp3.c
/* * mp3播放器控制程序 * 功能: k1:播放、暂停 k2:停止播放 k3:上一首 k4:下一首 * 附加:歌曲自动循环播放 * */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <signal.h> #include <sys/select.h> #include <sys/time.h> #include <errno.h> #include <sys/wait.h> #include <string.h> #include <sys/ipc.h> #include <sys/shm.h> /*共享内存申请标记*/ #define PERM S_IRUSR|S_IWUSR /*双向循环列表:存放歌曲名*/ struct song { char songname[20]; struct song *prev; struct song *next; }; /*孙子进程id号*/ pid_t gradchild; /*子进程id号*/ pid_t pid; /*共享内存描述标记*/ int shmid; char *p_addr; /*播放标记*/ int first_key=1; int play_flag=0; /************************************************* Function name: play Parameter : struct song * Description : 播放函数 Return : void Argument : void Autor & date : ada 09,12,07 **************************************************/ void play(struct song *currentsong) { pid_t fd; char *c_addr; char *p; int len; char my_song[30]="/mp3/"; while(currentsong) { /*创建子进程,即孙子进程*/ fd = fork(); if(fd == -1) { perror("fork"); exit(1); } else if(fd == 0) { /*把歌曲名加上根路径*/ strcat(my_song,currentsong->songname); p = my_song; len = strlen(p); /*去掉文件名最后的'\n'*/ my_song[len-1]='\0'; printf("THIS SONG IS %s\n",my_song); execl("/bin/madplay","madplay",my_song,NULL); printf("\n\n\n"); } else { /*内存映射*/ c_addr = shmat(shmid,0,0); /*把孙子进程的id和当前播放歌曲的节点指针传入共享内存*/ memcpy(c_addr,&fd,sizeof(pid_t)); memcpy(c_addr + sizeof(pid_t)+1,¤tsong,4); /*使用wait阻塞孙子进程,直到孙子进程播放完才能被唤醒; 当被唤醒时,表示播放MP3期间没有按键按下,则继续顺序播放下一首MP3*/ if(fd == wait(NULL)) { currentsong = currentsong->next; printf("THE NEXT SONG IS %s\n",currentsong->songname); } } } } /************************************************* Function name: creat_song_list Parameter : void Description : 创建歌曲名的双向循环链表 Return : struct song * Argument : void Autor & date : ada 09.12.07 **************************************************/ struct song *creat_song_list(void) { FILE *fd; size_t size; size_t len; char *line = NULL; struct song *head; struct song *p1; struct song *p2; system("ls /mp3 >song_list"); fd = fopen("song_list","r"); p1 = (struct song *)malloc(sizeof(struct song)); printf("==================================song list=====================================\n"); system("ls /mp3"); printf("\n"); printf("================================================================================\n"); size = getline(&line,&len,fd); strncpy(p1->songname,line,strlen(line)); head = p1; while((size = getline(&line,&len,fd)) != -1) { p2 = p1; p1 = (struct song *)malloc(sizeof(struct song)); strncpy(p1->songname,line,strlen(line)); p2->next = p1; p1->prev = p2; } p1->next = head; head->prev = p1; p1 = NULL; p2 = NULL; system("rm -rf song_list"); return head; } /************************************************* Function name: startplay Parameter : pid_t *,struct song * Description : 开始播放函数 Return : void Argument : void Autor & date : ada 09.12.07 **************************************************/ void startplay(pid_t *childpid,struct song *my_song) { pid_t pid; int ret; /*创建子进程*/ pid = fork(); if(pid > 0) { *childpid = pid; play_flag = 1; sleep(1); /*把孙子进程的pid传给父进程*/ memcpy(&gradchild,p_addr,sizeof(pid_t)); } else if(0 == pid) { /*子进程播放MP3函数*/ play(my_song); } } /************************************************* Function name: my_pause Parameter : pid_t Description : 暂停函数 Return : void Argument : void Autor & date : ada 09,12,07 **************************************************/ void my_pause(pid_t pid) { printf("=======================PAUSE!PRESS K1 TO CONTINUE===================\n"); kill(pid,SIGSTOP); //对孙子进程发送SKGSTOP信号 play_flag = 0; } /************************************************* Function name: my_pause Parameter : pid_t Description : 停止播放函数 Return : void Argument : void Autor & date : ada 09,12,07 **************************************************/ void my_stop(pid_t g_pid) { printf("=======================STOP!PRESS K1 TO START PLAY===================\n"); kill(g_pid,SIGKILL); //对孙子进程发送SKGKILL信号 kill(pid,SIGKILL); //对子进程发送SKGKILL信号 first_key=1; } /************************************************* Function name: conti_play Parameter : pid_t Description : 继续函数 Return : void Argument : void Autor & date : ada 09,12,07 **************************************************/ void conti_play(pid_t pid) { printf("===============================CONTINUE=============================\n"); kill(pid,SIGCONT); //对孙子进程发送SIGCONT信号 play_flag=1; } /************************************************* Function name: next Parameter : pid_t Description : 下一首函数 Return : void Argument : void Autor & date : ada 09.12.07 **************************************************/ void next(pid_t next_pid) { struct song *nextsong; printf("===============================NEXT MP3=============================\n"); /*从共享内存获得孙子进程播放歌曲的节点指针*/ memcpy(&nextsong,p_addr + sizeof(pid_t)+1,4); /*指向下首歌曲的节点*/ nextsong = nextsong->next; /*杀死当前歌曲播放的子进程,孙子进程*/ kill(pid,SIGKILL); kill(next_pid,SIGKILL); wait(NULL); startplay(&pid,nextsong); } /************************************************* Function name: prev Parameter : pid_t Description : 上一首函数 Return : void Argument : void Autor & date : yuanhui 09.12.08 **************************************************/ void prev(pid_t prev_pid) { struct song *prevsong; /*从共享内存获得孙子进程播放歌曲的节点指针*/ printf("===============================PRIOR MP3=============================\n"); memcpy(&prevsong,p_addr + sizeof(pid_t)+1,4); /*指向上首歌曲的节点*/ prevsong = prevsong->prev; /*杀死当前歌曲播放的子进程,孙子进程*/ kill(pid,SIGKILL); kill(prev_pid,SIGKILL); wait(NULL); //linux C中的wait(NULL)是什么意思?请问_百度知道 //答:等待子进程退出。NULL的意思是退出状态不关注。如果要获取退出状态应该写成wait(&status); startplay(&pid,prevsong); } /************************************************* Function name: main Parameter : void Description : 主函数 Return : int Argument : void Autor & date : ada 09.12.07 **************************************************/ int main(void) { int buttons_fd; int key_value; struct song *head; /*打开设备文件*/ buttons_fd = open("/dev/buttons", O_RDWR); if (buttons_fd < 0) { perror("open /dev/buttons fail!!!"); exit(1); } /*创建播放列表*/ head = creat_song_list(); printf("===================================OPTION=======================================\n\n\n\n"); printf(" K1:START/PAUSE K2:STOP K3:NEXT K4:PRIOR\n\n\n\n"); printf("================================================================================\n"); /*共享内存:用于存放子进程ID,播放列表位置*/ if((shmid = shmget(IPC_PRIVATE,5,PERM))== -1) exit(1); p_addr = shmat(shmid,0,0); memset(p_addr,'\0',1024); while(1) { unsigned char key_value; read(buttons_fd, &key_value, 1); key_value--; /*首次播放,必须是按键1*/ if(first_key) { switch(key_value) { case 0: startplay(&pid,head); first_key=0; break; case 1: case 2: case 3: printf("=======================PRESS K1 TO START PLAY===================\n"); break; default: printf("=======================PRESS K1 TO START PLAY===================\n"); break; } //end switch }//end if(first_key) /*若不是首次播放,则根据不同键值处理*/ else if(!first_key) { switch(key_value) { case 0: //printf("play_flag:%d\n",play_flag); if(play_flag) my_pause(gradchild); else conti_play(gradchild); break; case 1: my_stop(gradchild); break; case 2: next(gradchild); break; case 3: prev(gradchild); break; } //end switch }//end if(!first_key) } close(buttons_fd); return 0; }
准备工作四:
在开发板根目录建立mp3文件夹,拷贝几首MP3文件进去,注意文件名不要超过20个字符。
现在可以运行这个app-mp3应用程序了。
=======================PRESS K1 TO START PLAY===================
=======================PRESS K1 TO START PLAY===================
=======================PRESS K1 TO START PLAY===================
THIS SONG IS /mp3/Tank.mp3
MPEG Audio Decoder 0.15.2 (beta) - Copyright (C) 2000-2004 Robert Leslie et al.
s3c2410-uda1341-superlp: audio_set_dsp_speed:44100 prescaler:66
Title: 贩贩贩 Artist: Tank(贩s3c2410-uda1341-superlp: audio_set_dsp_speed:44100 prescaler:66
===============================NEXT MP3=============================
THIS SONG IS /mp3/beyond.mp3
MPEG Audio Decoder 0.15.2 (beta) - Copyright (C) 2000-2004 Robert Leslie et al.
s3c2410-uda1341-superlp: audio_set_dsp_speed:44100 prescaler:66
Artist: Beyond(黄家驹)
Album: 音乐殿堂Musics3c2410-uda1341-superlp: audio_set_dsp_speed:44100 prescaler:66
Palace
Comment: http://music.zkinfo.ha.cn
error: frame 12346: lost synchronization
12346 frames decoded (0:05:22.5), +0.6 dB peak amplitude, 19 clipped samples
THE NEXT SONG IS huanghun.mp3
THIS SONG IS /mp3/huanghun.mp3
MPEG Audio Decoder 0.15.2 (beta) - Copyright (C) 2000-2004 Robert Leslie et al.
s3c2410-uda1341-superlp: audio_set_dsp_speed:44100 prescaler:66
Title: 黄昏
Artist: 周传雄 (小刚)
s3c2410-uda1341-superlp: audio_set_dsp_speed:44100 prescaler:66
Album: transfer
Year: 2000
Genre: Pop
Comment: mp3.attin.com