【问题标题】:Why won't popen communicate with mpg123?popen为什么不能与mpg123通信?
【发布时间】:2015-11-12 18:14:52
【问题描述】:

我正在为我的树莓派编写一个媒体服务器。我能够创建一个使用 popen 通过遥控器控制 omxplayer 的程序。

我现在想控制 mpg123 播放音乐。我采用了在 omxplayer 程序中使用 popen 工作的相同代码并将其应用于 mpg123,但它不起作用。它启动,但不会确认发送给它的任何输入。我不知道为什么一个会工作而另一个不会。

这是我的代码:

void play_music (char *list, int random)
{
    FILE *pp;
    char c;
    char command[501];
    struct stat buf;

    if(access(list, R_OK) == -1)
    {
        fprintf(stderr, "%s: play_music: access failed (%s) (%s)\n", program_name, strerror(errno), list);
        exit(EXIT_FAILURE);
    }

    if(stat(list, &buf) == -1)
    {
        fprintf(stderr, "%s: play_music: stat failed (%s) (%s)\n", program_name, strerror(errno), list);
        exit(EXIT_FAILURE);
    }

    strcpy(command, "/usr/bin/mpg123 -C ");

    if(random == 1)
        strcat(command, "-z ");

    if(S_ISREG(buf.st_mode) == 1)
    {
        strcat(command, "-@ ");
        strcat(command, list);
    }
    else if(S_ISDIR(buf.st_mode) == 1)
    {
        strcat(command, list);

        if(list[strlen(list) - 1] != '*')
        {
            if(list[strlen(list) - 1] != '/')
                strcat(command, "/");

            strcat(command, "*");
        }
    }
    else
    {
        fprintf(stderr, "%s: play_music: stat reported unknown (%s)\n", program_name, list);
        exit(EXIT_FAILURE);
    }

    strcat(command, " > /dev/null 2>&1");

    if((pp = popen(command, "w")) == NULL)
    {
        fprintf(stderr, "%s: play_music popen failed (%s)\n", program_name, strerror(errno));
        exit(EXIT_FAILURE);
    }

    while((c = get_code()))
    {
        if(system("pidof mpg123 > /dev/null") != 0)
            return;

        switch(c)
        {
            case 31:
                fputc('f', pp);
                break;
            case 32:
                fputc('d', pp);
                break;
            case 33:
                fputc('s', pp);
                break;
            case 34:
                fputc('q', pp);
        }

        if(fflush(pp) == EOF)
        {
            fprintf(stderr, "%s: play_music fflush failed (%s)\n", program_name, strerror(errno));
            exit(EXIT_FAILURE);
        }
    }
}

我一直在努力解决这个问题太久了,请有人帮忙!

注意事项:

  • get_code() 是一个工作函数,它根据按下的遥控器按钮返回一个 int。

  • 变量“list”是目录路径或播放列表文件名。

  • 变量 'random' 是一个 int 标志(1 表示随机播放)。

【问题讨论】:

  • 您确定您的 mpg123 使用正确(在 shell 中手动检查)?例如,-@ 选项不应该暗示播放列表是在标准输入上给出的,而不是在文件中?
  • @J.F.Sebastian 是的,用法是正确的。我通过打印 popen 使用的完整命令并在命令行上运行它来测试它。像它应该的那样工作。
  • 您是从键盘输入命令还是使用{ echo -n command; sleep 5; echo -n command; } | mpg123 ..?它是直接从终端读取命令还是从其标准输入读取命令?无关:在 I/O 期间检查错误(fflush() 之后)
  • @J.F.Sebastian 是的,它应该来自键盘,因为我只是剪切并粘贴了它输出的内容。用回声做这件事似乎不起作用。 fflush() 没有报告错误。
  • 阅读第一个原因:Q: Why not just use a pipe (popen())?。找出是否有一个命令行开关会强制mpg123 从标准输入(或其他一些 fd)读取命令。否则,您可能需要自己提供一个伪 tty。 Here's an example in Python that shows how to read output printed to a tty directly (your case is writing)

标签: c linux popen


【解决方案1】:

正如 J.F. Sebastian 在 cmets 中所说,“自己提供一个伪 tty”原来是我需要做的。需要创建一个伪终端来充当来自键盘的输入。

这是修改后的代码:

void play_music (char *playlist, int random)
{
    char c;
    int fdm;
    int fds = 0;
    int x = 0;
    pid_t pid;
    char *flag1 = "/usr/bin/mpg123";
    char *flag2 = "-C";
    char *flag3 = "-z";
    char *flag4 = "-@";
    char *flag5 = TEMP_FILE; // /tmp/temp_playlist.pls
    char *slave_name;
    char *argv[6];
    struct stat buf;

    if(stat(playlist, &buf) == -1)
    {
        fprintf(stderr, "%s: play_music: stat failed (%s) (%s)\n", program_name, strerror(errno), playlist);
        exit(EXIT_FAILURE);
    }

    if((fdm = posix_openpt(O_RDWR)) == -1)
    {
        fprintf(stderr, "%s: posix_openpt failed (%s)\n", program_name, strerror(errno));
        exit(EXIT_FAILURE);
    }

    if(grantpt(fdm) == -1)
    {
        fprintf(stderr, "%s: grantpt failed (%s)\n", program_name, strerror(errno));
        close(fdm);
        exit(EXIT_FAILURE);
    }

    if(unlockpt(fdm) == -1)
    {
        fprintf(stderr, "%s: unlockpt failed (%s)\n", program_name, strerror(errno));
        close(fdm);
        exit(EXIT_FAILURE);
    }

    if((slave_name = ptsname(fdm)) == NULL)
    {
        fprintf(stderr, "%s: ptsname failed\n", program_name);
        close(fdm);
        exit(EXIT_FAILURE);
    }

    if((pid = fork()) == -1)
    {
        fprintf(stderr, "%s: fork failed (%s)\n", program_name, strerror(errno));
        close(fdm);
        exit(EXIT_FAILURE);
    }

    if(pid == 0) // Child
    {
        if(setsid() == -1)
        {
            fprintf(stderr, "%s: setsid failed (%s)\n", program_name, strerror(errno));
            close(fdm);
            exit(EXIT_FAILURE);
        }

        if((fds = open(slave_name, O_RDWR)) == -1)
        {
            fprintf(stderr, "%s: open failed (%s)\n", program_name, strerror(errno));
            close(fdm);
            exit(EXIT_FAILURE);
        }

        if(dup2(fds, STDIN_FILENO) == -1)
        {
            fprintf(stderr, "%s: dup2(1) failed (%s)\n", program_name, strerror(errno));
            close(fdm);
            close(fds);
            exit(EXIT_FAILURE);
        }

        if(dup2(fds, STDOUT_FILENO) == -1)
        {
            fprintf(stderr, "%s: dup2(2) failed (%s)\n", program_name, strerror(errno));
            close(fdm);
            close(fds);
            exit(EXIT_FAILURE);
        }

        if(dup2(fds, STDERR_FILENO) == -1)
        {
            fprintf(stderr, "%s: dup2(3) failed (%s)\n", program_name, strerror(errno));
            close(fdm);
            close(fds);
            exit(EXIT_FAILURE);
        }

        argv[x++] = flag1;
        argv[x++] = flag2;

        if(random == 1)
            argv[x++] = flag3;

        argv[x++] = flag4;

        if(S_ISREG(buf.st_mode) == 1)
            argv[x++] = playlist;
        else if(S_ISDIR(buf.st_mode) == 1)
        {
            if(make_playlist(playlist) == RETURN_FAILURE)
            {
                fprintf(stderr, "%s: play_music: make_playlist failed (%s)\n", program_name, playlist);
                close(fdm);
                close(fds);
                exit(EXIT_FAILURE);
            }

            argv[x++] = flag5;
        }
        else
        {
            fprintf(stderr, "%s: play_music: stat reported unknown (%s)\n", program_name, playlist);
            close(fdm);
            close(fds);
            exit(EXIT_FAILURE);
        }

        argv[x++] = NULL;

        if(execv("/usr/bin/mpg123", argv) == -1)
        {
            fprintf(stderr, "%s: execv failed (%s)\n", program_name, strerror(errno));
            close(fdm);
            close(fds);
            exit(EXIT_FAILURE);
        }
    }
    else // Parent
    {
        while((c = get_code()) != 31)
        {
            switch(c)
            {
                case 30:
                case 19:
                    write(fdm, " ", 1);
                    break;
                case 20: // Up
                    write(fdm, "+", 1);
                    break;
                case 22: // Down
                    write(fdm, "-", 1);
                    break;
                case 21: // Right
                    write(fdm, "f", 1);
                    break;
                case 23: // Left
                    write(fdm, "d", 1);
                    break;
            }
        }

        write(fdm, "q", 1);
        wait(&pid);
        close(fdm);

        if(fds != 0)
            close(fds);
    }

}

【讨论】:

    猜你喜欢
    • 2015-11-19
    • 1970-01-01
    • 2015-09-08
    • 1970-01-01
    • 1970-01-01
    • 2015-11-01
    • 1970-01-01
    • 2013-01-14
    • 1970-01-01
    相关资源
    最近更新 更多