Ejemplo n.º 1
0
FORCE_ALIGN static int PlaybackThreadProc(void *arg)
{
    ALCdevice *Device = (ALCdevice*)arg;
    WinMMData *data = Device->ExtraData;
    WAVEHDR *WaveHdr;
    MSG msg;

    SetRTPriority();
    althrd_setname(althrd_current(), MIXER_THREAD_NAME);

    while(GetMessage(&msg, NULL, 0, 0))
    {
        if(msg.message != WOM_DONE)
            continue;

        if(data->killNow)
        {
            if(ReadRef(&data->WaveBuffersCommitted) == 0)
                break;
            continue;
        }

        WaveHdr = ((WAVEHDR*)msg.lParam);
        aluMixData(Device, WaveHdr->lpData, WaveHdr->dwBufferLength /
                   data->Format.nBlockAlign);

        // Send buffer back to play more data
        waveOutWrite(data->WaveHandle.Out, WaveHdr, sizeof(WAVEHDR));
        IncrementRef(&data->WaveBuffersCommitted);
    }

    return 0;
}
Ejemplo n.º 2
0
static int CaptureThreadProc(void *arg)
{
    ALCdevice *Device = (ALCdevice*)arg;
    WinMMData *data = Device->ExtraData;
    WAVEHDR *WaveHdr;
    MSG msg;

    althrd_setname(althrd_current(), "alsoft-record");

    while(GetMessage(&msg, NULL, 0, 0))
    {
        if(msg.message != WIM_DATA)
            continue;
        /* Don't wait for other buffers to finish before quitting. We're
         * closing so we don't need them. */
        if(data->killNow)
            break;

        WaveHdr = ((WAVEHDR*)msg.lParam);
        WriteRingBuffer(data->Ring, (ALubyte*)WaveHdr->lpData,
                        WaveHdr->dwBytesRecorded/data->Format.nBlockAlign);

        // Send buffer back to capture more data
        waveInAddBuffer(data->WaveHandle.In, WaveHdr, sizeof(WAVEHDR));
        IncrementRef(&data->WaveBuffersCommitted);
    }

    return 0;
}
Ejemplo n.º 3
0
static int ALCwinmmCapture_captureProc(void *arg)
{
    ALCwinmmCapture *self = arg;
    WAVEHDR *WaveHdr;
    MSG msg;

    althrd_setname(althrd_current(), RECORD_THREAD_NAME);

    while(GetMessage(&msg, NULL, 0, 0))
    {
        if(msg.message != WIM_DATA)
            continue;
        /* Don't wait for other buffers to finish before quitting. We're
         * closing so we don't need them. */
        if(ATOMIC_LOAD(&self->killNow, almemory_order_acquire))
            break;

        WaveHdr = ((WAVEHDR*)msg.lParam);
        ll_ringbuffer_write(self->Ring, WaveHdr->lpData,
            WaveHdr->dwBytesRecorded / self->Format.nBlockAlign
        );

        // Send buffer back to capture more data
        waveInAddBuffer(self->InHdl, WaveHdr, sizeof(WAVEHDR));
        IncrementRef(&self->WaveBuffersCommitted);
    }

    return 0;
}
Ejemplo n.º 4
0
FORCE_ALIGN static int ALCwinmmPlayback_mixerProc(void *arg)
{
    ALCwinmmPlayback *self = arg;
    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
    WAVEHDR *WaveHdr;
    MSG msg;

    SetRTPriority();
    althrd_setname(althrd_current(), MIXER_THREAD_NAME);

    while(GetMessage(&msg, NULL, 0, 0))
    {
        if(msg.message != WOM_DONE)
            continue;

        if(ATOMIC_LOAD(&self->killNow, almemory_order_acquire))
        {
            if(ReadRef(&self->WaveBuffersCommitted) == 0)
                break;
            continue;
        }

        WaveHdr = ((WAVEHDR*)msg.lParam);
        ALCwinmmPlayback_lock(self);
        aluMixData(device, WaveHdr->lpData, WaveHdr->dwBufferLength /
                                            self->Format.nBlockAlign);
        ALCwinmmPlayback_unlock(self);

        // Send buffer back to play more data
        waveOutWrite(self->OutHdl, WaveHdr, sizeof(WAVEHDR));
        IncrementRef(&self->WaveBuffersCommitted);
    }

    return 0;
}
Ejemplo n.º 5
0
static int ALCnullBackend_mixerProc(void *ptr)
{
    ALCnullBackend *self = (ALCnullBackend*)ptr;
    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
    struct timespec now, start;
    ALuint64 avail, done;
    const long restTime = (long)((ALuint64)device->UpdateSize * 1000000000 /
                                 device->Frequency / 2);

    SetRTPriority();
    althrd_setname(althrd_current(), MIXER_THREAD_NAME);

    done = 0;
    if(altimespec_get(&start, AL_TIME_UTC) != AL_TIME_UTC)
    {
        ERR("Failed to get starting time\n");
        return 1;
    }
    while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) &&
          ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
    {
        if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC)
        {
            ERR("Failed to get current time\n");
            return 1;
        }

        avail  = (now.tv_sec - start.tv_sec) * device->Frequency;
        avail += (ALint64)(now.tv_nsec - start.tv_nsec) * device->Frequency / 1000000000;
        if(avail < done)
        {
            /* Oops, time skipped backwards. Reset the number of samples done
             * with one update available since we (likely) just came back from
             * sleeping. */
            done = avail - device->UpdateSize;
        }

        if(avail-done < device->UpdateSize)
            al_nssleep(restTime);
        else while(avail-done >= device->UpdateSize)
        {
            ALCnullBackend_lock(self);
            aluMixData(device, NULL, device->UpdateSize);
            ALCnullBackend_unlock(self);
            done += device->UpdateSize;
        }
    }

    return 0;
}
Ejemplo n.º 6
0
void althrd_setname(althrd_t thr, const char *name)
{
#if defined(HAVE_PTHREAD_SETNAME_NP)
#if defined(__GNUC__)
    pthread_setname_np(thr, name);
#elif defined(__APPLE__)
    if(althrd_equal(thr, althrd_current())
        pthread_setname_np(name);
#endif
#elif defined(HAVE_PTHREAD_SET_NAME_NP)
    pthread_set_name_np(thr, name);
#else
    (void)thr;
    (void)name;
#endif
}
Ejemplo n.º 7
0
void althrd_setname(althrd_t thr, const char *name)
{
#if defined(HAVE_PTHREAD_SETNAME_NP)
#if defined(PTHREAD_SETNAME_NP_ONE_PARAM)
    if(althrd_equal(thr, althrd_current()))
        pthread_setname_np(name);
#elif defined(PTHREAD_SETNAME_NP_THREE_PARAMS)
    pthread_setname_np(thr, "%s", (void*)name);
#else
    pthread_setname_np(thr, name);
#endif
#elif defined(HAVE_PTHREAD_SET_NAME_NP)
    pthread_set_name_np(thr, name);
#else
    (void)thr;
    (void)name;
#endif
}
Ejemplo n.º 8
0
static int sndio_proc(void *ptr)
{
    ALCdevice *device = ptr;
    sndio_data *data = device->ExtraData;
    ALsizei frameSize;
    size_t wrote;

    SetRTPriority();
    althrd_setname(althrd_current(), MIXER_THREAD_NAME);

    frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);

    while(!data->killNow && device->Connected)
    {
        ALsizei len = data->data_size;
        ALubyte *WritePtr = data->mix_data;

        aluMixData(device, WritePtr, len/frameSize);
        while(len > 0 && !data->killNow)
        {
            wrote = sio_write(data->sndHandle, WritePtr, len);
            if(wrote == 0)
            {
                ERR("sio_write failed\n");
                ALCdevice_Lock(device);
                aluHandleDisconnect(device);
                ALCdevice_Unlock(device);
                break;
            }

            len -= wrote;
            WritePtr += wrote;
        }
    }

    return 0;
}
Ejemplo n.º 9
0
FORCE_ALIGN static int qsa_proc_playback(void* ptr)
{
    ALCdevice* device=(ALCdevice*)ptr;
    qsa_data* data=(qsa_data*)device->ExtraData;
    char* write_ptr;
    int avail;
    snd_pcm_channel_status_t status;
    struct sched_param param;
    fd_set wfds;
    int selectret;
    struct timeval timeout;

    SetRTPriority();
    althrd_setname(althrd_current(), MIXER_THREAD_NAME);

    /* Increase default 10 priority to 11 to avoid jerky sound */
    SchedGet(0, 0, &param);
    param.sched_priority=param.sched_curpriority+1;
    SchedSet(0, 0, SCHED_NOCHANGE, &param);

    ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType);

    while (!data->killNow)
    {
        ALint len=data->size;
        write_ptr=data->buffer;

        avail=len/frame_size;
        aluMixData(device, write_ptr, avail);

        while (len>0 && !data->killNow)
        {
            FD_ZERO(&wfds);
            FD_SET(data->audio_fd, &wfds);
            timeout.tv_sec=2;
            timeout.tv_usec=0;

            /* Select also works like time slice to OS */
            selectret=select(data->audio_fd+1, NULL, &wfds, NULL, &timeout);
            switch (selectret)
            {
                case -1:
                     aluHandleDisconnect(device);
                     return 1;
                case 0:
                     break;
                default:
                     if (FD_ISSET(data->audio_fd, &wfds))
                     {
                         break;
                     }
                     break;
            }

            int wrote=snd_pcm_plugin_write(data->pcmHandle, write_ptr, len);

            if (wrote<=0)
            {
                if ((errno==EAGAIN) || (errno==EWOULDBLOCK))
                {
                    continue;
                }

                memset(&status, 0, sizeof (status));
                status.channel=SND_PCM_CHANNEL_PLAYBACK;

                snd_pcm_plugin_status(data->pcmHandle, &status);

                /* we need to reinitialize the sound channel if we've underrun the buffer */
                if ((status.status==SND_PCM_STATUS_UNDERRUN) ||
                    (status.status==SND_PCM_STATUS_READY))
                {
                    if ((snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK))<0)
                    {
                        aluHandleDisconnect(device);
                        break;
                    }
                }
            }
            else
            {
                write_ptr+=wrote;
                len-=wrote;
            }
        }
    }

    return 0;
}
Ejemplo n.º 10
0
Archivo: opensl.c Proyecto: dns/CLove
static int ALCopenslPlayback_mixerProc(void *arg)
{
    ALCopenslPlayback *self = arg;
    ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
    SLAndroidSimpleBufferQueueItf bufferQueue;
    ll_ringbuffer_data_t data[2];
    SLPlayItf player;
    SLresult result;
    size_t padding;

    SetRTPriority();
    althrd_setname(althrd_current(), MIXER_THREAD_NAME);

    result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
                                                       &bufferQueue);
    PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE");
    if(SL_RESULT_SUCCESS == result)
    {
        result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player);
        PRINTERR(result, "bufferQueue->GetInterface SL_IID_PLAY");
    }
    if(SL_RESULT_SUCCESS != result)
    {
        ALCopenslPlayback_lock(self);
        aluHandleDisconnect(device);
        ALCopenslPlayback_unlock(self);
        return 1;
    }

    /* NOTE: The ringbuffer will be larger than the desired buffer metrics.
     * Calculate the amount of extra space so we know how much to keep unused.
     */
    padding = ll_ringbuffer_write_space(self->mRing) - device->NumUpdates;

    ALCopenslPlayback_lock(self);
    while(ATOMIC_LOAD_SEQ(&self->mKillNow) == AL_FALSE && device->Connected)
    {
        size_t todo, len0, len1;

        if(ll_ringbuffer_write_space(self->mRing) <= padding)
        {
            SLuint32 state = 0;

            result = VCALL(player,GetPlayState)(&state);
            PRINTERR(result, "player->GetPlayState");
            if(SL_RESULT_SUCCESS == result && state != SL_PLAYSTATE_PLAYING)
            {
                result = VCALL(player,SetPlayState)(SL_PLAYSTATE_PLAYING);
                PRINTERR(result, "player->SetPlayState");
            }
            if(SL_RESULT_SUCCESS != result)
            {
                aluHandleDisconnect(device);
                break;
            }

            /* NOTE: Unfortunately, there is an unavoidable race condition
             * here. It's possible for the process() method to run, updating
             * the read pointer and signaling the condition variable, in
             * between checking the write size and waiting for the condition
             * variable here. This will cause alcnd_wait to wait until the
             * *next* process() invocation signals the condition variable
             * again.
             *
             * However, this should only happen if the mixer is running behind
             * anyway (as ideally we'll be asleep in alcnd_wait by the time the
             * process() method is invoked), so this behavior is not completely
             * unwarranted. It's unfortunate since it'll be wasting time
             * sleeping that could be used to catch up, but there's no way
             * around it without blocking in the process() method.
             */
            if(ll_ringbuffer_write_space(self->mRing) <= padding)
            {
                alcnd_wait(&self->mCond, &STATIC_CAST(ALCbackend,self)->mMutex);
                continue;
            }
        }

        ll_ringbuffer_get_write_vector(self->mRing, data);
        todo = data[0].len+data[1].len - padding;

        len0 = minu(todo, data[0].len);
        len1 = minu(todo-len0, data[1].len);

        aluMixData(device, data[0].buf, len0*device->UpdateSize);
        for(size_t i = 0;i < len0;i++)
        {
            result = VCALL(bufferQueue,Enqueue)(data[0].buf, device->UpdateSize*self->mFrameSize);
            PRINTERR(result, "bufferQueue->Enqueue");
            if(SL_RESULT_SUCCESS == result)
                ll_ringbuffer_write_advance(self->mRing, 1);

            data[0].buf += device->UpdateSize*self->mFrameSize;
        }

        if(len1 > 0)
        {
            aluMixData(device, data[1].buf, len1*device->UpdateSize);
            for(size_t i = 0;i < len1;i++)
            {
                result = VCALL(bufferQueue,Enqueue)(data[1].buf, device->UpdateSize*self->mFrameSize);
                PRINTERR(result, "bufferQueue->Enqueue");
                if(SL_RESULT_SUCCESS == result)
                    ll_ringbuffer_write_advance(self->mRing, 1);

                data[1].buf += device->UpdateSize*self->mFrameSize;
            }
        }
    }
    ALCopenslPlayback_unlock(self);

    return 0;
}
Ejemplo n.º 11
0
static int ALCsolarisBackend_mixerProc(void *ptr)
{
    ALCsolarisBackend *self = ptr;
    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
    struct timeval timeout;
    ALubyte *write_ptr;
    ALint frame_size;
    ALint to_write;
    ssize_t wrote;
    fd_set wfds;
    int sret;

    SetRTPriority();
    althrd_setname(althrd_current(), MIXER_THREAD_NAME);

    frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);

    ALCsolarisBackend_lock(self);
    while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) &&
          ATOMIC_LOAD(&device->Connected, almemory_order_acquire) != DeviceConnect_Disconnected)
    {
        FD_ZERO(&wfds);
        FD_SET(self->fd, &wfds);
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;

        ALCsolarisBackend_unlock(self);
        sret = select(self->fd+1, NULL, &wfds, NULL, &timeout);
        ALCsolarisBackend_lock(self);
        if(sret < 0)
        {
            if(errno == EINTR)
                continue;
            ERR("select failed: %s\n", strerror(errno));
            aluHandleDisconnect(device, "Failed to wait for playback buffer: %s", strerror(errno));
            break;
        }
        else if(sret == 0)
        {
            WARN("select timeout\n");
            continue;
        }

        write_ptr = self->mix_data;
        to_write = self->data_size;
        aluMixData(device, write_ptr, to_write/frame_size);
        while(to_write > 0 && !ATOMIC_LOAD_SEQ(&self->killNow))
        {
            wrote = write(self->fd, write_ptr, to_write);
            if(wrote < 0)
            {
                if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
                    continue;
                ERR("write failed: %s\n", strerror(errno));
                aluHandleDisconnect(device, "Failed to write playback samples: %s",
                                    strerror(errno));
                break;
            }

            to_write -= wrote;
            write_ptr += wrote;
        }
    }
    ALCsolarisBackend_unlock(self);

    return 0;
}