15

これは私のこれまでで最も悪い質問になります...

古いネットブックに、さらに古いバージョンのDebianをインストールして、少しいじってみました。かなり満足のいく結果の1つは、非常に基本的なMP3プレーヤー(libmpg123を使用)であり、まったく異なることを行う小さなアプリケーションにバックグラウンドミュージックを追加するために統合されました。私はこの小さな解決策がかなり好きになりました。

そのプログラムでは、デコードされたオーディオ(からmpg123_decode())を/dev/audio単純なを介してダンプしましたfwrite()

これはうまくいきました-ネットブックで。

今、私はそれ/dev/audioがOSSによって行われたものであり、新しい(ALSA)マシンではサポートされなくなったことを理解するようになりました。案の定、私のラップトップ(現在のLinux Mintを実行している)にはこのデバイスがありません。

どうやら私は代わりにALSAを使わなければなりません。ウェブを検索して、私はいくつかのチュートリアルを見つけました、そしてそれらは私の心をかなり吹き飛ばします。モード、パラメーター、機能、アクセスタイプ、サンプル形式、サンプルレート、チャネル数、期間数、期間サイズ... ALSAは野心的なAPIであると理解していますが、それは私が探しているものではありません(または時間があります)。私が探しているのは、の出力を再生する方法だけですmpg123_decode(フォーマットは私も知りません。長い目で見ればオーディオオタクではありません)。

誰かが私に何をする必要があるかについていくつかのヒントを与えることができますか?

tl; dr

ALSAに生のオーディオデータを再生させるにはどうすればよいですか?

4

4 に答える 4

4

alsa-ossパッケージにはALSA用のOSS互換性レイヤーがあります。それをインストールし、「aoss」プログラム内でプログラムを実行します。または、ここにリストされているモジュールをmodprobeします。

http://wiki.debian.org/SoundFAQ/#line-105

次に、「/ dev/audio」の代わりに「/dev/dsp」または「/dev/dsp0」を使用するようにプログラムを変更する必要があります。それはあなたが覚えているように機能するはずです...しかし、念のために指を交差させたいかもしれません。

于 2012-07-06T18:39:54.780 に答える
2

ALSAを直接使用することは非常に複雑なので、Gstreamerソリューションがあなたにも問題ないことを願っています。Gstreamerは、ALSA / OSS / Pulseaudio /あなたが名前を付けたものに素晴らしい抽象化を与えます-そして、Linuxの世界に遍在しています。

PCMデータをGstreamerファイルFILEにfwriteできるオブジェクト を開く小さなライブラリを作成しました。実際のコードは100行未満です。

次のように使用します。

FILE *output = fopen_gst(rate, channels, bit_depth); // open audio output file
while (have_more_data) fwrite(data, amount, 1, output); // output audio data
fclose(output); // close the output file

mpg123の例も追加しました。

これがファイル全体です(Githubが廃業した場合に備えて;-)):

/**
 * gstreamer_file.c
 * Copyright  2012  René Kijewski  <rene.SURNAME@fu-berlin.de>
 * License: LGPL 3.0  (http://www.gnu.org/licenses/lgpl-3.0)
 */

#include "gstreamer_file.h"

#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>

#include <glib.h>
#include <gst/gst.h>

#ifndef _GNU_SOURCE
#   error "You need to add -D_GNU_SOURCE to the GCC parameters!"
#endif

/**
 * Cookie passed to the callbacks.
 */
typedef struct {
    /** { file descriptor to read from, fd to write to } */
    int pipefd[2];
    /** Gstreamer pipeline */
    GstElement *pipeline;
} cookie_t;

static ssize_t write_gst(void *cookie_, const char *buf, size_t size) {
    cookie_t *cookie = cookie_;
    return write(cookie->pipefd[1], buf, size);
}

static int close_gst(void *cookie_) {
    cookie_t *cookie = cookie_;
    gst_element_set_state(cookie->pipeline, GST_STATE_NULL); /* we are finished */
    gst_object_unref(GST_OBJECT(cookie->pipeline)); /* we won't access the pipeline anymore */
    close(cookie->pipefd[0]); /* we won't write anymore */
    close(cookie->pipefd[1]); /* we won't read anymore */
    free(cookie); /* dispose the cookie */
    return 0;
}

FILE *fopen_gst(long rate, int channels, int depth) {
    /* initialize Gstreamer */
    if (!gst_is_initialized()) {
        GError *error;
        if (!gst_init_check(NULL, NULL, &error)) {
            g_error_free(error);
            return NULL;
        }
    }

    /* get a cookie */
    cookie_t *cookie = malloc(sizeof(*cookie));
    if (!cookie) {
        return NULL;
    }

    /* open a pipe to be used between the caller and the Gstreamer pipeline */
    if (pipe(cookie->pipefd) != 0) {
        close(cookie->pipefd[0]);
        close(cookie->pipefd[1]);
        free(cookie);
        return NULL;
    }

    /* set up the pipeline */
    char description[256];
    snprintf(description, sizeof(description),
            "fdsrc fd=%d ! " /* read from a file descriptor */
            "audio/x-raw-int, rate=%ld, channels=%d, " /* get PCM data */
                "endianness=1234, width=%d, depth=%d, signed=true ! "
            "audioconvert ! audioresample ! " /* convert/resample if needed */
            "autoaudiosink", /* output to speakers (using ALSA, OSS, Pulseaudio ...) */
            cookie->pipefd[0], rate, channels, depth, depth);
    cookie->pipeline = gst_parse_launch_full(description, NULL,
            GST_PARSE_FLAG_FATAL_ERRORS, NULL);
    if (!cookie->pipeline) {
        close(cookie->pipefd[0]);
        close(cookie->pipefd[1]);
        free(cookie);
        return NULL;
    }

    /* open a FILE with specialized write and close functions */
    cookie_io_functions_t io_funcs = { NULL, write_gst, NULL, close_gst };
    FILE *result = fopencookie(cookie, "w", io_funcs);
    if (!result) {
        close_gst(cookie);
        return NULL;
    }

    /* start the pipeline (of cause it will wait for some data first) */
    gst_element_set_state(cookie->pipeline, GST_STATE_PLAYING);
    return result;
}
于 2012-07-07T05:38:52.113 に答える
2

soxをインストールplayし、正しいサンプルレートとサンプルサイズの引数を使用してコマンドへのパイプを開くことができます。

于 2012-07-06T18:45:54.577 に答える
1

Artefact2のコメント(aplay出力に使用)とkayの回答(pipe()これまで触れたことのないを使用)を組み合わせて、この「最小限の」例を思いつきました。ALSAバージョンの場合、パイプを作成aplayし、適切なパラメーターを使用してプロセスをフォークし、デコードされたオーディオをそれにフィードします。

assert()個々の関数呼び出しに関連付けられたエラーコードを表示するために多くを使用します。もちろん、次のステップは追加ではなく-DNDEBUG(これにより、このプログラムは非常に高速で本当に役に立たなくなります)、アサートを人間が読めるエラーメッセージを含む適切なエラー処理に置き換えます。

// A small example program showing how to decode an MP3 file.

#include <assert.h>
#include <stdlib.h>

#include <mpg123.h>
#include <unistd.h>
#include <fcntl.h>

int main( int argc, char * argv[] )
{
    // buffer and counter for decoded audio data
    size_t OUTSIZE = 65536;
    unsigned char outmem[OUTSIZE];
    size_t outbytes;

    // output file descriptor
    int outfile;

    // handle, return code for mpg123
    mpg123_handle * handle;
    int rc;

    // one command line parameter, being the MP3 filename
    assert( argc == 2 );

#ifdef OSS
    assert( ( outfile = open( "/dev/audio", O_WRONLY ) ) != -1 );
#else // ALSA
    // pipe file descriptors
    int piped[2];

    assert( pipe( piped ) != -1 );

    // fork into decoder (parent) and player (child)
    if ( fork() )
    {
        // player (child)
        assert( dup2( piped[0], 0 ) != -1 ); // make pipe-in the new stdin
        assert( close( piped[1] ) == 0 ); // pipe-out, not needed
        assert( execlp( "aplay", "aplay", "-q", "-r44100", "-c2", "-fS16_LE", "-traw", NULL ) != -1 ); // should not return
    }
    else
    {
        // decoder (parent)
        close( piped[0] ); // pipe-in, not needed
        outfile = piped[1];
    }
#endif

    // initializing
    assert( mpg123_init() == MPG123_OK );
    assert( atexit( mpg123_exit ) == 0 );

    // setting up handle
    assert( ( handle = mpg123_new( NULL, NULL ) ) != NULL );

    // clearing the format list, and setting the one preferred format
    assert( mpg123_format_none( handle ) == MPG123_OK );
    assert( mpg123_format( handle, 44100, MPG123_STEREO, MPG123_ENC_SIGNED_16 ) == MPG123_OK );

    // open input MP3 file
    assert( mpg123_open( handle, argv[1] ) == MPG123_OK );

    // loop over input
    while ( rc != MPG123_DONE )
    {
        rc = mpg123_read( handle, outmem, OUTSIZE, &outbytes );
        assert( rc != MPG123_ERR && rc != MPG123_NEED_MORE );
        assert( write( outfile, outmem, outbytes ) != -1 );
    }

    // cleanup
    assert( close( outfile ) == 0 );
    mpg123_delete( handle );
    return EXIT_SUCCESS;
}

テンプレートとして、これが同様の問題を抱えている他の人に役立つことを願っています。

于 2012-07-07T10:39:47.867 に答える