From d0e99540372d50b961f2b139937e566cef35d715 Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Fri, 24 May 2024 14:13:20 +0200 Subject: [PATCH] i2s: Add stream for i2s_out Code provides wrapper to use i2s with streaming API Signed-off-by: Jerzy Kasenberg --- hw/drivers/i2s/include/i2s/i2s_stream.h | 46 ++++++++++++ hw/drivers/i2s/src/i2s_stream.c | 93 +++++++++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 hw/drivers/i2s/include/i2s/i2s_stream.h create mode 100644 hw/drivers/i2s/src/i2s_stream.c diff --git a/hw/drivers/i2s/include/i2s/i2s_stream.h b/hw/drivers/i2s/include/i2s/i2s_stream.h new file mode 100644 index 0000000000..83849a1ab0 --- /dev/null +++ b/hw/drivers/i2s/include/i2s/i2s_stream.h @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _HW_DRIVERS_I2S_STREAM_H +#define _HW_DRIVERS_I2S_STREAM_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct i2s_out_stream { + struct out_stream ostream; + struct i2s *i2s; + struct i2s_sample_buffer *buffer; +}; + +#define I2S_OUT_STREAM_DEF(var) \ + extern const struct out_stream_vft i2s_out_stream_vft; \ + struct i2s_out_stream var = { \ + OSTREAM_INIT(i2s_out_stream, ostream), \ + }; + +#ifdef __cplusplus +} +#endif + +#endif /* _HW_DRIVERS_I2S_STREAM_H */ diff --git a/hw/drivers/i2s/src/i2s_stream.c b/hw/drivers/i2s/src/i2s_stream.c new file mode 100644 index 0000000000..93a4e8a137 --- /dev/null +++ b/hw/drivers/i2s/src/i2s_stream.c @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include + +#include +#include +#include +#include + +OSTREAM_DEF(i2s_out_stream); + +static int +i2s_out_stream_pump_from(struct out_stream *ostream, struct in_stream *istream, uint32_t count) +{ + struct i2s_out_stream *i2s_str = CONTAINER_OF(ostream, struct i2s_out_stream, ostream); + struct i2s_sample_buffer *buffer = i2s_str->buffer; + struct i2s *i2s = i2s_str->i2s; + int written = 0; + uint32_t available = istream_available(istream); + uint32_t sample_count; + + if (available < count) { + count = available; + } + sample_count = count / i2s->sample_size_in_bytes; + + while (sample_count) { + if (buffer == NULL) { + buffer = i2s_buffer_get(i2s, 0); + if (buffer == NULL) { + break; + } + buffer->sample_count = 0; + } + uint32_t space = buffer->capacity - buffer->sample_count; + size_t copied = min(space, sample_count); + if (copied) { + uint8_t *buf = buffer->sample_data; + istream_read(istream, buf + buffer->sample_count * i2s->sample_size_in_bytes, + copied * i2s->sample_size_in_bytes); + buffer->sample_count += copied; + written += copied; + sample_count -= copied; + } + if (buffer->sample_count >= buffer->capacity) { + i2s_buffer_put(i2s, buffer); + buffer = NULL; + } + } + i2s_str->buffer = buffer; + return written * i2s_str->i2s->sample_size_in_bytes; +} + +static int +i2s_out_stream_write(struct out_stream *ostream, const uint8_t *buf, uint32_t count) +{ + struct mem_in_stream mstr; + mem_istream_init(&mstr, buf, count); + + return i2s_out_stream_pump_from(ostream, (struct in_stream *)&mstr, count); +} + +static int +i2s_out_stream_flush(struct out_stream *ostream) +{ + struct i2s_out_stream *str = CONTAINER_OF(ostream, struct i2s_out_stream, ostream); + struct i2s *i2s = str->i2s; + struct i2s_sample_buffer *buffer = str->buffer; + + str->buffer = NULL; + if (buffer) { + i2s_buffer_put(i2s, buffer); + } + + return 0; +}