コード例 #1
0
ファイル: SDL_alsa_audio.c プロジェクト: 0-wiz-0/mame
static void
ALSA_PlayDevice(_THIS)
{
    const Uint8 *sample_buf = (const Uint8 *) this->hidden->mixbuf;
    const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
                                this->spec.channels;
    snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t) this->spec.samples);

    swizzle_alsa_channels(this, this->hidden->mixbuf, frames_left);

    while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) {
        int status;

        /* This wait is a work-around for a hang when USB devices are
           unplugged.  Normally it should not result in any waiting,
           but in the case of a USB unplug, it serves as a way to
           join the playback thread after the timeout occurs */
        status = ALSA_snd_pcm_wait(this->hidden->pcm_handle, 1000);
        if (status == 0) {
            /*fprintf(stderr, "ALSA timeout waiting for available buffer space\n");*/
            SDL_OpenedAudioDeviceDisconnected(this);
            return;
        }

        status = ALSA_snd_pcm_writei(this->hidden->pcm_handle,
                                         sample_buf, frames_left);

        if (status < 0) {
            if (status == -EAGAIN) {
                /* Apparently snd_pcm_recover() doesn't handle this case -
                   does it assume snd_pcm_wait() above? */
                SDL_Delay(1);
                continue;
            }
            status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0);
            if (status < 0) {
                /* Hmm, not much we can do - abort */
                fprintf(stderr, "ALSA write failed (unrecoverable): %s\n",
                        ALSA_snd_strerror(status));
                SDL_OpenedAudioDeviceDisconnected(this);
                return;
            }
            continue;
        }
        sample_buf += status * frame_size;
        frames_left -= status;
    }
}
コード例 #2
0
ファイル: SDL_alsa_audio.c プロジェクト: 0-wiz-0/mame
static int
ALSA_CaptureFromDevice(_THIS, void *buffer, int buflen)
{
    Uint8 *sample_buf = (Uint8 *) buffer;
    const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
                                this->spec.channels;
    const int total_frames = buflen / frame_size;
    snd_pcm_uframes_t frames_left = total_frames;

    SDL_assert((buflen % frame_size) == 0);

    while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) {
        /* !!! FIXME: This works, but needs more testing before going live */
        /* ALSA_snd_pcm_wait(this->hidden->pcm_handle, -1); */
        int status = ALSA_snd_pcm_readi(this->hidden->pcm_handle,
                                        sample_buf, frames_left);

        if (status < 0) {
            /*printf("ALSA: capture error %d\n", status);*/
            if (status == -EAGAIN) {
                /* Apparently snd_pcm_recover() doesn't handle this case -
                   does it assume snd_pcm_wait() above? */
                SDL_Delay(1);
                continue;
            }
            status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0);
            if (status < 0) {
                /* Hmm, not much we can do - abort */
                fprintf(stderr, "ALSA read failed (unrecoverable): %s\n",
                        ALSA_snd_strerror(status));
                return -1;
            }
            continue;
        }

        /*printf("ALSA: captured %d bytes\n", status * frame_size);*/
        sample_buf += status * frame_size;
        frames_left -= status;
    }

    swizzle_alsa_channels(this, buffer, total_frames - frames_left);

    return (total_frames - frames_left) * frame_size;
}
コード例 #3
0
ファイル: SDL_alsa_audio.c プロジェクト: AMDmi3/symwars3
static void
ALSA_PlayDevice(_THIS)
{
    int status;
    const Uint8 *sample_buf = (const Uint8 *) this->hidden->mixbuf;
    const int frame_size = (((int) (this->spec.format & 0xFF)) / 8) *
                                this->spec.channels;
    snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t) this->spec.samples);

    swizzle_alsa_channels(this);

    while ( frames_left > 0 && this->enabled ) {
        /* !!! FIXME: This works, but needs more testing before going live */
        /* ALSA_snd_pcm_wait(this->hidden->pcm_handle, -1); */
        status = ALSA_snd_pcm_writei(this->hidden->pcm_handle,
                                     sample_buf, frames_left);

        if (status < 0) {
            if (status == -EAGAIN) {
                /* Apparently snd_pcm_recover() doesn't handle this case -
                   does it assume snd_pcm_wait() above? */
                SDL_Delay(1);
                continue;
            }
            status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0);
            if (status < 0) {
                /* Hmm, not much we can do - abort */
                fprintf(stderr, "ALSA write failed (unrecoverable): %s\n",
                        ALSA_snd_strerror(status));
                this->enabled = 0;
                return;
            }
            continue;
        }
        sample_buf += status * frame_size;
        frames_left -= status;
    }
}
コード例 #4
0
ファイル: SDL_alsa_audio.c プロジェクト: Cpasjuste/SDL-13
static int
ALSA_OpenDevice(_THIS, const char *devname, int iscapture)
{
    int status = 0;
    snd_pcm_t *pcm_handle = NULL;
    snd_pcm_hw_params_t *hwparams = NULL;
    snd_pcm_sw_params_t *swparams = NULL;
    snd_pcm_format_t format = 0;
    snd_pcm_uframes_t frames = 0;
    SDL_AudioFormat test_format = 0;

    /* Initialize all variables that we clean on shutdown */
    this->hidden = (struct SDL_PrivateAudioData *)
        SDL_malloc((sizeof *this->hidden));
    if (this->hidden == NULL) {
        SDL_OutOfMemory();
        return 0;
    }
    SDL_memset(this->hidden, 0, (sizeof *this->hidden));

    /* Open the audio device */
    /* Name of device should depend on # channels in spec */
    status = ALSA_snd_pcm_open(&pcm_handle,
                               get_audio_device(this->spec.channels),
                               SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);

    if (status < 0) {
        ALSA_CloseDevice(this);
        SDL_SetError("ALSA: Couldn't open audio device: %s",
                     ALSA_snd_strerror(status));
        return 0;
    }

    this->hidden->pcm_handle = pcm_handle;

    /* Figure out what the hardware is capable of */
    snd_pcm_hw_params_alloca(&hwparams);
    status = ALSA_snd_pcm_hw_params_any(pcm_handle, hwparams);
    if (status < 0) {
        ALSA_CloseDevice(this);
        SDL_SetError("ALSA: Couldn't get hardware config: %s",
                     ALSA_snd_strerror(status));
        return 0;
    }

    /* SDL only uses interleaved sample output */
    status = ALSA_snd_pcm_hw_params_set_access(pcm_handle, hwparams,
                                               SND_PCM_ACCESS_RW_INTERLEAVED);
    if (status < 0) {
        ALSA_CloseDevice(this);
        SDL_SetError("ALSA: Couldn't set interleaved access: %s",
                     ALSA_snd_strerror(status));
        return 0;
    }

    /* Try for a closest match on audio format */
    status = -1;
    for (test_format = SDL_FirstAudioFormat(this->spec.format);
         test_format && (status < 0);) {
        status = 0;             /* if we can't support a format, it'll become -1. */
        switch (test_format) {
        case AUDIO_U8:
            format = SND_PCM_FORMAT_U8;
            break;
        case AUDIO_S8:
            format = SND_PCM_FORMAT_S8;
            break;
        case AUDIO_S16LSB:
            format = SND_PCM_FORMAT_S16_LE;
            break;
        case AUDIO_S16MSB:
            format = SND_PCM_FORMAT_S16_BE;
            break;
        case AUDIO_U16LSB:
            format = SND_PCM_FORMAT_U16_LE;
            break;
        case AUDIO_U16MSB:
            format = SND_PCM_FORMAT_U16_BE;
            break;
        case AUDIO_S32LSB:
            format = SND_PCM_FORMAT_S32_LE;
            break;
        case AUDIO_S32MSB:
            format = SND_PCM_FORMAT_S32_BE;
            break;
        case AUDIO_F32LSB:
            format = SND_PCM_FORMAT_FLOAT_LE;
            break;
        case AUDIO_F32MSB:
            format = SND_PCM_FORMAT_FLOAT_BE;
            break;
        default:
            status = -1;
            break;
        }
        if (status >= 0) {
            status = ALSA_snd_pcm_hw_params_set_format(pcm_handle,
                                                       hwparams, format);
        }
        if (status < 0) {
            test_format = SDL_NextAudioFormat();
        }
    }
    if (status < 0) {
        ALSA_CloseDevice(this);
        SDL_SetError("ALSA: Couldn't find any hardware audio formats");
        return 0;
    }
    this->spec.format = test_format;

    /* Set the number of channels */
    status = ALSA_snd_pcm_hw_params_set_channels(pcm_handle, hwparams,
                                                 this->spec.channels);
    if (status < 0) {
        status = ALSA_snd_pcm_hw_params_get_channels(hwparams);
        if ((status <= 0) || (status > 2)) {
            ALSA_CloseDevice(this);
            SDL_SetError("ALSA: Couldn't set audio channels");
            return 0;
        }
        this->spec.channels = status;
    }

    /* Set the audio rate */
    status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
                                                  this->spec.freq, NULL);
    if (status < 0) {
        ALSA_CloseDevice(this);
        SDL_SetError("ALSA: Couldn't set audio frequency: %s",
                     ALSA_snd_strerror(status));
        return 0;
    }
    this->spec.freq = status;

    /* Set the buffer size, in samples */
    frames = this->spec.samples;
    frames = ALSA_snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams,
                                                         frames, NULL);
    this->spec.samples = frames;
    ALSA_snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, 2, NULL);

    /* "set" the hardware with the desired parameters */
    status = ALSA_snd_pcm_hw_params(pcm_handle, hwparams);
    if (status < 0) {
        ALSA_CloseDevice(this);
        SDL_SetError("ALSA: Couldn't set hardware audio parameters: %s",
                     ALSA_snd_strerror(status));
        return 0;
    }
#if AUDIO_DEBUG
    {
        snd_pcm_sframes_t bufsize;
        int fragments;
        bufsize = ALSA_snd_pcm_hw_params_get_period_size(hwparams);
        fragments = ALSA_snd_pcm_hw_params_get_periods(hwparams);
        fprintf(stderr, "ALSA: bufsize = %ld, fragments = %d\n", bufsize,
                fragments);
    }
#endif

    /* Set the software parameters */
    snd_pcm_sw_params_alloca(&swparams);
    status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams);
    if (status < 0) {
        ALSA_CloseDevice(this);
        SDL_SetError("ALSA: Couldn't get software config: %s",
                     ALSA_snd_strerror(status));
        return 0;
    }
    status =
        ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, 0);
    if (status < 0) {
        ALSA_CloseDevice(this);
        SDL_SetError("ALSA: Couldn't set start threshold: %s",
                     ALSA_snd_strerror(status));
        return 0;
    }
    status =
        ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, frames);
    if (status < 0) {
        ALSA_CloseDevice(this);
        SDL_SetError("Couldn't set avail min: %s", ALSA_snd_strerror(status));
        return 0;
    }
    status = ALSA_snd_pcm_sw_params(pcm_handle, swparams);
    if (status < 0) {
        ALSA_CloseDevice(this);
        SDL_SetError("Couldn't set software audio parameters: %s",
                     ALSA_snd_strerror(status));
        return 0;
    }

    /* Calculate the final parameters for this audio specification */
    SDL_CalculateAudioSpec(&this->spec);

    /* Allocate mixing buffer */
    this->hidden->mixlen = this->spec.size;
    this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
    if (this->hidden->mixbuf == NULL) {
        ALSA_CloseDevice(this);
        SDL_OutOfMemory();
        return 0;
    }
    SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);

    /* Get the parent process id (we're the parent of the audio thread) */
    this->hidden->parent = getpid();

    /* Switch to blocking mode for playback */
    ALSA_snd_pcm_nonblock(pcm_handle, 0);

    /* We're ready to rock and roll. :-) */
    return 1;
}