为madplay编写应用程序

这篇文章的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






你可能感兴趣的:(为madplay编写应用程序)