0

キーを入力すると、そのキーのASCII値に対応するFSK変調オーディオ信号を出力するように、基本的にモデムキーボードになることを意図したオペレーティングシステムプロジェクトのプログラムを書いています。私がプログラムをどのように設定したかというと、プロセスを fork し、minimodem と呼ばれるプログラムを実行します (詳細については、こちらを参照してください)。親は非正規入力モードに設定され、ユーザー入力を一度に 1 文字取得します。次に、各文字がパイプ経由で子に送信されます。今すぐコードを貼り付けます:

#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <string.h>
#include <termios.h>

extern char* program_invocation_short_name;

static struct termios old, new;
void init_termios(int echo);
void reset_termios(void);
int main(int argc, char* argv[])
{
pid_t pid;
int my_pipe[2];

char* baud = "300";
if (argc == 2) {
    if(atoi(argv[1]) == 0) {
        printf("Use: %s [baud]\n",program_invocation_short_name);
        return EXIT_SUCCESS;
    }
    baud = argv[1];
}

if (argc > 2) {
    printf("Too many arguments.\nUsage: %s [baud]\n",program_invocation_short_name);
    return EXIT_SUCCESS;
}

if (pipe(my_pipe) == -1) {
    fprintf(stderr, "%s: %s",program_invocation_short_name,strerror(errno));
    return EXIT_FAILURE;
}

pid = fork();
if (pid < (pid_t) 0) {
    fprintf(stderr, "%s: %s",program_invocation_short_name,strerror(errno));
    return EXIT_FAILURE;
}else if (pid == (pid_t) 0) {
    /***************/
    /*CHILD PROCESS*/
    /***************/
    close(my_pipe[1]); /*Child doesn't write*/
    dup2(my_pipe[0], 0); /*Redirect stdin to read side of pipe*/
    close(my_pipe[0]); /*Close read end as it's dup'd*/
    execl("/usr/local/bin/minimodem","minimodem","--tx", baud,"-q","-A",NULL);

    fprintf(stderr, "%s: %s",program_invocation_short_name,strerror(errno));
}else if (pid > (pid_t) 0) {
    /****************/
    /*PARENT PROCESS*/
    /****************/
    char c;
    close(my_pipe[0]); /*Parent doesn't read*/
    init_termios(1);
    atexit(reset_termios);

    while(1) {
        c = getchar();
        if (c == 0x03)
            break;
        if (write(my_pipe[1], &c, 1) == -1) {
            fprintf(stderr, "%s: %s",
                    program_invocation_short_name, strerror(errno));
            return EXIT_FAILURE;
        }
    }
    close(my_pipe[1]);
}
return EXIT_SUCCESS;
}

void init_termios(int echo)
{
    tcgetattr(0, &old); /*get old terminal i/o settings*/
    new = old; /*make new  settings same as old settings */
    new.c_lflag &= ~ICANON;
    new.c_lflag &= echo ? ECHO : ~ECHO; /*set appropriate echo mode*/
    tcsetattr(0, TCSANOW, &new); /*use new terminal i/o settings*/
}

void reset_termios(void)
{
    tcsetattr(0, TCSANOW, &old);
}

私の問題は、ユーザー入力にあります。入力すると、最初の文字が書き込まれ、オーディオが生成されたように見えます。その後、遅延が発生し、バッファ内の残りの文字が意図したとおりに継続的に生成されます。タイピングに十分な一時停止がある場合は、ブレーク後に入力された最初の文字が生成され、その後遅延が発生し、その後に意図された機能が生成される開始点に戻ります。これは、ミニモデム プログラムがこのように使用されるように作成されていないためではなく、この問題を克服できることを確信しています。誰かがこの問題に光を当てることができれば、私はすっごくうれしいです. ありがとう。

注:入力をリングバッファに入れてから、その入力を消費して別のスレッドで子に送信しようとしました。いいえ、良くありません。これが生産的だったかどうかさえわかりません。

4

1 に答える 1

0

Minimodem will write 0.5 seconds of silence when it detects that there isn't enough input data to keep the audio buffer full. This is an attempt to make sure that whatever audio it does write comes out continuously. It is typically the case with audio drivers or servers (like pulseaudio) that audio is only written in chunks. When you write less than a full chunk of data to the audio buffer, the card produces no sound, since the driver or the server is waiting for enough audio data so that it can write a full chunk at once. Since the data that minimodem writes is generally not going to match full chunks of audio, you have a situation where the last part of the audio data won't get written. To avoid this problem, minimodem writes enough silence to guarantee that the last part of the audio gets output to the card.

For example, let's say the audio driver or server writes in 1000 byte chunks. Now let's say that you type one character, and that produces 2500 bytes of audio data. The audio driver or server will cause 2000 bytes of data to be played and 500 bytes will be left in the buffer. Since a modem protocol requires continuous audio, it doesn't make any sense to just leave those 500 bytes of audio data in the buffer. The receiver wouldn't see a complete character. The receiver would then have to assume tha audio was garbled and discard the character.

So, to avoid this, minimodem will write 0.5 seconds of silence, which is probably thousands of bytes of audio data. This will guarantee that the 500 bytes of audio data that are left in the buffer get played, since there will certainly be enough audio data to finish out that chunk.

Now it is true that there will likely be some extra silence in the buffer, and that won't get played immediately, but that's not a big deal, since that won't cause any corruption. The receiver can handle varying amounts of silence between the data (note that this specific to how minimodem works, a real model would always be generating sound).

Minimodem could be improved by having it set the chunk size manually. This way, it would know exactly how much silence needs to be written to flush the audio instead of writing an arbitrary amount, so the delay could be reduced to a minimum.

于 2013-10-06T16:43:26.627 に答える