winecoreaudio: Add a temporary capture_resample syscall.
Eventually everything that calls this will reside in the unixlib. Signed-off-by: Huw Davies <huw@codeweavers.com> Signed-off-by: Andrew Eikum <aeikum@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
75b57ea13d
commit
de39001552
|
@ -693,6 +693,7 @@ static NTSTATUS release_stream( void *args )
|
||||||
}
|
}
|
||||||
|
|
||||||
if(stream->converter) AudioConverterDispose(stream->converter);
|
if(stream->converter) AudioConverterDispose(stream->converter);
|
||||||
|
free(stream->resamp_buffer);
|
||||||
free(stream->wrap_buffer);
|
free(stream->wrap_buffer);
|
||||||
free(stream->cap_buffer);
|
free(stream->cap_buffer);
|
||||||
if(stream->local_buffer)
|
if(stream->local_buffer)
|
||||||
|
@ -1012,6 +1013,108 @@ unsupported:
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static UINT buf_ptr_diff(UINT left, UINT right, UINT bufsize)
|
||||||
|
{
|
||||||
|
if(left <= right)
|
||||||
|
return right - left;
|
||||||
|
return bufsize - (left - right);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* place data from cap_buffer into provided AudioBufferList */
|
||||||
|
static OSStatus feed_cb(AudioConverterRef converter, UInt32 *nframes, AudioBufferList *data,
|
||||||
|
AudioStreamPacketDescription **packets, void *user)
|
||||||
|
{
|
||||||
|
struct coreaudio_stream *stream = user;
|
||||||
|
|
||||||
|
*nframes = min(*nframes, stream->cap_held_frames);
|
||||||
|
if(!*nframes){
|
||||||
|
data->mBuffers[0].mData = NULL;
|
||||||
|
data->mBuffers[0].mDataByteSize = 0;
|
||||||
|
data->mBuffers[0].mNumberChannels = stream->fmt->nChannels;
|
||||||
|
return noErr;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->mBuffers[0].mDataByteSize = *nframes * stream->fmt->nBlockAlign;
|
||||||
|
data->mBuffers[0].mNumberChannels = stream->fmt->nChannels;
|
||||||
|
|
||||||
|
if(stream->cap_offs_frames + *nframes > stream->cap_bufsize_frames){
|
||||||
|
UINT32 chunk_frames = stream->cap_bufsize_frames - stream->cap_offs_frames;
|
||||||
|
|
||||||
|
if(stream->wrap_bufsize_frames < *nframes){
|
||||||
|
free(stream->wrap_buffer);
|
||||||
|
stream->wrap_buffer = malloc(data->mBuffers[0].mDataByteSize);
|
||||||
|
stream->wrap_bufsize_frames = *nframes;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(stream->wrap_buffer, stream->cap_buffer + stream->cap_offs_frames * stream->fmt->nBlockAlign,
|
||||||
|
chunk_frames * stream->fmt->nBlockAlign);
|
||||||
|
memcpy(stream->wrap_buffer + chunk_frames * stream->fmt->nBlockAlign, stream->cap_buffer,
|
||||||
|
(*nframes - chunk_frames) * stream->fmt->nBlockAlign);
|
||||||
|
|
||||||
|
data->mBuffers[0].mData = stream->wrap_buffer;
|
||||||
|
}else
|
||||||
|
data->mBuffers[0].mData = stream->cap_buffer + stream->cap_offs_frames * stream->fmt->nBlockAlign;
|
||||||
|
|
||||||
|
stream->cap_offs_frames += *nframes;
|
||||||
|
stream->cap_offs_frames %= stream->cap_bufsize_frames;
|
||||||
|
stream->cap_held_frames -= *nframes;
|
||||||
|
|
||||||
|
if(packets)
|
||||||
|
*packets = NULL;
|
||||||
|
|
||||||
|
return noErr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS capture_resample(void *args)
|
||||||
|
{
|
||||||
|
struct coreaudio_stream *stream = args;
|
||||||
|
UINT32 resamp_period_frames = muldiv(stream->period_frames, stream->dev_desc.mSampleRate,
|
||||||
|
stream->fmt->nSamplesPerSec);
|
||||||
|
OSStatus sc;
|
||||||
|
|
||||||
|
/* the resampling process often needs more source frames than we'd
|
||||||
|
* guess from a straight conversion using the sample rate ratio. so
|
||||||
|
* only convert if we have extra source data. */
|
||||||
|
while(stream->cap_held_frames > resamp_period_frames * 2){
|
||||||
|
AudioBufferList converted_list;
|
||||||
|
UInt32 wanted_frames = stream->period_frames;
|
||||||
|
|
||||||
|
converted_list.mNumberBuffers = 1;
|
||||||
|
converted_list.mBuffers[0].mNumberChannels = stream->fmt->nChannels;
|
||||||
|
converted_list.mBuffers[0].mDataByteSize = wanted_frames * stream->fmt->nBlockAlign;
|
||||||
|
|
||||||
|
if(stream->resamp_bufsize_frames < wanted_frames){
|
||||||
|
free(stream->resamp_buffer);
|
||||||
|
stream->resamp_buffer = malloc(converted_list.mBuffers[0].mDataByteSize);
|
||||||
|
stream->resamp_bufsize_frames = wanted_frames;
|
||||||
|
}
|
||||||
|
|
||||||
|
converted_list.mBuffers[0].mData = stream->resamp_buffer;
|
||||||
|
|
||||||
|
sc = AudioConverterFillComplexBuffer(stream->converter, feed_cb,
|
||||||
|
stream, &wanted_frames, &converted_list, NULL);
|
||||||
|
if(sc != noErr){
|
||||||
|
WARN("AudioConverterFillComplexBuffer failed: %x\n", (int)sc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ca_wrap_buffer(stream->local_buffer,
|
||||||
|
stream->wri_offs_frames * stream->fmt->nBlockAlign,
|
||||||
|
stream->bufsize_frames * stream->fmt->nBlockAlign,
|
||||||
|
stream->resamp_buffer, wanted_frames * stream->fmt->nBlockAlign);
|
||||||
|
|
||||||
|
stream->wri_offs_frames += wanted_frames;
|
||||||
|
stream->wri_offs_frames %= stream->bufsize_frames;
|
||||||
|
if(stream->held_frames + wanted_frames > stream->bufsize_frames){
|
||||||
|
stream->lcl_offs_frames += buf_ptr_diff(stream->lcl_offs_frames, stream->wri_offs_frames,
|
||||||
|
stream->bufsize_frames);
|
||||||
|
stream->held_frames = stream->bufsize_frames;
|
||||||
|
}else
|
||||||
|
stream->held_frames += wanted_frames;
|
||||||
|
}
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
unixlib_entry_t __wine_unix_call_funcs[] =
|
unixlib_entry_t __wine_unix_call_funcs[] =
|
||||||
{
|
{
|
||||||
get_endpoint_ids,
|
get_endpoint_ids,
|
||||||
|
@ -1019,4 +1122,6 @@ unixlib_entry_t __wine_unix_call_funcs[] =
|
||||||
release_stream,
|
release_stream,
|
||||||
get_mix_format,
|
get_mix_format,
|
||||||
is_format_supported,
|
is_format_supported,
|
||||||
|
|
||||||
|
capture_resample /* temporary */
|
||||||
};
|
};
|
||||||
|
|
|
@ -138,10 +138,6 @@ struct ACImpl {
|
||||||
|
|
||||||
struct coreaudio_stream *stream;
|
struct coreaudio_stream *stream;
|
||||||
struct list entry;
|
struct list entry;
|
||||||
|
|
||||||
/* Temporary */
|
|
||||||
BYTE *feed_wrap_buffer;
|
|
||||||
UINT32 feed_wrap_bufsize_frames;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const IAudioClient3Vtbl AudioClient3_Vtbl;
|
static const IAudioClient3Vtbl AudioClient3_Vtbl;
|
||||||
|
@ -581,7 +577,6 @@ static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
|
||||||
if(This->stream->tmp_buffer)
|
if(This->stream->tmp_buffer)
|
||||||
NtFreeVirtualMemory(GetCurrentProcess(), (void **)&This->stream->tmp_buffer,
|
NtFreeVirtualMemory(GetCurrentProcess(), (void **)&This->stream->tmp_buffer,
|
||||||
&This->stream->tmp_buffer_size, MEM_RELEASE);
|
&This->stream->tmp_buffer_size, MEM_RELEASE);
|
||||||
HeapFree(GetProcessHeap(), 0, This->stream->resamp_buffer);
|
|
||||||
params.stream = This->stream;
|
params.stream = This->stream;
|
||||||
UNIX_CALL(release_stream, ¶ms);
|
UNIX_CALL(release_stream, ¶ms);
|
||||||
}
|
}
|
||||||
|
@ -591,7 +586,6 @@ static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
|
||||||
LeaveCriticalSection(&g_sessions_lock);
|
LeaveCriticalSection(&g_sessions_lock);
|
||||||
}
|
}
|
||||||
HeapFree(GetProcessHeap(), 0, This->vols);
|
HeapFree(GetProcessHeap(), 0, This->vols);
|
||||||
free(This->feed_wrap_buffer);
|
|
||||||
IMMDevice_Release(This->parent);
|
IMMDevice_Release(This->parent);
|
||||||
IUnknown_Release(This->pUnkFTMarshal);
|
IUnknown_Release(This->pUnkFTMarshal);
|
||||||
HeapFree(GetProcessHeap(), 0, This);
|
HeapFree(GetProcessHeap(), 0, This);
|
||||||
|
@ -736,103 +730,9 @@ static void silence_buffer(struct coreaudio_stream *stream, BYTE *buffer, UINT32
|
||||||
memset(buffer, 0, frames * stream->fmt->nBlockAlign);
|
memset(buffer, 0, frames * stream->fmt->nBlockAlign);
|
||||||
}
|
}
|
||||||
|
|
||||||
static UINT buf_ptr_diff(UINT left, UINT right, UINT bufsize)
|
|
||||||
{
|
|
||||||
if(left <= right)
|
|
||||||
return right - left;
|
|
||||||
return bufsize - (left - right);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* place data from cap_buffer into provided AudioBufferList */
|
|
||||||
static OSStatus feed_cb(AudioConverterRef converter, UInt32 *nframes, AudioBufferList *data,
|
|
||||||
AudioStreamPacketDescription **packets, void *user)
|
|
||||||
{
|
|
||||||
ACImpl *This = user;
|
|
||||||
|
|
||||||
*nframes = min(*nframes, This->stream->cap_held_frames);
|
|
||||||
if(!*nframes){
|
|
||||||
data->mBuffers[0].mData = NULL;
|
|
||||||
data->mBuffers[0].mDataByteSize = 0;
|
|
||||||
data->mBuffers[0].mNumberChannels = This->stream->fmt->nChannels;
|
|
||||||
return noErr;
|
|
||||||
}
|
|
||||||
|
|
||||||
data->mBuffers[0].mDataByteSize = *nframes * This->stream->fmt->nBlockAlign;
|
|
||||||
data->mBuffers[0].mNumberChannels = This->stream->fmt->nChannels;
|
|
||||||
|
|
||||||
if(This->stream->cap_offs_frames + *nframes > This->stream->cap_bufsize_frames){
|
|
||||||
UINT32 chunk_frames = This->stream->cap_bufsize_frames - This->stream->cap_offs_frames;
|
|
||||||
|
|
||||||
if(This->feed_wrap_bufsize_frames < *nframes){
|
|
||||||
free(This->feed_wrap_buffer);
|
|
||||||
This->feed_wrap_buffer = malloc(data->mBuffers[0].mDataByteSize);
|
|
||||||
This->feed_wrap_bufsize_frames = *nframes;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(This->feed_wrap_buffer, This->stream->cap_buffer + This->stream->cap_offs_frames * This->stream->fmt->nBlockAlign,
|
|
||||||
chunk_frames * This->stream->fmt->nBlockAlign);
|
|
||||||
memcpy(This->feed_wrap_buffer + chunk_frames * This->stream->fmt->nBlockAlign, This->stream->cap_buffer,
|
|
||||||
(*nframes - chunk_frames) * This->stream->fmt->nBlockAlign);
|
|
||||||
|
|
||||||
data->mBuffers[0].mData = This->feed_wrap_buffer;
|
|
||||||
}else
|
|
||||||
data->mBuffers[0].mData = This->stream->cap_buffer + This->stream->cap_offs_frames * This->stream->fmt->nBlockAlign;
|
|
||||||
|
|
||||||
This->stream->cap_offs_frames += *nframes;
|
|
||||||
This->stream->cap_offs_frames %= This->stream->cap_bufsize_frames;
|
|
||||||
This->stream->cap_held_frames -= *nframes;
|
|
||||||
|
|
||||||
if(packets)
|
|
||||||
*packets = NULL;
|
|
||||||
|
|
||||||
return noErr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void capture_resample(ACImpl *This)
|
static void capture_resample(ACImpl *This)
|
||||||
{
|
{
|
||||||
UINT32 resamp_period_frames = MulDiv(This->stream->period_frames, This->stream->dev_desc.mSampleRate, This->stream->fmt->nSamplesPerSec);
|
UNIX_CALL(capture_resample, This->stream);
|
||||||
OSStatus sc;
|
|
||||||
|
|
||||||
/* the resampling process often needs more source frames than we'd
|
|
||||||
* guess from a straight conversion using the sample rate ratio. so
|
|
||||||
* only convert if we have extra source data. */
|
|
||||||
while(This->stream->cap_held_frames > resamp_period_frames * 2){
|
|
||||||
AudioBufferList converted_list;
|
|
||||||
UInt32 wanted_frames = This->stream->period_frames;
|
|
||||||
|
|
||||||
converted_list.mNumberBuffers = 1;
|
|
||||||
converted_list.mBuffers[0].mNumberChannels = This->stream->fmt->nChannels;
|
|
||||||
converted_list.mBuffers[0].mDataByteSize = wanted_frames * This->stream->fmt->nBlockAlign;
|
|
||||||
|
|
||||||
if(This->stream->resamp_bufsize_frames < wanted_frames){
|
|
||||||
HeapFree(GetProcessHeap(), 0, This->stream->resamp_buffer);
|
|
||||||
This->stream->resamp_buffer = HeapAlloc(GetProcessHeap(), 0, converted_list.mBuffers[0].mDataByteSize);
|
|
||||||
This->stream->resamp_bufsize_frames = wanted_frames;
|
|
||||||
}
|
|
||||||
|
|
||||||
converted_list.mBuffers[0].mData = This->stream->resamp_buffer;
|
|
||||||
|
|
||||||
sc = AudioConverterFillComplexBuffer(This->stream->converter, feed_cb,
|
|
||||||
This, &wanted_frames, &converted_list, NULL);
|
|
||||||
if(sc != noErr){
|
|
||||||
WARN("AudioConverterFillComplexBuffer failed: %x\n", (int)sc);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ca_wrap_buffer(This->stream->local_buffer,
|
|
||||||
This->stream->wri_offs_frames * This->stream->fmt->nBlockAlign,
|
|
||||||
This->stream->bufsize_frames * This->stream->fmt->nBlockAlign,
|
|
||||||
This->stream->resamp_buffer, wanted_frames * This->stream->fmt->nBlockAlign);
|
|
||||||
|
|
||||||
This->stream->wri_offs_frames += wanted_frames;
|
|
||||||
This->stream->wri_offs_frames %= This->stream->bufsize_frames;
|
|
||||||
if(This->stream->held_frames + wanted_frames > This->stream->bufsize_frames){
|
|
||||||
This->stream->lcl_offs_frames += buf_ptr_diff(This->stream->lcl_offs_frames,
|
|
||||||
This->stream->wri_offs_frames, This->stream->bufsize_frames);
|
|
||||||
This->stream->held_frames = This->stream->bufsize_frames;
|
|
||||||
}else
|
|
||||||
This->stream->held_frames += wanted_frames;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
|
static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
|
||||||
|
|
|
@ -100,6 +100,8 @@ enum unix_funcs
|
||||||
unix_release_stream,
|
unix_release_stream,
|
||||||
unix_get_mix_format,
|
unix_get_mix_format,
|
||||||
unix_is_format_supported,
|
unix_is_format_supported,
|
||||||
|
|
||||||
|
unix_capture_resample /* temporary */
|
||||||
};
|
};
|
||||||
|
|
||||||
extern unixlib_handle_t coreaudio_handle;
|
extern unixlib_handle_t coreaudio_handle;
|
||||||
|
|
Loading…
Reference in New Issue