libobs: Implement audio monitoring

Adds functions to turn on audio monitoring to allow the user to hear
playback of an audio source over the user's speaker.  It can be set to
turn off monitoring and only output to stream, or it can be set to
output only to monitoring, or it can be set to both.

On windows, audio monitoring uses WASAPI.  Windows also is capable of
syncing the audio to the video according to when the video frame itself
was played.

On mac, it uses AudioQueue.

On linux, it's not currently implemented and won't do anything (to be
implemented).
This commit is contained in:
jp9000
2017-02-05 21:37:35 -08:00
parent 74f9c389cb
commit d2934eca7e
13 changed files with 1170 additions and 7 deletions

View File

@@ -488,10 +488,22 @@ static bool obs_init_audio(struct audio_output_info *ai)
struct obs_core_audio *audio = &obs->audio;
int errorcode;
/* TODO: sound subsystem */
pthread_mutexattr_t attr;
pthread_mutex_init_value(&audio->monitoring_mutex);
if (pthread_mutexattr_init(&attr) != 0)
return false;
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0)
return false;
if (pthread_mutex_init(&audio->monitoring_mutex, &attr) != 0)
return false;
audio->user_volume = 1.0f;
audio->monitoring_device_name = bstrdup("Default");
audio->monitoring_device_id = bstrdup("default");
errorcode = audio_output_open(&audio->audio, ai);
if (errorcode == AUDIO_OUTPUT_SUCCESS)
return true;
@@ -513,6 +525,11 @@ static void obs_free_audio(void)
da_free(audio->render_order);
da_free(audio->root_nodes);
da_free(audio->monitors);
bfree(audio->monitoring_device_name);
bfree(audio->monitoring_device_id);
pthread_mutex_destroy(&audio->monitoring_mutex);
memset(audio, 0, sizeof(struct obs_core_audio));
}
@@ -725,6 +742,8 @@ static bool obs_init(const char *locale, const char *module_config_path,
{
obs = bzalloc(sizeof(struct obs_core));
pthread_mutex_init_value(&obs->audio.monitoring_mutex);
obs->name_store_owned = !store;
obs->name_store = store ? store : profiler_name_store_create();
if (!obs->name_store) {
@@ -1454,6 +1473,7 @@ static obs_source_t *obs_load_source_type(obs_data_t *source_data)
uint32_t mixers;
int di_order;
int di_mode;
int monitoring_type;
source = obs_source_create(id, name, settings, hotkeys);
@@ -1505,6 +1525,10 @@ static obs_source_t *obs_load_source_type(obs_data_t *source_data)
obs_source_set_deinterlace_field_order(source,
(enum obs_deinterlace_field_order)di_order);
monitoring_type = (int)obs_data_get_int(source_data, "monitoring_type");
obs_source_set_monitoring_type(source,
(enum obs_monitoring_type)monitoring_type);
if (filters) {
size_t count = obs_data_array_count(filters);
@@ -1601,6 +1625,7 @@ obs_data_t *obs_save_source(obs_source_t *source)
uint64_t ptm_delay = obs_source_get_push_to_mute_delay(source);
bool push_to_talk= obs_source_push_to_talk_enabled(source);
uint64_t ptt_delay = obs_source_get_push_to_talk_delay(source);
int m_type = (int)obs_source_get_monitoring_type(source);
int di_mode = (int)obs_source_get_deinterlace_mode(source);
int di_order =
(int)obs_source_get_deinterlace_field_order(source);
@@ -1630,6 +1655,7 @@ obs_data_t *obs_save_source(obs_source_t *source)
obs_data_set_obj (source_data, "hotkeys", hotkey_data);
obs_data_set_int (source_data, "deinterlace_mode", di_mode);
obs_data_set_int (source_data, "deinterlace_field_order", di_order);
obs_data_set_int (source_data, "monitoring_type", m_type);
if (source->info.type == OBS_SOURCE_TYPE_TRANSITION)
obs_transition_save(source, source_data);
@@ -1876,3 +1902,45 @@ bool obs_obj_invalid(void *obj)
return !context->data;
}
bool obs_set_audio_monitoring_device(const char *name, const char *id)
{
if (!obs || !name || !id || !*name || !*id)
return false;
#ifdef _WIN32
pthread_mutex_lock(&obs->audio.monitoring_mutex);
if (strcmp(id, obs->audio.monitoring_device_id) == 0)
return true;
if (obs->audio.monitoring_device_name)
bfree(obs->audio.monitoring_device_name);
if (obs->audio.monitoring_device_id)
bfree(obs->audio.monitoring_device_id);
obs->audio.monitoring_device_name = bstrdup(name);
obs->audio.monitoring_device_id = bstrdup(id);
for (size_t i = 0; i < obs->audio.monitors.num; i++) {
struct audio_monitor *monitor = obs->audio.monitors.array[i];
audio_monitor_reset(monitor);
}
pthread_mutex_unlock(&obs->audio.monitoring_mutex);
return true;
#else
return false;
#endif
}
void obs_get_audio_monitoring_device(const char **name, const char **id)
{
if (!obs)
return;
if (name)
*name = obs->audio.monitoring_device_name;
if (id)
*id = obs->audio.monitoring_device_id;
}