예제 #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;
}
예제 #2
0
void g_processBuffer(void *buffer, size_t size)
{
	if (g_mixerRunning)
	{
		aluMixData(g_device, buffer, size);
	}
}
예제 #3
0
/*
    PlaybackThreadProc

    Used by "MMSYSTEM" Device.  Called when a WaveOut buffer has used up its
    audio data.
*/
static DWORD WINAPI PlaybackThreadProc(LPVOID lpParameter)
{
    ALCdevice *pDevice = (ALCdevice*)lpParameter;
    WinMMData *pData = pDevice->ExtraData;
    LPWAVEHDR pWaveHdr;
    ALuint FrameSize;
    MSG msg;

    FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);

    while(GetMessage(&msg, NULL, 0, 0))
    {
        if(msg.message != WOM_DONE || pData->bWaveShutdown)
            continue;

        pWaveHdr = ((LPWAVEHDR)msg.lParam);

        aluMixData(pDevice, pWaveHdr->lpData, pWaveHdr->dwBufferLength/FrameSize);

        // Send buffer back to play more data
        waveOutWrite(pData->hWaveHandle.Out, pWaveHdr, sizeof(WAVEHDR));
        InterlockedIncrement(&pData->lWaveBuffersCommitted);
    }

    // Signal Wave Thread completed event
    if(pData->hWaveThreadEvent)
        SetEvent(pData->hWaveThreadEvent);

    ExitThread(0);

    return 0;
}
예제 #4
0
static ALuint sndio_proc(ALvoid *ptr)
{
    ALCdevice *device = ptr;
    sndio_data *data = device->ExtraData;
    ALsizei frameSize;
    size_t wrote;

    SetRTPriority();

    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");
                aluHandleDisconnect(device);
                break;
            }

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

    return 0;
}
예제 #5
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;
}
// PulseAudio I/O Callbacks //{{{
static void stream_write_callback( pa_stream* stream, size_t len, void* pdata ) //{{{
{
	ALCdevice* Device = pdata;
	pulse_data* data = Device->ExtraData;

	while ( len > 0 )
	{
		size_t newlen = len;
		void* buf;
		pa_free_cb_t free_func = NULL;

#if PA_CHECK_VERSION(0,9,16)

		if ( !ppa_stream_begin_write ||
		     ppa_stream_begin_write( stream, &buf, &newlen ) < 0 )
#endif
		{
			buf = ppa_xmalloc( newlen );
			free_func = ppa_xfree;
		}

		aluMixData( Device, buf, newlen / data->frame_size );
		ppa_stream_write( stream, buf, newlen, free_func, 0, PA_SEEK_RELATIVE );
		len -= newlen;
	}
} //}}}
예제 #7
0
static void *playback_function(void * context) {
    LOGV("playback_function started");
    outputBuffer_t *buffer = NULL;
    SLresult result;
    struct timespec ts;
    int rc;
    assert(NULL != context);
    ALCdevice *pDevice = (ALCdevice *) context;
    opesles_data_t *devState = (opesles_data_t *) pDevice->ExtraData;
    unsigned int bufferIndex = devState->lastBufferMixed;

    ALint frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);

    // Show a sensible name for the thread in debug tools
    prctl(PR_SET_NAME, (unsigned long)"OpenAL/sl/m", 0, 0, 0);

    while (1) {
        if (devState->threadShouldRun == 0) {
            return NULL;
        }

        bufferIndex = (++bufferIndex) % bufferCount;
        buffer = &(devState->outputBuffers[bufferIndex]);

        pthread_mutex_lock(&(buffer->mutex));


        while (1) {
            if (devState->threadShouldRun == 0) {
                pthread_mutex_unlock(&(buffer->mutex));
                return NULL;
            }

            // This is a little hacky, but here we avoid mixing too much data            
            if (buffer->state == OUTPUT_BUFFER_STATE_FREE) {
                int i = (bufferIndex - premixCount) % bufferCount;
                outputBuffer_t *buffer1 = &(devState->outputBuffers[i]);
                if (buffer1->state == OUTPUT_BUFFER_STATE_ENQUEUED ||
                    buffer1->state == OUTPUT_BUFFER_STATE_FREE) {
                    break;
                }
            } 

            // No buffer available, wait for a buffer to become available
            // or until playback is stopped/suspended
            clock_gettime(CLOCK_REALTIME, &ts);
            ts.tv_nsec += 5000000;
            rc = pthread_cond_timedwait(&(buffer->cond), &(buffer->mutex), &ts);
        }
        devState->threadIsReady = 1;

        aluMixData(pDevice, buffer->buffer, bufferSize/frameSize);
        buffer->state = OUTPUT_BUFFER_STATE_MIXED;
        pthread_cond_signal(&(buffer->cond));
        pthread_mutex_unlock(&(buffer->mutex));

        devState->lastBufferMixed = bufferIndex;
    }
}
예제 #8
0
static int pa_callback(const void *UNUSED(inputBuffer), void *outputBuffer,
                       unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
                       const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
{
    ALCdevice *device = (ALCdevice*)userData;

    aluMixData(device, outputBuffer, framesPerBuffer);
    return 0;
}
예제 #9
0
파일: alsa.c 프로젝트: LighFusion/surreal
static ALuint ALSANoMMapProc(ALvoid *ptr)
{
    ALCdevice *Device = (ALCdevice*)ptr;
    alsa_data *data = (alsa_data*)Device->ExtraData;
    snd_pcm_sframes_t avail;
    char *WritePtr;

    SetRTPriority();

    while(!data->killNow)
    {
        int state = verify_state(data->pcmHandle);
        if(state < 0)
        {
            ERR("Invalid state detected: %s\n", snd_strerror(state));
            aluHandleDisconnect(Device);
            break;
        }

        WritePtr = data->buffer;
        avail = data->size / snd_pcm_frames_to_bytes(data->pcmHandle, 1);
        aluMixData(Device, WritePtr, avail);

        while(avail > 0)
        {
            int ret = snd_pcm_writei(data->pcmHandle, WritePtr, avail);
            switch (ret)
            {
            case -EAGAIN:
                continue;
            case -ESTRPIPE:
            case -EPIPE:
            case -EINTR:
                ret = snd_pcm_recover(data->pcmHandle, ret, 1);
                if(ret < 0)
                    avail = 0;
                break;
            default:
                if (ret >= 0)
                {
                    WritePtr += snd_pcm_frames_to_bytes(data->pcmHandle, ret);
                    avail -= ret;
                }
                break;
            }
            if (ret < 0)
            {
                ret = snd_pcm_prepare(data->pcmHandle);
                if(ret < 0)
                    break;
            }
        }
    }

    return 0;
}
예제 #10
0
static OSStatus ca_callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp,
                            UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
{
    ALCdevice *device = (ALCdevice*)inRefCon;
    ca_data *data = (ca_data*)device->ExtraData;

    aluMixData(device, ioData->mBuffers[0].mData,
               ioData->mBuffers[0].mDataByteSize / data->frameSize);

    return noErr;
}
예제 #11
0
// PulseAudio I/O Callbacks //{{{
static void stream_write_callback(pa_stream *stream, size_t len, void *pdata) //{{{
{
    ALCdevice *Device = pdata;
    pulse_data *data = Device->ExtraData;
    void *buf = ppa_xmalloc0(data->attr.minreq);
    (void)len;

    aluMixData(Device, buf, data->attr.minreq/data->frame_size);
    ppa_stream_write(stream, buf, data->attr.minreq, ppa_xfree, 0,
                     PA_SEEK_RELATIVE);
} //}}}
예제 #12
0
/* this callback handler is called every time a buffer finishes playing */
static void opensl_callback(SLAndroidSimpleBufferQueueItf bq, void *context)
{
    ALCdevice *Device = context;
    osl_data *data = Device->ExtraData;
    SLresult result;

    aluMixData(Device, data->buffer, data->bufferSize/data->frameSize);

    result = (*bq)->Enqueue(bq, data->buffer, data->bufferSize);
    PRINTERR(result, "bq->Enqueue");
}
예제 #13
0
static ALuint ALSANoMMapProc(ALvoid *ptr)
{
    ALCdevice *pDevice = (ALCdevice*)ptr;
    alsa_data *data = (alsa_data*)pDevice->ExtraData;
    snd_pcm_sframes_t avail;
    char *WritePtr;

    while(!data->killNow)
    {
        int state = verify_state(data->pcmHandle);
        if(state < 0)
        {
            AL_PRINT("Invalid state detected: %s\n", psnd_strerror(state));
            aluHandleDisconnect(pDevice);
            break;
        }

        WritePtr = data->buffer;
        avail = data->size / psnd_pcm_frames_to_bytes(data->pcmHandle, 1);
        aluMixData(pDevice, WritePtr, avail);

        while(avail > 0)
        {
            int ret = psnd_pcm_writei(data->pcmHandle, WritePtr, avail);
            switch (ret)
            {
            case -EAGAIN:
                continue;
            case -ESTRPIPE:
                while((ret=psnd_pcm_resume(data->pcmHandle)) == -EAGAIN)
                    Sleep(1);
                break;
            case -EPIPE:
                break;
            default:
                if (ret >= 0)
                {
                    WritePtr += psnd_pcm_frames_to_bytes(data->pcmHandle, ret);
                    avail -= ret;
                }
                break;
            }
            if (ret < 0)
            {
                ret = psnd_pcm_prepare(data->pcmHandle);
                if(ret < 0)
                    break;
            }
        }
    }

    return 0;
}
예제 #14
0
// PulseAudio I/O Callbacks //{{{
static void stream_write_callback(pa_stream *stream, size_t len, void *pdata) //{{{
{
    ALCdevice *Device = pdata;
    pulse_data *data = Device->ExtraData;

    len -= len%data->attr.minreq;
    if(len > 0)
    {
        void *buf = ppa_xmalloc0(len);
        aluMixData(Device, buf, len/data->frame_size);
        ppa_stream_write(stream, buf, len, ppa_xfree, 0, PA_SEEK_RELATIVE);
    }
} //}}}
예제 #15
0
static int pa_callback(const void *inputBuffer, void *outputBuffer,
                       unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
                       const PaStreamCallbackFlags statusFlags, void *userData)
{
    ALCdevice *device = (ALCdevice*)userData;

    (void)inputBuffer;
    (void)timeInfo;
    (void)statusFlags;

    aluMixData(device, outputBuffer, framesPerBuffer);
    return 0;
}
예제 #16
0
static void* thread_function(void* arg)
{
    ALCdevice* device = (ALCdevice*)arg;
    AndroidData* data = (AndroidData*)device->ExtraData;

    JNIEnv* env;
    (*javaVM)->AttachCurrentThread(javaVM, &env, NULL);

    (*env)->PushLocalFrame(env, 2);

    int sampleRateInHz = device->Frequency;
    int channelConfig = aluChannelsFromFormat(device->Format) == 1 ? CHANNEL_CONFIGURATION_MONO : CHANNEL_CONFIGURATION_STEREO;
    int audioFormat = aluBytesFromFormat(device->Format) == 1 ? ENCODING_PCM_8BIT : ENCODING_PCM_16BIT;

    int bufferSizeInBytes = (*env)->CallStaticIntMethod(env, cAudioTrack, 
        mGetMinBufferSize, sampleRateInHz, channelConfig, audioFormat) / 4;

    int bufferSizeInSamples = bufferSizeInBytes / aluFrameSizeFromFormat(device->Format);

    jobject track = (*env)->NewObject(env, cAudioTrack, mAudioTrack,
        STREAM_MUSIC, sampleRateInHz, channelConfig, audioFormat, device->NumUpdates * bufferSizeInBytes, MODE_STREAM);

    (*env)->CallNonvirtualVoidMethod(env, track, cAudioTrack, mPlay);

    jarray buffer = (*env)->NewByteArray(env, bufferSizeInBytes);

    while (data->running)
    {
        void* pBuffer = (*env)->GetPrimitiveArrayCritical(env, buffer, NULL);

        if (pBuffer)
        {
            aluMixData(device, pBuffer, bufferSizeInSamples);
            (*env)->ReleasePrimitiveArrayCritical(env, buffer, pBuffer, 0);

            (*env)->CallNonvirtualIntMethod(env, track, cAudioTrack, mWrite, buffer, 0, bufferSizeInBytes);
        }
        else
        {
            AL_PRINT("Failed to get pointer to array bytes");
        }
    }
    
    (*env)->CallNonvirtualVoidMethod(env, track, cAudioTrack, mStop);
    (*env)->CallNonvirtualVoidMethod(env, track, cAudioTrack, mRelease);

    (*env)->PopLocalFrame(env, NULL);

    (*javaVM)->DetachCurrentThread(javaVM);
    return NULL;
}
예제 #17
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;
}
예제 #18
0
/* this callback handler is called every time a buffer finishes playing */
static void opensl_callback(SLAndroidSimpleBufferQueueItf bq, void *context)
{
    ALCdevice *Device = context;
    osl_data *data = Device->ExtraData;
    ALvoid *buf;
    SLresult result;

    buf = (ALbyte*)data->buffer + data->curBuffer*data->bufferSize;
    aluMixData(Device, buf, data->bufferSize/data->frameSize);

    result = VCALL(bq,Enqueue)(buf, data->bufferSize);
    PRINTERR(result, "bq->Enqueue");

    data->curBuffer = (data->curBuffer+1) % Device->NumUpdates;
}
예제 #19
0
static ALuint PulseProc(ALvoid *param)
{
    ALCdevice *Device = param;
    pulse_data *data = Device->ExtraData;
    ssize_t len;

    SetRTPriority();

    pa_threaded_mainloop_lock(data->loop);
    do {
        len = (Device->Connected ? pa_stream_writable_size(data->stream) : 0);
        len -= len%(Device->UpdateSize*data->frame_size);
        if(len == 0)
        {
            pa_threaded_mainloop_wait(data->loop);
            continue;
        }

        while(len > 0)
        {
            size_t newlen = len;
            void *buf;
            pa_free_cb_t free_func = NULL;

#if PA_CHECK_VERSION(0,9,16)
            if(!pa_stream_begin_write ||
               pa_stream_begin_write(data->stream, &buf, &newlen) < 0)
#endif
            {
                buf = pa_xmalloc(newlen);
                free_func = pa_xfree;
            }
            pa_threaded_mainloop_unlock(data->loop);

            aluMixData(Device, buf, newlen/data->frame_size);

            pa_threaded_mainloop_lock(data->loop);
            pa_stream_write(data->stream, buf, newlen, free_func, 0, PA_SEEK_RELATIVE);
            len -= newlen;
        }
    } while(Device->Connected && !data->killNow);
    pa_threaded_mainloop_unlock(data->loop);

    return 0;
}
예제 #20
0
COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE XAudio2SourceVoiceCallback::OnVoiceProcessingPassStart(UINT32 numBytesRequired)
{
	XAudio2Data* data = (XAudio2Data*)device->ExtraData;
	LONG running;

	if (data->buffer == NULL)
	{
		CreateBuffer(data, numBytesRequired);
		SetEvent(this->callbackEvent);
	}
	else {
		InterlockedExchange(&running, data->running);
		if (running)
		{
			HRESULT hr;
			if (data->bufferSize < numBytesRequired)
				CreateBuffer(data, numBytesRequired);
			size_t samples = numBytesRequired / data->frameSize;
			size_t bufferRegionSize = samples * data->frameSize;//must be divisible by frame size

			aluMixData(device, data->buffer, samples);//mix data

#if 0//audio glitch simulation
			for (int i = 0; i < 10000000; ++i)
			{
				int a = 0;
			}
#endif

			/*------------submit buffer region-------------*/
			XAUDIO2_BUFFER bufferRegionToSubmit;
			memset(&bufferRegionToSubmit, 0, sizeof(bufferRegionToSubmit));
			bufferRegionToSubmit.AudioBytes = bufferRegionSize;
			bufferRegionToSubmit.pAudioData = data->buffer;

			hr = data->sourceVoice->SubmitSourceBuffer(&bufferRegionToSubmit);
			if (FAILED(hr))
			{
				ERR("SubmitSourceBuffer() failed: 0x%08lx\n", hr);
			}
		}//if (running)
	}//if (data->buffer == NULL)
}
static ALuint OSSProc( ALvoid* ptr )
{
	ALCdevice* pDevice = ( ALCdevice* )ptr;
	oss_data* data = ( oss_data* )pDevice->ExtraData;
	ALint frameSize;
	ssize_t wrote;

	SetRTPriority();

	frameSize = aluFrameSizeFromFormat( pDevice->Format );

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

		aluMixData( pDevice, WritePtr, len / frameSize );

		while ( len > 0 && !data->killNow )
		{
			wrote = write( data->fd, WritePtr, len );

			if ( wrote < 0 )
			{
				if ( errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR )
				{
					AL_PRINT( "write failed: %s\n", strerror( errno ) );
					aluHandleDisconnect( pDevice );
					break;
				}

				Sleep( 1 );
				continue;
			}

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

	return 0;
}
예제 #22
0
static ALuint NullProc(ALvoid *ptr)
{
    ALCdevice *Device = (ALCdevice*)ptr;
    null_data *data = (null_data*)Device->ExtraData;
    ALuint now, start;
    ALuint64 avail, done;
    const ALuint restTime = (ALuint64)Device->UpdateSize * 1000 /
                            Device->Frequency / 2;

    done = 0;
    start = timeGetTime();
    while(!data->killNow && Device->Connected)
    {
        now = timeGetTime();

        avail = (ALuint64)(now-start) * Device->Frequency / 1000;
        if(avail < done)
        {
            /* Timer wrapped (50 days???). Add the remainder of the cycle to
             * the available count and reset the number of samples done */
            avail += ((ALuint64)1<<32)*Device->Frequency/1000 - done;
            done = 0;
        }
        if(avail-done < Device->UpdateSize)
        {
            Sleep(restTime);
            continue;
        }

        while(avail-done >= Device->UpdateSize)
        {
            aluMixData(Device, NULL, Device->UpdateSize);
            done += Device->UpdateSize;
        }
    }

    return 0;
}
예제 #23
0
파일: oss.c 프로젝트: ghoulsblade/vegaogre
static ALuint OSSProc(ALvoid *ptr)
{
    ALCdevice *pDevice = (ALCdevice*)ptr;
    oss_data *data = (oss_data*)pDevice->ExtraData;
    int remaining = 0;
    int wrote;

    while(!data->killNow)
    {
        int len = data->data_size - remaining;

        if(len > 0)
        {
            SuspendContext(NULL);
            aluMixData(pDevice->Context, data->mix_data+remaining, len, pDevice->Format);
            ProcessContext(NULL);
        }

        remaining += len;
        wrote = write(data->fd, data->mix_data, remaining);
        if(wrote < 0)
        {
            AL_PRINT("write failed: %s\n", strerror(errno));
            remaining = 0;
        }
        else if(wrote > 0)
        {
            remaining -= wrote;
            if(remaining > 0)
                memmove(data->mix_data, data->mix_data+wrote, remaining);
        }
        else
            Sleep(1);
    }

    return 0;
}
예제 #24
0
static ALuint ALSAProc(ALvoid *ptr)
{
    ALCdevice *pDevice = (ALCdevice*)ptr;
    alsa_data *data = (alsa_data*)pDevice->ExtraData;
    const snd_pcm_channel_area_t *areas = NULL;
    snd_pcm_sframes_t avail, commitres;
    snd_pcm_uframes_t offset, frames;
    char *WritePtr;
    int err;

    while(!data->killNow)
    {
        int state = verify_state(data->pcmHandle);
        if(state < 0)
        {
            AL_PRINT("Invalid state detected: %s\n", psnd_strerror(state));
            aluHandleDisconnect(pDevice);
            break;
        }

        avail = psnd_pcm_avail_update(data->pcmHandle);
        if(avail < 0)
        {
            AL_PRINT("available update failed: %s\n", psnd_strerror(avail));
            continue;
        }

        // make sure there's frames to process
        if(avail >= 0 && avail < (snd_pcm_sframes_t)pDevice->UpdateSize)
        {
            if(state != SND_PCM_STATE_RUNNING)
            {
                err = psnd_pcm_start(data->pcmHandle);
                if(err < 0)
                {
                    AL_PRINT("start failed: %s\n", psnd_strerror(err));
                    continue;
                }
            }
            if(psnd_pcm_wait(data->pcmHandle, 1000) == 0)
                AL_PRINT("Wait timeout... buffer size too low?\n");
            continue;
        }
        avail -= avail%pDevice->UpdateSize;

        // it is possible that contiguous areas are smaller, thus we use a loop
        while(avail > 0)
        {
            frames = avail;

            err = psnd_pcm_mmap_begin(data->pcmHandle, &areas, &offset, &frames);
            if(err < 0)
            {
                AL_PRINT("mmap begin error: %s\n", psnd_strerror(err));
                break;
            }

            WritePtr = (char*)areas->addr + (offset * areas->step / 8);
            aluMixData(pDevice, WritePtr, frames);

            commitres = psnd_pcm_mmap_commit(data->pcmHandle, offset, frames);
            if(commitres < 0 || (commitres-frames) != 0)
            {
                AL_PRINT("mmap commit error: %s\n",
                         psnd_strerror(commitres >= 0 ? -EPIPE : commitres));
                break;
            }

            avail -= frames;
        }
    }

    return 0;
}
예제 #25
0
static ALuint PulseProc(ALvoid *param)
{
    ALCdevice *Device = param;
    pulse_data *data = Device->ExtraData;
    ALuint buffer_size;
    ALint update_size;
    size_t frame_size;
    ssize_t len;

    SetRTPriority();

    pa_threaded_mainloop_lock(data->loop);
    frame_size = pa_frame_size(&data->spec);
    update_size = Device->UpdateSize * frame_size;

    /* Sanitize buffer metrics, in case we actually have less than what we
     * asked for. */
    buffer_size = minu(update_size*Device->NumUpdates, data->attr.tlength);
    update_size = minu(update_size, buffer_size/2);
    do {
        len = pa_stream_writable_size(data->stream) - data->attr.tlength +
              buffer_size;
        if(len < update_size)
        {
            if(pa_stream_is_corked(data->stream) == 1)
            {
                pa_operation *o;
                o = pa_stream_cork(data->stream, 0, NULL, NULL);
                if(o) pa_operation_unref(o);
            }
            pa_threaded_mainloop_unlock(data->loop);
            Sleep(1);
            pa_threaded_mainloop_lock(data->loop);
            continue;
        }
        len -= len%update_size;

        while(len > 0)
        {
            size_t newlen = len;
            void *buf;
            pa_free_cb_t free_func = NULL;

#if PA_CHECK_VERSION(0,9,16)
            if(!pa_stream_begin_write ||
               pa_stream_begin_write(data->stream, &buf, &newlen) < 0)
#endif
            {
                buf = pa_xmalloc(newlen);
                free_func = pa_xfree;
            }
            pa_threaded_mainloop_unlock(data->loop);

            aluMixData(Device, buf, newlen/frame_size);

            pa_threaded_mainloop_lock(data->loop);
            pa_stream_write(data->stream, buf, newlen, free_func, 0, PA_SEEK_RELATIVE);
            len -= newlen;
        }
    } while(!data->killNow && Device->Connected);
    pa_threaded_mainloop_unlock(data->loop);

    return 0;
}
예제 #26
0
파일: dsound.c 프로젝트: 3dseals/furseal
static ALuint DSoundProc(ALvoid *ptr)
{
    ALCdevice *pDevice = (ALCdevice*)ptr;
    DSoundData *pData = (DSoundData*)pDevice->ExtraData;
    DSBCAPS DSBCaps;
    DWORD LastCursor = 0;
    DWORD PlayCursor;
    VOID *WritePtr1, *WritePtr2;
    DWORD WriteCnt1,  WriteCnt2;
    DWORD FrameSize;
    DWORD FragSize;
    DWORD avail;
    HRESULT err;

    SetRTPriority();

    memset(&DSBCaps, 0, sizeof(DSBCaps));
    DSBCaps.dwSize = sizeof(DSBCaps);
    err = IDirectSoundBuffer_GetCaps(pData->DSsbuffer, &DSBCaps);
    if(FAILED(err))
    {
        AL_PRINT("Failed to get buffer caps: 0x%lx\n", err);
        aluHandleDisconnect(pDevice);
        return 1;
    }

    FrameSize = aluFrameSizeFromFormat(pDevice->Format);
    FragSize = pDevice->UpdateSize * FrameSize;

    IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &LastCursor, NULL);
    while(!pData->killNow)
    {
        // Get current play and write cursors
        IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &PlayCursor, NULL);
        avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes;

        if(avail < FragSize)
        {
            Sleep(1);
            continue;
        }
        avail -= avail%FragSize;

        // Lock output buffer
        WriteCnt1 = 0;
        WriteCnt2 = 0;
        err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);

        // If the buffer is lost, restore it, play and lock
        if(err == DSERR_BUFFERLOST)
        {
            err = IDirectSoundBuffer_Restore(pData->DSsbuffer);
            if(SUCCEEDED(err))
                err = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING);
            if(SUCCEEDED(err))
                err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
        }

        // Successfully locked the output buffer
        if(SUCCEEDED(err))
        {
            // If we have an active context, mix data directly into output buffer otherwise fill with silence
            aluMixData(pDevice, WritePtr1, WriteCnt1/FrameSize);
            aluMixData(pDevice, WritePtr2, WriteCnt2/FrameSize);

            // Unlock output buffer only when successfully locked
            IDirectSoundBuffer_Unlock(pData->DSsbuffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2);
        }
        else
            AL_PRINT("Buffer lock error: %#lx\n", err);

        // Update old write cursor location
        LastCursor += WriteCnt1+WriteCnt2;
        LastCursor %= DSBCaps.dwBufferBytes;
    }

    return 0;
}
static ALuint WaveProc( ALvoid* ptr )
{
	ALCdevice* pDevice = ( ALCdevice* )ptr;
	wave_data* data = ( wave_data* )pDevice->ExtraData;
	ALuint frameSize;
	ALuint now, last;
	size_t fs;
	ALuint avail;
	union
	{
		short s;
		char b[sizeof( short )];
	} uSB;

	uSB.s = 1;
	frameSize = aluFrameSizeFromFormat( pDevice->Format );

	last = timeGetTime() << 8;

	while ( !data->killNow && pDevice->Connected )
	{
		now = timeGetTime() << 8;

		avail = ( ALuint64 )( now - last ) * pDevice->Frequency / ( 1000 << 8 );

		if ( avail < pDevice->UpdateSize )
		{
			Sleep( 1 );
			continue;
		}

		while ( avail >= pDevice->UpdateSize )
		{
			aluMixData( pDevice, data->buffer, pDevice->UpdateSize );

			if ( uSB.b[0] != 1 )
			{
				ALubyte* bytes = data->buffer;
				ALuint i;

				if ( aluBytesFromFormat( pDevice->Format ) == 1 )
				{
					for ( i = 0; i < data->size; i++ )
					{
						fputc( bytes[i], data->f );
					}
				}
				else if ( aluBytesFromFormat( pDevice->Format ) == 2 )
				{
					for ( i = 0; i < data->size; i++ )
					{
						fputc( bytes[i ^ 1], data->f );
					}
				}
				else if ( aluBytesFromFormat( pDevice->Format ) == 4 )
				{
					for ( i = 0; i < data->size; i++ )
					{
						fputc( bytes[i ^ 3], data->f );
					}
				}
			}
			else
				fs = fwrite( data->buffer, frameSize, pDevice->UpdateSize,
				             data->f );

			if ( ferror( data->f ) )
			{
				AL_PRINT( "Error writing to file\n" );
				aluHandleDisconnect( pDevice );
				break;
			}

			avail -= pDevice->UpdateSize;
			last += ( ALuint64 )pDevice->UpdateSize * ( 1000 << 8 ) / pDevice->Frequency;
		}
	}

	return 0;
}
예제 #28
0
static ALuint DSoundPlaybackProc(ALvoid *ptr)
{
    ALCdevice *Device = (ALCdevice*)ptr;
    DSoundPlaybackData *data = (DSoundPlaybackData*)Device->ExtraData;
    DSBCAPS DSBCaps;
    DWORD LastCursor = 0;
    DWORD PlayCursor;
    VOID *WritePtr1, *WritePtr2;
    DWORD WriteCnt1,  WriteCnt2;
    BOOL Playing = FALSE;
    DWORD FrameSize;
    DWORD FragSize;
    DWORD avail;
    HRESULT err;

    SetRTPriority();

    memset(&DSBCaps, 0, sizeof(DSBCaps));
    DSBCaps.dwSize = sizeof(DSBCaps);
    err = IDirectSoundBuffer_GetCaps(data->Buffer, &DSBCaps);
    if(FAILED(err))
    {
        ERR("Failed to get buffer caps: 0x%lx\n", err);
        ALCdevice_Lock(Device);
        aluHandleDisconnect(Device);
        ALCdevice_Unlock(Device);
        return 1;
    }

    FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
    FragSize = Device->UpdateSize * FrameSize;

    IDirectSoundBuffer_GetCurrentPosition(data->Buffer, &LastCursor, NULL);
    while(!data->killNow)
    {
        // Get current play cursor
        IDirectSoundBuffer_GetCurrentPosition(data->Buffer, &PlayCursor, NULL);
        avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes;

        if(avail < FragSize)
        {
            if(!Playing)
            {
                err = IDirectSoundBuffer_Play(data->Buffer, 0, 0, DSBPLAY_LOOPING);
                if(FAILED(err))
                {
                    ERR("Failed to play buffer: 0x%lx\n", err);
                    ALCdevice_Lock(Device);
                    aluHandleDisconnect(Device);
                    ALCdevice_Unlock(Device);
                    return 1;
                }
                Playing = TRUE;
            }

            avail = WaitForSingleObjectEx(data->NotifyEvent, 2000, FALSE);
            if(avail != WAIT_OBJECT_0)
                ERR("WaitForSingleObjectEx error: 0x%lx\n", avail);
            continue;
        }
        avail -= avail%FragSize;

        // Lock output buffer
        WriteCnt1 = 0;
        WriteCnt2 = 0;
        err = IDirectSoundBuffer_Lock(data->Buffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);

        // If the buffer is lost, restore it and lock
        if(err == DSERR_BUFFERLOST)
        {
            WARN("Buffer lost, restoring...\n");
            err = IDirectSoundBuffer_Restore(data->Buffer);
            if(SUCCEEDED(err))
            {
                Playing = FALSE;
                LastCursor = 0;
                err = IDirectSoundBuffer_Lock(data->Buffer, 0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
            }
        }

        // Successfully locked the output buffer
        if(SUCCEEDED(err))
        {
            // If we have an active context, mix data directly into output buffer otherwise fill with silence
            aluMixData(Device, WritePtr1, WriteCnt1/FrameSize);
            aluMixData(Device, WritePtr2, WriteCnt2/FrameSize);

            // Unlock output buffer only when successfully locked
            IDirectSoundBuffer_Unlock(data->Buffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2);
        }
        else
        {
            ERR("Buffer lock error: %#lx\n", err);
            ALCdevice_Lock(Device);
            aluHandleDisconnect(Device);
            ALCdevice_Unlock(Device);
            return 1;
        }

        // Update old write cursor location
        LastCursor += WriteCnt1+WriteCnt2;
        LastCursor %= DSBCaps.dwBufferBytes;
    }

    return 0;
}
예제 #29
0
파일: wave.c 프로젝트: soundsrc/openal-soft
static ALuint WaveProc(ALvoid *ptr)
{
    ALCdevice *pDevice = (ALCdevice*)ptr;
    wave_data *data = (wave_data*)pDevice->ExtraData;
    ALuint frameSize;
    ALuint now, start;
    ALuint64 avail, done;
    size_t fs;
    union {
        short s;
        char b[sizeof(short)];
    } uSB;
    const ALuint restTime = (ALuint64)pDevice->UpdateSize * 1000 /
                            pDevice->Frequency / 2;

    uSB.s = 1;
    frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);

    done = 0;
    start = timeGetTime();
    while(!data->killNow && pDevice->Connected)
    {
        now = timeGetTime();

        avail = (ALuint64)(now-start) * pDevice->Frequency / 1000;
        if(avail < done)
        {
            /* Timer wrapped. Add the remainder of the cycle to the available
             * count and reset the number of samples done */
            avail += (ALuint64)0xFFFFFFFFu*pDevice->Frequency/1000 - done;
            done = 0;
        }
        if(avail-done < pDevice->UpdateSize)
        {
            Sleep(restTime);
            continue;
        }

        while(avail-done >= pDevice->UpdateSize)
        {
            aluMixData(pDevice, data->buffer, pDevice->UpdateSize);
            done += pDevice->UpdateSize;

            if(uSB.b[0] != 1)
            {
                ALuint bytesize = BytesFromDevFmt(pDevice->FmtType);
                ALubyte *bytes = data->buffer;
                ALuint i;

                if(bytesize == 1)
                {
                    for(i = 0;i < data->size;i++)
                        fputc(bytes[i], data->f);
                }
                else if(bytesize == 2)
                {
                    for(i = 0;i < data->size;i++)
                        fputc(bytes[i^1], data->f);
                }
                else if(bytesize == 4)
                {
                    for(i = 0;i < data->size;i++)
                        fputc(bytes[i^3], data->f);
                }
            }
            else
                fs = fwrite(data->buffer, frameSize, pDevice->UpdateSize,
                            data->f);
            if(ferror(data->f))
            {
                AL_PRINT("Error writing to file\n");
                aluHandleDisconnect(pDevice);
                break;
            }
        }
    }

    return 0;
}
예제 #30
0
파일: qsa.c 프로젝트: Sponk/NeoEditor
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;
}