#include "mainwindow.h" #include "ui_mainwindow.h" #include int mplayer_pid; pthread_t t1,t2; // void *getTimerThreadFunc(void *arg); // 发送获取当前时间的 mplayer 命令 void *readPipeMSG(void *arg); // 获取当前时间的线程 MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); initMainWindow(); // 初始化主界面 mplayerInit(); // 初始化 mplayer kill(mplayer_pid,SIGSTOP); scanSong(); // 扫描歌曲列表 setSongList(); // 将扫描的歌曲显示到歌曲列表中 // 捕获当前时间信号 connect(this, SIGNAL(currentTimeSignal(int)), this, SLOT(setCurrentTimeLabel(int))); // 建立滑块修改信号通讯 connect(this, SIGNAL(currentProgressSignal(int)), this, SLOT(setCurrentSlider(int))); } MainWindow::~MainWindow() { if(mplayer_pid != 0) kill(mplayer_pid,SIGKILL); delete ui; } void MainWindow::initMainWindow() { // 设置主窗体属性 setWindowTitle("音乐播放器"); setWindowIcon(QIcon(":/icon/button")); // 设置子组件背景透明 ui->song_list_widget->setAttribute(Qt::WA_TranslucentBackground); ui->label_artist->setAttribute(Qt::WA_TranslucentBackground); ui->label_song_list->setAttribute(Qt::WA_TranslucentBackground); ui->label_song_name->setAttribute(Qt::WA_TranslucentBackground); ui->label_meta_album->setAttribute(Qt::WA_TranslucentBackground); ui->contrl_widget->setAttribute(Qt::WA_TranslucentBackground); ui->widget_show->setAttribute(Qt::WA_TranslucentBackground); ui->volume_widget->setAttribute(Qt::WA_TranslucentBackground); ui->widget_3->setAttribute(Qt::WA_TranslucentBackground); ui->time_left_label->setAttribute(Qt::WA_TranslucentBackground); ui->time_right_label->setAttribute(Qt::WA_TranslucentBackground); ui->time_widget->setAttribute(Qt::WA_TranslucentBackground); // 设置滑块属性 ui->time_slider->setStyleSheet("QSlider::groove:horizontal { background-color: white; }" "QSlider::handle:horizontal { background-color: blue; width: 20px;}"); ui->volume_slider->setStyleSheet("QSlider::groove:horizontal { background-color: gray; }" "QSlider::handle:horizontal { background-color: yellow; width: 20px;}"); ui->volume_slider->setMinimum(0); // 最小音量 0 ui->volume_slider->setMaximum(100); // 最大音量 100 // 当前音量从 mplayer 属性获取 // QSlider* slider = new QSlider(Qt::Horizontal); // slider->setMinimum(0); // 设置最小值 // slider->setMaximum(100); // 设置最大值 // slider->setValue(50); // 设置当前值 // slider->setSingleStep(1); // 设置步长 } void MainWindow::mplayerInit() { // 创建一个无名管道 pipe(fd); // 创建有名管道 mkfifo("fifo_cmd", 0666); // 创建 子进程启动 mplayer pid_t pid = fork(); if(pid == 0) // 子进程 { // 重定向标准输出 dup2(fd[1], 1); // 使用 exec 启动 mplayer // execlp("mplayer","mplayer","-idle","-slave","-quiet","/home/flykhan/qtmplayer/song/StopLove.mp3",NULL); execlp("/usr/bin/mplayer","mplayer","-idle","-slave","-quiet","-input","file=fifo_cmd","/home/flykhan/qtmplayer/song/Diamonds.mp3",NULL); _exit(-1); // 异常退出 } else if(pid>0) // 父进程 { mplayer_pid = pid; pthread_create(&t1,NULL,getTimerThreadFunc,this); pthread_create(&t2,NULL,readPipeMSG,this); // pthread_detach(t1); // pthread_detach(t2); // 打开管道 // 以写的方式打开(阻塞到某进程 以读的方式打开) fifo_fd = open("fifo_cmd", O_WRONLY); if(fifo_fd < 0){ perror("open"); // return 0; _exit(0); // 管道打开失败直接返回 } } } void MainWindow::scanSong() { // 1. 得到目录句柄 DIR *dir = opendir("/home/flykhan/qtmplayer/song"); if(NULL == dir) { perror("opendir"); _exit(0); // 目录为空返回 } // 2. 根据目录句柄扫描当前文件 while(1) { // 读取文件目录 struct dirent *dirent = readdir(dir); if(NULL==dirent) break; // 判断类型为 DT_REG->文件类型 if(dirent->d_type == DT_REG) { // 如果扫描到的文件名包含 ".mp3",则将该文件名添加到向量数组中 if(strstr(dirent->d_name, ".mp3") != NULL) { vectorSong.push_back(string(dirent->d_name)); } } } // 关闭目录句柄 closedir(dir); } void MainWindow::playNextSong() { index++; if(index == vectorSong.size()) index = 0; // 当索引到达歌曲最后一个时,将索引置为 0 ,循环索引 char changeSongBuf[128] = ""; // 将 loadfile 'song_name_path' 写入字符数组 int len = sprintf(changeSongBuf, "loadfile /home/flykhan/qtmplayer/song/%s\n", vectorSong[index].c_str()); // int len = sprintf(changeSongBuf, "loadfile ./song/%s\n", vectorSong[index].c_str()); qDebug() << changeSongBuf << endl; // 控制台打印下一首歌的名字 // write(this->fifo_fd, changeSongBuf.toUtf8().toStdString().c_str(),changeSongBuf.toUtf8().toStdString().size()); write(this->fifo_fd, changeSongBuf, len); // 将获取的下一首歌曲名写入到有名管道中 } void MainWindow::playLastSong() { index--; if(index == -1) index = vectorSong.size() - 1; // 当索引到达歌曲 0 时,将索引置为最后一个歌曲,循环索引 char changeSongBuf[128] = ""; // 将 loadfile 'song_name_path' 写入字符数组 int len = sprintf(changeSongBuf, "loadfile /home/flykhan/qtmplayer/song/%s\n", vectorSong[index].c_str()); // int len = sprintf(changeSongBuf, "loadfile ./song/%s\n", vectorSong[index].c_str()); qDebug() << changeSongBuf << endl; // 控制台打印下一首歌的名字 // write(this->fifo_fd, changeSongBuf.toUtf8().toStdString().c_str(),changeSongBuf.toUtf8().toStdString().size()); write(this->fifo_fd, changeSongBuf, len); // 将获取的下一首歌曲名写入到有名管道中 } void MainWindow::setCurrentTimeLabel(int time) { int m = 0, s = 0; m = time / 60; // 算分钟 s = time % 60; // 算秒钟 char buf[32] = ""; sprintf(buf,"%02d:%02d",m,s); // 将歌曲当前时间设置到 label ui->time_left_label->setText(QString(buf)); } void MainWindow::setCurrentSlider(int currentProgress) { // 设置时间滑动条状态 ui->time_slider->setValue(currentProgress); } void *getTimerThreadFunc(void *arg) { MainWindow *p = (MainWindow *)arg; while (1) { // 发送获取的当前时间的命令 // 发送 get_time_pos 命令到管道中 write(p->fifo_fd, "get_time_pos\n", strlen("get_time_pos\n")); // usleep(500*1000); // 休眠 0.5 秒 // 发送获取当前歌曲进度的命令 write(p->fifo_fd,"get_percent_pos\n",strlen("get_percent_pos\n")); usleep(500*1000); // 休眠 0.5 秒 // // 发送获取的当前歌曲元数据信息的命令 // // 发送获取当前歌曲长度的命令 ANS_LENGTH // write(p->fifo_fd, "get_time_length\n", strlen("get_time_length\n")); // usleep(125*1000); // // 发送获取当前歌曲名的命令 ANS_META_TITLE // write(p->fifo_fd, "get_file_name\n", strlen("get_file_name\n")); // usleep(125*1000); // // 发送获取当前歌曲歌手的命令 ANS_META_ARTIST // write(p->fifo_fd, "get_meta_artist\n", strlen("get_meta_artist\n")); // usleep(125*1000); // // 发送获取当前歌曲专辑的命令 ANS_META_ALBU // write(p->fifo_fd, "get_meta_album\n", strlen("get_meta_album\n")); // usleep(125*1000); } } void *readPipeMSG(void *arg) { MainWindow *p = (MainWindow *)arg; // 不停的获取无名管道的数据 while (1) { char buf[256] = ""; int ret = read(p->fd[0], buf, sizeof(buf)); // 从无名管道读取内容到 buf if(ret > 0) { // 判断消息的类型 : // 如果消息是 "当前歌曲播放时间位置" if(strncmp(buf,"ANS_TIME_POSITION",strlen("ANS_TIME_POSITION")) == 0) { int time = 0; sscanf(buf,"ANS_TIME_POSITION=%d",&time); // 从数据流 buf 中读取时间到 time // 给 UI 发送当前时间信号 emit p->currentTimeSignal(time); } // 如果消息是 "当前歌曲播放进度" else if(strncmp(buf,"ANS_PERCENT_POSITION", strlen("ANS_PERCENT_POSITION")) == 0) { int currentProgress = 0; sscanf(buf, "ANS_PERCENT_POSITION=%d", ¤tProgress); // 给 UI 发送进度信号 emit p->currentProgressSignal(currentProgress); } // // 如果消息是 "当前歌曲元数据信息" // else if(strncmp(buf,"ANS_LENGTH", strlen("ANS_LENGTH")) == 0) // { // int currentProgress = 0; // sscanf(buf, "ANS_LENGTH=%d", ¤tProgress); // // 给 UI 发送进度信号 // emit p->currentProgressSignal(currentProgress); // } } } } void MainWindow::setSongList() { // 将 vector 内容转存入 QStringList QStringList strList; for(vector::const_iterator it = vectorSong.begin(); it != vectorSong.end(); ++it) { strList.append(QString::fromStdString(*it)); } ui->song_list_widget->addItems(strList); // ui->song_list_widget->setCurrentRow(2); } void MainWindow::on_play_btn_clicked() { if(play_btn_flag == 0) { ui->play_btn->setIcon(QIcon(":/icon/button_play")); kill(mplayer_pid,SIGCONT); play_btn_flag = 1; } else if (play_btn_flag == 1) { ui->play_btn->setIcon(QIcon(":/icon/button")); kill(mplayer_pid,SIGSTOP); play_btn_flag = 0; } } void MainWindow::on_back_btn_clicked() { playLastSong(); } void MainWindow::on_front_btn_clicked() { playNextSong(); // 切换下一首歌 } void MainWindow::player_rewind_or_forward(int seconds) { char changeSongBuf[128] = ""; int len = sprintf(changeSongBuf, "seek %d\n", seconds); // 快进快退 seconds 秒 (seconds 为正->进,为负->退) write(this->fifo_fd, changeSongBuf, len); // 将快进快退指令写入到有名管道中 } void MainWindow::volume_control(int value) { char changeSongBuf[128] = ""; int len = sprintf(changeSongBuf, "volume %d\n", value); // 音量调整到 value 大小 write(this->fifo_fd, changeSongBuf, len); // 将音量控制指令写入到有名管道中 } void MainWindow::volume_mute_switch(int mute_arg) { char changeSongBuf[128] = ""; int len = sprintf(changeSongBuf, "mute %d\n", mute_arg); // mute_arg 静音开关参数 (1->静音,0->取消静音) write(this->fifo_fd, changeSongBuf, len); // 将静音控制指令写入到有名管道中 } void MainWindow::on_last_btn_clicked() { player_rewind_or_forward(-10); // 快退 10 秒 } void MainWindow::on_next_btn_clicked() { player_rewind_or_forward(10); // 快退 10 秒 } void MainWindow::on_mute_btn_clicked() { if(mute_flag == 0) // 没静音则按下后设置静音 { ui->mute_btn->setIcon(QIcon(":/icon/mute1")); // volume_mute_switch(1); // mute_flag = 1; volume_mute_switch(++mute_flag); } else if (mute_flag == 1) // 已静音则按下后取消静音 { ui->mute_btn->setIcon(QIcon(":/icon/mute2")); volume_mute_switch(--mute_flag); } } void MainWindow::on_volume_down_btn_clicked() { volume_control(-10); // 减 10 音量 } void MainWindow::on_volume_up_btn_clicked() { volume_control(10); // 加 10 音量 }