Example #1
0
int
codec_sbc_decode(void *ctx, const void *input, int inputSizeBytes, void *output,
        int *outputSizeBytes)
{
    size_t         size_in = (size_t) inputSizeBytes;
    size_t         size_out = SBC_BUFFER;
    size_t         len;
    int            framelen;
    int            xframe_pos = 0;
    const guint8  *data_in  = (const guint8 *) input;
    guint8        *data_out = (guint8 *) output;
    sbc_t         *sbc = (sbc_t *) ctx;
    guint8        *i_data;
    guint8         tmp;

    if (!output || !outputSizeBytes) {
        return size_out;
    }

    sbc->endian = SBC_BE;

    *outputSizeBytes = 0;
    while (xframe_pos < inputSizeBytes) {
        framelen = sbc_decode(sbc, data_in, size_in, data_out, size_out, &len);
        xframe_pos += framelen;
        data_in += framelen;
        *outputSizeBytes += len;

        for (i_data = data_out; i_data < data_out + len; i_data += 2) {
                tmp = i_data[0];
                i_data[0] = i_data[1];
                i_data[1] = tmp;
        }

        data_out += len;
    }

    return *outputSizeBytes;
}
Example #2
0
static void decode(char *filename, char *output, int tofile, bool msbc)
{
	unsigned char buf[BUF_SIZE], *stream;
	struct stat st;
	sbc_t sbc;
	int fd, ad, pos, streamlen, framelen, count;
	size_t len;
	int format = AFMT_S16_BE, frequency, channels;
	ssize_t written;

	if (stat(filename, &st) < 0) {
		fprintf(stderr, "Can't get size of file %s: %s\n",
						filename, strerror(errno));
		return;
	}

	stream = malloc(st.st_size);

	if (!stream) {
		fprintf(stderr, "Can't allocate memory for %s: %s\n",
						filename, strerror(errno));
		return;
	}

	fd = open(filename, O_RDONLY);
	if (fd < 0) {
		fprintf(stderr, "Can't open file %s: %s\n",
						filename, strerror(errno));
		goto free;
	}

	if (read(fd, stream, st.st_size) != st.st_size) {
		fprintf(stderr, "Can't read content of %s: %s\n",
						filename, strerror(errno));
		close(fd);
		goto free;
	}

	close(fd);

	pos = 0;
	streamlen = st.st_size;

	if (tofile)
		ad = open(output, O_WRONLY | O_CREAT | O_TRUNC, 0644);
	else
		ad = open(output, O_WRONLY, 0);

	if (ad < 0) {
		fprintf(stderr, "Can't open output %s: %s\n",
						output, strerror(errno));
		goto free;
	}

	if (msbc)
		sbc_init_msbc(&sbc, 0L);
	else
		sbc_init(&sbc, 0L);
	sbc.endian = SBC_BE;

	framelen = sbc_decode(&sbc, stream, streamlen, buf, sizeof(buf), &len);
	channels = sbc.mode == SBC_MODE_MONO ? 1 : 2;
	switch (sbc.frequency) {
	case SBC_FREQ_16000:
		frequency = 16000;
		break;

	case SBC_FREQ_32000:
		frequency = 32000;
		break;

	case SBC_FREQ_44100:
		frequency = 44100;
		break;

	case SBC_FREQ_48000:
		frequency = 48000;
		break;
	default:
		frequency = 0;
	}

	if (verbose) {
		fprintf(stderr,"decoding %s with rate %d, %d subbands, "
			"%d bits, allocation method %s and mode %s\n",
			filename, frequency, sbc.subbands * 4 + 4, sbc.bitpool,
			sbc.allocation == SBC_AM_SNR ? "SNR" : "LOUDNESS",
			sbc.mode == SBC_MODE_MONO ? "MONO" :
					sbc.mode == SBC_MODE_STEREO ?
						"STEREO" : "JOINTSTEREO");
	}

	if (tofile) {
		struct au_header au_hdr;

		au_hdr.magic       = AU_MAGIC;
		au_hdr.hdr_size    = BE_INT(24);
		au_hdr.data_size   = BE_INT(0);
		au_hdr.encoding    = BE_INT(AU_FMT_LIN16);
		au_hdr.sample_rate = BE_INT(frequency);
		au_hdr.channels    = BE_INT(channels);

		written = write(ad, &au_hdr, sizeof(au_hdr));
		if (written < (ssize_t) sizeof(au_hdr)) {
			fprintf(stderr, "Failed to write header\n");
			goto close;
		}
	} else {
		if (ioctl(ad, SNDCTL_DSP_SETFMT, &format) < 0) {
			fprintf(stderr, "Can't set audio format on %s: %s\n",
						output, strerror(errno));
			goto close;
		}

		if (ioctl(ad, SNDCTL_DSP_CHANNELS, &channels) < 0) {
			fprintf(stderr, "Can't set number of channels on %s: %s\n",
						output, strerror(errno));
			goto close;
		}

		if (ioctl(ad, SNDCTL_DSP_SPEED, &frequency) < 0) {
			fprintf(stderr, "Can't set audio rate on %s: %s\n",
						output, strerror(errno));
			goto close;
		}
	}

	count = len;

	while (framelen > 0) {
		/* we have completed an sbc_decode at this point sbc.len is the
		 * length of the frame we just decoded count is the number of
		 * decoded bytes yet to be written */

		if (count + len >= BUF_SIZE) {
			/* buffer is too full to stuff decoded audio in so it
			 * must be written to the device */
			written = write(ad, buf, count);
			if (written > 0)
				count -= written;
		}

		/* sanity check */
		if (count + len >= BUF_SIZE) {
			fprintf(stderr,
				"buffer size of %d is too small for decoded"
				" data (%lu)\n", BUF_SIZE, (unsigned long) (len + count));
			exit(1);
		}

		/* push the pointer in the file forward to the next bit to be
		 * decoded tell the decoder to decode up to the remaining
		 * length of the file (!) */
		pos += framelen;
		framelen = sbc_decode(&sbc, stream + pos, streamlen - pos,
					buf + count, sizeof(buf) - count, &len);

		/* increase the count */
		count += len;
	}

	if (count > 0) {
		written = write(ad, buf, count);
		if (written > 0)
			count -= written;
	}

close:
	sbc_finish(&sbc);

	close(ad);

free:
	free(stream);
}
Example #3
0
static void decode(char *filename, char *audiodevice, int tofile)
{
	unsigned char buf[BUF_SIZE], *stream;
	struct stat st;
	off_t filesize;
	sbc_t sbc;
	int fd, ad, pos, streamlen, framelen, count, format = AFMT_S16_BE;

	if (stat(filename, &st) < 0) {
		fprintf(stderr, "Can't get size of file %s: %s\n",
						filename, strerror(errno));
		return;
	}

	filesize = st.st_size;
	stream = malloc(st.st_size);

	if (!stream) {
		fprintf(stderr, "Can't allocate memory for %s: %s\n",
						filename, strerror(errno));
		return;
	}

	fd = open(filename, O_RDONLY);
	if (fd < 0) {
		fprintf(stderr, "Can't open file %s: %s\n",
						filename, strerror(errno));
		goto free;
	}

	if (read(fd, stream, st.st_size) != st.st_size) {
		fprintf(stderr, "Can't read content of %s: %s\n",
						filename, strerror(errno));
		close(fd);
		goto free;
	}

	close(fd);

	pos = 0;
	streamlen = st.st_size;

	ad = open(audiodevice, O_WRONLY | (tofile ? (O_CREAT | O_TRUNC) : 0), tofile ? 0644 : 0);
	if (ad < 0) {
		fprintf(stderr, "Can't open audio device %s: %s\n",
						audiodevice, strerror(errno));
		goto free;
	}

	sbc_init(&sbc, SBC_NULL);

	framelen = sbc_decode(&sbc, stream, streamlen);
	printf("%d Hz, %d channels\n", sbc.rate, sbc.channels);
	if (!tofile) {
		if (ioctl(ad, SNDCTL_DSP_SETFMT, &format) < 0) {
			fprintf(stderr, "Can't set audio format on %s: %s\n",
							audiodevice, strerror(errno));
			goto close;
		}
		if (ioctl(ad, SNDCTL_DSP_CHANNELS, &sbc.channels) < 0) {
			fprintf(stderr, "Can't set number of channels on %s: %s\n",
							audiodevice, strerror(errno));
			goto close;
		}

		if (ioctl(ad, SNDCTL_DSP_SPEED, &sbc.rate) < 0) {
			fprintf(stderr, "Can't set audio rate on %s: %s\n",
							audiodevice, strerror(errno));
			goto close;
		}
	}

	count = 0;
	while (framelen > 0) {
		// we have completed an sbc_decode at this point
		// sbc.len is the length of the frame we just decoded
		// count is the number of decoded bytes yet to be written

		if (count + sbc.len > BUF_SIZE) {
			// buffer is too full to stuff decoded audio in
			// so it must be written to the device
			write(ad, buf, count);
			count = 0;
		}

		// sanity check
		if(count + sbc.len > BUF_SIZE) {
			fprintf(stderr, "buffer size of %d is too small for decoded data (%d)\n", BUF_SIZE, sbc.len + count);
			exit(1);
		}

		// move the latest decoded data into buf and increase the count
		memcpy(buf + count, sbc.data, sbc.len);
		count += sbc.len;

		// push the pointer in the file forward to the next bit to be decoded
		// tell the decoder to decode up to the remaining length of the file (!)
		pos += framelen;
		framelen = sbc_decode(&sbc, stream + pos, streamlen - pos);
	}

	if (count > 0)
		write(ad, buf, count);

close:
	sbc_finish(&sbc);

	close(ad);

free:
	free(stream);
}
Example #4
0
void *io_thread_a2dp_sink_sbc(void *arg) {
	struct ba_transport *t = (struct ba_transport *)arg;

	/* Cancellation should be possible only in the carefully selected place
	 * in order to prevent memory leaks and resources not being released. */
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
	pthread_cleanup_push(CANCEL_ROUTINE(io_thread_release), t);

	if (t->bt_fd == -1) {
		error("Invalid BT socket: %d", t->bt_fd);
		goto fail_init;
	}

	/* Check for invalid (e.g. not set) reading MTU. If buffer allocation does
	 * not return NULL (allocating zero bytes might return NULL), we will read
	 * zero bytes from the BT socket, which will be wrongly identified as a
	 * "connection closed" action. */
	if (t->mtu_read <= 0) {
		error("Invalid reading MTU: %zu", t->mtu_read);
		goto fail_init;
	}

	sbc_t sbc;

	if ((errno = -sbc_init_a2dp(&sbc, 0, t->a2dp.cconfig, t->a2dp.cconfig_size)) != 0) {
		error("Couldn't initialize SBC codec: %s", strerror(errno));
		goto fail_init;
	}

	const size_t sbc_codesize = sbc_get_codesize(&sbc);
	const size_t sbc_frame_len = sbc_get_frame_length(&sbc);

	const size_t in_buffer_size = t->mtu_read;
	const size_t out_buffer_size = sbc_codesize * (in_buffer_size / sbc_frame_len + 1);
	uint8_t *in_buffer = malloc(in_buffer_size);
	int16_t *out_buffer = malloc(out_buffer_size);

	pthread_cleanup_push(CANCEL_ROUTINE(sbc_finish), &sbc);
	pthread_cleanup_push(CANCEL_ROUTINE(free), in_buffer);
	pthread_cleanup_push(CANCEL_ROUTINE(free), out_buffer);

	if (in_buffer == NULL || out_buffer == NULL) {
		error("Couldn't create data buffers: %s", strerror(ENOMEM));
		goto fail;
	}

	struct pollfd pfds[] = {
		{ t->event_fd, POLLIN, 0 },
		{ -1, POLLIN, 0 },
	};

	debug("Starting IO loop: %s",
			bluetooth_profile_to_string(t->profile, t->codec));
	for (;;) {
		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

		ssize_t len;

		/* add BT socket to the poll if transport is active */
		pfds[1].fd = t->state == TRANSPORT_ACTIVE ? t->bt_fd : -1;

		if (poll(pfds, sizeof(pfds) / sizeof(*pfds), -1) == -1) {
			error("Transport poll error: %s", strerror(errno));
			goto fail;
		}

		if (pfds[0].revents & POLLIN) {
			/* dispatch incoming event */
			eventfd_t event;
			eventfd_read(pfds[0].fd, &event);
			continue;
		}

		if ((len = read(pfds[1].fd, in_buffer, in_buffer_size)) == -1) {
			debug("BT read error: %s", strerror(errno));
			continue;
		}

		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

		/* it seems that zero is never returned... */
		if (len == 0) {
			debug("BT socket has been closed: %d", pfds[1].fd);
			/* Prevent sending the release request to the BlueZ. If the socket has
			 * been closed, it means that BlueZ has already closed the connection. */
			close(pfds[1].fd);
			t->bt_fd = -1;
			goto fail;
		}

		if (io_thread_open_pcm_write(&t->a2dp.pcm) == -1) {
			if (errno != ENXIO)
				error("Couldn't open FIFO: %s", strerror(errno));
			continue;
		}

		const rtp_header_t *rtp_header = (rtp_header_t *)in_buffer;
		const rtp_payload_sbc_t *rtp_payload = (rtp_payload_sbc_t *)&rtp_header->csrc[rtp_header->cc];

		if (rtp_header->paytype != 96) {
			warn("Unsupported RTP payload type: %u", rtp_header->paytype);
			continue;
		}

		const uint8_t *input = (uint8_t *)(rtp_payload + 1);
		int16_t *output = out_buffer;
		size_t input_len = len - (input - in_buffer);
		size_t output_len = out_buffer_size;
		size_t frames = rtp_payload->frame_count;

		/* decode retrieved SBC frames */
		while (frames && input_len >= sbc_frame_len) {

			ssize_t len;
			size_t decoded;

			if ((len = sbc_decode(&sbc, input, input_len, output, output_len, &decoded)) < 0) {
				error("SBC decoding error: %s", strerror(-len));
				break;
			}

			input += len;
			input_len -= len;
			output += decoded / sizeof(int16_t);
			output_len -= decoded;
			frames--;

		}

		const size_t size = output - out_buffer;
		if (io_thread_write_pcm(&t->a2dp.pcm, out_buffer, size) == -1)
			error("FIFO write error: %s", strerror(errno));

	}

fail:
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
	pthread_cleanup_pop(1);
	pthread_cleanup_pop(1);
	pthread_cleanup_pop(1);
fail_init:
	pthread_cleanup_pop(1);
	return NULL;
}
Example #5
0
static GstFlowReturn
gst_sbc_dec_handle_frame (GstAudioDecoder * audio_dec, GstBuffer * buf)
{
  GstSbcDec *dec = GST_SBC_DEC (audio_dec);
  GstBuffer *outbuf = NULL;
  GstMapInfo out_map;
  GstMapInfo in_map;
  gsize output_size;
  guint num_frames, i;

  /* no fancy draining */
  if (G_UNLIKELY (buf == NULL))
    return GST_FLOW_OK;

  if (G_UNLIKELY (dec->frame_len == 0))
    return GST_FLOW_NOT_NEGOTIATED;

  gst_buffer_map (buf, &in_map, GST_MAP_READ);

  if (G_UNLIKELY (in_map.size == 0))
    goto done;

  /* we assume all frames are of the same size, this is implied by the
   * input caps applying to the whole input buffer, and the parser should
   * also have made sure of that */
  if (G_UNLIKELY (in_map.size % dec->frame_len != 0))
    goto mixed_frames;

  num_frames = in_map.size / dec->frame_len;
  output_size = num_frames * dec->samples_per_frame * sizeof (gint16);

  outbuf = gst_audio_decoder_allocate_output_buffer (audio_dec, output_size);

  if (outbuf == NULL)
    goto no_buffer;

  gst_buffer_map (outbuf, &out_map, GST_MAP_WRITE);

  for (i = 0; i < num_frames; ++i) {
    gssize ret;
    gsize written;

    ret = sbc_decode (&dec->sbc, in_map.data + (i * dec->frame_len),
        dec->frame_len, out_map.data + (i * dec->samples_per_frame * 2),
        dec->samples_per_frame * 2, &written);

    if (ret <= 0 || written != (dec->samples_per_frame * 2)) {
      GST_WARNING_OBJECT (dec, "decoding error, ret = %" G_GSSIZE_FORMAT ", "
          "written = %" G_GSSIZE_FORMAT, ret, written);
      break;
    }
  }

  gst_buffer_unmap (outbuf, &out_map);

  if (i > 0)
    gst_buffer_set_size (outbuf, i * dec->samples_per_frame * 2);
  else
    gst_buffer_replace (&outbuf, NULL);

done:

  gst_buffer_unmap (buf, &in_map);

  return gst_audio_decoder_finish_frame (audio_dec, outbuf, 1);

/* ERRORS */
mixed_frames:
  {
    GST_WARNING_OBJECT (dec, "inconsistent input data/frames, skipping");
    goto done;
  }
no_buffer:
  {
    GST_ERROR_OBJECT (dec, "could not allocate output buffer");
    goto done;
  }
}