嵌入式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);



            /*去掉文件名最后的'\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_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=====================================\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: 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);

    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=======================================\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下到板子就可以了.

 

你可能感兴趣的:(嵌入式)