• 嵌入式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.config 4.配置内核: make menuconfig ARCH=arm CROSS_COMPILE=arm-linux- 选择声卡驱动:device drivers-->sound card support-->advanced linux sound architecture-->alsa for soc audio support-->UA134x 5.编译内核: make uImage ARCH=arm CROSS_COMPILE=arm-linux- 内核映像uImage位于arch/arm/boot 将其拷贝到tftpboot目录 6.解压rootfs.tar.gz并拷贝到nfsroot 7.按键驱动移植: cd SDK-MP3/driver make clean;make cp mini2440_buttons.ko /nfroot/rootfs/mp3 8.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: 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/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);
    
                /*去掉文件名最后的'
    '*/
                my_song[len-1]='';
    
                printf("THIS SONG IS %s
    ",my_song);
                execl("/mp3/madplay","madplay",my_song,NULL);
                printf("
    
    
    ");
            }
            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
    ",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 >song_list");
        fd = fopen("song_list","r");
    
        p1 = (struct song *)malloc(sizeof(struct song));
    
        printf("==================================song list=====================================
    ");
        system("ls /mp3/song");    
        printf("
    ");
        printf("================================================================================
    ");
        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===================
    ");
        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===================
    ");
        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=============================
    ");
        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=============================
    ");
        /*从共享内存获得孙子进程播放歌曲的节点指针*/
        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=============================
    ");
        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: 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", 0);
        if (buttons_fd < 0) {
            perror("open device buttons");
            exit(1);
        }
    
    
      /*创建播放列表*/
        head = creat_song_list();
        printf("===================================OPTION=======================================
    
    
    
    ");
        printf("        K1:START/PAUSE     K2:STOP   K3:NEXT      K4:PRIOR
    
    
    
    ");
        printf("================================================================================
    ");
    
    
      /*共享内存:用于存放子进程ID,播放列表位置*/
        if((shmid = shmget(IPC_PRIVATE,5,PERM))== -1)
            exit(1);
        p_addr = shmat(shmid,0,0);
        memset(p_addr,'',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.
    ");
            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
    ");
                    continue;
                } 
                else
                {
                    //printf("buttons_value: %d
    ", 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===================
    ");
                            break;
                        default:
                            printf("=======================PRESS K1 TO START PLAY===================
    ");
                            break;
                        } //end switch
                    }//end if(first_key)
                    /*若不是首次播放,则根据不同键值处理*/
                    else if(!first_key){
                        switch(key_value)
                        {
                        case 0:
                            //printf("play_flag:%d
    ",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
    ");
        key_values = button_irqs->number;
            ev_press = 1;
            wake_up_interruptible(&button_waitq);
        }
       else {
        //printk("falling
    ");
        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
    ");//ykz
    #endif
        printk (DEVICE_NAME"	initialized
    ");
    
        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下到板子就可以了.
  • 相关阅读:
    哈夫曼树
    顺序栈和链栈
    线性表(二) 单链表的增删改查及源码 (修改)
    线性表(二):单链表的增删改查及源码
    线性表(一):顺序表的增删改查及源码
    从头学数据结构--跟随浙大陈越姥姥的步伐
    Java学习笔记--scanner获取键盘输入
    关于方法、变量、类等命名规范
    Java学习笔记--类型自动转换、强制类型转换、溢出
    java学习笔记--重载
  • 原文地址:https://www.cnblogs.com/timssd/p/4101742.html
Copyright © 2020-2023  润新知