189 lines
5 KiB
Go
189 lines
5 KiB
Go
// mpg123.go contains all bindings to the C library
|
|
|
|
package mpg123
|
|
|
|
/*
|
|
#include <stdlib.h>
|
|
#include <mpg123.h>
|
|
#cgo LDFLAGS: -lmpg123
|
|
|
|
int do_mpg123_read(mpg123_handle *mh, void *outmemory, size_t outmemsize, size_t *done) {
|
|
return mpg123_read(mh, outmemory, outmemsize, done);
|
|
}
|
|
*/
|
|
import "C"
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"unsafe"
|
|
)
|
|
|
|
var EOF = errors.New("EOF")
|
|
|
|
// All output encoding formats supported by mpg123
|
|
const (
|
|
ENC_8 = C.MPG123_ENC_8
|
|
ENC_16 = C.MPG123_ENC_16
|
|
ENC_24 = C.MPG123_ENC_24
|
|
ENC_32 = C.MPG123_ENC_32
|
|
ENC_SIGNED = C.MPG123_ENC_SIGNED
|
|
ENC_FLOAT = C.MPG123_ENC_FLOAT
|
|
ENC_SIGNED_8 = C.MPG123_ENC_SIGNED_8
|
|
ENC_UNSIGNED_8 = C.MPG123_ENC_UNSIGNED_8
|
|
ENC_ULAW_8 = C.MPG123_ENC_ULAW_8
|
|
ENC_ALAW_8 = C.MPG123_ENC_ALAW_8
|
|
ENC_SIGNED_16 = C.MPG123_ENC_SIGNED_16
|
|
ENC_UNSIGNED_16 = C.MPG123_ENC_UNSIGNED_16
|
|
ENC_SIGNED_24 = C.MPG123_ENC_SIGNED_24
|
|
ENC_UNSIGNED_24 = C.MPG123_ENC_UNSIGNED_24
|
|
ENC_SIGNED_32 = C.MPG123_ENC_SIGNED_32
|
|
ENC_UNSIGNED_32 = C.MPG123_ENC_UNSIGNED_32
|
|
ENC_FLOAT_32 = C.MPG123_ENC_FLOAT_32
|
|
ENC_FLOAT_64 = C.MPG123_ENC_FLOAT_64
|
|
ENC_ANY = C.MPG123_ENC_ANY
|
|
)
|
|
|
|
// Contains a handle for and mpg123 decoder instance
|
|
type Decoder struct {
|
|
handle *C.mpg123_handle
|
|
}
|
|
|
|
// init initializes the mpg123 library when package is loaded
|
|
func init() {
|
|
err := C.mpg123_init()
|
|
if err != C.MPG123_OK {
|
|
//return fmt.Errorf("error initializing mpg123")
|
|
panic("failed to initialize mpg123")
|
|
}
|
|
//return nil
|
|
}
|
|
|
|
///////////////////////////
|
|
// DECODER INSTANCE CODE //
|
|
///////////////////////////
|
|
|
|
// NewDecoder creates a new mpg123 decoder instance
|
|
func NewDecoder(decoder string) (*Decoder, error) {
|
|
var err C.int
|
|
var mh *C.mpg123_handle
|
|
if decoder != "" {
|
|
mh = C.mpg123_new(nil, &err)
|
|
} else {
|
|
cdecoder := C.CString(decoder)
|
|
defer C.free(unsafe.Pointer(cdecoder))
|
|
mh = C.mpg123_new(cdecoder, &err)
|
|
}
|
|
if mh == nil {
|
|
errstring := C.mpg123_plain_strerror(err)
|
|
err := C.GoString(errstring)
|
|
C.free(unsafe.Pointer(errstring))
|
|
return nil, fmt.Errorf("error initializing mpg123 decoder: %s", err)
|
|
}
|
|
dec := new(Decoder)
|
|
dec.handle = mh
|
|
return dec, nil
|
|
}
|
|
|
|
// Delete frees an mpg123 decoder instance
|
|
func (d *Decoder) Delete() {
|
|
C.mpg123_delete(d.handle)
|
|
}
|
|
|
|
// returns a string containing the most recent error message corresponding to
|
|
// an mpg123 decoder instance
|
|
func (d *Decoder) strerror() string {
|
|
return C.GoString(C.mpg123_strerror(d.handle))
|
|
}
|
|
|
|
////////////////////////
|
|
// OUTPUT FORMAT CODE //
|
|
////////////////////////
|
|
|
|
// FormatNone disables all decoder output formats (used to specifying supported formats)
|
|
func (d *Decoder) FormatNone() {
|
|
C.mpg123_format_none(d.handle)
|
|
}
|
|
|
|
// FromatAll enables all decoder output formats (this is the default setting)
|
|
func (d *Decoder) FormatAll() {
|
|
C.mpg123_format_all(d.handle)
|
|
}
|
|
|
|
// GetFormat returns current output format
|
|
func (d *Decoder) GetFormat() (rate int64, channels int, encoding int) {
|
|
var cRate C.long
|
|
var cChans, cEnc C.int
|
|
C.mpg123_getformat(d.handle, &cRate, &cChans, &cEnc)
|
|
return int64(cRate), int(cChans), int(cEnc)
|
|
}
|
|
|
|
// Format sets the audio output format for decoder
|
|
func (d *Decoder) Format(rate int64, channels int, encodings int) {
|
|
C.mpg123_format(d.handle, C.long(rate), C.int(channels), C.int(encodings))
|
|
}
|
|
|
|
/////////////////////////////
|
|
// INPUT AND DECODING CODE //
|
|
/////////////////////////////
|
|
|
|
// Open initializes a decoder for an mp3 file using a filename
|
|
func (d *Decoder) Open(file string) error {
|
|
cfile := C.CString(file)
|
|
defer C.free(unsafe.Pointer(cfile))
|
|
err := C.mpg123_open(d.handle, cfile)
|
|
if err != C.MPG123_OK {
|
|
return fmt.Errorf("error opening %s: %s", file, d.strerror())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// OpenFile binds to an fd from an open *os.File for decoding
|
|
func (d *Decoder) OpenFile(f *os.File) error {
|
|
err := C.mpg123_open_fd(d.handle, C.int(f.Fd()))
|
|
if err != C.MPG123_OK {
|
|
return fmt.Errorf("error attaching file: %s", d.strerror())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// OpenFeed prepares a decoder for direct feeding via Feed(..)
|
|
func (d *Decoder) OpenFeed() error {
|
|
err := C.mpg123_open_feed(d.handle)
|
|
if err != C.MPG123_OK {
|
|
return fmt.Errorf("mpg123 error: %s", d.strerror())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Close closes an input file if one was opened by mpg123
|
|
func (d *Decoder) Close() error {
|
|
err := C.mpg123_close(d.handle)
|
|
if err != C.MPG123_OK {
|
|
return fmt.Errorf("mpg123 error: %s", d.strerror())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Read decodes data and into buf and returns number of bytes decoded.
|
|
func (d *Decoder) Read(buf []byte) (int, error) {
|
|
var done C.size_t
|
|
err := C.do_mpg123_read(d.handle, (unsafe.Pointer)(&buf[0]), C.size_t(len(buf)), &done)
|
|
if err == C.MPG123_DONE {
|
|
return int(done), EOF
|
|
}
|
|
if err != C.MPG123_OK {
|
|
return int(done), fmt.Errorf("mpg123 error: %s", d.strerror())
|
|
}
|
|
return int(done), nil
|
|
}
|
|
|
|
// Feed provides data bytes into the decoder
|
|
func (d *Decoder) Feed(buf []byte) error {
|
|
err := C.mpg123_feed(d.handle, (*C.uchar)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)))
|
|
if err != C.MPG123_OK {
|
|
return fmt.Errorf("mpg123 error: %s", d.strerror())
|
|
}
|
|
return nil
|
|
}
|