Skip to content

Instantly share code, notes, and snippets.

@saivert
Created April 8, 2021 10:15
Show Gist options
  • Select an option

  • Save saivert/c8168ed82a2f5e26eab88c893ab5133a to your computer and use it in GitHub Desktop.

Select an option

Save saivert/c8168ed82a2f5e26eab88c893ab5133a to your computer and use it in GitHub Desktop.
// Excerpt from my client code. bits that calls pw_stream_connect
static int ddbpw_set_spec(ddb_waveformat_t *fmt)
{
memcpy (&plugin.fmt, fmt, sizeof (ddb_waveformat_t));
if (!plugin.fmt.channels) {
// generic format
plugin.fmt.bps = 16;
plugin.fmt.is_float = 0;
plugin.fmt.channels = 2;
plugin.fmt.samplerate = 44100;
plugin.fmt.channelmask = 3;
}
if (plugin.fmt.samplerate > 192000) {
plugin.fmt.samplerate = 192000;
}
trace ("format %dbit %s %dch %dHz channelmask=%X\n", plugin.fmt.bps, plugin.fmt.is_float ? "float" : "int", plugin.fmt.channels, plugin.fmt.samplerate, plugin.fmt.channelmask);
const struct spa_pod *params[2];
enum spa_audio_format pwfmt;
switch (fmt->bps) {
case 8:
pwfmt = SPA_AUDIO_FORMAT_S8;
break;
case 16:
pwfmt = SPA_AUDIO_FORMAT_S16_LE;
break;
case 24:
pwfmt = SPA_AUDIO_FORMAT_S24_LE;
break;
case 32:
if (fmt->is_float) {
pwfmt = SPA_AUDIO_FORMAT_F32_LE;
}
else {
pwfmt = SPA_AUDIO_FORMAT_S32_LE;
}
break;
default:
pwfmt = SPA_AUDIO_FORMAT_UNKNOWN;
};
uint8_t buffer[1024];
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
struct spa_audio_info_raw rawinfo = SPA_AUDIO_INFO_RAW_INIT(
.format = pwfmt,
.channels = fmt->channels,
.rate = fmt->samplerate );
set_channel_map(fmt->channels, &rawinfo);
params[0] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &rawinfo);
struct spa_pod_frame f[2];
float vols[SPA_AUDIO_MAX_CHANNELS], plvol;
int i;
spa_pod_builder_push_object(&b, &f[0],
SPA_TYPE_OBJECT_Props, SPA_PARAM_Props);
spa_pod_builder_add(&b,
SPA_PROP_volume, SPA_POD_Float(1.0f),
SPA_PROP_mute, SPA_POD_Bool(0.0f),
0);
spa_pod_builder_prop(&b, SPA_PROP_channelVolumes, 0);
if (1/* plugin.has_volume */) {
plvol = deadbeef->volume_get_amp();
} else {
plvol = 1.0f;
}
for (i = 0; i < fmt->channels; i++) {
vols[i] = plvol;
}
spa_pod_builder_array(&b, sizeof(float), SPA_TYPE_Float,
fmt->channels, vols);
spa_pod_builder_prop(&b, SPA_PROP_channelMap, 0);
spa_pod_builder_array(&b, sizeof(uint32_t), SPA_TYPE_Id,
rawinfo.channels, rawinfo.position);
params[1] = spa_pod_builder_pop(&b, &f[0]);
spa_debug_pod(2, NULL, params[0]);
spa_debug_pod(2, NULL, params[1]);
if (0 != pw_stream_connect(data.stream,
PW_DIRECTION_OUTPUT,
PW_ID_ANY,
PW_STREAM_FLAG_AUTOCONNECT |
PW_STREAM_FLAG_MAP_BUFFERS |
PW_STREAM_FLAG_RT_PROCESS,
params, 2)) {
log_err("PipeWire: Error connecting stream!\n");
if (pw_properties_get(pw_stream_get_properties(data.stream), PW_KEY_REMOTE_NAME)) {
log_err("PipeWire: Please check if remote daemon name is valid and daemon is up.\n")
}
return -1;
};
state = DDB_PLAYBACK_STATE_PLAYING;
return OP_ERROR_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment