+static void add_data_chunk(const struct sr_output *o, GString *gs)
+{
+ struct out_context *outc;
+ char tmp[4];
+
+ outc = o->priv;
+ g_string_append(gs, "fmt ");
+ /* Remaining chunk size */
+ WL32(tmp, 0x12);
+ g_string_append_len(gs, tmp, 4);
+ /* Format code 3 = IEEE float */
+ WL16(tmp, 0x0003);
+ g_string_append_len(gs, tmp, 2);
+ /* Number of channels */
+ WL16(tmp, outc->num_channels);
+ g_string_append_len(gs, tmp, 2);
+ /* Samplerate */
+ WL32(tmp, outc->samplerate);
+ g_string_append_len(gs, tmp, 4);
+ /* Byterate, using 32-bit floats. */
+ WL32(tmp, outc->samplerate * outc->num_channels * 4);
+ g_string_append_len(gs, tmp, 4);
+ /* Blockalign */
+ WL16(tmp, outc->num_channels * 4);
+ g_string_append_len(gs, tmp, 2);
+ /* Bits per sample */
+ WL16(tmp, 32);
+ g_string_append_len(gs, tmp, 2);
+ WL16(tmp, 0);
+ g_string_append_len(gs, tmp, 2);
+
+ g_string_append(gs, "data");
+ /* Data chunk size, max it out. */
+ WL32(tmp, 0xffffffff);
+ g_string_append_len(gs, tmp, 4);
+}
+
+static GString *gen_header(const struct sr_output *o)
+{
+ struct out_context *outc;
+ GVariant *gvar;
+ GString *header;
+ char tmp[4];
+
+ outc = o->priv;
+ if (outc->samplerate == 0) {
+ if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
+ &gvar) == SR_OK) {
+ outc->samplerate = g_variant_get_uint64(gvar);
+ g_variant_unref(gvar);
+ }
+ }
+
+ header = g_string_sized_new(512);
+ g_string_append(header, "RIFF");
+ /* Total size. Max out the field. */
+ WL32(tmp, 0xffffffff);
+ g_string_append_len(header, tmp, 4);
+ g_string_append(header, "WAVE");
+ add_data_chunk(o, header);
+
+ return header;
+}
+
+/*
+ * Stores the float in little-endian BINARY32 IEEE-754 2008 format.
+ */
+static void float_to_le(uint8_t *buf, float value)
+{
+ char *old;
+
+ old = (char *)&value;
+#ifdef WORDS_BIGENDIAN
+ buf[0] = old[3];
+ buf[1] = old[2];
+ buf[2] = old[1];
+ buf[3] = old[0];
+#else
+ buf[0] = old[0];
+ buf[1] = old[1];
+ buf[2] = old[2];
+ buf[3] = old[3];
+#endif
+}
+
+/*
+ * Returns the number of samples used in the current channel buffers,
+ * or -1 if they're not all the same.
+ */
+static int check_chanbuf_size(const struct sr_output *o)
+{
+ struct out_context *outc;
+ int size, i;
+
+ outc = o->priv;
+ size = 0;
+ for (i = 0; i < outc->num_channels; i++) {
+ if (size == 0) {
+ if (outc->chanbuf_used[i] == 0) {
+ /* Nothing in all the buffers yet. */
+ size = -1;
+ break;
+ } else
+ /* New high water mark. */
+ size = outc->chanbuf_used[i];
+ } else if (outc->chanbuf_used[i] != size) {
+ /* All channel buffers are not equally full yet. */
+ size = -1;
+ break;
+ }
+ }
+
+ return size;
+}