{"id":6192,"date":"2024-03-27T15:34:01","date_gmt":"2024-03-27T14:34:01","guid":{"rendered":"https:\/\/www.pschatzmann.ch\/home\/?p=6192"},"modified":"2024-03-27T17:25:01","modified_gmt":"2024-03-27T16:25:01","slug":"libhelix-behind-the-scene","status":"publish","type":"post","link":"https:\/\/www.pschatzmann.ch\/home\/2024\/03\/27\/libhelix-behind-the-scene\/","title":{"rendered":"Libhelix &#8211; Behind the Scene"},"content":{"rendered":"<p>I am providing an <a href=\"https:\/\/github.com\/pschatzmann\/arduino-libhelix\/tree\/development\">Arduino MP3 and AAC decoder library for Arduino<\/a> which is based on <strong>libhelix<\/strong>.<\/p>\n<p>In this library I added a simple Arduino inspired <strong>C++ API<\/strong>. This was one of my first libraries and I found my implementation quite confusing. So it was time to do <strong>some refactoring<\/strong> to clean things up. After all, the C API should be quite easy to use and there must be some reason why I ended up with this complexity.<\/p>\n<p>I am taking the opportunity here to <strong>document the quirks<\/strong> of the C API of libhelix and how I managed around them. But let&#8217;s start with the API:<\/p>\n<h2>Basic Libhelix C API<\/h2>\n<pre><code>HMP3Decoder MP3InitDecoder(void);\nvoid MP3FreeDecoder(HMP3Decoder hMP3Decoder);\nint MP3Decode(HMP3Decoder hMP3Decoder, unsigned char **inbuf, int *bytesLeft, short *outbuf, int useSize);\nvoid MP3GetLastFrameInfo(HMP3Decoder hMP3Decoder, MP3FrameInfo *mp3FrameInfo);\nint MP3GetNextFrameInfo(HMP3Decoder hMP3Decoder, MP3FrameInfo *mp3FrameInfo, unsigned char *buf);\nint MP3FindSyncWord(unsigned char *buf, int nBytes);\n\n<\/code><\/pre>\n<p>So decoding is quite simple: you just MP3Decode() until it reports an underflow with -1 and then you continue to provide the next batch of data.<\/p>\n<p>I was testing this with a MP3 stream from the Internet and it was working like a charm. The AAC side looks the same:<\/p>\n<pre><code>HAACDecoder AACInitDecoder(void);\nHAACDecoder AACInitDecoderPre(void *ptr, int sz);\nvoid AACFreeDecoder(HAACDecoder hAACDecoder);\nint AACDecode(HAACDecoder hAACDecoder, unsigned char **inbuf, int *bytesLeft, short *outbuf);\n\nint AACFindSyncWord(unsigned char *buf, int nBytes);\nvoid AACGetLastFrameInfo(HAACDecoder hAACDecoder, AACFrameInfo *aacFrameInfo);\nint AACSetRawBlockParams(HAACDecoder hAACDecoder, int copyLast, AACFrameInfo *aacFrameInfo);\nint AACFlushCodec(HAACDecoder hAACDecoder);\n<\/code><\/pre>\n<p>Except, this was not working as expected: Instead of getting a -1 the AACDecode() got stuck and never returned when it was running out of data.<\/p>\n<p>The solution was simple: Just make sure that the decoding buffer is <strong>keeping a minimum size<\/strong> and if this is used up, request for more data: I was initially using 400 bytes as limit, but later increased this.<\/p>\n<p>So <strong>internet music streaming<\/strong> was working now for MP3 and AAC. The next thing was to test with some files and here this simple approach falls down and needs some extension.<\/p>\n<h2>Handling of Invalid Audio Data<\/h2>\n<p>Files might contain some <strong>ID3 Header<\/strong> or they might just be damaged and it turns out if this is fed to the decoder, it will not be able to generate any audio any more. So I extended the logic as follows:<\/p>\n<ul>\n<li>I make sure that the data <strong>starts with a Sync Word<\/strong>, before calling the decoding. This means that we need to remove any invalid data before the synch word. I was calling this step <strong>presync<\/strong>.<\/p>\n<\/li>\n<li>\n<p>The MP3 files started to play audio, but then it suddenly the got stuck in an <strong>endless loop<\/strong> where the decoder was reporting that it decoded 0 bytes. I am handling this case as follows: first, I request for more data, because it might be, that we are in an underflow situation without getting the expected -1. If this did not help, I remove the actual data up to the next synch word. This logic needs to run after the decoding, so I called it <strong>resync<\/strong>:<\/p>\n<\/li>\n<\/ul>\n<p>In a nutshell my new C++ API decoding method looks as follows:<\/p>\n<pre><code>  virtual size_t writeChunk(const void *in_ptr, size_t in_size) {\n    LOG_HELIX(LogLevelHelix::Info, \"writeChunk %zu\", in_size);\n    time_last_write = millis();\n    size_t result = frame_buffer.writeArray((uint8_t *)in_ptr, in_size);\n\n    while (frame_buffer.available() &gt;= minFrameBufferSize()) {\n\n      if (!presync()) break;\n      int rc = decode();\n      if (!resynch(rc)) break;\n      \/\/ remove processed data\n      frame_buffer.clearArray(rc);\n\n      LOG_HELIX(LogLevelHelix::Info, \"rc: %d - available %d\", rc,\n                frame_buffer.available());\n\n    }\n\n    return result;\n  }\n\n<\/code><\/pre>\n<p>I think this is quite easy to understand now. This is a common logic which works both for AAC and MP3, so it is implemented in the CommonHelix class which is the base class for the MP3DecoderHelix in AACDecoderHelix which implement the format specific functionality.<\/p>\n<p>If you are interested in the full source code, you can find it currently in the <a href=\"https:\/\/github.com\/pschatzmann\/arduino-libhelix\/blob\/development\/src\/\">Development Branch in Github<\/a>, but it might move to the <a href=\"https:\/\/github.com\/pschatzmann\/arduino-libhelix\/blob\/main\/src\/\">Main Branch<\/a> soon.<\/p>\n<h2>PSRAM Support<\/h2>\n<p>I also decided to add the support for PSRAM when using an ESP32, so instead of calling malloc() or new, I am using my custom allocation logic which is provided by my <a href=\"https:\/\/github.com\/pschatzmann\/arduino-libhelix\/blob\/development\/src\/utils\/Allocator.h\">Allocator.h<\/a><\/p>\n<p>This is used for allocating<\/p>\n<ul>\n<li>the decoder itself<\/li>\n<li>the frame and result buffer of the C++ API<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>I am providing an Arduino MP3 and AAC decoder library for Arduino which is based on libhelix. In this library I added a simple Arduino inspired C++ API. This was one of my first libraries and I found my implementation quite confusing. So it was time to do some refactoring [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3546,"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,22],"tags":[38],"class_list":["post-6192","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-arduino","category-machine-sound","tag-codecs"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Libhelix - Behind the Scene - 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\/2024\/03\/27\/libhelix-behind-the-scene\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Libhelix - Behind the Scene - Phil Schatzmann\" \/>\n<meta property=\"og:description\" content=\"I am providing an Arduino MP3 and AAC decoder library for Arduino which is based on libhelix. In this library I added a simple Arduino inspired C++ API. This was one of my first libraries and I found my implementation quite confusing. So it was time to do some refactoring [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.pschatzmann.ch\/home\/2024\/03\/27\/libhelix-behind-the-scene\/\" \/>\n<meta property=\"og:site_name\" content=\"Phil Schatzmann\" \/>\n<meta property=\"article:published_time\" content=\"2024-03-27T14:34:01+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-03-27T16:25:01+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.pschatzmann.ch\/wp-content\/uploads\/2021\/10\/mp3.png\" \/>\n\t<meta property=\"og:image:width\" content=\"316\" \/>\n\t<meta property=\"og:image:height\" content=\"159\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\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=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/2024\\\/03\\\/27\\\/libhelix-behind-the-scene\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/2024\\\/03\\\/27\\\/libhelix-behind-the-scene\\\/\"},\"author\":{\"name\":\"pschatzmann\",\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/#\\\/schema\\\/person\\\/73a53638a4e34e8373405fd737dac9b1\"},\"headline\":\"Libhelix &#8211; Behind the Scene\",\"datePublished\":\"2024-03-27T14:34:01+00:00\",\"dateModified\":\"2024-03-27T16:25:01+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/2024\\\/03\\\/27\\\/libhelix-behind-the-scene\\\/\"},\"wordCount\":567,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/#\\\/schema\\\/person\\\/73a53638a4e34e8373405fd737dac9b1\"},\"image\":{\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/2024\\\/03\\\/27\\\/libhelix-behind-the-scene\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.pschatzmann.ch\\\/wp-content\\\/uploads\\\/2021\\\/10\\\/mp3.png\",\"keywords\":[\"Codecs\"],\"articleSection\":[\"Arduino\",\"Machine Sound\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/2024\\\/03\\\/27\\\/libhelix-behind-the-scene\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/2024\\\/03\\\/27\\\/libhelix-behind-the-scene\\\/\",\"url\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/2024\\\/03\\\/27\\\/libhelix-behind-the-scene\\\/\",\"name\":\"Libhelix - Behind the Scene - Phil Schatzmann\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/2024\\\/03\\\/27\\\/libhelix-behind-the-scene\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/2024\\\/03\\\/27\\\/libhelix-behind-the-scene\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.pschatzmann.ch\\\/wp-content\\\/uploads\\\/2021\\\/10\\\/mp3.png\",\"datePublished\":\"2024-03-27T14:34:01+00:00\",\"dateModified\":\"2024-03-27T16:25:01+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/2024\\\/03\\\/27\\\/libhelix-behind-the-scene\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/2024\\\/03\\\/27\\\/libhelix-behind-the-scene\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/2024\\\/03\\\/27\\\/libhelix-behind-the-scene\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.pschatzmann.ch\\\/wp-content\\\/uploads\\\/2021\\\/10\\\/mp3.png\",\"contentUrl\":\"https:\\\/\\\/www.pschatzmann.ch\\\/wp-content\\\/uploads\\\/2021\\\/10\\\/mp3.png\",\"width\":316,\"height\":159},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/2024\\\/03\\\/27\\\/libhelix-behind-the-scene\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.pschatzmann.ch\\\/home\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Libhelix &#8211; Behind the Scene\"}]},{\"@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":"Libhelix - Behind the Scene - 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\/2024\/03\/27\/libhelix-behind-the-scene\/","og_locale":"en_US","og_type":"article","og_title":"Libhelix - Behind the Scene - Phil Schatzmann","og_description":"I am providing an Arduino MP3 and AAC decoder library for Arduino which is based on libhelix. In this library I added a simple Arduino inspired C++ API. This was one of my first libraries and I found my implementation quite confusing. So it was time to do some refactoring [&hellip;]","og_url":"https:\/\/www.pschatzmann.ch\/home\/2024\/03\/27\/libhelix-behind-the-scene\/","og_site_name":"Phil Schatzmann","article_published_time":"2024-03-27T14:34:01+00:00","article_modified_time":"2024-03-27T16:25:01+00:00","og_image":[{"width":316,"height":159,"url":"https:\/\/www.pschatzmann.ch\/wp-content\/uploads\/2021\/10\/mp3.png","type":"image\/png"}],"author":"pschatzmann","twitter_card":"summary_large_image","twitter_misc":{"Written by":"pschatzmann","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.pschatzmann.ch\/home\/2024\/03\/27\/libhelix-behind-the-scene\/#article","isPartOf":{"@id":"https:\/\/www.pschatzmann.ch\/home\/2024\/03\/27\/libhelix-behind-the-scene\/"},"author":{"name":"pschatzmann","@id":"https:\/\/www.pschatzmann.ch\/home\/#\/schema\/person\/73a53638a4e34e8373405fd737dac9b1"},"headline":"Libhelix &#8211; Behind the Scene","datePublished":"2024-03-27T14:34:01+00:00","dateModified":"2024-03-27T16:25:01+00:00","mainEntityOfPage":{"@id":"https:\/\/www.pschatzmann.ch\/home\/2024\/03\/27\/libhelix-behind-the-scene\/"},"wordCount":567,"commentCount":2,"publisher":{"@id":"https:\/\/www.pschatzmann.ch\/home\/#\/schema\/person\/73a53638a4e34e8373405fd737dac9b1"},"image":{"@id":"https:\/\/www.pschatzmann.ch\/home\/2024\/03\/27\/libhelix-behind-the-scene\/#primaryimage"},"thumbnailUrl":"https:\/\/www.pschatzmann.ch\/wp-content\/uploads\/2021\/10\/mp3.png","keywords":["Codecs"],"articleSection":["Arduino","Machine Sound"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.pschatzmann.ch\/home\/2024\/03\/27\/libhelix-behind-the-scene\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.pschatzmann.ch\/home\/2024\/03\/27\/libhelix-behind-the-scene\/","url":"https:\/\/www.pschatzmann.ch\/home\/2024\/03\/27\/libhelix-behind-the-scene\/","name":"Libhelix - Behind the Scene - Phil Schatzmann","isPartOf":{"@id":"https:\/\/www.pschatzmann.ch\/home\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.pschatzmann.ch\/home\/2024\/03\/27\/libhelix-behind-the-scene\/#primaryimage"},"image":{"@id":"https:\/\/www.pschatzmann.ch\/home\/2024\/03\/27\/libhelix-behind-the-scene\/#primaryimage"},"thumbnailUrl":"https:\/\/www.pschatzmann.ch\/wp-content\/uploads\/2021\/10\/mp3.png","datePublished":"2024-03-27T14:34:01+00:00","dateModified":"2024-03-27T16:25:01+00:00","breadcrumb":{"@id":"https:\/\/www.pschatzmann.ch\/home\/2024\/03\/27\/libhelix-behind-the-scene\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.pschatzmann.ch\/home\/2024\/03\/27\/libhelix-behind-the-scene\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.pschatzmann.ch\/home\/2024\/03\/27\/libhelix-behind-the-scene\/#primaryimage","url":"https:\/\/www.pschatzmann.ch\/wp-content\/uploads\/2021\/10\/mp3.png","contentUrl":"https:\/\/www.pschatzmann.ch\/wp-content\/uploads\/2021\/10\/mp3.png","width":316,"height":159},{"@type":"BreadcrumbList","@id":"https:\/\/www.pschatzmann.ch\/home\/2024\/03\/27\/libhelix-behind-the-scene\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.pschatzmann.ch\/home\/"},{"@type":"ListItem","position":2,"name":"Libhelix &#8211; Behind the Scene"}]},{"@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\/6192","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=6192"}],"version-history":[{"count":24,"href":"https:\/\/www.pschatzmann.ch\/home\/wp-json\/wp\/v2\/posts\/6192\/revisions"}],"predecessor-version":[{"id":6194,"href":"https:\/\/www.pschatzmann.ch\/home\/wp-json\/wp\/v2\/posts\/6192\/revisions\/6194"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.pschatzmann.ch\/home\/wp-json\/wp\/v2\/media\/3546"}],"wp:attachment":[{"href":"https:\/\/www.pschatzmann.ch\/home\/wp-json\/wp\/v2\/media?parent=6192"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.pschatzmann.ch\/home\/wp-json\/wp\/v2\/categories?post=6192"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.pschatzmann.ch\/home\/wp-json\/wp\/v2\/tags?post=6192"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}