{"id":13907860,"url":"https://github.com/hraban/opus","last_synced_at":"2025-04-04T12:10:00.002Z","repository":{"id":27512682,"uuid":"30993396","full_name":"hraban/opus","owner":"hraban","description":"Go wrapper for libopus (golang)","archived":false,"fork":false,"pushed_at":"2024-06-21T15:08:21.000Z","size":806,"stargazers_count":295,"open_issues_count":6,"forks_count":62,"subscribers_count":7,"default_branch":"v2","last_synced_at":"2025-03-28T11:09:59.626Z","etag":null,"topics":["go","libopus","opus"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hraban.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-02-18T23:51:35.000Z","updated_at":"2025-03-28T09:19:47.000Z","dependencies_parsed_at":"2024-06-18T13:35:23.631Z","dependency_job_id":"6d77381b-45b5-480e-82a1-16696270da64","html_url":"https://github.com/hraban/opus","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hraban%2Fopus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hraban%2Fopus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hraban%2Fopus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hraban%2Fopus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hraban","download_url":"https://codeload.github.com/hraban/opus/tar.gz/refs/heads/v2","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247174455,"owners_count":20896078,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","libopus","opus"],"created_at":"2024-08-06T23:02:14.493Z","updated_at":"2025-04-04T12:09:59.981Z","avatar_url":"https://github.com/hraban.png","language":"Go","funding_links":[],"categories":["HarmonyOS","Go"],"sub_categories":["Windows Manager"],"readme":"[![Test](https://github.com/hraban/opus/workflows/Test/badge.svg)](https://github.com/hraban/opus/actions?query=workflow%3ATest)\n\n## Go wrapper for Opus\n\nThis package provides Go bindings for the xiph.org C libraries libopus and\nlibopusfile.\n\nThe C libraries and docs are hosted at https://opus-codec.org/. This package\njust handles the wrapping in Go, and is unaffiliated with xiph.org.\n\nFeatures:\n\n- ✅ encode and decode raw PCM data to raw Opus data\n- ✅ useful when you control the recording device, _and_ the playback\n- ✅ decode .opus and .ogg files into raw audio data (\"PCM\")\n- ✅ reuse the system libraries for opus decoding (libopus)\n- ✅ works easily on Linux, Mac and Docker; needs libs on Windows\n- ❌ does not _create_ .opus or .ogg files (but feel free to send a PR)\n- ❌ does not work with .wav files (you need a separate .wav library for that)\n- ❌ no self-contained binary (you need the xiph.org libopus lib, e.g. through a package manager)\n- ❌ no cross compiling (because it uses CGo)\n\nGood use cases:\n\n- 👍 you are writing a music player app in Go, and you want to play back .opus files\n- 👍 you record raw wav in a web app or mobile app, you encode it as Opus on the client, you send the opus to a remote webserver written in Go, and you want to decode it back to raw audio data on that server\n\n## Details\n\nThis wrapper provides a Go translation layer for three elements from the\nxiph.org opus libs:\n\n* encoders\n* decoders\n* files \u0026 streams\n\n### Import\n\n```go\nimport \"gopkg.in/hraban/opus.v2\"\n```\n\n### Encoding\n\nTo encode raw audio to the Opus format, create an encoder first:\n\n```go\nconst sampleRate = 48000\nconst channels = 1 // mono; 2 for stereo\n\nenc, err := opus.NewEncoder(sampleRate, channels, opus.AppVoIP)\nif err != nil {\n    ...\n}\n```\n\nThen pass it some raw PCM data to encode.\n\nMake sure that the raw PCM data you want to encode has a legal Opus frame size.\nThis means it must be exactly 2.5, 5, 10, 20, 40 or 60 ms long. The number of\nbytes this corresponds to depends on the sample rate (see the [libopus\ndocumentation](https://www.opus-codec.org/docs/opus_api-1.1.3/group__opus__encoder.html)).\n\n```go\nvar pcm []int16 = ... // obtain your raw PCM data somewhere\nconst bufferSize = 1000 // choose any buffer size you like. 1k is plenty.\n\n// Check the frame size. You don't need to do this if you trust your input.\nframeSize := len(pcm) // must be interleaved if stereo\nframeSizeMs := float32(frameSize) / channels * 1000 / sampleRate\nswitch frameSizeMs {\ncase 2.5, 5, 10, 20, 40, 60:\n    // Good.\ndefault:\n    return fmt.Errorf(\"Illegal frame size: %d bytes (%f ms)\", frameSize, frameSizeMs)\n}\n\ndata := make([]byte, bufferSize)\nn, err := enc.Encode(pcm, data)\nif err != nil {\n    ...\n}\ndata = data[:n] // only the first N bytes are opus data. Just like io.Reader.\n```\n\nNote that you must choose a target buffer size, and this buffer size will affect\nthe encoding process:\n\n\u003e Size of the allocated memory for the output payload. This may be used to\n\u003e impose an upper limit on the instant bitrate, but should not be used as the\n\u003e only bitrate control. Use `OPUS_SET_BITRATE` to control the bitrate.\n\n-- https://opus-codec.org/docs/opus_api-1.1.3/group__opus__encoder.html\n\n### Decoding\n\nTo decode opus data to raw PCM format, first create a decoder:\n\n```go\ndec, err := opus.NewDecoder(sampleRate, channels)\nif err != nil {\n    ...\n}\n```\n\nNow pass it the opus bytes, and a buffer to store the PCM sound in:\n\n```go\nvar frameSizeMs float32 = ...  // if you don't know, go with 60 ms.\nframeSize := channels * frameSizeMs * sampleRate / 1000\npcm := make([]int16, int(frameSize))\nn, err := dec.Decode(data, pcm)\nif err != nil {\n    ...\n}\n\n// To get all samples (interleaved if multiple channels):\npcm = pcm[:n*channels] // only necessary if you didn't know the right frame size\n\n// or access sample per sample, directly:\nfor i := 0; i \u003c n; i++ {\n    ch1 := pcm[i*channels+0]\n    // For stereo output: copy ch1 into ch2 in mono mode, or deinterleave stereo\n    ch2 := pcm[(i*channels)+(channels-1)]\n}\n```\n\nTo handle packet loss from an unreliable network, see the\n[DecodePLC](https://godoc.org/gopkg.in/hraban/opus.v2#Decoder.DecodePLC) and\n[DecodeFEC](https://godoc.org/gopkg.in/hraban/opus.v2#Decoder.DecodeFEC)\noptions.\n\n### Streams (and Files)\n\nTo decode a .opus file (or .ogg with Opus data), or to decode a \"Opus stream\"\n(which is a Ogg stream with Opus data), use the `Stream` interface. It wraps an\nio.Reader providing the raw stream bytes and returns the decoded Opus data.\n\nA crude example for reading from a .opus file:\n\n```go\nf, err := os.Open(fname)\nif err != nil {\n    ...\n}\ns, err := opus.NewStream(f)\nif err != nil {\n    ...\n}\ndefer s.Close()\npcmbuf := make([]int16, 16384)\nfor {\n    n, err = s.Read(pcmbuf)\n    if err == io.EOF {\n        break\n    } else if err != nil {\n        ...\n    }\n    pcm := pcmbuf[:n*channels]\n\n    // send pcm to audio device here, or write to a .wav file\n\n}\n```\n\nSee https://godoc.org/gopkg.in/hraban/opus.v2#Stream for further info.\n\n### \"My .ogg/.opus file doesn't play!\" or \"How do I play Opus in VLC / mplayer / ...?\"\n\nNote: this package only does _encoding_ of your audio, to _raw opus data_. You can't just dump those all in one big file and play it back. You need extra info. First of all, you need to know how big each individual block is. Remember: opus data is a stream of encoded separate blocks, not one big stream of bytes. Second, you need meta-data: how many channels? What's the sampling rate? Frame size? Etc.\n\nLook closely at the decoding sample code (not stream), above: we're passing all that meta-data in, hard-coded. If you just put all your encoded bytes in one big file and gave that to a media player, it wouldn't know what to do with it. It wouldn't even know that it's Opus data. It would just look like `/dev/random`.\n\nWhat you need is a [container format](https://en.wikipedia.org/wiki/Container_format_(computing)).\n\nCompare it to video:\n\n* Encodings: MPEG[1234], VP9, H26[45], AV1\n* Container formats: .mkv, .avi, .mov, .ogv\n\nFor Opus audio, the most common container format is OGG, aka .ogg or .opus. You'll know OGG from OGG/Vorbis: that's [Vorbis](https://xiph.org/vorbis/) encoded audio in an OGG container. So for Opus, you'd call it OGG/Opus. But technically you could stick opus data in any container format that supports it, including e.g. Matroska (.mka for audio, you probably know it from .mkv for video).\n\nNote: libopus, the C library that this wraps, technically comes with libopusfile, which can help with the creation of OGG/Opus streams from raw audio data. I just never needed it myself, so I haven't added the necessary code for it. If you find yourself adding it: send me a PR and we'll get it merged.\n\nThis libopus wrapper _does_ come with code for _decoding_ an OGG/Opus stream. Just not for writing one.\n\n### API Docs\n\nGo wrapper API reference:\nhttps://godoc.org/gopkg.in/hraban/opus.v2\n\nFull libopus C API reference:\nhttps://www.opus-codec.org/docs/opus_api-1.1.3/\n\nFor more examples, see the `_test.go` files.\n\n## Build \u0026 Installation\n\nThis package requires libopus and libopusfile development packages to be\ninstalled on your system. These are available on Debian based systems from\naptitude as `libopus-dev` and `libopusfile-dev`, and on Mac OS X from homebrew.\n\nThey are linked into the app using pkg-config.\n\nDebian, Ubuntu, ...:\n```sh\nsudo apt-get install pkg-config libopus-dev libopusfile-dev\n```\n\nMac:\n```sh\nbrew install pkg-config opus opusfile\n```\n\n### Building Without `libopusfile`\n\nThis package can be built without `libopusfile` by using the build tag `nolibopusfile`.\nThis enables the compilation of statically-linked binaries with no external\ndependencies on operating systems without a static `libopusfile`, such as\n[Alpine Linux](https://pkgs.alpinelinux.org/contents?branch=edge\u0026name=opusfile-dev\u0026arch=x86_64\u0026repo=main).\n\n**Note:** this will disable all file and `Stream` APIs.\n\nTo enable this feature, add `-tags nolibopusfile` to your `go build` or `go test` commands:\n\n```sh\n# Build\ngo build -tags nolibopusfile ...\n\n# Test\ngo test -tags nolibopusfile ./...\n```\n\n### Using in Docker\n\nIf your Dockerized app has this library as a dependency (directly or\nindirectly), it will need to install the aforementioned packages, too.\n\nThis means you can't use the standard `golang:*-onbuild` images, because those\nwill try to build the app from source before allowing you to install extra\ndependencies. Instead, try this as a Dockerfile:\n\n```Dockerfile\n# Choose any golang image, just make sure it doesn't have -onbuild\nFROM golang:1\n\nRUN apt-get update \u0026\u0026 apt-get -y install libopus-dev libopusfile-dev\n\n# Everything below is copied manually from the official -onbuild image,\n# with the ONBUILD keywords removed.\n\nRUN mkdir -p /go/src/app\nWORKDIR /go/src/app\n\nCMD [\"go-wrapper\", \"run\"]\nCOPY . /go/src/app\nRUN go-wrapper download\nRUN go-wrapper install\n```\n\nFor more information, see \u003chttps://hub.docker.com/_/golang/\u003e.\n\n### Linking libopus and libopusfile\n\nThe opus and opusfile libraries will be linked into your application\ndynamically. This means everyone who uses the resulting binary will need those\nlibraries available on their system. E.g. if you use this wrapper to write a\nmusic app in Go, everyone using that music app will need libopus and libopusfile\non their system. On Debian systems the packages are called `libopus0` and\n`libopusfile0`.\n\nThe \"cleanest\" way to do this is to publish your software through a package\nmanager and specify libopus and libopusfile as dependencies of your program. If\nthat is not an option, you can compile the dynamic libraries yourself and ship\nthem with your software as seperate (.dll or .so) files.\n\nOn Linux, for example, you would need the libopus.so.0 and libopusfile.so.0\nfiles in the same directory as the binary. Set your ELF binary's rpath to\n`$ORIGIN` (this is not a shell variable but elf magic):\n\n```sh\npatchelf --set-origin '$ORIGIN' your-app-binary\n```\n\nNow you can run the binary and it will automatically pick up shared library\nfiles from its own directory.\n\nWrap it all in a .zip, and ship.\n\nI know there is a similar trick for Mac (involving prefixing the shared library\nnames with `./`, which is, arguably, better). And Windows... probably just picks\nup .dll files from the same dir by default? I don't know. But there are ways.\n\n## License\n\nThe licensing terms for the Go bindings are found in the LICENSE file. The\nauthors and copyright holders are listed in the AUTHORS file.\n\nThe copyright notice uses range notation to indicate all years in between are\nsubject to copyright, as well. This statement is necessary, apparently. For all\nthose nefarious actors ready to abuse a copyright notice with incorrect\nnotation, but thwarted by a mention in the README. Pfew!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhraban%2Fopus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhraban%2Fopus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhraban%2Fopus/lists"}