這篇文章的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");
復制代碼
準備工作三:
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
|