diff --git a/libobs/audio-monitoring/pulse/pulseaudio-output.c b/libobs/audio-monitoring/pulse/pulseaudio-output.c index 44da2cf4c2f367e3c6e2cff55ae308f9246afb66..8656ef9c4df21af3b0f4e1e0c6d9a9fec9e3825a 100644 --- a/libobs/audio-monitoring/pulse/pulseaudio-output.c +++ b/libobs/audio-monitoring/pulse/pulseaudio-output.c @@ -61,6 +61,61 @@ static enum audio_format pulseaudio_to_obs_audio_format( } } +static pa_channel_map pulseaudio_channel_map(enum speaker_layout layout) +{ + pa_channel_map ret; + + ret.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + ret.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + ret.map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; + ret.map[3] = PA_CHANNEL_POSITION_LFE; + ret.map[4] = PA_CHANNEL_POSITION_REAR_LEFT; + ret.map[5] = PA_CHANNEL_POSITION_REAR_RIGHT; + ret.map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; + ret.map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; + + switch (layout) { + case SPEAKERS_MONO: + ret.channels = 1; + ret.map[0] = PA_CHANNEL_POSITION_MONO; + break; + + case SPEAKERS_STEREO: + ret.channels = 2; + break; + + case SPEAKERS_2POINT1: + ret.channels = 3; + ret.map[2] = PA_CHANNEL_POSITION_LFE; + break; + + case SPEAKERS_4POINT0: + ret.channels = 4; + ret.map[3] = PA_CHANNEL_POSITION_REAR_CENTER; + break; + + case SPEAKERS_4POINT1: + ret.channels = 5; + ret.map[4] = PA_CHANNEL_POSITION_REAR_CENTER; + break; + + case SPEAKERS_5POINT1: + ret.channels = 6; + break; + + case SPEAKERS_7POINT1: + ret.channels = 8; + break; + + case SPEAKERS_UNKNOWN: + default: + ret.channels = 0; + break; + } + + return ret; +} + static void process_byte(void *p, size_t frames, size_t channels, float vol) { register char *cur = (char *) p; @@ -370,8 +425,10 @@ static bool audio_monitor_init(struct audio_monitor *monitor, monitor->speakers = pulseaudio_channels_to_obs_speakers(spec.channels); monitor->bytes_per_frame = pa_frame_size(&spec); + pa_channel_map channel_map = pulseaudio_channel_map(monitor->speakers); + monitor->stream = pulseaudio_stream_new( - obs_source_get_name(monitor->source), &spec, NULL); + obs_source_get_name(monitor->source), &spec, &channel_map); if (!monitor->stream) { blog(LOG_ERROR, "Unable to create stream"); return false; diff --git a/libobs/media-io/audio-io.h b/libobs/media-io/audio-io.h index 0cf9fe1de00ed59029b1ba72f9f8182ca62b1179..f0166977f369093db472538e8872832c0166b900 100644 --- a/libobs/media-io/audio-io.h +++ b/libobs/media-io/audio-io.h @@ -51,15 +51,24 @@ enum audio_format { AUDIO_FORMAT_FLOAT_PLANAR, }; +/** + * The speaker layout describes where the speakers are located in the room. + * For OBS it dictates: + * * how many channels are available and + * * which channels are used for which speakers. + * + * Standard channel layouts where retrieved from ffmpeg documentation at: + * https://trac.ffmpeg.org/wiki/AudioChannelManipulation + */ enum speaker_layout { - SPEAKERS_UNKNOWN, - SPEAKERS_MONO, - SPEAKERS_STEREO, - SPEAKERS_2POINT1, - SPEAKERS_4POINT0, - SPEAKERS_4POINT1, - SPEAKERS_5POINT1, - SPEAKERS_7POINT1=8, + SPEAKERS_UNKNOWN, /**< Unknown setting, fallback is stereo. */ + SPEAKERS_MONO, /**< Channels: MONO */ + SPEAKERS_STEREO, /**< Channels: FL, FR */ + SPEAKERS_2POINT1, /**< Channels: FL, FR, LFE */ + SPEAKERS_4POINT0, /**< Channels: FL, FR, FC, RC */ + SPEAKERS_4POINT1, /**< Channels: FL, FR, FC, LFE, RC */ + SPEAKERS_5POINT1, /**< Channels: FL, FR, FC, LFE, RL, RR */ + SPEAKERS_7POINT1=8, /**< Channels: FL, FR, FC, LFE, RL, RR, SL, SR */ }; struct audio_data { diff --git a/plugins/linux-pulseaudio/pulse-input.c b/plugins/linux-pulseaudio/pulse-input.c index b53b0b9ddb8888cd7ab43498f24bf5ebb0f39839..9b6e244104e05b1238352f39045411620b767918 100644 --- a/plugins/linux-pulseaudio/pulse-input.c +++ b/plugins/linux-pulseaudio/pulse-input.c @@ -93,6 +93,61 @@ static enum speaker_layout pulse_channels_to_obs_speakers( return SPEAKERS_UNKNOWN; } +static pa_channel_map pulse_channel_map(enum speaker_layout layout) +{ + pa_channel_map ret; + + ret.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + ret.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + ret.map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; + ret.map[3] = PA_CHANNEL_POSITION_LFE; + ret.map[4] = PA_CHANNEL_POSITION_REAR_LEFT; + ret.map[5] = PA_CHANNEL_POSITION_REAR_RIGHT; + ret.map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; + ret.map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; + + switch (layout) { + case SPEAKERS_MONO: + ret.channels = 1; + ret.map[0] = PA_CHANNEL_POSITION_MONO; + break; + + case SPEAKERS_STEREO: + ret.channels = 2; + break; + + case SPEAKERS_2POINT1: + ret.channels = 3; + ret.map[2] = PA_CHANNEL_POSITION_LFE; + break; + + case SPEAKERS_4POINT0: + ret.channels = 4; + ret.map[3] = PA_CHANNEL_POSITION_REAR_CENTER; + break; + + case SPEAKERS_4POINT1: + ret.channels = 5; + ret.map[4] = PA_CHANNEL_POSITION_REAR_CENTER; + break; + + case SPEAKERS_5POINT1: + ret.channels = 6; + break; + + case SPEAKERS_7POINT1: + ret.channels = 8; + break; + + case SPEAKERS_UNKNOWN: + default: + ret.channels = 0; + break; + } + + return ret; +} + static inline uint64_t samples_to_ns(size_t frames, uint_fast32_t rate) { return frames * NSEC_PER_SEC / rate; @@ -286,8 +341,10 @@ static int_fast32_t pulse_start_recording(struct pulse_data *data) data->speakers = pulse_channels_to_obs_speakers(spec.channels); data->bytes_per_frame = pa_frame_size(&spec); + pa_channel_map channel_map = pulse_channel_map(data->speakers); + data->stream = pulse_stream_new(obs_source_get_name(data->source), - &spec, NULL); + &spec, &channel_map); if (!data->stream) { blog(LOG_ERROR, "Unable to create stream"); return -1;