6 #cgo LDFLAGS: -lstdc++ -g
8 #cgo linux CXXFLAGS: -D__LINUX_ALSA__
9 #cgo linux LDFLAGS: -lm -lasound -pthread
11 #cgo linux,pulseaudio CXXFLAGS: -D__LINUX_PULSE__
12 #cgo linux,pulseaudio LDFLAGS: -lpulse -lpulse-simple
14 #cgo jack CXXFLAGS: -D__UNIX_JACK__
15 #cgo jack LDFLAGS: -ljack
17 #cgo windows CXXFLAGS: -D__WINDOWS_WASAPI__
18 #cgo windows LDFLAGS: -lm -luuid -lksuser -lwinmm -lole32
20 #cgo darwin CXXFLAGS: -D__MACOSX_CORE__
21 #cgo darwin LDFLAGS: -framework CoreAudio -framework CoreFoundation
23 #include "rtaudio_c.h"
25 extern int goCallback(void *out, void *in, unsigned int nFrames,
26 double stream_time, rtaudio_stream_status_t status,
38 // API is an enumeration of available compiled APIs. Supported API include
39 // Alsa/PulseAudio/OSS, Jack, CoreAudio, WASAPI/ASIO/DS and dummy API.
40 type API C.rtaudio_api_t
43 // APIUnspecified looks for a working compiled API.
44 APIUnspecified API = C.RTAUDIO_API_UNSPECIFIED
45 // APILinuxALSA uses the Advanced Linux Sound Architecture API.
46 APILinuxALSA = C.RTAUDIO_API_LINUX_ALSA
47 // APILinuxPulse uses the Linux PulseAudio API.
48 APILinuxPulse = C.RTAUDIO_API_LINUX_PULSE
49 // APILinuxOSS uses the Linux Open Sound System API.
50 APILinuxOSS = C.RTAUDIO_API_LINUX_OSS
51 // APIUnixJack uses the Jack Low-Latency Audio Server API.
52 APIUnixJack = C.RTAUDIO_API_UNIX_JACK
53 // APIMacOSXCore uses Macintosh OS-X Core Audio API.
54 APIMacOSXCore = C.RTAUDIO_API_MACOSX_CORE
55 // APIWindowsWASAPI uses the Microsoft WASAPI API.
56 APIWindowsWASAPI = C.RTAUDIO_API_WINDOWS_WASAPI
57 // APIWindowsASIO uses the Steinberg Audio Stream I/O API.
58 APIWindowsASIO = C.RTAUDIO_API_WINDOWS_ASIO
59 // APIWindowsDS uses the Microsoft Direct Sound API.
60 APIWindowsDS = C.RTAUDIO_API_WINDOWS_DS
61 // APIDummy is a compilable but non-functional API.
62 APIDummy = C.RTAUDIO_API_DUMMY
65 func (api API) String() string {
79 case APIWindowsWASAPI:
91 // StreamStatus defines over- or underflow flags in the audio callback.
92 type StreamStatus C.rtaudio_stream_status_t
95 // StatusInputOverflow indicates that data was discarded because of an
96 // overflow condition at the driver.
97 StatusInputOverflow StreamStatus = C.RTAUDIO_STATUS_INPUT_OVERFLOW
98 // StatusOutputUnderflow indicates that the output buffer ran low, likely
99 // producing a break in the output sound.
100 StatusOutputUnderflow StreamStatus = C.RTAUDIO_STATUS_OUTPUT_UNDERFLOW
103 // Version returns current RtAudio library version string.
104 func Version() string {
105 return C.GoString(C.rtaudio_version())
108 // CompiledAPI determines the available compiled audio APIs.
109 func CompiledAPI() (apis []API) {
110 capis := (*[1 << 30]C.rtaudio_api_t)(unsafe.Pointer(C.rtaudio_compiled_api()))
113 if api == C.RTAUDIO_API_UNSPECIFIED {
116 apis = append(apis, API(api))
121 // DeviceInfo is the public device information structure for returning queried values.
122 type DeviceInfo struct {
125 NumOutputChannels int
127 NumDuplexChannels int
131 //rtaudio_format_t native_formats;
133 PreferredSampleRate uint
137 // StreamParams is the structure for specifying input or output stream parameters.
138 type StreamParams struct {
144 // StreamFlags is a set of RtAudio stream option flags.
145 type StreamFlags C.rtaudio_stream_flags_t
148 // FlagsNoninterleaved is set to use non-interleaved buffers (default = interleaved).
149 FlagsNoninterleaved = C.RTAUDIO_FLAGS_NONINTERLEAVED
150 // FlagsMinimizeLatency when set attempts to configure stream parameters for lowest possible latency.
151 FlagsMinimizeLatency = C.RTAUDIO_FLAGS_MINIMIZE_LATENCY
152 // FlagsHogDevice when set attempts to grab device for exclusive use.
153 FlagsHogDevice = C.RTAUDIO_FLAGS_HOG_DEVICE
154 // FlagsScheduleRealtime is set in attempt to select realtime scheduling (round-robin) for the callback thread.
155 FlagsScheduleRealtime = C.RTAUDIO_FLAGS_SCHEDULE_REALTIME
156 // FlagsAlsaUseDefault is set to use the "default" PCM device (ALSA only).
157 FlagsAlsaUseDefault = C.RTAUDIO_FLAGS_ALSA_USE_DEFAULT
160 // StreamOptions is the structure for specifying stream options.
161 type StreamOptions struct {
168 // RtAudio is a "controller" used to select an available audio i/o interface.
169 type RtAudio interface {
172 Devices() ([]DeviceInfo, error)
173 DefaultOutputDevice() int
174 DefaultInputDevice() int
176 Open(out, in *StreamParams, format Format, sampleRate uint, frames uint, cb Callback, opts *StreamOptions) error
185 Latency() (int, error)
186 SampleRate() (uint, error)
187 Time() (time.Duration, error)
188 SetTime(time.Duration) error
193 type rtaudio struct {
201 var _ RtAudio = &rtaudio{}
203 // Create a new RtAudio instance using the given API.
204 func Create(api API) (RtAudio, error) {
205 audio := C.rtaudio_create(C.rtaudio_api_t(api))
206 if C.rtaudio_error(audio) != nil {
207 return nil, errors.New(C.GoString(C.rtaudio_error(audio)))
209 return &rtaudio{audio: audio}, nil
212 func (audio *rtaudio) Destroy() {
213 C.rtaudio_destroy(audio.audio)
216 func (audio *rtaudio) CurrentAPI() API {
217 return API(C.rtaudio_current_api(audio.audio))
220 func (audio *rtaudio) DefaultInputDevice() int {
221 return int(C.rtaudio_get_default_input_device(audio.audio))
224 func (audio *rtaudio) DefaultOutputDevice() int {
225 return int(C.rtaudio_get_default_output_device(audio.audio))
228 func (audio *rtaudio) Devices() ([]DeviceInfo, error) {
229 n := C.rtaudio_device_count(audio.audio)
230 devices := []DeviceInfo{}
231 for i := C.int(0); i < n; i++ {
232 cinfo := C.rtaudio_get_device_info(audio.audio, i)
233 if C.rtaudio_error(audio.audio) != nil {
234 return nil, errors.New(C.GoString(C.rtaudio_error(audio.audio)))
237 for _, r := range cinfo.sample_rates {
241 sr = append(sr, int(r))
243 devices = append(devices, DeviceInfo{
244 Name: C.GoString(&cinfo.name[0]),
245 Probed: cinfo.probed != 0,
246 NumInputChannels: int(cinfo.input_channels),
247 NumOutputChannels: int(cinfo.output_channels),
248 NumDuplexChannels: int(cinfo.duplex_channels),
249 IsDefaultOutput: cinfo.is_default_output != 0,
250 IsDefaultInput: cinfo.is_default_input != 0,
251 PreferredSampleRate: uint(cinfo.preferred_sample_rate),
259 // Format defines RtAudio data format type.
263 // FormatInt8 uses 8-bit signed integer.
264 FormatInt8 Format = C.RTAUDIO_FORMAT_SINT8
265 // FormatInt16 uses 16-bit signed integer.
266 FormatInt16 = C.RTAUDIO_FORMAT_SINT16
267 // FormatInt24 uses 24-bit signed integer.
268 FormatInt24 = C.RTAUDIO_FORMAT_SINT24
269 // FormatInt32 uses 32-bit signed integer.
270 FormatInt32 = C.RTAUDIO_FORMAT_SINT32
271 // FormatFloat32 uses 32-bit floating point values normalized between (-1..1).
272 FormatFloat32 = C.RTAUDIO_FORMAT_FLOAT32
273 // FormatFloat64 uses 64-bit floating point values normalized between (-1..1).
274 FormatFloat64 = C.RTAUDIO_FORMAT_FLOAT64
277 // Buffer is a common interface for audio buffers of various data format types.
278 type Buffer interface {
288 // Int24 is a helper type to convert int32 values to int24 and back.
291 // Set Int24 value using the least significant bytes of the given number n.
292 func (i *Int24) Set(n int32) {
293 (*i)[0], (*i)[1], (*i)[2] = byte(n&0xff), byte((n&0xff00)>>8), byte((n&0xff0000)>>16)
296 // Get Int24 value as int32.
297 func (i Int24) Get() int32 {
298 n := int32(i[0]) | int32(i[1])<<8 | int32(i[2])<<16
312 func (b *buffer) Len() int {
319 func (b *buffer) Int8() []int8 {
320 if b.format != FormatInt8 {
326 return (*[1 << 30]int8)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
329 func (b *buffer) Int16() []int16 {
330 if b.format != FormatInt16 {
336 return (*[1 << 30]int16)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
339 func (b *buffer) Int24() []Int24 {
340 if b.format != FormatInt24 {
346 return (*[1 << 30]Int24)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
349 func (b *buffer) Int32() []int32 {
350 if b.format != FormatInt32 {
356 return (*[1 << 30]int32)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
359 func (b *buffer) Float32() []float32 {
360 if b.format != FormatFloat32 {
366 return (*[1 << 30]float32)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
369 func (b *buffer) Float64() []float64 {
370 if b.format != FormatFloat64 {
376 return (*[1 << 30]float64)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
379 // Callback is a client-defined function that will be invoked when input data
380 // is available and/or output data is needed.
381 type Callback func(out Buffer, in Buffer, dur time.Duration, status StreamStatus) int
385 audios = map[int]*rtaudio{}
388 func registerAudio(a *rtaudio) int {
392 if _, ok := audios[i]; !ok {
399 func unregisterAudio(a *rtaudio) {
402 for i := 0; i < len(audios); i++ {
410 func findAudio(k int) *rtaudio {
417 func goCallback(out, in unsafe.Pointer, frames C.uint, sec C.double,
418 status C.rtaudio_stream_status_t, userdata unsafe.Pointer) C.int {
420 k := int(uintptr(userdata))
421 audio := findAudio(k)
422 dur := time.Duration(time.Microsecond * time.Duration(sec*1000000.0))
423 inbuf := &buffer{audio.format, int(frames), audio.inputChannels, in}
424 outbuf := &buffer{audio.format, int(frames), audio.outputChannels, out}
425 return C.int(audio.cb(outbuf, inbuf, dur, StreamStatus(status)))
428 func (audio *rtaudio) Open(out, in *StreamParams, format Format, sampleRate uint,
429 frames uint, cb Callback, opts *StreamOptions) error {
431 cInPtr *C.rtaudio_stream_parameters_t
432 cOutPtr *C.rtaudio_stream_parameters_t
433 cOptsPtr *C.rtaudio_stream_options_t
434 cIn C.rtaudio_stream_parameters_t
435 cOut C.rtaudio_stream_parameters_t
436 cOpts C.rtaudio_stream_options_t
439 audio.inputChannels = 0
440 audio.outputChannels = 0
442 audio.outputChannels = int(out.NumChannels)
443 cOut.device_id = C.uint(out.DeviceID)
444 cOut.num_channels = C.uint(out.NumChannels)
445 cOut.first_channel = C.uint(out.FirstChannel)
449 audio.inputChannels = int(in.NumChannels)
450 cIn.device_id = C.uint(in.DeviceID)
451 cIn.num_channels = C.uint(in.NumChannels)
452 cIn.first_channel = C.uint(in.FirstChannel)
456 cOpts.flags = C.rtaudio_stream_flags_t(opts.Flags)
457 cOpts.num_buffers = C.uint(opts.NumBuffers)
458 cOpts.priority = C.int(opts.Priotity)
461 framesCount := C.uint(frames)
462 audio.format = format
465 k := registerAudio(audio)
466 C.rtaudio_open_stream(audio.audio, cOutPtr, cInPtr,
467 C.rtaudio_format_t(format), C.uint(sampleRate), &framesCount,
468 C.rtaudio_cb_t(C.goCallback), unsafe.Pointer(uintptr(k)), cOptsPtr, nil)
469 if C.rtaudio_error(audio.audio) != nil {
470 return errors.New(C.GoString(C.rtaudio_error(audio.audio)))
475 func (audio *rtaudio) Close() {
476 unregisterAudio(audio)
477 C.rtaudio_close_stream(audio.audio)
480 func (audio *rtaudio) Start() error {
481 C.rtaudio_start_stream(audio.audio)
482 if C.rtaudio_error(audio.audio) != nil {
483 return errors.New(C.GoString(C.rtaudio_error(audio.audio)))
488 func (audio *rtaudio) Stop() error {
489 C.rtaudio_stop_stream(audio.audio)
490 if C.rtaudio_error(audio.audio) != nil {
491 return errors.New(C.GoString(C.rtaudio_error(audio.audio)))
496 func (audio *rtaudio) Abort() error {
497 C.rtaudio_abort_stream(audio.audio)
498 if C.rtaudio_error(audio.audio) != nil {
499 return errors.New(C.GoString(C.rtaudio_error(audio.audio)))
504 func (audio *rtaudio) IsOpen() bool {
505 return C.rtaudio_is_stream_open(audio.audio) != 0
508 func (audio *rtaudio) IsRunning() bool {
509 return C.rtaudio_is_stream_running(audio.audio) != 0
512 func (audio *rtaudio) Latency() (int, error) {
513 latency := C.rtaudio_get_stream_latency(audio.audio)
514 if C.rtaudio_error(audio.audio) != nil {
515 return 0, errors.New(C.GoString(C.rtaudio_error(audio.audio)))
517 return int(latency), nil
520 func (audio *rtaudio) SampleRate() (uint, error) {
521 sampleRate := C.rtaudio_get_stream_sample_rate(audio.audio)
522 if C.rtaudio_error(audio.audio) != nil {
523 return 0, errors.New(C.GoString(C.rtaudio_error(audio.audio)))
525 return uint(sampleRate), nil
528 func (audio *rtaudio) Time() (time.Duration, error) {
529 sec := C.rtaudio_get_stream_time(audio.audio)
530 if C.rtaudio_error(audio.audio) != nil {
531 return 0, errors.New(C.GoString(C.rtaudio_error(audio.audio)))
533 return time.Duration(time.Microsecond * time.Duration(sec*1000000.0)), nil
536 func (audio *rtaudio) SetTime(t time.Duration) error {
537 sec := float64(t) * 1000000.0 / float64(time.Microsecond)
538 C.rtaudio_set_stream_time(audio.audio, C.double(sec))
539 if C.rtaudio_error(audio.audio) != nil {
540 return errors.New(C.GoString(C.rtaudio_error(audio.audio)))
545 func (audio *rtaudio) ShowWarnings(show bool) {
547 C.rtaudio_show_warnings(audio.audio, 1)
549 C.rtaudio_show_warnings(audio.audio, 0)