コード例 #1
0
AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer,
  ALsizei offset, ALsizei samples,
  ALenum channels, ALenum type, ALvoid *data)
{
    ALCdevice *device;
    ALCcontext *context;
    ALbuffer *albuf;
    ALsizei align;

    context = GetContextRef();
    if(!context) return;

    device = context->Device;
    LockBuffersRead(device);
    if((albuf=LookupBuffer(device, buffer)) == NULL)
        SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
    if(!(samples >= 0 && offset >= 0))
        SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
    if(IsValidType(type) == AL_FALSE)
        SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);

    ReadLock(&albuf->lock);
    align = ATOMIC_LOAD_SEQ(&albuf->PackAlign);
    if(SanitizeAlignment(type, &align) == AL_FALSE)
    {
        ReadUnlock(&albuf->lock);
        SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
    }
    if(channels != (ALenum)albuf->FmtChannels)
    {
        ReadUnlock(&albuf->lock);
        SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
    }
    if(offset > albuf->SampleLen || samples > albuf->SampleLen-offset)
    {
        ReadUnlock(&albuf->lock);
        SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
    }
    if((samples%align) != 0)
    {
        ReadUnlock(&albuf->lock);
        SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
    }

    /* offset -> byte offset */
    offset *= FrameSizeFromFmt(albuf->FmtChannels, albuf->FmtType);
    ConvertData(data, type, (char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
                ChannelsFromFmt(albuf->FmtChannels), samples, align);
    ReadUnlock(&albuf->lock);

done:
    UnlockBuffersRead(device);
    ALCcontext_DecRef(context);
}
コード例 #2
0
ファイル: alAuxEffectSlot.c プロジェクト: xxxbxxx/openal-soft
void DeinitEffectSlot(ALeffectslot *slot)
{
    struct ALeffectslotProps *props;

    props = ATOMIC_LOAD_SEQ(&slot->Update);
    if(props)
    {
        if(props->State) ALeffectState_DecRef(props->State);
        TRACE("Freed unapplied AuxiliaryEffectSlot update %p\n", props);
        al_free(props);
    }

    ALeffectState_DecRef(slot->Effect.State);
    if(slot->Params.EffectState)
        ALeffectState_DecRef(slot->Params.EffectState);
}
コード例 #3
0
AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer,
  ALuint samplerate, ALenum internalformat, ALsizei samples,
  ALenum channels, ALenum type, const ALvoid *data)
{
    ALCdevice *device;
    ALCcontext *context;
    ALbuffer *albuf;
    ALsizei align;
    ALenum err;

    context = GetContextRef();
    if(!context) return;

    device = context->Device;
    LockBuffersRead(device);
    if((albuf=LookupBuffer(device, buffer)) == NULL)
        SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
    if(!(samples >= 0 && samplerate != 0))
        SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
    if(IsValidType(type) == AL_FALSE || IsValidChannels(channels) == AL_FALSE)
        SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);

    align = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign);
    if(SanitizeAlignment(type, &align) == AL_FALSE)
        SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
    if((samples%align) != 0)
        SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);

    err = LoadData(albuf, samplerate, internalformat, samples,
                   channels, type, data, align, AL_FALSE);
    if(err != AL_NO_ERROR)
        SET_ERROR_AND_GOTO(context, err, done);

done:
    UnlockBuffersRead(device);
    ALCcontext_DecRef(context);
}
コード例 #4
0
ファイル: alAuxEffectSlot.c プロジェクト: xxxbxxx/openal-soft
ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect)
{
    ALCdevice *Device = Context->Device;
    ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL);
    struct ALeffectslotProps *props;
    ALeffectState *State;

    if(newtype != EffectSlot->Effect.Type)
    {
        EffectStateFactory *factory;

        factory = getFactoryByType(newtype);
        if(!factory)
        {
            ERR("Failed to find factory for effect type 0x%04x\n", newtype);
            return AL_INVALID_ENUM;
        }
        State = EffectStateFactory_create(factory);
        if(!State) return AL_OUT_OF_MEMORY;

        START_MIXER_MODE();
        almtx_lock(&Device->BackendLock);
        State->OutBuffer = Device->Dry.Buffer;
        State->OutChannels = Device->Dry.NumChannels;
        if(V(State,deviceUpdate)(Device) == AL_FALSE)
        {
            almtx_unlock(&Device->BackendLock);
            LEAVE_MIXER_MODE();
            ALeffectState_DecRef(State);
            return AL_OUT_OF_MEMORY;
        }
        almtx_unlock(&Device->BackendLock);
        END_MIXER_MODE();

        if(!effect)
        {
            EffectSlot->Effect.Type = AL_EFFECT_NULL;
            memset(&EffectSlot->Effect.Props, 0, sizeof(EffectSlot->Effect.Props));
        }
        else
        {
            EffectSlot->Effect.Type = effect->type;
            EffectSlot->Effect.Props = effect->Props;
        }

        ALeffectState_DecRef(EffectSlot->Effect.State);
        EffectSlot->Effect.State = State;
    }
    else if(effect)
        EffectSlot->Effect.Props = effect->Props;

    /* Remove state references from old effect slot property updates. */
    props = ATOMIC_LOAD_SEQ(&Context->FreeEffectslotProps);
    while(props)
    {
        if(props->State)
            ALeffectState_DecRef(props->State);
        props->State = NULL;
        props = ATOMIC_LOAD(&props->next, almemory_order_relaxed);
    }

    return AL_NO_ERROR;
}
コード例 #5
0
AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value)
{
    ALCdevice *device;
    ALCcontext *context;
    ALbuffer *albuf;

    context = GetContextRef();
    if(!context) return;

    device = context->Device;
    LockBuffersRead(device);
    if((albuf=LookupBuffer(device, buffer)) == NULL)
        SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);

    if(!(value))
        SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
    switch(param)
    {
    case AL_FREQUENCY:
        *value = albuf->Frequency;
        break;

    case AL_BITS:
        *value = BytesFromFmt(albuf->FmtType) * 8;
        break;

    case AL_CHANNELS:
        *value = ChannelsFromFmt(albuf->FmtChannels);
        break;

    case AL_SIZE:
        ReadLock(&albuf->lock);
        *value = albuf->SampleLen * FrameSizeFromFmt(albuf->FmtChannels,
                                                     albuf->FmtType);
        ReadUnlock(&albuf->lock);
        break;

    case AL_INTERNAL_FORMAT_SOFT:
        *value = albuf->Format;
        break;

    case AL_BYTE_LENGTH_SOFT:
        *value = albuf->OriginalSize;
        break;

    case AL_SAMPLE_LENGTH_SOFT:
        *value = albuf->SampleLen;
        break;

    case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
        *value = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign);
        break;

    case AL_PACK_BLOCK_ALIGNMENT_SOFT:
        *value = ATOMIC_LOAD_SEQ(&albuf->PackAlign);
        break;

    default:
        SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
    }

done:
    UnlockBuffersRead(device);
    ALCcontext_DecRef(context);
}
コード例 #6
0
AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei offset, ALsizei length)
{
    enum UserFmtChannels srcchannels = UserFmtMono;
    enum UserFmtType srctype = UserFmtByte;
    ALCdevice *device;
    ALCcontext *context;
    ALbuffer *albuf;
    ALsizei byte_align;
    ALsizei channels;
    ALsizei bytes;
    ALsizei align;

    context = GetContextRef();
    if(!context) return;

    device = context->Device;
    LockBuffersRead(device);
    if((albuf=LookupBuffer(device, buffer)) == NULL)
        SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
    if(!(length >= 0 && offset >= 0))
        SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
    if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)
        SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);

    WriteLock(&albuf->lock);
    align = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign);
    if(SanitizeAlignment(srctype, &align) == AL_FALSE)
    {
        WriteUnlock(&albuf->lock);
        SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
    }
    if(srcchannels != albuf->OriginalChannels || srctype != albuf->OriginalType)
    {
        WriteUnlock(&albuf->lock);
        SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
    }
    if(align != albuf->OriginalAlign)
    {
        WriteUnlock(&albuf->lock);
        SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
    }

    if(albuf->OriginalType == UserFmtIMA4)
    {
        byte_align  = (albuf->OriginalAlign-1)/2 + 4;
        byte_align *= ChannelsFromUserFmt(albuf->OriginalChannels);
    }
    else if(albuf->OriginalType == UserFmtMSADPCM)
    {
        byte_align  = (albuf->OriginalAlign-2)/2 + 7;
        byte_align *= ChannelsFromUserFmt(albuf->OriginalChannels);
    }
    else
    {
        byte_align  = albuf->OriginalAlign;
        byte_align *= FrameSizeFromUserFmt(albuf->OriginalChannels,
                                           albuf->OriginalType);
    }

    if(offset > albuf->OriginalSize || length > albuf->OriginalSize-offset ||
       (offset%byte_align) != 0 || (length%byte_align) != 0)
    {
        WriteUnlock(&albuf->lock);
        SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
    }

    channels = ChannelsFromFmt(albuf->FmtChannels);
    bytes = BytesFromFmt(albuf->FmtType);
    /* offset -> byte offset, length -> sample count */
    offset = offset/byte_align * channels*bytes;
    length = length/byte_align * albuf->OriginalAlign;

    ConvertData((char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType,
                data, srctype, channels, length, align);
    WriteUnlock(&albuf->lock);

done:
    UnlockBuffersRead(device);
    ALCcontext_DecRef(context);
}
コード例 #7
0
AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq)
{
    enum UserFmtChannels srcchannels = UserFmtMono;
    enum UserFmtType srctype = UserFmtByte;
    ALCdevice *device;
    ALCcontext *context;
    ALbuffer *albuf;
    ALenum newformat = AL_NONE;
    ALsizei framesize;
    ALsizei align;
    ALenum err;

    context = GetContextRef();
    if(!context) return;

    device = context->Device;
    LockBuffersRead(device);
    if((albuf=LookupBuffer(device, buffer)) == NULL)
        SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
    if(!(size >= 0 && freq > 0))
        SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
    if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)
        SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);

    align = ATOMIC_LOAD_SEQ(&albuf->UnpackAlign);
    if(SanitizeAlignment(srctype, &align) == AL_FALSE)
        SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
    switch(srctype)
    {
        case UserFmtByte:
        case UserFmtUByte:
        case UserFmtShort:
        case UserFmtUShort:
        case UserFmtFloat:
            framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align;
            if((size%framesize) != 0)
                SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);

            err = LoadData(albuf, freq, format, size/framesize*align,
                           srcchannels, srctype, data, align, AL_TRUE);
            if(err != AL_NO_ERROR)
                SET_ERROR_AND_GOTO(context, err, done);
            break;

        case UserFmtInt:
        case UserFmtUInt:
        case UserFmtByte3:
        case UserFmtUByte3:
        case UserFmtDouble:
            framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align;
            if((size%framesize) != 0)
                SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);

            switch(srcchannels)
            {
                case UserFmtMono: newformat = AL_FORMAT_MONO_FLOAT32; break;
                case UserFmtStereo: newformat = AL_FORMAT_STEREO_FLOAT32; break;
                case UserFmtRear: newformat = AL_FORMAT_REAR32; break;
                case UserFmtQuad: newformat = AL_FORMAT_QUAD32; break;
                case UserFmtX51: newformat = AL_FORMAT_51CHN32; break;
                case UserFmtX61: newformat = AL_FORMAT_61CHN32; break;
                case UserFmtX71: newformat = AL_FORMAT_71CHN32; break;
                case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_FLOAT32; break;
                case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_FLOAT32; break;
            }
            err = LoadData(albuf, freq, newformat, size/framesize*align,
                           srcchannels, srctype, data, align, AL_TRUE);
            if(err != AL_NO_ERROR)
                SET_ERROR_AND_GOTO(context, err, done);
            break;

        case UserFmtMulaw:
        case UserFmtAlaw:
            framesize = FrameSizeFromUserFmt(srcchannels, srctype) * align;
            if((size%framesize) != 0)
                SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);

            switch(srcchannels)
            {
                case UserFmtMono: newformat = AL_FORMAT_MONO16; break;
                case UserFmtStereo: newformat = AL_FORMAT_STEREO16; break;
                case UserFmtRear: newformat = AL_FORMAT_REAR16; break;
                case UserFmtQuad: newformat = AL_FORMAT_QUAD16; break;
                case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
                case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
                case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
                case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_16; break;
                case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break;
            }
            err = LoadData(albuf, freq, newformat, size/framesize*align,
                           srcchannels, srctype, data, align, AL_TRUE);
            if(err != AL_NO_ERROR)
                SET_ERROR_AND_GOTO(context, err, done);
            break;

        case UserFmtIMA4:
            framesize  = (align-1)/2 + 4;
            framesize *= ChannelsFromUserFmt(srcchannels);
            if((size%framesize) != 0)
                SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);

            switch(srcchannels)
            {
                case UserFmtMono: newformat = AL_FORMAT_MONO16; break;
                case UserFmtStereo: newformat = AL_FORMAT_STEREO16; break;
                case UserFmtRear: newformat = AL_FORMAT_REAR16; break;
                case UserFmtQuad: newformat = AL_FORMAT_QUAD16; break;
                case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
                case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
                case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
                case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_16; break;
                case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break;
            }
            err = LoadData(albuf, freq, newformat, size/framesize*align,
                           srcchannels, srctype, data, align, AL_TRUE);
            if(err != AL_NO_ERROR)
                SET_ERROR_AND_GOTO(context, err, done);
            break;

        case UserFmtMSADPCM:
            framesize  = (align-2)/2 + 7;
            framesize *= ChannelsFromUserFmt(srcchannels);
            if((size%framesize) != 0)
                SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);

            switch(srcchannels)
            {
                case UserFmtMono: newformat = AL_FORMAT_MONO16; break;
                case UserFmtStereo: newformat = AL_FORMAT_STEREO16; break;
                case UserFmtRear: newformat = AL_FORMAT_REAR16; break;
                case UserFmtQuad: newformat = AL_FORMAT_QUAD16; break;
                case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
                case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
                case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
                case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_16; break;
                case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break;
            }
            err = LoadData(albuf, freq, newformat, size/framesize*align,
                           srcchannels, srctype, data, align, AL_TRUE);
            if(err != AL_NO_ERROR)
                SET_ERROR_AND_GOTO(context, err, done);
            break;
    }

done:
    UnlockBuffersRead(device);
    ALCcontext_DecRef(context);
}
コード例 #8
0
ファイル: opensl.c プロジェクト: 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;
}
コード例 #9
0
ファイル: solaris.c プロジェクト: xxxbxxx/openal-soft
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;
}