Exemplo n.º 1
0
static HRESULT DSOUND_WaveFormat(DirectSoundDevice *device, IAudioClient *client,
				 BOOL forcewave, WAVEFORMATEX **wfx)
{
    WAVEFORMATEXTENSIBLE *retwfe = NULL;
    WAVEFORMATEX *w;
    HRESULT hr;

    if (!forcewave) {
        WAVEFORMATEXTENSIBLE *mixwfe;
        hr = IAudioClient_GetMixFormat(client, (WAVEFORMATEX**)&mixwfe);

        if (FAILED(hr))
            return hr;

        if (mixwfe->Format.nChannels < device->num_speakers) {
            device->speaker_config = DSOUND_FindSpeakerConfig(device->mmdevice, mixwfe->Format.nChannels);
            DSOUND_ParseSpeakerConfig(device);
        } else if (mixwfe->Format.nChannels > device->num_speakers) {
            mixwfe->Format.nChannels = device->num_speakers;
            mixwfe->Format.nBlockAlign = mixwfe->Format.nChannels * mixwfe->Format.wBitsPerSample / 8;
            mixwfe->Format.nAvgBytesPerSec = mixwfe->Format.nSamplesPerSec * mixwfe->Format.nBlockAlign;
            mixwfe->dwChannelMask = speaker_config_to_channel_mask(device->speaker_config);
        }

        if (!IsEqualGUID(&mixwfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) {
            WAVEFORMATEXTENSIBLE testwfe = *mixwfe;

            testwfe.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
            testwfe.Samples.wValidBitsPerSample = testwfe.Format.wBitsPerSample = 32;
            testwfe.Format.nBlockAlign = testwfe.Format.nChannels * testwfe.Format.wBitsPerSample / 8;
            testwfe.Format.nAvgBytesPerSec = testwfe.Format.nSamplesPerSec * testwfe.Format.nBlockAlign;

            if (FAILED(IAudioClient_IsFormatSupported(client, AUDCLNT_SHAREMODE_SHARED, &testwfe.Format, (WAVEFORMATEX**)&retwfe)))
                w = DSOUND_CopyFormat(&mixwfe->Format);
            else if (retwfe)
                w = DSOUND_CopyFormat(&retwfe->Format);
            else
                w = DSOUND_CopyFormat(&testwfe.Format);
            CoTaskMemFree(retwfe);
            retwfe = NULL;
        } else
            w = DSOUND_CopyFormat(&mixwfe->Format);
        CoTaskMemFree(mixwfe);
    } else if (device->primary_pwfx->wFormatTag == WAVE_FORMAT_PCM ||
               device->primary_pwfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
        WAVEFORMATEX *wi = device->primary_pwfx;
        WAVEFORMATEXTENSIBLE *wfe;

        /* Convert to WAVEFORMATEXTENSIBLE */
        w = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEXTENSIBLE));
        wfe = (WAVEFORMATEXTENSIBLE*)w;
        if (!wfe)
            return DSERR_OUTOFMEMORY;

        wfe->Format = *wi;
        w->wFormatTag = WAVE_FORMAT_EXTENSIBLE;
        w->cbSize = sizeof(*wfe) - sizeof(*w);
        w->nBlockAlign = w->nChannels * w->wBitsPerSample / 8;
        w->nAvgBytesPerSec = w->nSamplesPerSec * w->nBlockAlign;

        wfe->dwChannelMask = 0;
        if (wi->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
            w->wBitsPerSample = 32;
            wfe->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
        } else
            wfe->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
        wfe->Samples.wValidBitsPerSample = w->wBitsPerSample;
    } else
        w = DSOUND_CopyFormat(device->primary_pwfx);

    if (!w)
        return DSERR_OUTOFMEMORY;

    hr = IAudioClient_IsFormatSupported(client, AUDCLNT_SHAREMODE_SHARED, w, (WAVEFORMATEX**)&retwfe);
    if (retwfe) {
        memcpy(w, retwfe, sizeof(WAVEFORMATEX) + retwfe->Format.cbSize);
        CoTaskMemFree(retwfe);
    }
    if (FAILED(hr)) {
        WARN("IsFormatSupported failed: %08x\n", hr);
        HeapFree(GetProcessHeap(), 0, w);
        return hr;
    }
    *wfx = w;
    return S_OK;
}
Exemplo n.º 2
0
HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
{
    HRESULT hres;
    REFERENCE_TIME period;
    UINT32 frames;
    DWORD period_ms;
    IAudioClient *client = NULL;
    IAudioRenderClient *render = NULL;
    IAudioStreamVolume *volume = NULL;
    DWORD fraglen;
    WAVEFORMATEX *wfx = NULL;
    DWORD oldspeakerconfig = device->speaker_config;

    TRACE("(%p, %d)\n", device, forcewave);

    hres = IMMDevice_Activate(device->mmdevice, &IID_IAudioClient,
            CLSCTX_INPROC_SERVER, NULL, (void **)&client);
    if(FAILED(hres)){
        WARN("Activate failed: %08x\n", hres);
        return hres;
    }

    hres = DSOUND_WaveFormat(device, client, forcewave, &wfx);
    if (FAILED(hres)) {
        IAudioClient_Release(client);
        return hres;
    }

    hres = IAudioClient_Initialize(client,
            AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST |
            AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 800000, 0, wfx, NULL);
    if(FAILED(hres)){
        IAudioClient_Release(client);
        ERR("Initialize failed: %08x\n", hres);
        return hres;
    }

    IAudioClient_SetEventHandle(client, device->sleepev);

    hres = IAudioClient_GetService(client, &IID_IAudioRenderClient, (void**)&render);
    if(FAILED(hres))
        goto err_service;

    hres = IAudioClient_GetService(client, &IID_IAudioStreamVolume, (void**)&volume);
    if(FAILED(hres))
        goto err_service;

    /* Now kick off the timer so the event fires periodically */
    hres = IAudioClient_Start(client);
    if (FAILED(hres)) {
        WARN("Start failed with %08x\n", hres);
        goto err;
    }
    hres = IAudioClient_GetStreamLatency(client, &period);
    if (FAILED(hres)) {
        WARN("GetStreamLatency failed with %08x\n", hres);
        goto err;
    }
    hres = IAudioClient_GetBufferSize(client, &frames);
    if (FAILED(hres)) {
        WARN("GetBufferSize failed with %08x\n", hres);
        goto err;
    }

    period_ms = (period + 9999) / 10000;
    fraglen = MulDiv(wfx->nSamplesPerSec, period, 10000000) * wfx->nBlockAlign;
    TRACE("period %u ms fraglen %u buflen %u\n", period_ms, fraglen, frames * wfx->nBlockAlign);

    hres = DSOUND_PrimaryOpen(device, wfx, frames, forcewave);
    if(FAILED(hres))
        goto err;

    DSOUND_ReleaseDevice(device);
    device->client = client;
    device->render = render;
    device->volume = volume;
    device->fraglen = fraglen;
    device->aclen = frames * wfx->nBlockAlign;

    if (period_ms < 3)
        device->sleeptime = 5;
    else
        device->sleeptime = period_ms * 5 / 2;

    return S_OK;

err_service:
    WARN("GetService failed: %08x\n", hres);
err:
    device->speaker_config = oldspeakerconfig;
    DSOUND_ParseSpeakerConfig(device);
    if (volume)
        IAudioStreamVolume_Release(volume);
    if (render)
        IAudioRenderClient_Release(render);
    IAudioClient_Release(client);
    HeapFree(GetProcessHeap(), 0, wfx);
    return hres;
}
Exemplo n.º 3
0
HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
{
    UINT prebuf_frames;
    REFERENCE_TIME prebuf_rt;
    WAVEFORMATEX *wfx = NULL;
    HRESULT hres;
    REFERENCE_TIME period;
    DWORD period_ms;

    TRACE("(%p, %d)\n", device, forcewave);

    if(device->client){
        IAudioClient_Release(device->client);
        device->client = NULL;
    }
    if(device->render){
        IAudioRenderClient_Release(device->render);
        device->render = NULL;
    }
    if(device->clock){
        IAudioClock_Release(device->clock);
        device->clock = NULL;
    }
    if(device->volume){
        IAudioStreamVolume_Release(device->volume);
        device->volume = NULL;
    }

    hres = IMMDevice_Activate(device->mmdevice, &IID_IAudioClient,
            CLSCTX_INPROC_SERVER, NULL, (void **)&device->client);
    if(FAILED(hres)) {
        WARN("Activate failed: %08x\n", hres);
        return hres;
    }

    device->speaker_config = DSOUND_FindSpeakerConfig(device->mmdevice, 0);

    DSOUND_ParseSpeakerConfig(device);

    hres = DSOUND_WaveFormat(device, device->client, forcewave, &wfx);
    if (FAILED(hres)) {
        IAudioClient_Release(device->client);
        device->client = NULL;
        return hres;
    }
    HeapFree(GetProcessHeap(), 0, device->pwfx);
    device->pwfx = wfx;

    prebuf_frames = device->prebuf * DSOUND_fraglen(device) / device->pwfx->nBlockAlign;
    prebuf_rt = (10000000 * (UINT64)prebuf_frames) / device->pwfx->nSamplesPerSec;

    hres = IAudioClient_Initialize(device->client,
            AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST |
            AUDCLNT_STREAMFLAGS_EVENTCALLBACK, prebuf_rt, 0, device->pwfx, NULL);
    if(FAILED(hres)){
        IAudioClient_Release(device->client);
        device->client = NULL;
        WARN("Initialize failed: %08x\n", hres);
        return hres;
    }
    IAudioClient_SetEventHandle(device->client, device->sleepev);

    hres = IAudioClient_GetService(device->client, &IID_IAudioRenderClient,
            (void**)&device->render);
    if(FAILED(hres)){
        IAudioClient_Release(device->client);
        device->client = NULL;
        WARN("GetService failed: %08x\n", hres);
        return hres;
    }

    hres = IAudioClient_GetService(device->client, &IID_IAudioClock,
            (void**)&device->clock);
    if(FAILED(hres)){
        IAudioClient_Release(device->client);
        IAudioRenderClient_Release(device->render);
        device->client = NULL;
        device->render = NULL;
        WARN("GetService failed: %08x\n", hres);
        return hres;
    }

    hres = IAudioClient_GetService(device->client, &IID_IAudioStreamVolume,
            (void**)&device->volume);
    if(FAILED(hres)){
        IAudioClient_Release(device->client);
        IAudioRenderClient_Release(device->render);
        IAudioClock_Release(device->clock);
        device->client = NULL;
        device->render = NULL;
        device->clock = NULL;
        WARN("GetService failed: %08x\n", hres);
        return hres;
    }

    /* Now kick off the timer so the event fires periodically */
    hres = IAudioClient_Start(device->client);
    if (FAILED(hres))
        WARN("starting failed with %08x\n", hres);

    hres = IAudioClient_GetStreamLatency(device->client, &period);
    if (FAILED(hres)) {
        WARN("GetStreamLatency failed with %08x\n", hres);
        period_ms = 10;
    } else
        period_ms = (period + 9999) / 10000;
    TRACE("period %u ms fraglen %u prebuf %u\n", period_ms, device->fraglen, device->prebuf);

    if (period_ms < 3)
        device->sleeptime = 5;
    else
        device->sleeptime = period_ms * 5 / 2;

    return S_OK;
}