{"id":5592,"date":"2023-04-28T16:42:55","date_gmt":"2023-04-28T14:42:55","guid":{"rendered":"https:\/\/www.pschatzmann.ch\/home\/?p=5592"},"modified":"2023-05-21T11:21:11","modified_gmt":"2023-05-21T09:21:11","slug":"arduino-audio-tools-codecs-and-containers","status":"publish","type":"post","link":"https:\/\/www.pschatzmann.ch\/home\/2023\/04\/28\/arduino-audio-tools-codecs-and-containers\/","title":{"rendered":"Arduino Audio Tools: Codecs and Containers"},"content":{"rendered":"<p>So far I have created <a href=\"https:\/\/www.pschatzmann.ch\/home\/tag\/codecs\/\">quite a few posts about the supported codecs<\/a>, but I never provided any detailed information how things work behind the scene. Audio codecs are used to compress and decompress <a href=\"https:\/\/github.com\/pschatzmann\/arduino-audio-tools\/wiki\/Introduction\">PCM audio data<\/a>.<\/p>\n<p>I tried to eliminate all the complexity but sometimes it helps to know how things are working, so from an API point of view you can just stream audio PCM data to an encoder and stream (compressed) encoded data to a decoder to get the data in PCM format.<\/p>\n<h2>Fixed Length vs Variable Length Codecs<\/h2>\n<p>Many codecs have some <strong>fixed length<\/strong> for the <strong>encoded<\/strong> frames and the corresponding <strong>decoded frames<\/strong>. This length is usually dependent on additional parameters e.g. the sampling rate. Examples are SBC, AptX or all the voice codecs like GSM, ALaw, ULaw, G7XX etc.<\/p>\n<p>So to make things work easily, I just needed to split the received bytes up automatically to feed the codec with the right amount of data!<\/p>\n<p>This works if you can make sure that you don&#8217;t miss any bytes e.g. in the beginning. And then there are some codecs that might produce some variable length. To solve this we need some audio containers.<\/p>\n<h2>Containers<\/h2>\n<p>To be able to reproduce the original segments you can use a container format. To keep things simple here as well, I just provide a simple and lean custom binary container format that consists of records that start with a header with a line-feed as separator, the length and the record type. Alternatively you can also use the Ogg container.<\/p>\n<h2>Arduino Sketch<\/h2>\n<p>Here is a simple Arduino sketch that demonstrates the <strong>BinaryContainerDecoder<\/strong> and <strong>BinaryContainerDecoder<\/strong> classes that can be used e.g. with an <strong>Opus<\/strong> Encoder and Decoder.<\/p>\n<pre><code>#include \"AudioTools.h\"\n#include \"AudioCodecs\/ContainerBinary.h\"\n#include \"AudioCodecs\/CodecOpus.h\"\n#include \"AudioLibs\/AudioKit.h\"\n\nAudioInfo info(8000,1,16);\nSineWaveGenerator&lt;int16_t&gt; sineWave( 32000);  \nGeneratedSoundStream&lt;int16_t&gt; sound( sineWave); \nAudioKitStream out; \/\/ or any other output e.g. I2SStream, CsvStream&lt;int16&gt;\nEncodedAudioStream decoder(&amp;out, new BinaryContainerDecoder(new OpusAudioDecoder())); \nEncodedAudioStream encoder(&amp;decoder, new BinaryContainerEncoder(new OpusAudioEncoder()));StreamCopy copier(encoder, sound);     \n\nvoid setup() {\n  Serial.begin(115200);\n  AudioLogger::instance().begin(Serial, AudioLogger::Warning);\n\n  \/\/ start I2S\n  Serial.println(\"starting I2S...\");\n  auto cfgi = out.defaultConfig(TX_MODE);\n  cfgi.copyFrom(info);\n  out.begin(cfgi);\n\n  \/\/ Setup sine wave\n  sineWave.begin(info, N_B4);\n\n  \/\/ start decoder\n  decoder.begin(info);\n\n  \/\/ start encoder\n  encoder.begin(info);\n\n  Serial.println(\"Test started...\");\n}\n\n\nvoid loop() { \n  copier.copy();\n}\n<\/code><\/pre>\n<p>Instead of providing a codec as argument to the EncodedAudioStream we provide the container and in the constructor of the container we provide the codec to be used:<\/p>\n<p>In this example, we just feed a sine signal to an OpusAudioDecoder which forwards the data to the BinaryContainerDecoder to make sure that we can reconstruct the encoded format. The packaged data is then forwarded to the BinaryContainerDecoder which submits the orignal packages created by the encoder to the OpusAudioDecoder.<\/p>\n<p>The decoded result is finally written to the AudioKitStream!<\/p>\n<p>Of cause this is a simplification and you usually have some communication stream between the encoder and decoder: e.g. TCP\/IP, UDP or ESP-Now&#8230;<\/p>\n<h2>Extended Functionality of the Binary Container<\/h2>\n<ul>\n<li>You can write you own <strong>additional (meta) data<\/strong> in the encoder with writeMeta(const uint8_t *data, size_t len) and retrieve it in the decoder with a callback method. (See this <a href=\"https:\/\/github.com\/pschatzmann\/arduino-audio-tools\/blob\/main\/examples\/tests\/codecs\/test-container-binary-meta\/test-container-binary-meta.ino\">test example<\/a>)<\/li>\n<li>The binary container classes can also be used w\/o any codec. This is useful if you want to distribute pure audio pcm data along with some additional custom (meta) information.<\/li>\n<\/ul>\n<h2>MP3, AAC Container Formats<\/h2>\n<p>MP3 and AAC contain their own (container) formats which are provided by the codec itself: That&#8217;s the reason why you can usually just start in the middle of an encoded stream and get perfect PCM from the decoders.<\/p>\n<h2>Further Reading:<\/h2>\n<ul>\n<li><a href=\"https:\/\/github.com\/pschatzmann\/arduino-audio-tools\/wiki\/Encoding-and-Decoding-of-Audio\">Codecs Wiki<\/a><\/li>\n<li><a href=\"https:\/\/pschatzmann.github.io\/arduino-audio-tools\/classaudio__tools_1_1_audio_encoder.html\">Encoder Classes<\/a><\/li>\n<li><a href=\"https:\/\/pschatzmann.github.io\/arduino-audio-tools\/classaudio__tools_1_1_audio_decoder.html\">Decoder Classes<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>So far I have created quite a few posts about the supported codecs, but I never provided any detailed information how things work behind the scene. Audio codecs are used to compress and decompress PCM audio data. I tried to eliminate all the complexity but sometimes it helps to know [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_crdt_document":"","_import_markdown_pro_load_document_selector":0,"_import_markdown_pro_submit_text_textarea":"","_exactmetrics_skip_tracking":false,"_exactmetrics_sitenote_active":false,"_exactmetrics_sitenote_note":"","_exactmetrics_sitenote_category":0,"footnotes":""},"categories":[20],"tags":[38],"class_list":["post-5592","post","type-post","status-publish","format-standard","hentry","category-arduino","tag-codecs"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Arduino Audio Tools: Codecs and Containers - Phil Schatzmann<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.pschatzmann.ch\/home\/2023\/04\/28\/arduino-audio-tools-codecs-and-containers\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Arduino Audio Tools: Codecs and Containers - Phil Schatzmann\" \/>\n<meta property=\"og:description\" content=\"So far I have created quite a few posts about the supported codecs, but I never provided any detailed information how things work behind the scene. Audio codecs are used to compress and decompress PCM audio data. I tried to eliminate all the complexity but sometimes it helps to know [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.pschatzmann.ch\/home\/2023\/04\/28\/arduino-audio-tools-codecs-and-containers\/\" \/>\n<meta property=\"og:site_name\" content=\"Phil Schatzmann\" \/>\n<meta property=\"article:published_time\" content=\"2023-04-28T14:42:55+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-05-21T09:21:11+00:00\" \/>\n<meta name=\"author\" content=\"pschatzmann\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"pschatzmann\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"3 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/2023\\\/04\\\/28\\\/arduino-audio-tools-codecs-and-containers\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/2023\\\/04\\\/28\\\/arduino-audio-tools-codecs-and-containers\\\/\"},\"author\":{\"name\":\"pschatzmann\",\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/#\\\/schema\\\/person\\\/73a53638a4e34e8373405fd737dac9b1\"},\"headline\":\"Arduino Audio Tools: Codecs and Containers\",\"datePublished\":\"2023-04-28T14:42:55+00:00\",\"dateModified\":\"2023-05-21T09:21:11+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/2023\\\/04\\\/28\\\/arduino-audio-tools-codecs-and-containers\\\/\"},\"wordCount\":529,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/#\\\/schema\\\/person\\\/73a53638a4e34e8373405fd737dac9b1\"},\"keywords\":[\"Codecs\"],\"articleSection\":[\"Arduino\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/2023\\\/04\\\/28\\\/arduino-audio-tools-codecs-and-containers\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/2023\\\/04\\\/28\\\/arduino-audio-tools-codecs-and-containers\\\/\",\"url\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/2023\\\/04\\\/28\\\/arduino-audio-tools-codecs-and-containers\\\/\",\"name\":\"Arduino Audio Tools: Codecs and Containers - Phil Schatzmann\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/#website\"},\"datePublished\":\"2023-04-28T14:42:55+00:00\",\"dateModified\":\"2023-05-21T09:21:11+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/2023\\\/04\\\/28\\\/arduino-audio-tools-codecs-and-containers\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/2023\\\/04\\\/28\\\/arduino-audio-tools-codecs-and-containers\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/2023\\\/04\\\/28\\\/arduino-audio-tools-codecs-and-containers\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Arduino Audio Tools: Codecs and Containers\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/#website\",\"url\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/\",\"name\":\"Phil Schatzmann Consulting\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/#\\\/schema\\\/person\\\/73a53638a4e34e8373405fd737dac9b1\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/#\\\/schema\\\/person\\\/73a53638a4e34e8373405fd737dac9b1\",\"name\":\"pschatzmann\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/wp-content\\\/uploads\\\/2022\\\/08\\\/pschatzmann.png\",\"url\":\"https:\\\/\\\/www.pschatzmann.ch\\\/wp-content\\\/uploads\\\/2022\\\/08\\\/pschatzmann.png\",\"contentUrl\":\"https:\\\/\\\/www.pschatzmann.ch\\\/wp-content\\\/uploads\\\/2022\\\/08\\\/pschatzmann.png\",\"width\":305,\"height\":305,\"caption\":\"pschatzmann\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/wp-content\\\/uploads\\\/2022\\\/08\\\/pschatzmann.png\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Arduino Audio Tools: Codecs and Containers - Phil Schatzmann","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.pschatzmann.ch\/home\/2023\/04\/28\/arduino-audio-tools-codecs-and-containers\/","og_locale":"en_US","og_type":"article","og_title":"Arduino Audio Tools: Codecs and Containers - Phil Schatzmann","og_description":"So far I have created quite a few posts about the supported codecs, but I never provided any detailed information how things work behind the scene. Audio codecs are used to compress and decompress PCM audio data. I tried to eliminate all the complexity but sometimes it helps to know [&hellip;]","og_url":"https:\/\/www.pschatzmann.ch\/home\/2023\/04\/28\/arduino-audio-tools-codecs-and-containers\/","og_site_name":"Phil Schatzmann","article_published_time":"2023-04-28T14:42:55+00:00","article_modified_time":"2023-05-21T09:21:11+00:00","author":"pschatzmann","twitter_card":"summary_large_image","twitter_misc":{"Written by":"pschatzmann","Est. reading time":"3 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.pschatzmann.ch\/home\/2023\/04\/28\/arduino-audio-tools-codecs-and-containers\/#article","isPartOf":{"@id":"https:\/\/www.pschatzmann.ch\/home\/2023\/04\/28\/arduino-audio-tools-codecs-and-containers\/"},"author":{"name":"pschatzmann","@id":"https:\/\/www.pschatzmann.ch\/home\/#\/schema\/person\/73a53638a4e34e8373405fd737dac9b1"},"headline":"Arduino Audio Tools: Codecs and Containers","datePublished":"2023-04-28T14:42:55+00:00","dateModified":"2023-05-21T09:21:11+00:00","mainEntityOfPage":{"@id":"https:\/\/www.pschatzmann.ch\/home\/2023\/04\/28\/arduino-audio-tools-codecs-and-containers\/"},"wordCount":529,"commentCount":0,"publisher":{"@id":"https:\/\/www.pschatzmann.ch\/home\/#\/schema\/person\/73a53638a4e34e8373405fd737dac9b1"},"keywords":["Codecs"],"articleSection":["Arduino"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.pschatzmann.ch\/home\/2023\/04\/28\/arduino-audio-tools-codecs-and-containers\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.pschatzmann.ch\/home\/2023\/04\/28\/arduino-audio-tools-codecs-and-containers\/","url":"https:\/\/www.pschatzmann.ch\/home\/2023\/04\/28\/arduino-audio-tools-codecs-and-containers\/","name":"Arduino Audio Tools: Codecs and Containers - Phil Schatzmann","isPartOf":{"@id":"https:\/\/www.pschatzmann.ch\/home\/#website"},"datePublished":"2023-04-28T14:42:55+00:00","dateModified":"2023-05-21T09:21:11+00:00","breadcrumb":{"@id":"https:\/\/www.pschatzmann.ch\/home\/2023\/04\/28\/arduino-audio-tools-codecs-and-containers\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.pschatzmann.ch\/home\/2023\/04\/28\/arduino-audio-tools-codecs-and-containers\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.pschatzmann.ch\/home\/2023\/04\/28\/arduino-audio-tools-codecs-and-containers\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.pschatzmann.ch\/home\/"},{"@type":"ListItem","position":2,"name":"Arduino Audio Tools: Codecs and Containers"}]},{"@type":"WebSite","@id":"https:\/\/www.pschatzmann.ch\/home\/#website","url":"https:\/\/www.pschatzmann.ch\/home\/","name":"Phil Schatzmann Consulting","description":"","publisher":{"@id":"https:\/\/www.pschatzmann.ch\/home\/#\/schema\/person\/73a53638a4e34e8373405fd737dac9b1"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.pschatzmann.ch\/home\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.pschatzmann.ch\/home\/#\/schema\/person\/73a53638a4e34e8373405fd737dac9b1","name":"pschatzmann","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.pschatzmann.ch\/wp-content\/uploads\/2022\/08\/pschatzmann.png","url":"https:\/\/www.pschatzmann.ch\/wp-content\/uploads\/2022\/08\/pschatzmann.png","contentUrl":"https:\/\/www.pschatzmann.ch\/wp-content\/uploads\/2022\/08\/pschatzmann.png","width":305,"height":305,"caption":"pschatzmann"},"logo":{"@id":"https:\/\/www.pschatzmann.ch\/wp-content\/uploads\/2022\/08\/pschatzmann.png"}}]}},"post_mailing_queue_ids":[],"_links":{"self":[{"href":"https:\/\/www.pschatzmann.ch\/home\/wp-json\/wp\/v2\/posts\/5592","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.pschatzmann.ch\/home\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.pschatzmann.ch\/home\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.pschatzmann.ch\/home\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.pschatzmann.ch\/home\/wp-json\/wp\/v2\/comments?post=5592"}],"version-history":[{"count":30,"href":"https:\/\/www.pschatzmann.ch\/home\/wp-json\/wp\/v2\/posts\/5592\/revisions"}],"predecessor-version":[{"id":5685,"href":"https:\/\/www.pschatzmann.ch\/home\/wp-json\/wp\/v2\/posts\/5592\/revisions\/5685"}],"wp:attachment":[{"href":"https:\/\/www.pschatzmann.ch\/home\/wp-json\/wp\/v2\/media?parent=5592"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.pschatzmann.ch\/home\/wp-json\/wp\/v2\/categories?post=5592"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.pschatzmann.ch\/home\/wp-json\/wp\/v2\/tags?post=5592"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}