Пример #1
0
void audio_output::data(const audio_blob &blob)
{
    assert(blob.data);
    ALenum format = get_al_format(blob);
    msg::dbg(std::string("Buffering ") + str::from(blob.size) + " bytes of audio data.");
    if (_state == 0)
    {
        set_source_parameters();
        // Initial buffering
        assert(blob.size == _num_buffers * _buffer_size);
        char *data = static_cast<char *>(blob.data);
        for (size_t j = 0; j < _num_buffers; j++)
        {
            _buffer_channels.push_back(blob.channels);
            _buffer_sample_bits.push_back(blob.sample_bits());
            _buffer_rates.push_back(blob.rate);
            alBufferData(_buffers[j], format, data, _buffer_size, blob.rate);
            alSourceQueueBuffers(_source, 1, &(_buffers[j]));
            data += _buffer_size;
        }
        if (alGetError() != AL_NO_ERROR)
        {
            throw exc(_("Cannot buffer initial OpenAL data."));
        }
    }
    else if (blob.size > 0)
    {
        // Replace one buffer
        assert(blob.size == _buffer_size);
        ALuint buf = 0;
        alSourceUnqueueBuffers(_source, 1, &buf);
        assert(buf != 0);
        alBufferData(buf, format, blob.data, _buffer_size, blob.rate);
        alSourceQueueBuffers(_source, 1, &buf);
        if (alGetError() != AL_NO_ERROR)
        {
            throw exc(_("Cannot buffer OpenAL data."));
        }
        // Update the time spent on all past buffers
        int64_t current_buffer_samples = _buffer_size / _buffer_channels[0] * 8 / _buffer_sample_bits[0];
        int64_t current_buffer_time = current_buffer_samples * 1000000 / _buffer_rates[0];
        _past_time += current_buffer_time;
        // Remove current buffer entries
        _buffer_channels.erase(_buffer_channels.begin());
        _buffer_sample_bits.erase(_buffer_sample_bits.begin());
        _buffer_rates.erase(_buffer_rates.begin());
        // Add entries for the new buffer
        _buffer_channels.push_back(blob.channels);
        _buffer_sample_bits.push_back(blob.sample_bits());
        _buffer_rates.push_back(blob.rate);
    }
}
Пример #2
0
static int init(struct ao *ao)
{
    float position[3] = {0, 0, 0};
    float direction[6] = {0, 0, -1, 0, 1, 0};
    ALCdevice *dev = NULL;
    ALCcontext *ctx = NULL;
    ALCint freq = 0;
    ALCint attribs[] = {ALC_FREQUENCY, ao->samplerate, 0, 0};
    int i;
    struct priv *p = ao->priv;
    if (ao_data) {
        MP_FATAL(ao, "Not reentrant!\n");
        return -1;
    }
    ao_data = ao;
    struct mp_chmap_sel sel = {0};
    for (i = 0; speaker_pos[i].id != -1; i++)
        mp_chmap_sel_add_speaker(&sel, speaker_pos[i].id);
    if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
        goto err_out;
    struct speaker speakers[MAX_CHANS];
    for (i = 0; i < ao->channels.num; i++) {
        speakers[i].id = -1;
        for (int n = 0; speaker_pos[n].id >= 0; n++) {
            if (speaker_pos[n].id == ao->channels.speaker[i])
                speakers[i] = speaker_pos[n];
        }
        if (speakers[i].id < 0) {
            MP_FATAL(ao, "Unknown channel layout\n");
            goto err_out;
        }
    }
    char *dev_name = ao->device;
    dev = alcOpenDevice(dev_name && dev_name[0] ? dev_name : NULL);
    if (!dev) {
        MP_FATAL(ao, "could not open device\n");
        goto err_out;
    }
    ctx = alcCreateContext(dev, attribs);
    alcMakeContextCurrent(ctx);
    alListenerfv(AL_POSITION, position);
    alListenerfv(AL_ORIENTATION, direction);
    alGenSources(ao->channels.num, sources);
    for (i = 0; i < ao->channels.num; i++) {
        cur_buf[i] = 0;
        unqueue_buf[i] = 0;
        alGenBuffers(NUM_BUF, buffers[i]);
        alSourcefv(sources[i], AL_POSITION, speakers[i].pos);
        alSource3f(sources[i], AL_VELOCITY, 0, 0, 0);
    }
    alcGetIntegerv(dev, ALC_FREQUENCY, 1, &freq);
    if (alcGetError(dev) == ALC_NO_ERROR && freq)
        ao->samplerate = freq;

    p->al_format = AL_FALSE;
    int try_formats[AF_FORMAT_COUNT];
    af_get_best_sample_formats(ao->format, try_formats);
    for (int n = 0; try_formats[n]; n++) {
        p->al_format = get_al_format(try_formats[n]);
        if (p->al_format != AL_FALSE) {
            ao->format = try_formats[n];
            break;
        }
    }

    if (p->al_format == AL_FALSE) {
        MP_FATAL(ao, "Can't find appropriate sample format.\n");
        uninit(ao);
        goto err_out;
    }

    p->chunk_size = CHUNK_SAMPLES * af_fmt_to_bytes(ao->format);
    return 0;

err_out:
    ao_data = NULL;
    return -1;
}