Example #1
0
const struct Hrtf *GetHrtf(ALCdevice *device)
{
    if(device->FmtChans == DevFmtStereo)
    {
        ALuint i;
        for(i = 0;i < NumLoadedHrtfs;i++)
        {
            if(device->Frequency == LoadedHrtfs[i].sampleRate)
                return &LoadedHrtfs[i];
        }
        if(device->Frequency == DefaultHrtf.sampleRate)
            return &DefaultHrtf;
    }
    ERR("Incompatible format: %s %uhz\n",
        DevFmtChannelsString(device->FmtChans), device->Frequency);
    return NULL;
}
Example #2
0
const struct Hrtf *GetHrtf(ALCdevice *device)
{
    if(device->FmtChans == DevFmtStereo)
    {
        struct Hrtf *Hrtf = LoadedHrtfs;
        while(Hrtf != NULL)
        {
            if(device->Frequency == Hrtf->sampleRate)
                return Hrtf;
            Hrtf = Hrtf->next;
        }

        Hrtf = LoadHrtf(device->Frequency);
        if(Hrtf != NULL)
            return Hrtf;

        if(device->Frequency == DefaultHrtf.sampleRate)
            return &DefaultHrtf;
    }
    ERR("Incompatible format: %s %uhz\n",
        DevFmtChannelsString(device->FmtChans), device->Frequency);
    return NULL;
}
Example #3
0
static ALCenum oss_open_capture(ALCdevice *device, const ALCchar *deviceName)
{
    int numFragmentsLogSize;
    int log2FragmentSize;
    unsigned int periods;
    audio_buf_info info;
    ALuint frameSize;
    int numChannels;
    oss_data *data;
    int ossFormat;
    int ossSpeed;
    char *err;

    if(!deviceName)
        deviceName = oss_device;
    else if(strcmp(deviceName, oss_device) != 0)
        return ALC_INVALID_VALUE;

    data = (oss_data*)calloc(1, sizeof(oss_data));
    data->killNow = 0;

    data->fd = open(oss_capture, O_RDONLY);
    if(data->fd == -1)
    {
        free(data);
        ERR("Could not open %s: %s\n", oss_capture, strerror(errno));
        return ALC_INVALID_VALUE;
    }

    switch(device->FmtType)
    {
        case DevFmtByte:
            ossFormat = AFMT_S8;
            break;
        case DevFmtUByte:
            ossFormat = AFMT_U8;
            break;
        case DevFmtShort:
            ossFormat = AFMT_S16_NE;
            break;
        case DevFmtUShort:
        case DevFmtInt:
        case DevFmtUInt:
        case DevFmtFloat:
            free(data);
            ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
            return ALC_INVALID_VALUE;
    }

    periods = 4;
    numChannels = ChannelsFromDevFmt(device->FmtChans);
    frameSize = numChannels * BytesFromDevFmt(device->FmtType);
    ossSpeed = device->Frequency;
    log2FragmentSize = log2i(device->UpdateSize * device->NumUpdates *
                             frameSize / periods);

    /* according to the OSS spec, 16 bytes are the minimum */
    if (log2FragmentSize < 4)
        log2FragmentSize = 4;
    numFragmentsLogSize = (periods << 16) | log2FragmentSize;

#define CHECKERR(func) if((func) < 0) {                                       \
    err = #func;                                                              \
    goto err;                                                                 \
}
    CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize));
    CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFMT, &ossFormat));
    CHECKERR(ioctl(data->fd, SNDCTL_DSP_CHANNELS, &numChannels));
    CHECKERR(ioctl(data->fd, SNDCTL_DSP_SPEED, &ossSpeed));
    CHECKERR(ioctl(data->fd, SNDCTL_DSP_GETISPACE, &info));
    if(0)
    {
    err:
        ERR("%s failed: %s\n", err, strerror(errno));
        close(data->fd);
        free(data);
        return ALC_INVALID_VALUE;
    }
#undef CHECKERR

    if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels)
    {
        ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels);
        close(data->fd);
        free(data);
        return ALC_INVALID_VALUE;
    }

    if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) ||
         (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) ||
         (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort)))
    {
        ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat);
        close(data->fd);
        free(data);
        return ALC_INVALID_VALUE;
    }

    data->ring = CreateRingBuffer(frameSize, device->UpdateSize * device->NumUpdates);
    if(!data->ring)
    {
        ERR("Ring buffer create failed\n");
        close(data->fd);
        free(data);
        return ALC_OUT_OF_MEMORY;
    }

    data->data_size = info.fragsize;
    data->mix_data = calloc(1, data->data_size);

    device->ExtraData = data;
    data->thread = StartThread(OSSCaptureProc, device);
    if(data->thread == NULL)
    {
        device->ExtraData = NULL;
        free(data->mix_data);
        free(data);
        return ALC_OUT_OF_MEMORY;
    }

    device->szDeviceName = strdup(deviceName);
    return ALC_NO_ERROR;
}
Example #4
0
static ALCboolean oss_reset_playback(ALCdevice *device)
{
    oss_data *data = (oss_data*)device->ExtraData;
    int numFragmentsLogSize;
    int log2FragmentSize;
    unsigned int periods;
    audio_buf_info info;
    ALuint frameSize;
    int numChannels;
    int ossFormat;
    int ossSpeed;
    char *err;

    switch(device->FmtType)
    {
        case DevFmtByte:
            ossFormat = AFMT_S8;
            break;
        case DevFmtUByte:
            ossFormat = AFMT_U8;
            break;
        case DevFmtUShort:
        case DevFmtInt:
        case DevFmtUInt:
        case DevFmtFloat:
            device->FmtType = DevFmtShort;
            /* fall-through */
        case DevFmtShort:
            ossFormat = AFMT_S16_NE;
            break;
    }

    periods = device->NumUpdates;
    numChannels = ChannelsFromDevFmt(device->FmtChans);
    frameSize = numChannels * BytesFromDevFmt(device->FmtType);

    ossSpeed = device->Frequency;
    log2FragmentSize = log2i(device->UpdateSize * frameSize);

    /* according to the OSS spec, 16 bytes are the minimum */
    if (log2FragmentSize < 4)
        log2FragmentSize = 4;
    /* Subtract one period since the temp mixing buffer counts as one. Still
     * need at least two on the card, though. */
    if(periods > 2) periods--;
    numFragmentsLogSize = (periods << 16) | log2FragmentSize;

#define CHECKERR(func) if((func) < 0) {                                       \
    err = #func;                                                              \
    goto err;                                                                 \
}
    /* Don't fail if SETFRAGMENT fails. We can handle just about anything
     * that's reported back via GETOSPACE */
    ioctl(data->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize);
    CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFMT, &ossFormat));
    CHECKERR(ioctl(data->fd, SNDCTL_DSP_CHANNELS, &numChannels));
    CHECKERR(ioctl(data->fd, SNDCTL_DSP_SPEED, &ossSpeed));
    CHECKERR(ioctl(data->fd, SNDCTL_DSP_GETOSPACE, &info));
    if(0)
    {
    err:
        ERR("%s failed: %s\n", err, strerror(errno));
        return ALC_FALSE;
    }
#undef CHECKERR

    if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels)
    {
        ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels);
        return ALC_FALSE;
    }

    if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) ||
         (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) ||
         (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort)))
    {
        ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat);
        return ALC_FALSE;
    }

    device->Frequency = ossSpeed;
    device->UpdateSize = info.fragsize / frameSize;
    device->NumUpdates = info.fragments + 1;

    SetDefaultChannelOrder(device);

    return ALC_TRUE;
}
Example #5
0
static struct Hrtf *LoadHrtf(ALuint deviceRate)
{
    const char *fnamelist = NULL;

    if(!ConfigValueStr(NULL, "hrtf_tables", &fnamelist))
        return NULL;
    while(*fnamelist != '\0')
    {
        struct Hrtf *Hrtf = NULL;
        char fname[PATH_MAX];
        ALchar magic[8];
        ALuint i;
        FILE *f;

        while(isspace(*fnamelist) || *fnamelist == ',')
            fnamelist++;
        i = 0;
        while(*fnamelist != '\0' && *fnamelist != ',')
        {
            const char *next = strpbrk(fnamelist, "%,");
            while(fnamelist != next && *fnamelist && i < sizeof(fname))
                fname[i++] = *(fnamelist++);

            if(!next || *next == ',')
                break;

            /* *next == '%' */
            next++;
            if(*next == 'r')
            {
                int wrote = snprintf(&fname[i], sizeof(fname)-i, "%u", deviceRate);
                i += minu(wrote, sizeof(fname)-i);
                next++;
            }
            else if(*next == '%')
            {
                if(i < sizeof(fname))
                    fname[i++] = '%';
                next++;
            }
            else
                ERR("Invalid marker '%%%c'\n", *next);
            fnamelist = next;
        }
        i = minu(i, sizeof(fname)-1);
        fname[i] = '\0';
        while(i > 0 && isspace(fname[i-1]))
            i--;
        fname[i] = '\0';

        if(fname[0] == '\0')
            continue;

        TRACE("Loading %s...\n", fname);
        f = fopen(fname, "rb");
        if(f == NULL)
        {
            ERR("Could not open %s\n", fname);
            continue;
        }

        if(fread(magic, 1, sizeof(magic), f) != sizeof(magic))
            ERR("Failed to read magic marker\n");
        else
        {
            if(memcmp(magic, magicMarker00, sizeof(magicMarker00)) == 0)
            {
                TRACE("Detected data set format v0\n");
                Hrtf = LoadHrtf00(f, deviceRate);
            }
            else if(memcmp(magic, magicMarker01, sizeof(magicMarker01)) == 0)
            {
                TRACE("Detected data set format v1\n");
                Hrtf = LoadHrtf01(f, deviceRate);
            }
            else
                ERR("Invalid magic marker: \"%.8s\"\n", magic);
        }

        fclose(f);
        f = NULL;

        if(Hrtf)
        {
            Hrtf->next = LoadedHrtfs;
            LoadedHrtfs = Hrtf;
            TRACE("Loaded HRTF support for format: %s %uhz\n",
                  DevFmtChannelsString(DevFmtStereo), Hrtf->sampleRate);
            return Hrtf;
        }

        ERR("Failed to load %s\n", fname);
    }

    return NULL;
}
static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
{
    AudioStreamBasicDescription requestedFormat;  // The application requested format
    AudioStreamBasicDescription hardwareFormat;   // The hardware format
    AudioStreamBasicDescription outputFormat;     // The AudioUnit output format
    AURenderCallbackStruct input;
    ComponentDescription desc;
    AudioDeviceID inputDevice;
    UInt32 outputFrameCount;
    UInt32 propertySize;
    UInt32 enableIO;
    Component comp;
    ca_data *data;
    OSStatus err;

    desc.componentType = kAudioUnitType_Output;
    desc.componentSubType = kAudioUnitSubType_HALOutput;
    desc.componentManufacturer = kAudioUnitManufacturer_Apple;
    desc.componentFlags = 0;
    desc.componentFlagsMask = 0;

    // Search for component with given description
    comp = FindNextComponent(NULL, &desc);
    if(comp == NULL)
    {
        ERR("FindNextComponent failed\n");
        return ALC_INVALID_VALUE;
    }

    data = calloc(1, sizeof(*data));
    device->ExtraData = data;

    // Open the component
    err = OpenAComponent(comp, &data->audioUnit);
    if(err != noErr)
    {
        ERR("OpenAComponent failed\n");
        goto error;
    }

    // Turn off AudioUnit output
    enableIO = 0;
    err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint));
    if(err != noErr)
    {
        ERR("AudioUnitSetProperty failed\n");
        goto error;
    }

    // Turn on AudioUnit input
    enableIO = 1;
    err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint));
    if(err != noErr)
    {
        ERR("AudioUnitSetProperty failed\n");
        goto error;
    }

    // Get the default input device
    propertySize = sizeof(AudioDeviceID);
    err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propertySize, &inputDevice);
    if(err != noErr)
    {
        ERR("AudioHardwareGetProperty failed\n");
        goto error;
    }

    if(inputDevice == kAudioDeviceUnknown)
    {
        ERR("No input device found\n");
        goto error;
    }

    // Track the input device
    err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID));
    if(err != noErr)
    {
        ERR("AudioUnitSetProperty failed\n");
        goto error;
    }

    // set capture callback
    input.inputProc = ca_capture_callback;
    input.inputProcRefCon = device;

    err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct));
    if(err != noErr)
    {
        ERR("AudioUnitSetProperty failed\n");
        goto error;
    }

    // Initialize the device
    err = AudioUnitInitialize(data->audioUnit);
    if(err != noErr)
    {
        ERR("AudioUnitInitialize failed\n");
        goto error;
    }

    // Get the hardware format
    propertySize = sizeof(AudioStreamBasicDescription);
    err = AudioUnitGetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize);
    if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription))
    {
        ERR("AudioUnitGetProperty failed\n");
        goto error;
    }

    // Set up the requested format description
    switch(device->FmtType)
    {
        case DevFmtUByte:
            requestedFormat.mBitsPerChannel = 8;
            requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked;
            break;
        case DevFmtShort:
            requestedFormat.mBitsPerChannel = 16;
            requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
            break;
        case DevFmtInt:
            requestedFormat.mBitsPerChannel = 32;
            requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
            break;
        case DevFmtFloat:
            requestedFormat.mBitsPerChannel = 32;
            requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked;
            break;
        case DevFmtByte:
        case DevFmtUShort:
        case DevFmtUInt:
            ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType));
            goto error;
    }

    switch(device->FmtChans)
    {
        case DevFmtMono:
            requestedFormat.mChannelsPerFrame = 1;
            break;
        case DevFmtStereo:
            requestedFormat.mChannelsPerFrame = 2;
            break;

        case DevFmtQuad:
        case DevFmtX51:
        case DevFmtX51Side:
        case DevFmtX61:
        case DevFmtX71:
            ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans));
            goto error;
    }

    requestedFormat.mBytesPerFrame = requestedFormat.mChannelsPerFrame * requestedFormat.mBitsPerChannel / 8;
    requestedFormat.mBytesPerPacket = requestedFormat.mBytesPerFrame;
    requestedFormat.mSampleRate = device->Frequency;
    requestedFormat.mFormatID = kAudioFormatLinearPCM;
    requestedFormat.mReserved = 0;
    requestedFormat.mFramesPerPacket = 1;

    // save requested format description for later use
    data->format = requestedFormat;
    data->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);

    // Use intermediate format for sample rate conversion (outputFormat)
    // Set sample rate to the same as hardware for resampling later
    outputFormat = requestedFormat;
    outputFormat.mSampleRate = hardwareFormat.mSampleRate;

    // Determine sample rate ratio for resampling
    data->sampleRateRatio = outputFormat.mSampleRate / device->Frequency;

    // The output format should be the requested format, but using the hardware sample rate
    // This is because the AudioUnit will automatically scale other properties, except for sample rate
    err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, (void *)&outputFormat, sizeof(outputFormat));
    if(err != noErr)
    {
        ERR("AudioUnitSetProperty failed\n");
        goto error;
    }

    // Set the AudioUnit output format frame count
    outputFrameCount = device->UpdateSize * data->sampleRateRatio;
    err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount));
    if(err != noErr)
    {
        ERR("AudioUnitSetProperty failed: %d\n", err);
        goto error;
    }

    // Set up sample converter
    err = AudioConverterNew(&outputFormat, &requestedFormat, &data->audioConverter);
    if(err != noErr)
    {
        ERR("AudioConverterNew failed: %d\n", err);
        goto error;
    }

    // Create a buffer for use in the resample callback
    data->resampleBuffer = malloc(device->UpdateSize * data->frameSize * data->sampleRateRatio);

    // Allocate buffer for the AudioUnit output
    data->bufferList = allocate_buffer_list(outputFormat.mChannelsPerFrame, device->UpdateSize * data->frameSize * data->sampleRateRatio);
    if(data->bufferList == NULL)
        goto error;

    data->ring = CreateRingBuffer(data->frameSize, (device->UpdateSize * data->sampleRateRatio) * device->NumUpdates);
    if(data->ring == NULL)
        goto error;

    al_string_copy_cstr(&device->DeviceName, deviceName);

    return ALC_NO_ERROR;

error:
    DestroyRingBuffer(data->ring);
    free(data->resampleBuffer);
    destroy_buffer_list(data->bufferList);

    if(data->audioConverter)
        AudioConverterDispose(data->audioConverter);
    if(data->audioUnit)
        CloseComponent(data->audioUnit);

    free(data);
    device->ExtraData = NULL;

    return ALC_INVALID_VALUE;
}
Example #7
0
void InitHrtf(void)
{
    char *fnamelist=NULL, *next=NULL;
    const char *val;

    if(ConfigValueStr(NULL, "hrtf_tables", &val))
        next = fnamelist = strdup(val);
    while(next && *next)
    {
        const ALubyte maxDelay = SRC_HISTORY_LENGTH-1;
        struct Hrtf newdata;
        ALboolean failed;
        ALchar magic[9];
        ALsizei i, j;
        char *fname;
        FILE *f;

        fname = next;
        next = strchr(fname, ',');
        if(next)
        {
            while(next != fname)
            {
                next--;
                if(!isspace(*next))
                {
                    *(next++) = '\0';
                    break;
                }
            }
            while(isspace(*next) || *next == ',')
                next++;
        }

        if(!fname[0])
            continue;
        TRACE("Loading %s\n", fname);
        f = fopen(fname, "rb");
        if(f == NULL)
        {
            ERR("Could not open %s\n", fname);
            continue;
        }

        failed = AL_FALSE;
        if(fread(magic, 1, sizeof(magicMarker), f) != sizeof(magicMarker))
        {
            ERR("Failed to read magic marker\n");
            failed = AL_TRUE;
        }
        else if(memcmp(magic, magicMarker, sizeof(magicMarker)) != 0)
        {
            magic[8] = 0;
            ERR("Invalid magic marker: \"%s\"\n", magic);
            failed = AL_TRUE;
        }

        if(!failed)
        {
            ALushort hrirCount, hrirSize;
            ALubyte  evCount;

            newdata.sampleRate  = fgetc(f);
            newdata.sampleRate |= fgetc(f)<<8;
            newdata.sampleRate |= fgetc(f)<<16;
            newdata.sampleRate |= fgetc(f)<<24;

            hrirCount  = fgetc(f);
            hrirCount |= fgetc(f)<<8;

            hrirSize  = fgetc(f);
            hrirSize |= fgetc(f)<<8;

            evCount = fgetc(f);

            if(hrirCount != HRIR_COUNT || hrirSize != HRIR_LENGTH || evCount != ELEV_COUNT)
            {
                ERR("Unsupported value: hrirCount=%d (%d), hrirSize=%d (%d), evCount=%d (%d)\n",
                    hrirCount, HRIR_COUNT, hrirSize, HRIR_LENGTH, evCount, ELEV_COUNT);
                failed = AL_TRUE;
            }
        }

        if(!failed)
        {
            for(i = 0;i < ELEV_COUNT;i++)
            {
                ALushort offset;
                offset  = fgetc(f);
                offset |= fgetc(f)<<8;
                if(offset != evOffset[i])
                {
                    ERR("Unsupported evOffset[%d] value: %d (%d)\n", i, offset, evOffset[i]);
                    failed = AL_TRUE;
                }
            }
        }

        if(!failed)
        {
            for(i = 0;i < HRIR_COUNT;i++)
            {
                for(j = 0;j < HRIR_LENGTH;j++)
                {
                    ALshort coeff;
                    coeff  = fgetc(f);
                    coeff |= fgetc(f)<<8;
                    newdata.coeffs[i][j] = coeff;
                }
            }
            for(i = 0;i < HRIR_COUNT;i++)
            {
                ALubyte delay;
                delay = fgetc(f);
                newdata.delays[i] = delay;
                if(delay > maxDelay)
                {
                    ERR("Invalid delay[%d]: %d (%d)\n", i, delay, maxDelay);
                    failed = AL_TRUE;
                }
            }

            if(feof(f))
            {
                ERR("Premature end of data\n");
                failed = AL_TRUE;
            }
        }

        fclose(f);
        f = NULL;

        if(!failed)
        {
            void *temp = realloc(LoadedHrtfs, (NumLoadedHrtfs+1)*sizeof(LoadedHrtfs[0]));
            if(temp != NULL)
            {
                LoadedHrtfs = temp;
                TRACE("Loaded HRTF support for format: %s %uhz\n",
                      DevFmtChannelsString(DevFmtStereo), newdata.sampleRate);
                LoadedHrtfs[NumLoadedHrtfs++] = newdata;
            }
        }
        else
            ERR("Failed to load %s\n", fname);
    }
    free(fnamelist);
    fnamelist = NULL;
}
Example #8
0
static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self)
{
    ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
    audio_info_t info;
    ALsizei frameSize;
    ALsizei numChannels;

    AUDIO_INITINFO(&info);

    info.play.sample_rate = device->Frequency;

    if(device->FmtChans != DevFmtMono)
        device->FmtChans = DevFmtStereo;
    numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
    info.play.channels = numChannels;

    switch(device->FmtType)
    {
        case DevFmtByte:
            info.play.precision = 8;
            info.play.encoding = AUDIO_ENCODING_LINEAR;
            break;
        case DevFmtUByte:
            info.play.precision = 8;
            info.play.encoding = AUDIO_ENCODING_LINEAR8;
            break;
        case DevFmtUShort:
        case DevFmtInt:
        case DevFmtUInt:
        case DevFmtFloat:
            device->FmtType = DevFmtShort;
            /* fall-through */
        case DevFmtShort:
            info.play.precision = 16;
            info.play.encoding = AUDIO_ENCODING_LINEAR;
            break;
    }

    frameSize = numChannels * BytesFromDevFmt(device->FmtType);
    info.play.buffer_size = device->UpdateSize*device->NumUpdates * frameSize;

    if(ioctl(self->fd, AUDIO_SETINFO, &info) < 0)
    {
        ERR("ioctl failed: %s\n", strerror(errno));
        return ALC_FALSE;
    }

    if(ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != (ALsizei)info.play.channels)
    {
        ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(device->FmtChans), info.play.channels);
        return ALC_FALSE;
    }

    if(!((info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR8 && device->FmtType == DevFmtUByte) ||
         (info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtByte) ||
         (info.play.precision == 16 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtShort) ||
         (info.play.precision == 32 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtInt)))
    {
        ERR("Could not set %s samples, got %d (0x%x)\n", DevFmtTypeString(device->FmtType),
            info.play.precision, info.play.encoding);
        return ALC_FALSE;
    }

    device->Frequency = info.play.sample_rate;
    device->UpdateSize = (info.play.buffer_size/device->NumUpdates) + 1;

    SetDefaultChannelOrder(device);

    free(self->mix_data);
    self->data_size = device->UpdateSize * FrameSizeFromDevFmt(
        device->FmtChans, device->FmtType, device->AmbiOrder
    );
    self->mix_data = calloc(1, self->data_size);

    return ALC_TRUE;
}
Example #9
0
static ALCenum pa_open_playback(ALCdevice *device, const ALCchar *deviceName)
{
    PaStreamParameters outParams;
    pa_data *data;
    PaError err;

    if(!deviceName)
        deviceName = pa_device;
    else if(strcmp(deviceName, pa_device) != 0)
        return ALC_INVALID_VALUE;

    data = (pa_data*)calloc(1, sizeof(pa_data));
    data->update_size = device->UpdateSize;

    device->ExtraData = data;

    outParams.device = -1;
    if(!ConfigValueInt("port", "device", &outParams.device) || outParams.device < 0)
        outParams.device = Pa_GetDefaultOutputDevice();
    outParams.suggestedLatency = (device->UpdateSize*device->NumUpdates) /
                                 (float)device->Frequency;
    outParams.hostApiSpecificStreamInfo = NULL;

    switch(device->FmtType)
    {
        case DevFmtByte:
            outParams.sampleFormat = paInt8;
            break;
        case DevFmtUByte:
            outParams.sampleFormat = paUInt8;
            break;
        case DevFmtUShort:
            device->FmtType = DevFmtShort;
            /* fall-through */
        case DevFmtShort:
            outParams.sampleFormat = paInt16;
            break;
        case DevFmtFloat:
            outParams.sampleFormat = paFloat32;
            break;
    }
    outParams.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2);

    SetDefaultChannelOrder(device);

    err = Pa_OpenStream(&data->stream, NULL, &outParams, device->Frequency,
                        device->UpdateSize, paNoFlag, pa_callback, device);
    if(err != paNoError)
    {
        ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err));
        device->ExtraData = NULL;
        free(data);
        return ALC_INVALID_VALUE;
    }

    device->szDeviceName = strdup(deviceName);

    if((ALuint)outParams.channelCount != ChannelsFromDevFmt(device->FmtChans))
    {
        if(outParams.channelCount != 1 && outParams.channelCount != 2)
        {
            ERR("Unhandled channel count: %u\n", outParams.channelCount);
            Pa_CloseStream(data->stream);
            device->ExtraData = NULL;
            free(data);
            return ALC_INVALID_VALUE;
        }
        if((device->Flags&DEVICE_CHANNELS_REQUEST))
            ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(device->FmtChans), outParams.channelCount);
        device->Flags &= ~DEVICE_CHANNELS_REQUEST;
        device->FmtChans = ((outParams.channelCount==1) ? DevFmtMono : DevFmtStereo);
    }

    return ALC_NO_ERROR;
}
Example #10
0
File: winmm.c Project: 9heart/DT3
static ALCenum WinMMOpenPlayback(ALCdevice *pDevice, const ALCchar *deviceName)
{
    WAVEFORMATEX wfexFormat;
    WinMMData *pData = NULL;
    UINT lDeviceID = 0;
    MMRESULT res;
    ALuint i = 0;

    // Find the Device ID matching the deviceName if valid
    if(!deviceName || strcmp(deviceName, woDefault) == 0)
        lDeviceID = WAVE_MAPPER;
    else
    {
        if(!PlaybackDeviceList)
            ProbePlaybackDevices();

        for(i = 0;i < NumPlaybackDevices;i++)
        {
            if(PlaybackDeviceList[i] &&
               strcmp(deviceName, PlaybackDeviceList[i]) == 0)
            {
                lDeviceID = i;
                break;
            }
        }
        if(i == NumPlaybackDevices)
            return ALC_INVALID_VALUE;
    }

    pData = calloc(1, sizeof(*pData));
    if(!pData)
        return ALC_OUT_OF_MEMORY;
    pDevice->ExtraData = pData;

    if(pDevice->FmtChans != DevFmtMono)
    {
        if((pDevice->Flags&DEVICE_CHANNELS_REQUEST) &&
           pDevice->FmtChans != DevFmtStereo)
        {
            ERR("Failed to set %s, got Stereo instead\n", DevFmtChannelsString(pDevice->FmtChans));
            pDevice->Flags &= ~DEVICE_CHANNELS_REQUEST;
        }
        pDevice->FmtChans = DevFmtStereo;
    }
    switch(pDevice->FmtType)
    {
        case DevFmtByte:
            pDevice->FmtType = DevFmtUByte;
            break;
        case DevFmtUShort:
            pDevice->FmtType = DevFmtShort;
            break;
        case DevFmtUByte:
        case DevFmtShort:
        case DevFmtFloat:
            break;
    }

retry_open:
    memset(&wfexFormat, 0, sizeof(WAVEFORMATEX));
    wfexFormat.wFormatTag = ((pDevice->FmtType == DevFmtFloat) ?
                             WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM);
    wfexFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans);
    wfexFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8;
    wfexFormat.nBlockAlign = wfexFormat.wBitsPerSample *
                             wfexFormat.nChannels / 8;
    wfexFormat.nSamplesPerSec = pDevice->Frequency;
    wfexFormat.nAvgBytesPerSec = wfexFormat.nSamplesPerSec *
                                 wfexFormat.nBlockAlign;
    wfexFormat.cbSize = 0;

    if((res=waveOutOpen(&pData->hWaveHandle.Out, lDeviceID, &wfexFormat, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
    {
        if(pDevice->FmtType == DevFmtFloat)
        {
            pDevice->FmtType = DevFmtShort;
            goto retry_open;
        }
        ERR("waveOutOpen failed: %u\n", res);
        goto failure;
    }

    pData->hWaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    if(pData->hWaveThreadEvent == NULL)
    {
        ERR("CreateEvent failed: %lu\n", GetLastError());
        goto failure;
    }

    pData->Frequency = pDevice->Frequency;

    pDevice->szDeviceName = strdup((lDeviceID==WAVE_MAPPER) ? woDefault :
                                   PlaybackDeviceList[lDeviceID]);
    return ALC_NO_ERROR;

failure:
    if(pData->hWaveThreadEvent)
        CloseHandle(pData->hWaveThreadEvent);

    if(pData->hWaveHandle.Out)
        waveOutClose(pData->hWaveHandle.Out);

    free(pData);
    pDevice->ExtraData = NULL;
    return ALC_INVALID_VALUE;
}
Example #11
0
static ALCboolean alsa_reset_playback(ALCdevice *device)
{
    alsa_data *data = (alsa_data*)device->ExtraData;
    snd_pcm_uframes_t periodSizeInFrames;
    unsigned int periodLen, bufferLen;
    snd_pcm_sw_params_t *sp = NULL;
    snd_pcm_hw_params_t *p = NULL;
    snd_pcm_access_t access;
    snd_pcm_format_t format;
    unsigned int periods;
    unsigned int rate;
    int allowmmap;
    char *err;
    int i;


    format = -1;
    switch(device->FmtType)
    {
        case DevFmtByte:
            format = SND_PCM_FORMAT_S8;
            break;
        case DevFmtUByte:
            format = SND_PCM_FORMAT_U8;
            break;
        case DevFmtShort:
            format = SND_PCM_FORMAT_S16;
            break;
        case DevFmtUShort:
            format = SND_PCM_FORMAT_U16;
            break;
        case DevFmtFloat:
            format = SND_PCM_FORMAT_FLOAT;
            break;
    }

    allowmmap = GetConfigValueBool("alsa", "mmap", 1);
    periods = device->NumUpdates;
    periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency;
    bufferLen = periodLen * periods;
    rate = device->Frequency;

    err = NULL;
    snd_pcm_hw_params_malloc(&p);

    if((i=snd_pcm_hw_params_any(data->pcmHandle, p)) < 0)
        err = "any";
    /* set interleaved access */
    if(i >= 0 && (!allowmmap || (i=snd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0))
    {
        if(periods > 2)
        {
            periods--;
            bufferLen = periodLen * periods;
        }
        if((i=snd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
            err = "set access";
    }
    /* set format (implicitly sets sample bits) */
    if(i >= 0 && (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, format)) < 0)
    {
        device->FmtType = DevFmtFloat;
        if(format == SND_PCM_FORMAT_FLOAT ||
           (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_FLOAT)) < 0)
        {
            device->FmtType = DevFmtShort;
            if(format == SND_PCM_FORMAT_S16 ||
               (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_S16)) < 0)
            {
                device->FmtType = DevFmtUByte;
                if(format == SND_PCM_FORMAT_U8 ||
                   (i=snd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_U8)) < 0)
                    err = "set format";
            }
        }
    }
    /* set channels (implicitly sets frame bits) */
    if(i >= 0 && (i=snd_pcm_hw_params_set_channels(data->pcmHandle, p, ChannelsFromDevFmt(device->FmtChans))) < 0)
    {
        if((i=snd_pcm_hw_params_set_channels(data->pcmHandle, p, 2)) < 0)
        {
            if((i=snd_pcm_hw_params_set_channels(data->pcmHandle, p, 1)) < 0)
                err = "set channels";
            else
            {
                if((device->Flags&DEVICE_CHANNELS_REQUEST))
                    ERR("Failed to set %s, got Mono instead\n", DevFmtChannelsString(device->FmtChans));
                device->FmtChans = DevFmtMono;
            }
        }
        else
        {
            if((device->Flags&DEVICE_CHANNELS_REQUEST))
                ERR("Failed to set %s, got Stereo instead\n", DevFmtChannelsString(device->FmtChans));
            device->FmtChans = DevFmtStereo;
        }
        device->Flags &= ~DEVICE_CHANNELS_REQUEST;
    }
    if(i >= 0 && (i=snd_pcm_hw_params_set_rate_resample(data->pcmHandle, p, 0)) < 0)
    {
        ERR("Failed to disable ALSA resampler\n");
        i = 0;
    }
    /* set rate (implicitly constrains period/buffer parameters) */
    if(i >= 0 && (i=snd_pcm_hw_params_set_rate_near(data->pcmHandle, p, &rate, NULL)) < 0)
        err = "set rate near";
    /* set buffer time (implicitly constrains period/buffer parameters) */
    if(i >= 0 && (i=snd_pcm_hw_params_set_buffer_time_near(data->pcmHandle, p, &bufferLen, NULL)) < 0)
        err = "set buffer time near";
    /* set period time in frame units (implicitly sets buffer size/bytes/time and period size/bytes) */
    if(i >= 0 && (i=snd_pcm_hw_params_set_period_time_near(data->pcmHandle, p, &periodLen, NULL)) < 0)
        err = "set period time near";
    /* install and prepare hardware configuration */
    if(i >= 0 && (i=snd_pcm_hw_params(data->pcmHandle, p)) < 0)
        err = "set params";
    if(i >= 0 && (i=snd_pcm_hw_params_get_access(p, &access)) < 0)
        err = "get access";
    if(i >= 0 && (i=snd_pcm_hw_params_get_period_size(p, &periodSizeInFrames, NULL)) < 0)
        err = "get period size";
    if(i >= 0 && (i=snd_pcm_hw_params_get_periods(p, &periods, NULL)) < 0)
        err = "get periods";
    if(i < 0)
    {
        ERR("%s failed: %s\n", err, snd_strerror(i));
        snd_pcm_hw_params_free(p);
        return ALC_FALSE;
    }

    snd_pcm_hw_params_free(p);

    err = NULL;
    snd_pcm_sw_params_malloc(&sp);

    if((i=snd_pcm_sw_params_current(data->pcmHandle, sp)) != 0)
        err = "sw current";
    if(i == 0 && (i=snd_pcm_sw_params_set_avail_min(data->pcmHandle, sp, periodSizeInFrames)) != 0)
        err = "sw set avail min";
    if(i == 0 && (i=snd_pcm_sw_params(data->pcmHandle, sp)) != 0)
        err = "sw set params";
    if(i != 0)
    {
        ERR("%s failed: %s\n", err, snd_strerror(i));
        snd_pcm_sw_params_free(sp);
        return ALC_FALSE;
    }

    snd_pcm_sw_params_free(sp);

    if(device->Frequency != rate)
    {
        if((device->Flags&DEVICE_FREQUENCY_REQUEST))
            ERR("Failed to set %dhz, got %dhz instead\n", device->Frequency, rate);
        device->Flags &= ~DEVICE_FREQUENCY_REQUEST;
        device->Frequency = rate;
    }

    SetDefaultChannelOrder(device);

    data->size = snd_pcm_frames_to_bytes(data->pcmHandle, periodSizeInFrames);
    if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
    {
        /* Increase periods by one, since the temp buffer counts as an extra
         * period */
        periods++;
        data->buffer = malloc(data->size);
        if(!data->buffer)
        {
            ERR("buffer malloc failed\n");
            return ALC_FALSE;
        }
        device->UpdateSize = periodSizeInFrames;
        device->NumUpdates = periods;
        data->thread = StartThread(ALSANoMMapProc, device);
    }
    else
    {
        i = snd_pcm_prepare(data->pcmHandle);
        if(i < 0)
        {
            ERR("prepare error: %s\n", snd_strerror(i));
            return ALC_FALSE;
        }
        device->UpdateSize = periodSizeInFrames;
        device->NumUpdates = periods;
        data->thread = StartThread(ALSAProc, device);
    }
    if(data->thread == NULL)
    {
        ERR("Could not create playback thread\n");
        free(data->buffer);
        data->buffer = NULL;
        return ALC_FALSE;
    }

    return ALC_TRUE;
}