libobs/audio-monitoring: Add WASAPI init helper
audio_monitor_init_wasapi will be used for reconnect logic.master
parent
63ffae7d74
commit
7af886581d
|
@ -139,95 +139,6 @@ static bool process_audio_delay(struct audio_monitor *monitor, float **data,
|
|||
return false;
|
||||
}
|
||||
|
||||
static void on_audio_playback(void *param, obs_source_t *source,
|
||||
const struct audio_data *audio_data, bool muted)
|
||||
{
|
||||
struct audio_monitor *monitor = param;
|
||||
IAudioRenderClient *render = monitor->render;
|
||||
uint8_t *resample_data[MAX_AV_PLANES];
|
||||
float vol = source->user_volume;
|
||||
uint32_t resample_frames;
|
||||
uint64_t ts_offset;
|
||||
bool success;
|
||||
BYTE *output;
|
||||
|
||||
if (!TryAcquireSRWLockExclusive(&monitor->playback_mutex)) {
|
||||
return;
|
||||
}
|
||||
if (os_atomic_load_long(&source->activate_refs) == 0) {
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
success = audio_resampler_resample(
|
||||
monitor->resampler, resample_data, &resample_frames, &ts_offset,
|
||||
(const uint8_t *const *)audio_data->data,
|
||||
(uint32_t)audio_data->frames);
|
||||
if (!success) {
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
UINT32 pad = 0;
|
||||
monitor->client->lpVtbl->GetCurrentPadding(monitor->client, &pad);
|
||||
|
||||
bool decouple_audio = source->async_unbuffered &&
|
||||
source->async_decoupled;
|
||||
|
||||
if (monitor->source_has_video && !decouple_audio) {
|
||||
uint64_t ts = audio_data->timestamp - ts_offset;
|
||||
|
||||
if (!process_audio_delay(monitor, (float **)(&resample_data[0]),
|
||||
&resample_frames, ts, pad)) {
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT hr =
|
||||
render->lpVtbl->GetBuffer(render, resample_frames, &output);
|
||||
if (FAILED(hr)) {
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!muted) {
|
||||
/* apply volume */
|
||||
if (!close_float(vol, 1.0f, EPSILON)) {
|
||||
register float *cur = (float *)resample_data[0];
|
||||
register float *end =
|
||||
cur + resample_frames * monitor->channels;
|
||||
|
||||
while (cur < end)
|
||||
*(cur++) *= vol;
|
||||
}
|
||||
memcpy(output, resample_data[0],
|
||||
resample_frames * monitor->channels * sizeof(float));
|
||||
}
|
||||
|
||||
render->lpVtbl->ReleaseBuffer(render, resample_frames,
|
||||
muted ? AUDCLNT_BUFFERFLAGS_SILENT : 0);
|
||||
|
||||
unlock:
|
||||
ReleaseSRWLockExclusive(&monitor->playback_mutex);
|
||||
}
|
||||
|
||||
static inline void audio_monitor_free(struct audio_monitor *monitor)
|
||||
{
|
||||
if (monitor->ignore)
|
||||
return;
|
||||
|
||||
if (monitor->source) {
|
||||
obs_source_remove_audio_capture_callback(
|
||||
monitor->source, on_audio_playback, monitor);
|
||||
}
|
||||
|
||||
if (monitor->client)
|
||||
monitor->client->lpVtbl->Stop(monitor->client);
|
||||
|
||||
safe_release(monitor->client);
|
||||
safe_release(monitor->render);
|
||||
audio_resampler_destroy(monitor->resampler);
|
||||
circlebuf_free(&monitor->delay_buffer);
|
||||
da_free(monitor->buf);
|
||||
}
|
||||
|
||||
static enum speaker_layout convert_speaker_layout(DWORD layout, WORD channels)
|
||||
{
|
||||
switch (layout) {
|
||||
|
@ -246,37 +157,14 @@ static enum speaker_layout convert_speaker_layout(DWORD layout, WORD channels)
|
|||
return (enum speaker_layout)channels;
|
||||
}
|
||||
|
||||
extern bool devices_match(const char *id1, const char *id2);
|
||||
|
||||
static bool audio_monitor_init(struct audio_monitor *monitor,
|
||||
obs_source_t *source)
|
||||
static bool audio_monitor_init_wasapi(struct audio_monitor *monitor)
|
||||
{
|
||||
bool success = false;
|
||||
IMMDeviceEnumerator *immde = NULL;
|
||||
WAVEFORMATEX *wfex = NULL;
|
||||
bool success = false;
|
||||
UINT32 frames;
|
||||
HRESULT hr;
|
||||
|
||||
monitor->source = source;
|
||||
|
||||
const char *id = obs->audio.monitoring_device_id;
|
||||
if (!id) {
|
||||
warn("%s: No device ID set", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (source->info.output_flags & OBS_SOURCE_DO_NOT_SELF_MONITOR) {
|
||||
obs_data_t *s = obs_source_get_settings(source);
|
||||
const char *s_dev_id = obs_data_get_string(s, "device_id");
|
||||
bool match = devices_match(s_dev_id, id);
|
||||
obs_data_release(s);
|
||||
|
||||
if (match) {
|
||||
monitor->ignore = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------ *
|
||||
* Init device */
|
||||
|
||||
|
@ -289,6 +177,7 @@ static bool audio_monitor_init(struct audio_monitor *monitor,
|
|||
}
|
||||
|
||||
IMMDevice *device = NULL;
|
||||
const char *const id = obs->audio.monitoring_device_id;
|
||||
if (strcmp(id, "default") == 0) {
|
||||
hr = immde->lpVtbl->GetDefaultAudioEndpoint(immde, eRender,
|
||||
eConsole, &device);
|
||||
|
@ -378,8 +267,6 @@ static bool audio_monitor_init(struct audio_monitor *monitor,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
InitializeSRWLock(&monitor->playback_mutex);
|
||||
|
||||
success = true;
|
||||
|
||||
fail:
|
||||
|
@ -389,6 +276,125 @@ fail:
|
|||
return success;
|
||||
}
|
||||
|
||||
static void on_audio_playback(void *param, obs_source_t *source,
|
||||
const struct audio_data *audio_data, bool muted)
|
||||
{
|
||||
struct audio_monitor *monitor = param;
|
||||
IAudioRenderClient *render = monitor->render;
|
||||
uint8_t *resample_data[MAX_AV_PLANES];
|
||||
float vol = source->user_volume;
|
||||
uint32_t resample_frames;
|
||||
uint64_t ts_offset;
|
||||
bool success;
|
||||
BYTE *output;
|
||||
|
||||
if (!TryAcquireSRWLockExclusive(&monitor->playback_mutex)) {
|
||||
return;
|
||||
}
|
||||
if (os_atomic_load_long(&source->activate_refs) == 0) {
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
success = audio_resampler_resample(
|
||||
monitor->resampler, resample_data, &resample_frames, &ts_offset,
|
||||
(const uint8_t *const *)audio_data->data,
|
||||
(uint32_t)audio_data->frames);
|
||||
if (!success) {
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
UINT32 pad = 0;
|
||||
monitor->client->lpVtbl->GetCurrentPadding(monitor->client, &pad);
|
||||
|
||||
bool decouple_audio = source->async_unbuffered &&
|
||||
source->async_decoupled;
|
||||
|
||||
if (monitor->source_has_video && !decouple_audio) {
|
||||
uint64_t ts = audio_data->timestamp - ts_offset;
|
||||
|
||||
if (!process_audio_delay(monitor, (float **)(&resample_data[0]),
|
||||
&resample_frames, ts, pad)) {
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT hr =
|
||||
render->lpVtbl->GetBuffer(render, resample_frames, &output);
|
||||
if (FAILED(hr)) {
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!muted) {
|
||||
/* apply volume */
|
||||
if (!close_float(vol, 1.0f, EPSILON)) {
|
||||
register float *cur = (float *)resample_data[0];
|
||||
register float *end =
|
||||
cur + resample_frames * monitor->channels;
|
||||
|
||||
while (cur < end)
|
||||
*(cur++) *= vol;
|
||||
}
|
||||
memcpy(output, resample_data[0],
|
||||
resample_frames * monitor->channels * sizeof(float));
|
||||
}
|
||||
|
||||
render->lpVtbl->ReleaseBuffer(render, resample_frames,
|
||||
muted ? AUDCLNT_BUFFERFLAGS_SILENT : 0);
|
||||
|
||||
unlock:
|
||||
ReleaseSRWLockExclusive(&monitor->playback_mutex);
|
||||
}
|
||||
|
||||
static inline void audio_monitor_free(struct audio_monitor *monitor)
|
||||
{
|
||||
if (monitor->ignore)
|
||||
return;
|
||||
|
||||
if (monitor->source) {
|
||||
obs_source_remove_audio_capture_callback(
|
||||
monitor->source, on_audio_playback, monitor);
|
||||
}
|
||||
|
||||
if (monitor->client)
|
||||
monitor->client->lpVtbl->Stop(monitor->client);
|
||||
|
||||
safe_release(monitor->client);
|
||||
safe_release(monitor->render);
|
||||
audio_resampler_destroy(monitor->resampler);
|
||||
circlebuf_free(&monitor->delay_buffer);
|
||||
da_free(monitor->buf);
|
||||
}
|
||||
|
||||
extern bool devices_match(const char *id1, const char *id2);
|
||||
|
||||
static bool audio_monitor_init(struct audio_monitor *monitor,
|
||||
obs_source_t *source)
|
||||
{
|
||||
monitor->source = source;
|
||||
|
||||
const char *id = obs->audio.monitoring_device_id;
|
||||
if (!id) {
|
||||
warn("%s: No device ID set", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (source->info.output_flags & OBS_SOURCE_DO_NOT_SELF_MONITOR) {
|
||||
obs_data_t *s = obs_source_get_settings(source);
|
||||
const char *s_dev_id = obs_data_get_string(s, "device_id");
|
||||
bool match = devices_match(s_dev_id, id);
|
||||
obs_data_release(s);
|
||||
|
||||
if (match) {
|
||||
monitor->ignore = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
InitializeSRWLock(&monitor->playback_mutex);
|
||||
|
||||
return audio_monitor_init_wasapi(monitor);
|
||||
}
|
||||
|
||||
static void audio_monitor_init_final(struct audio_monitor *monitor)
|
||||
{
|
||||
if (monitor->ignore)
|
||||
|
|
Loading…
Reference in New Issue