微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > ARM技术讨论 > 嵌入式MP3应用程序

嵌入式MP3应用程序

时间:10-02 整理:3721RD 点击:

  1. /*
  2. *     mp3播放器控制程序
  3. *           功能:
  4. *                 k1:播放、暂停
  5. *                 k2:停止播放
  6. *                 k3:上一首
  7. *                 k4:下一首
  8. *     附加:歌曲自动循环播放
  9. */
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <unistd.h>
  13. #include <sys/ioctl.h>
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include <fcntl.h>
  17. #include <signal.h>
  18. #include <sys/select.h>
  19. #include <sys/time.h>
  20. #include <errno.h>
  21. #include <sys/wait.h>
  22. #include <string.h>
  23. #include <sys/ipc.h>
  24. #include <sys/shm.h>

  25. /*共享内存申请标记*/
  26. #define PERM S_IRUSR|S_IWUSR         //定义模式为可读可写                                                                                               

  27. /*双向循环列表:存放歌曲名*/
  28. struct song                               
  29. {
  30.         char songname[20];  //歌名
  31.         struct song *prev;   //
  32.         struct song *next;
  33. };

  34. /*孙子进程id号*/
  35. pid_t gradchild;

  36. /*子进程id号*/
  37. pid_t pid;

  38. /*共享内存描述标记*/
  39. int shmid;

  40. char *p_addr;

  41. /*播放标记*/
  42. int first_key=1;
  43. int play_flag=0;

  44. /*************************************************
  45. Function name: play
  46. Parameter    : struct song *
  47. Description         : 播放函数
  48. Return                 : void
  49. Argument     : void
  50. Autor & date : ada 09,12,07
  51. **************************************************/
  52. void play(struct song *currentsong)
  53. {
  54.         pid_t fd;
  55.         char *c_addr;
  56.         char *p;
  57.         int len;
  58.         char my_song[30]="/mp3/song/";   //存放歌曲的路径
  59.         while(currentsong)
  60.         {
  61.                 /*创建子进程,即孙子进程*/
  62.                 fd = fork();
  63.                 if(fd == -1)  //先判断是否创建成功
  64.                 {       
  65.                         perror("fork");
  66.                         exit(1);
  67.                 }
  68.                 else if(fd == 0)  
  69.                 {
  70.                         /*把歌曲名加上根路径*/
  71.                         strcat(my_song,currentsong->songname);
  72.                         p = my_song;
  73.                         len = strlen(p);

  74.                         /*去掉文件名最后的'\n'*/
  75.                         my_song[len-1]='\0';

  76.                         printf("THIS SONG IS %s\n",my_song);
  77.                         execl("/usr/bin/madplay","madplay",my_song,NULL);  //孙子进程调用execl函数,执行madplay程序
  78.                         printf("\n\n\n");
  79.                 }
  80.                 else
  81.                 {
  82.                         /*内存映射*/
  83.                         c_addr = shmat(shmid,0,0);

  84.                         /*把孙子进程的id和当前播放歌曲的节点指针传入共享内存*/
  85.                         memcpy(c_addr,&fd,sizeof(pid_t));
  86.                         memcpy(c_addr + sizeof(pid_t)+1,¤tsong,4);
  87.                         /*使用wait阻塞孙子进程,直到孙子进程播放完才能被唤醒;
  88.                           当被唤醒时,表示播放MP3期间没有按键按下,则继续顺序播放下一首MP3*/
  89.                         if(fd == wait(NULL))  //等待进程结束
  90.                         {
  91.                                 currentsong = currentsong->next;  //歌曲链表移向下一首歌
  92.                                 printf("THE NEXT SONG IS %s\n",currentsong->songname);
  93.                         }
  94.                 }
  95.         }
  96. }

  97. /*************************************************
  98. Function name: creat_song_list
  99. Parameter    : void
  100. Description         : 创建歌曲名的双向循环链表
  101. Return                 : struct song *
  102. Argument     : void
  103. Autor & date : ada 09.12.07
  104. **************************************************/
  105. struct song *creat_song_list(void)
  106. {       
  107.         FILE *fd;
  108.         size_t size;
  109.         size_t len=0;
  110.         char *line = NULL;
  111.         struct song *head;
  112.         struct song *p1;
  113.         struct song *p2;
  114.         system("ls /mp3/song >song_list");   //重定向生成song_list文件
  115.         fd = fopen("song_list","r");  //打开 song_list文件

  116.         p1 = (struct song *)malloc(sizeof(struct song));

  117.         printf("==================================song list=====================================\n");
  118.         system("ls /mp3/song");        //打印所有歌曲名
  119.         printf("\n");
  120.         printf("================================================================================\n");
  121.         size = getline(&line,&len,fd);//读取一首歌曲名,返回size为歌名字符串的长度 ,size大小由系统malloc

  122.         strncpy(p1->songname,line,strlen(line));//将第一首歌名存入第一个节点
  123.         head = p1;
  124.         while((size = getline(&line,&len,fd)) != -1)//继续看是否有其他歌曲
  125.         {       
  126.                 p2 = p1;   
  127.                 p1 = (struct song *)malloc(sizeof(struct song));  //创建节点空间
  128.                 strncpy(p1->songname,line,strlen(line));  //读取歌曲名
  129.                
  130.                 p2->next = p1;  //前一个节点的next指向下一节点
  131.                 p1->prev = p2;        //后一个节点的prev指向上一个节点
  132.         }
  133.        
  134.         p1->next = head; //尾节点的next指向头节点
  135.         head->prev = p1;  //头节点的prev指向尾节点
  136.        
  137.         //链表创建完成,让p1,p2为空指针
  138.         p1 = NULL;
  139.         p2 = NULL;
  140.        
  141.         system("rm -rf song_list");//把之前重定向生成的文件删除
  142.        
  143.         return head;//返回双向循环链表的头节点的指针
  144. }
  145. /*************************************************
  146. Function name: startplay
  147. Parameter    : pid_t *,struct song *
  148. Description         : 开始播放函数
  149. Return                 : void
  150. Argument     : void
  151. Autor & date : ada 09.12.07
  152. **************************************************/
  153. void startplay(pid_t *childpid,struct song *my_song)
  154. {
  155.         pid_t pid;
  156.         int ret;
  157.         /*创建子进程*/
  158.         pid = fork();

  159.         if(pid > 0)
  160.         {
  161.                 *childpid = pid;
  162.                 play_flag = 1;
  163.                 sleep(1);  //等待一秒,让孙子进程创建和保存
  164.                 /*把孙子进程的pid传给父进程*/
  165.                 memcpy(&gradchild,p_addr,sizeof(pid_t));  //因为使用共享内存,p_addr就是play(my_song)函数中的c_addr
  166.         }
  167.         else if(0 == pid)
  168.         {       
  169.                 /*子进程播放MP3函数*/
  170.                 play(my_song);
  171.         }
  172. }
  173. /*************************************************
  174. Function name: my_pause
  175. Parameter    : pid_t
  176. Description         : 暂停函数
  177. Return                 : void
  178. Argument     : void
  179. Autor & date : ada 09,12,07
  180. **************************************************/
  181. void my_pause(pid_t pid)
  182. {
  183.         printf("=======================PAUSE!PRESS K1 TO CONTINUE===================\n");
  184.         kill(pid,SIGSTOP); //对孙子进程发送SKGSTOP信号
  185.         play_flag = 0;
  186. }

  187. /*************************************************
  188. Function name: my_pause
  189. Parameter    : pid_t
  190. Description         : 停止播放函数
  191. Return                 : void
  192. Argument     : void
  193. Autor & date : ada 09,12,07
  194. **************************************************/
  195. void my_stop(pid_t g_pid)
  196. {

  197.         printf("=======================STOP!PRESS K1 TO START PLAY===================\n");
  198.         kill(g_pid,SIGKILL); //对孙子进程发送SKGKILL信号
  199.         kill(pid,SIGKILL);   //对子进程发送SKGKILL信号
  200.         first_key=1;

  201. }

  202. /*************************************************
  203. Function name: conti_play
  204. Parameter    : pid_t
  205. Description         : 继续函数
  206. Return                 : void
  207. Argument     : void
  208. Autor & date : ada 09,12,07
  209. **************************************************/
  210. void conti_play(pid_t pid)
  211. {
  212.         printf("===============================CONTINUE=============================\n");
  213.         kill(pid,SIGCONT); //对孙子进程发送SIGCONT信号
  214.         play_flag=1;
  215. }

  216. /*************************************************
  217. Function name: next
  218. Parameter    : pid_t
  219. Description         : 下一首函数
  220. Return                 : void
  221. Argument     : void
  222. Autor & date : ada 09.12.07
  223. **************************************************/
  224. void next(pid_t next_pid)
  225. {
  226.         struct song *nextsong;

  227.         printf("===============================NEXT MP3=============================\n");
  228.         /*从共享内存获得孙子进程播放歌曲的节点指针*/
  229.         memcpy(&nextsong,p_addr + sizeof(pid_t)+1,4);
  230.         /*指向下首歌曲的节点*/
  231.         nextsong = nextsong->next;
  232.         /*杀死当前歌曲播放的子进程,孙子进程*/
  233.         kill(pid,SIGKILL);
  234.         kill(next_pid,SIGKILL);
  235.         wait(NULL);
  236.         startplay(&pid,nextsong);
  237. }

  238. /*************************************************
  239. Function name: prev
  240. Parameter    : pid_t
  241. Description         : 上一首函数
  242. Return                 : void
  243. Argument     : void
  244. Autor & date : yuanhui 09.12.08
  245. **************************************************/
  246. void prev(pid_t prev_pid)
  247. {
  248.         struct song *prevsong;
  249.         /*从共享内存获得孙子进程播放歌曲的节点指针*/
  250.         printf("===============================PRIOR MP3=============================\n");
  251.         memcpy(&prevsong,p_addr + sizeof(pid_t)+1,4);
  252.         /*指向上首歌曲的节点*/
  253.         prevsong = prevsong->prev;
  254.         /*杀死当前歌曲播放的子进程,孙子进程*/
  255.         kill(pid,SIGKILL);
  256.         kill(prev_pid,SIGKILL);
  257.         wait(NULL);
  258.         startplay(&pid,prevsong);
  259. }

  260. /*************************************************
  261. Function name: main
  262. Parameter    : void
  263. Description         : 主函数
  264. Return                 : int
  265. Argument     : void
  266. Autor & date : ada 09.12.07
  267. **************************************************/
  268. int main(void)
  269. {
  270.        
  271.      int buttons_fd;//按键设备的文件标识符
  272.      
  273.         char buttons[6] = {'0', '0', '0', '0', '0', '0'};  //初始化六个按键,未按下为'0'
  274.        
  275.    /*打开设备文件*/
  276.         buttons_fd = open("/dev/buttons", 0);  
  277.         if (buttons_fd < 0) {   //判断打开按键设备是否成功
  278.                 perror("open device buttons");
  279.                 exit(1);
  280.         }
  281.         struct song *head;  //定义歌曲链表头节点

  282.   /*创建播放列表*/
  283.         head = creat_song_list();
  284.         printf("===================================OPTION=======================================\n\n\n\n");
  285.         printf("        K1:START/PAUSE     K2:STOP   K3:NEXT      K4:PRIOR\n\n\n\n");
  286.         printf("================================================================================\n");


  287.   /*共享内存:用于存放子进程ID,播放列表位置*/
  288.         if((shmid = shmget(IPC_PRIVATE,5,PERM))== -1)//从内存中获取大小5个字节的共享内存,并判断获取是否成功
  289.                 exit(1);
  290.         p_addr = shmat(shmid,0,0);//映射共享内存的地址到p_addr
  291.         memset(p_addr,'\0',1024);  //把该内存的值全部初始化为'\0'

  292.    for (;;) {
  293.                 char current_buttons[6];  //定义当前按键的值
  294.                 int keys_id;
  295.                 if (read(buttons_fd, current_buttons, sizeof current_buttons) != sizeof current_buttons) {
  296.                         perror("read buttons:");
  297.                         exit(1);
  298.                 }

  299.                 for (keys_id = 0; keys_id < sizeof buttons / sizeof buttons[0]; keys_id++) {
  300.                         if (buttons[keys_id] != current_buttons[keys_id])  //表示有按键按下
  301.                                  {
  302.                                
  303.                                 /*首次播放,必须是按键1*/
  304.                                 if(first_key){
  305.                                         switch(keys_id)
  306.                                         {       
  307.                                         case 0:
  308.                                                 startplay(&pid,head);  //开始播放音乐
  309.                                                 first_key=0;   //按键1已经按下了
  310.                                                 break;
  311.                                         case 1:
  312.                                         case 2:
  313.                                         case 3:
  314.                                                 printf("=======================PRESS K1 TO START PLAY===================\n");
  315.                                                 break;
  316.                                     default:
  317.                                                 printf("=======================PRESS K1 TO START PLAY===================\n");
  318.                                                 break;
  319.                                         }
  320.                                 }
  321.                                 /*若不是首次播放,则根据不同键值处理*/
  322.                                 else if(!first_key){
  323.                                     switch(keys_id)
  324.                                         {
  325.                                         case 0:      //按键1还可以控制歌曲暂停和播放
  326.                                                 if(play_flag)
  327.                                                         my_pause(gradchild);  //暂停
  328.                                                 else
  329.                                                         conti_play(gradchild);//继续播放
  330.                                                 break;
  331.                                         case 1:
  332.                                                 my_stop(gradchild);  //关闭当前播放的歌曲
  333.                                                 break;
  334.                                         case 2:
  335.                                                 next(gradchild);  //播放下一首
  336.                                                 break;
  337.                                         case 3:
  338.                                                 prev(gradchild);  //播放上一首
  339.                                                 break;
  340.                                         }
  341.                          }
  342.                                
  343.                         }
  344.                 }
  345.        
  346.                
  347.                
  348.         }

  349.         close(buttons_fd);  //关闭按键设备文件
  350.         return 0;
  351. }

复制代码


..看了小编的这篇我文章,我再也不害怕指针了  

为什么看了这个代码就不害怕指针呢?

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top