首页 > 代码库 > 嵌入式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,&currentsong,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播放器