Vraag ALSA gelijk aan / dev / audio dump?


Dit zal mijn armste vraag ooit zijn ...

Op een oude netbook installeerde ik een nog oudere versie van Debian en speelde ik een beetje rond. Een van de vrij aangename resultaten was een zeer eenvoudige MP3-speler (met behulp van libmpg123), geïntegreerd voor het toevoegen van achtergrondmuziek aan een kleine applicatie die iets geheel anders deed. Ik werd nogal dol op deze kleine oplossing.

In dat programma heb ik de gedecodeerde audio gedumpt (van mpg123_decode()) naar /dev/audio via een eenvoudig fwrite().

Dit werkte prima - op de netbook.

Nu, ik begon dat te begrijpen /dev/audio is iets gedaan door OSS en wordt niet langer ondersteund op nieuwere (ALSA) computers. Zeker, mijn laptop (met een huidige Linux Mint) heeft dit apparaat niet.

Dus blijkbaar moet ik ALSA gebruiken. Ik heb op het web een aantal tutorials gevonden en ze zijn zo goed als gek. Modi, parameters, mogelijkheden, toegangstype, voorbeeldformaat, sample-snelheid, aantal kanalen, aantal perioden, periode-omvang ... Ik begrijp dat ALSA een krachtige API is voor de ambitieuze, maar dat is niet wat ik zoek (of heb de tijd om te grok). Het enige waar ik naar op zoek ben, is hoe de uitvoer van te spelen mpg123_decode (het formaat waarvan ik niet eens weet, dat het niet lang een audio-eend is).

Kan iemand me wat hints geven over wat er moet gebeuren?

tl; Dr.

Hoe krijg ik dat ALSA onbewerkte audiogegevens afspeelt?


12
2017-07-05 15:16


oorsprong


antwoorden:


Er is een OSS-compatibiliteitslaag voor ALSA in het pakket alsa-oss. Installeer het en voer uw programma uit binnen het "aoss" -programma. Of, modprobe de modules die hier worden vermeld:

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

Vervolgens moet je je programma wijzigen om "/ dev / dsp" of "/ dev / dsp0" te gebruiken in plaats van "/ dev / audio". Het zou moeten werken hoe je je herinnerde ... maar misschien wil je je vingers kruisen voor het geval dat.


3
2017-07-06 18:39



Je zou kunnen installeren sox en open een pijp naar de play commando met de juiste samplerate en sample size argumenten.


2
2017-07-06 18:45



ALSA rechtstreeks gebruiken is te ingewikkeld, dus ik hoop dat een Gstreamer-oplossing ook goed voor u is. Gstreamer geeft een mooie abstractie aan ALSA / OSS / Pulseaudio / noem maar op - en is alomtegenwoordig in de Linux-wereld.

Ik heb een kleine bibliotheek geschreven die wordt geopend FILE object waar u PCM-gegevens kunt invoeren in: Gstreamer-bestand. De feitelijke code is minder dan 100 regels.

Gebruik het zo gebruiken:

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

Ik heb er een toegevoegd mpg123 voorbeeldook.

Hier is het hele bestand (voor het geval Github niet werkt ;-)):

/**
 * 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;
}

2
2017-07-07 05:38



Combineer de opmerking van Artefact2 (met aplay voor uitvoer) en het antwoord van Kay (met pipe(), die ik nog niet eerder had aangeraakt), kwam ik met dit "minimale" voorbeeld. Voor de ALSA-versie maakt het een pijp, vorken een aplay verwerken met de juiste parameters en de gedecodeerde audio ernaar sturen.

Veel gebruiken assert() om de foutcodes weer te geven die horen bij de individuele functieaanroepen. De volgende stap is natuurlijk niet het toevoegen van -DNDEBUG(wat dit programma zou maken werkelijk snel en werkelijk nutteloos), maar het vervangen van de beweringen door juiste foutafhandeling inclusief door mensen leesbare foutmeldingen.

// 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;
}

Ik hoop dat dit anderen helpt met soortgelijke problemen, als een sjabloon.


1
2017-07-07 10:39