Skip to content

Commit bf6995d

Browse files
committed
TimedStream
1 parent a6bbd92 commit bf6995d

File tree

2 files changed

+172
-0
lines changed

2 files changed

+172
-0
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
*
3+
*/
4+
#include "AudioTools.h"
5+
#include "AudioCodecs/CodecMP3Helix.h"
6+
//#include "AudioLibs/AudioKit.h"
7+
8+
9+
URLStream url("ssid","password");
10+
I2SStream i2s; // or any other output of decoded stream (e.g. AudioKitStream)
11+
TimedStream timed(i2s, 10, 20); // timed output with times
12+
EncodedAudioStream dec(&timed, new MP3DecoderHelix()); // Decoding stream
13+
StreamCopy copier(dec, url); // copy url to decoder
14+
15+
16+
void setup(){
17+
Serial.begin(115200);
18+
AudioLogger::instance().begin(Serial, AudioLogger::Info);
19+
20+
// setup i2s
21+
auto config = i2s.defaultConfig(TX_MODE);
22+
// you could define e.g your pins and change other settings
23+
//config.pin_ws = 10;
24+
//config.pin_bck = 11;
25+
//config.pin_data = 12;
26+
//config.mode = I2S_STD_FORMAT;
27+
i2s.begin(config);
28+
29+
// start timed
30+
//timed.setStartSecond(10);
31+
//timed.setEndSecond(20);
32+
timed.begin();
33+
34+
// setup I2S based on sampling rate provided by decoder
35+
dec.begin();
36+
37+
// mp3 radio
38+
url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128","audio/mp3");
39+
40+
}
41+
42+
void loop(){
43+
copier.copy();
44+
}

src/AudioTools/AudioStreams.h

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1631,6 +1631,134 @@ class FilteredStream : public AudioStream {
16311631

16321632
};
16331633

1634+
/**
1635+
* @brief AudioStream class that can define a start and (an optional) stop time
1636+
* Usually it is used to wrap an Audio Sink (e.g. I2SStream), but wrapping an
1637+
* Audio Source is supported as well. Only wrap classes which represent PCM
1638+
* data!
1639+
* @author Phil Schatzmann
1640+
* @copyright GPLv3
1641+
*/
1642+
class TimedStream : public AudioStream {
1643+
public:
1644+
TimedStream(AudioStream &io, long startSeconds = 0, long endSeconds = -1) {
1645+
p_stream = &io;
1646+
p_print = &io;
1647+
p_info = &io;
1648+
setStartSecond(startSeconds);
1649+
setEndSecond(endSeconds);
1650+
}
1651+
1652+
TimedStream(AudioOutput &o, long startSeconds = 0, long endSeconds = -1) {
1653+
p_print = &o;
1654+
p_info = &o;
1655+
setStartSecond(startSeconds);
1656+
setEndSecond(endSeconds);
1657+
}
1658+
1659+
/// Defines the start time in seconds. The audio before the start time will be
1660+
/// skipped
1661+
void setStartSecond(long startSeconds) { start_seconds = startSeconds; }
1662+
1663+
/// Defines (an optional) the end time in seconds. After the end time no audio
1664+
/// is played and available() will return 0
1665+
void setEndSecond(long endSeconds) { end_seconds = endSeconds; }
1666+
1667+
/// Returns true if we are in a valid time range and are still playing sound
1668+
bool isPlaying() {
1669+
if (current_bytes < start_bytes) return false;
1670+
if (end_bytes > 0 && current_bytes > end_bytes) return false;
1671+
return true;
1672+
}
1673+
1674+
/// Returns true if we are not past the end time;
1675+
bool isActive() {
1676+
return (current_bytes < end_bytes && current_bytes > start_bytes);
1677+
}
1678+
1679+
bool begin(AudioInfo info) {
1680+
setAudioInfo(info);
1681+
return begin();
1682+
}
1683+
1684+
bool begin() {
1685+
calculateByteLimits();
1686+
current_bytes = 0;
1687+
return true;
1688+
}
1689+
1690+
operator bool() { return isActive(); }
1691+
1692+
/// Provides only data for the indicated start and end time. Only supported
1693+
/// for data which does not contain any heder information: so PCM, mp3 should
1694+
/// work!
1695+
size_t readBytes(uint8_t *buffer, size_t length) override {
1696+
// if reading is not supported we stop
1697+
if (p_stream == nullptr) return 0;
1698+
// if we are past the end we stop
1699+
if (!isActive()) return 0;
1700+
// read the data now
1701+
size_t result = 0;
1702+
do {
1703+
result = p_stream->readBytes(buffer, length);
1704+
current_bytes += length;
1705+
// ignore data before start time
1706+
} while (result > 0 && current_bytes < start_bytes);
1707+
return isPlaying() ? result : 0;
1708+
}
1709+
1710+
/// Plays only data for the indiated start and end time
1711+
size_t write(const uint8_t *buffer, size_t length) override {
1712+
current_bytes += length;
1713+
return isPlaying() ? p_print->write(buffer, length) : length;
1714+
}
1715+
1716+
/// Provides the available bytes until the end time has reached
1717+
int available() override {
1718+
if (p_stream == nullptr) return 0;
1719+
return isActive() ? p_stream->available() : 0;
1720+
}
1721+
1722+
/// Updates the AudioInfo in the current object and in the source or target
1723+
void setAudioInfo(AudioInfo info) override {
1724+
AudioStream::setAudioInfo(info);
1725+
p_info->setAudioInfo(info);
1726+
calculateByteLimits();
1727+
}
1728+
1729+
int availableForWrite() override { return p_print->availableForWrite(); }
1730+
1731+
/// Experimental: if used on mp3 you can set the compression ratio e.g. to 11
1732+
/// which will be used to approximate the time
1733+
void setCompressionRatio(float ratio) { compression_ratio = ratio; }
1734+
1735+
/// Calculates the bytes per second from the AudioInfo
1736+
int bytesPerSecond() {
1737+
return info.sample_rate * info.channels * info.bits_per_sample / 8;
1738+
}
1739+
1740+
protected:
1741+
Stream *p_stream = nullptr;
1742+
Print *p_print = nullptr;
1743+
AudioInfoDependent *p_info = nullptr;
1744+
uint32_t start_seconds = 0;
1745+
uint32_t end_seconds = UINT32_MAX;
1746+
uint32_t start_bytes = 0;
1747+
uint32_t end_bytes = UINT32_MAX;
1748+
uint32_t current_bytes = 0;
1749+
float compression_ratio = 1.0;
1750+
1751+
void calculateByteLimits() {
1752+
int bytes_per_second = bytesPerSecond();
1753+
if (bytes_per_second > 0) {
1754+
start_bytes = bytes_per_second * start_seconds / compression_ratio;
1755+
end_bytes = bytes_per_second * end_seconds / compression_ratio;
1756+
} else {
1757+
LOGE("AudioInfo not defined");
1758+
}
1759+
}
1760+
};
1761+
16341762

16351763
#ifdef USE_TIMER
16361764
/**

0 commit comments

Comments
 (0)