首页 > 代码库 > 嵌入式mp3播放器
嵌入式mp3播放器
分四部分:按键驱动,声卡驱动,Madplay播放器移植,MP3主播放器处理
按键1:播放,按键2:停止,按键3:上一曲,按键4:下一曲
UA1341内核自带声卡驱动1.解压内核:
tar zxvf linux.2.6.29.tar.gz
2.清理中间件,配置文件:
cd linux-linux2.6.29;make clean
3.选择参考配置文件:
cp config-mp3.config4.配置内核:make menuconfig ARCH=armCROSS_COMPILE=arm-linux-选择声卡驱动:device drivers-->sound card support-->advanced linux sound architecture-->alsa for soc audio support-->UA134x5.编译内核:make uImage ARCH=armCROSS_COMPILE=arm-linux-内核映像uImage位于arch/arm/boot将其拷贝到tftpboot目录6.解压rootfs.tar.gz并拷贝到nfsroot7.按键驱动移植:cd SDK-MP3/drivermake clean;makecp mini2440_buttons.ko /nfroot/rootfs/mp38.madplay移植
见最后
9.播放处理:
cd SDK-MP3/app;make clean;make
cp app-mp3 /nfsroot/rootfs/mp3
10.测试
采用NFS方式起文件系统,加载按键驱动,运行mp3程序:
insmod mini2440_buttons.ko
./app-mp3
会显示播放列表,播放option,1,2,3,4按键控制播放。
主要程序为mp3播放控制程序:/* * 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: playParameter : struct song *Description : 播放函数Return : voidArgument : voidAutor & 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/song/"; 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("/mp3/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_listParameter : voidDescription : 创建歌曲名的双向循环链表Return : struct song *Argument : voidAutor & 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 >song_list"); fd = fopen("song_list","r"); p1 = (struct song *)malloc(sizeof(struct song)); printf("==================================song list=====================================\n"); system("ls /mp3/song"); 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: startplayParameter : pid_t *,struct song *Description : 开始播放函数Return : voidArgument : voidAutor & 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_pauseParameter : pid_tDescription : 暂停函数Return : voidArgument : voidAutor & 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_pauseParameter : pid_tDescription : 停止播放函数Return : voidArgument : voidAutor & 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_playParameter : pid_tDescription : 继续函数Return : voidArgument : voidAutor & date : ada 09,12,07**************************************************/void conti_play(pid_t pid){ printf("===============================CONTINUE=============================\n"); kill(pid,SIGCONT); //对孙子进程发送SIGCONT信号 play_flag=1;}/*************************************************Function name: nextParameter : pid_tDescription : 下一首函数Return : voidArgument : voidAutor & 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: prevParameter : pid_tDescription : 上一首函数Return : voidArgument : voidAutor & 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); startplay(&pid,prevsong);}/*************************************************Function name: mainParameter : voidDescription : 主函数Return : intArgument : voidAutor & date : ada 09.12.07**************************************************/int main(void){ int buttons_fd; int key_value; struct song *head; /*打开设备文件*/ buttons_fd = open("/dev/buttons", 0); if (buttons_fd < 0) { perror("open device buttons"); 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) { fd_set rds; int ret; FD_ZERO(&rds); FD_SET(buttons_fd, &rds); /*监听获取键值*/ ret = select(buttons_fd + 1, &rds, NULL, NULL, NULL); if (ret < 0) { perror("select"); exit(1); } if (ret == 0) printf("Timeout.\n"); else if (FD_ISSET(buttons_fd, &rds)) { int ret = read(buttons_fd, &key_value, sizeof key_value); if (ret != sizeof key_value) { if (errno != EAGAIN) perror("read buttons\n"); continue; } else { //printf("buttons_value: %d\n", key_value+1); /*首次播放,必须是按键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;}
all:
arm-linux-gcc -static app.c -o app-mp3
clean:
rm -rf app-mp3
mini2440_buttons.c#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/poll.h>#include <linux/irq.h>#include <asm/irq.h>#include <linux/interrupt.h>#include <asm/uaccess.h>#include <mach/regs-gpio.h>#include <mach/hardware.h>#include <linux/platform_device.h>#include <linux/cdev.h>#include <linux/miscdevice.h>#define DEVICE_NAME "buttons"//#define DEBUG struct button_irq_desc { int irq; int pin; int pin_setting; int number; char *name; };#if !defined (CONFIG_QQ2440_BUTTONS)static struct button_irq_desc button_irqs [] = { {IRQ_EINT8 , S3C2410_GPG0 , S3C2410_GPG0_EINT8 , 0, "KEY0"}, {IRQ_EINT11, S3C2410_GPG3 , S3C2410_GPG3_EINT11 , 1, "KEY1"}, {IRQ_EINT13, S3C2410_GPG5 , S3C2410_GPG5_EINT13 , 2, "KEY2"}, {IRQ_EINT14, S3C2410_GPG6 , S3C2410_GPG6_EINT14 , 3, "KEY3"}, {IRQ_EINT15, S3C2410_GPG7 , S3C2410_GPG7_EINT15 , 4, "KEY4"}, {IRQ_EINT19, S3C2410_GPG11, S3C2410_GPG11_EINT19, 5, "KEY5"},};#else /* means QQ */static struct button_irq_desc button_irqs [] = { {IRQ_EINT19, S3C2410_GPG11, S3C2410_GPG11_EINT19, 0, "KEY0"}, {IRQ_EINT11, S3C2410_GPG3, S3C2410_GPG3_EINT11, 1, "KEY1"}, {IRQ_EINT2, S3C2410_GPF2, S3C2410_GPF2_EINT2, 2, "KEY2"}, {IRQ_EINT0, S3C2410_GPF0, S3C2410_GPF0_EINT0, 3, "KEY3"}, { -1, -1, -1, 4, "KEY4"}, { -1, -1, -1, 5, "KEY5"},};#endif//static volatile char key_values [] = {‘0‘, ‘0‘, ‘0‘, ‘0‘, ‘0‘, ‘0‘};static int key_values = 0;static DECLARE_WAIT_QUEUE_HEAD(button_waitq);static volatile int ev_press = 0;static irqreturn_t buttons_interrupt(int irq, void *dev_id){ struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id; int down; // udelay(0); /*上升沿触发,GPIO DAT 应该为非0 的数*/ down = !s3c2410_gpio_getpin(button_irqs->pin); if (!down) { //printk("rising\n"); key_values = button_irqs->number; ev_press = 1; wake_up_interruptible(&button_waitq); } else { //printk("falling\n"); ev_press = 0; return 0; } return IRQ_RETVAL(IRQ_HANDLED);}static int s3c24xx_buttons_open(struct inode *inode, struct file *file){ int i; int err = 0; for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) { if (button_irqs[i].irq < 0) { continue; } /* 设置中断触发方式 IRQ_TYPE_EDGE_FALLING,IRQ_TYPE_EDGE_RISING,IRQ_TYPE_EDGE_BOTH ;我们这里设置为上升沿触发*/ //err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_BOTH, // button_irqs[i].name, (void *)&button_irqs[i]); err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_RISING, button_irqs[i].name, (void *)&button_irqs[i]); if (err) break; } if (err) { i--; for (; i >= 0; i--) { if (button_irqs[i].irq < 0) { continue; } disable_irq(button_irqs[i].irq); free_irq(button_irqs[i].irq, (void *)&button_irqs[i]); } return -EBUSY; } ev_press = 0; return 0;}static int s3c24xx_buttons_close(struct inode *inode, struct file *file){ int i; for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) { if (button_irqs[i].irq < 0) { continue; } free_irq(button_irqs[i].irq, (void *)&button_irqs[i]); } return 0;}static int s3c24xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp){ unsigned long err; //int i=0; if (!ev_press) { if (filp->f_flags & O_NONBLOCK) return -EAGAIN; else wait_event_interruptible(button_waitq, ev_press); } if(count != sizeof key_values) return -EINVAL; ev_press = 0; err = copy_to_user(buff, &key_values, sizeof(key_values)); return sizeof(key_values);}static unsigned int s3c24xx_buttons_poll( struct file *file, struct poll_table_struct *wait){ unsigned int mask = 0; poll_wait(file, &button_waitq, wait); if (ev_press) mask |= POLLIN | POLLRDNORM; return mask;}static struct file_operations dev_fops = { .owner = THIS_MODULE, .open = s3c24xx_buttons_open, .release = s3c24xx_buttons_close, .read = s3c24xx_buttons_read, .poll = s3c24xx_buttons_poll,};static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops,};static int __init dev_init(void){ int ret; ret = misc_register(&misc);#ifdef DEBUG printk("debug test\n");//ykz#endif printk (DEVICE_NAME"\tinitialized\n"); return ret;}static void __exit dev_exit(void){ misc_deregister(&misc);}module_init(dev_init);module_exit(dev_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("FriendlyARM Inc.");
ifneq ($(KERNELRELEASE),)
obj-m := mini2440_buttons.o
else
KDIR := /home/project/mp3/SDK-MP3/kernel/linux-2.6.29
all:
make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers app-key
endif
Madplay移植说明一.准备移植Madplay所需四个软件包分别为libid3tag-0.15.1b.tar.gz,libmad-0.15.1b.tar.gz,zlib-1.1.4.tar.gz,madplay-0.15.2b.tar.gz二.解压 1.mkdir /mp3 建立MP3目录 2. tar -zxvf libid3tag-0.15.1b.tar.gz -C /mp3 3. tar -zxvf ibmad-0.15.1b.tar.gz -C /mp3 4. tar -zxvf zlib-1.1.4.tar.gz -C /mp3 5. tar -zxvf madplay-0.15.2b.tar.gz -C /mp3 三.编译zlib#cd /mp3/zlib-1.1.4 #./configure --prefix=/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/lib 修改Makefile AR=/usr/local/arm/4.3.2/bin/arm-linux-ar rcs CC=/usr/local/arm/4.3.2/bin/arm-linux-gcc RANLIB=/usr/local/arm/4.3.2/bin/arm-linux-ranlib 执行 #make #make install四.编译libid3tag#cd /mp3/libid3tat-0.15.1d#./configure --host=arm-linux CC=arm-linux-gcc --disable-debugging --disable-shared --prefix=/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/lib #make #make install五.编译libmad#cd /mp3/libmad-0.15.1b #./configure --enable-fpm=arm --host=arm-linux --disable-shared --disable-debugging --prefix=/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/lib修改 Makefile 129行 去掉 –fforce-mem #make #make install六.编译madplay#cd /mp3/madplay-0.15.2b #./configure --host=arm-linux CC=arm-linux-gcc --disable-debugging --disable-shared #make 但是,这样得到的是动态连接的。 #rm madplay 拷贝make的最后一个连接的命令,在最后加上-static 和 -lz,然后运行,得到静态连接的程序 如arm-linux-gcc -Wall -O2 -fomit-frame-pointer -o madplay madplay.o getopt.o getopt1.o version.o resample.o filter.o tag.o crc.o rgain.o player.o audio.o audio_aiff.o audio_cdda.o audio_hex.o audio_null.o audio_raw.o audio_snd.o audio_wave.o audio_oss.o -lmad -lid3tag -lm -lz -static最后把madplay下到板子就可以了.
嵌入式mp3播放器
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。