You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

564 lines
15KB

  1. package rtaudio
  2. /*
  3. #cgo CXXFLAGS: -g
  4. #cgo LDFLAGS: -lstdc++ -g
  5. #cgo linux CXXFLAGS: -D__LINUX_ALSA__
  6. #cgo linux LDFLAGS: -lm -lasound -pthread
  7. #cgo linux,pulseaudio CXXFLAGS: -D__LINUX_PULSE__
  8. #cgo linux,pulseaudio LDFLAGS: -lpulse -lpulse-simple
  9. #cgo jack CXXFLAGS: -D__UNIX_JACK__
  10. #cgo jack LDFLAGS: -ljack
  11. #cgo windows CXXFLAGS: -D__WINDOWS_WASAPI__
  12. #cgo windows LDFLAGS: -lm -luuid -lksuser -lwinmm -lole32
  13. #cgo darwin CXXFLAGS: -D__MACOSX_CORE__
  14. #cgo darwin LDFLAGS: -framework CoreAudio -framework CoreFoundation
  15. #include <stdlib.h>
  16. #include <stdint.h>
  17. #include "rtaudio_c.h"
  18. extern int goCallback(void *out, void *in, unsigned int nFrames,
  19. double stream_time, rtaudio_stream_status_t status, void *userdata);
  20. static inline void cgoRtAudioOpenStream(rtaudio_t audio,
  21. rtaudio_stream_parameters_t *output_params,
  22. rtaudio_stream_parameters_t *input_params,
  23. rtaudio_format_t format,
  24. unsigned int sample_rate,
  25. unsigned int *buffer_frames,
  26. int cb_id,
  27. rtaudio_stream_options_t *options) {
  28. rtaudio_open_stream(audio, output_params, input_params,
  29. format, sample_rate, buffer_frames,
  30. goCallback, (void *)(uintptr_t)cb_id, options, NULL);
  31. }
  32. */
  33. import "C"
  34. import (
  35. "errors"
  36. "sync"
  37. "time"
  38. "unsafe"
  39. )
  40. // API is an enumeration of available compiled APIs. Supported API include
  41. // Alsa/PulseAudio/OSS, Jack, CoreAudio, WASAPI/ASIO/DS and dummy API.
  42. type API C.rtaudio_api_t
  43. const (
  44. // APIUnspecified looks for a working compiled API.
  45. APIUnspecified API = C.RTAUDIO_API_UNSPECIFIED
  46. // APILinuxALSA uses the Advanced Linux Sound Architecture API.
  47. APILinuxALSA = C.RTAUDIO_API_LINUX_ALSA
  48. // APILinuxPulse uses the Linux PulseAudio API.
  49. APILinuxPulse = C.RTAUDIO_API_LINUX_PULSE
  50. // APILinuxOSS uses the Linux Open Sound System API.
  51. APILinuxOSS = C.RTAUDIO_API_LINUX_OSS
  52. // APIUnixJack uses the Jack Low-Latency Audio Server API.
  53. APIUnixJack = C.RTAUDIO_API_UNIX_JACK
  54. // APIMacOSXCore uses Macintosh OS-X Core Audio API.
  55. APIMacOSXCore = C.RTAUDIO_API_MACOSX_CORE
  56. // APIWindowsWASAPI uses the Microsoft WASAPI API.
  57. APIWindowsWASAPI = C.RTAUDIO_API_WINDOWS_WASAPI
  58. // APIWindowsASIO uses the Steinberg Audio Stream I/O API.
  59. APIWindowsASIO = C.RTAUDIO_API_WINDOWS_ASIO
  60. // APIWindowsDS uses the Microsoft Direct Sound API.
  61. APIWindowsDS = C.RTAUDIO_API_WINDOWS_DS
  62. // APIDummy is a compilable but non-functional API.
  63. APIDummy = C.RTAUDIO_API_DUMMY
  64. )
  65. func (api API) String() string {
  66. switch api {
  67. case APIUnspecified:
  68. return "unspecified"
  69. case APILinuxALSA:
  70. return "alsa"
  71. case APILinuxPulse:
  72. return "pulse"
  73. case APILinuxOSS:
  74. return "oss"
  75. case APIUnixJack:
  76. return "jack"
  77. case APIMacOSXCore:
  78. return "coreaudio"
  79. case APIWindowsWASAPI:
  80. return "wasapi"
  81. case APIWindowsASIO:
  82. return "asio"
  83. case APIWindowsDS:
  84. return "directsound"
  85. case APIDummy:
  86. return "dummy"
  87. }
  88. return "?"
  89. }
  90. // StreamStatus defines over- or underflow flags in the audio callback.
  91. type StreamStatus C.rtaudio_stream_status_t
  92. const (
  93. // StatusInputOverflow indicates that data was discarded because of an
  94. // overflow condition at the driver.
  95. StatusInputOverflow StreamStatus = C.RTAUDIO_STATUS_INPUT_OVERFLOW
  96. // StatusOutputUnderflow indicates that the output buffer ran low, likely
  97. // producing a break in the output sound.
  98. StatusOutputUnderflow StreamStatus = C.RTAUDIO_STATUS_OUTPUT_UNDERFLOW
  99. )
  100. // Version returns current RtAudio library version string.
  101. func Version() string {
  102. return C.GoString(C.rtaudio_version())
  103. }
  104. // CompiledAPI determines the available compiled audio APIs.
  105. func CompiledAPI() (apis []API) {
  106. capis := (*[1 << 30]C.rtaudio_api_t)(unsafe.Pointer(C.rtaudio_compiled_api()))
  107. for i := 0; ; i++ {
  108. api := capis[i]
  109. if api == C.RTAUDIO_API_UNSPECIFIED {
  110. break
  111. }
  112. apis = append(apis, API(api))
  113. }
  114. return apis
  115. }
  116. // DeviceInfo is the public device information structure for returning queried values.
  117. type DeviceInfo struct {
  118. Name string
  119. Probed bool
  120. NumOutputChannels int
  121. NumInputChannels int
  122. NumDuplexChannels int
  123. IsDefaultOutput bool
  124. IsDefaultInput bool
  125. //rtaudio_format_t native_formats;
  126. PreferredSampleRate uint
  127. SampleRates []int
  128. }
  129. // StreamParams is the structure for specifying input or output stream parameters.
  130. type StreamParams struct {
  131. DeviceID uint
  132. NumChannels uint
  133. FirstChannel uint
  134. }
  135. // StreamFlags is a set of RtAudio stream option flags.
  136. type StreamFlags C.rtaudio_stream_flags_t
  137. const (
  138. // FlagsNoninterleaved is set to use non-interleaved buffers (default = interleaved).
  139. FlagsNoninterleaved = C.RTAUDIO_FLAGS_NONINTERLEAVED
  140. // FlagsMinimizeLatency when set attempts to configure stream parameters for lowest possible latency.
  141. FlagsMinimizeLatency = C.RTAUDIO_FLAGS_MINIMIZE_LATENCY
  142. // FlagsHogDevice when set attempts to grab device for exclusive use.
  143. FlagsHogDevice = C.RTAUDIO_FLAGS_HOG_DEVICE
  144. // FlagsScheduleRealtime is set in attempt to select realtime scheduling (round-robin) for the callback thread.
  145. FlagsScheduleRealtime = C.RTAUDIO_FLAGS_SCHEDULE_REALTIME
  146. // FlagsAlsaUseDefault is set to use the "default" PCM device (ALSA only).
  147. FlagsAlsaUseDefault = C.RTAUDIO_FLAGS_ALSA_USE_DEFAULT
  148. )
  149. // StreamOptions is the structure for specifying stream options.
  150. type StreamOptions struct {
  151. Flags StreamFlags
  152. NumBuffers uint
  153. Priotity int
  154. Name string
  155. }
  156. // RtAudio is a "controller" used to select an available audio i/o interface.
  157. type RtAudio interface {
  158. Destroy()
  159. CurrentAPI() API
  160. Devices() ([]DeviceInfo, error)
  161. DefaultOutputDevice() int
  162. DefaultInputDevice() int
  163. Open(out, in *StreamParams, format Format, sampleRate uint, frames uint, cb Callback, opts *StreamOptions) error
  164. Close()
  165. Start() error
  166. Stop() error
  167. Abort() error
  168. IsOpen() bool
  169. IsRunning() bool
  170. Latency() (int, error)
  171. SampleRate() (uint, error)
  172. Time() (time.Duration, error)
  173. SetTime(time.Duration) error
  174. ShowWarnings(bool)
  175. }
  176. type rtaudio struct {
  177. audio C.rtaudio_t
  178. cb Callback
  179. inputChannels int
  180. outputChannels int
  181. format Format
  182. }
  183. var _ RtAudio = &rtaudio{}
  184. // Create a new RtAudio instance using the given API.
  185. func Create(api API) (RtAudio, error) {
  186. audio := C.rtaudio_create(C.rtaudio_api_t(api))
  187. if C.rtaudio_error(audio) != nil {
  188. return nil, errors.New(C.GoString(C.rtaudio_error(audio)))
  189. }
  190. return &rtaudio{audio: audio}, nil
  191. }
  192. func (audio *rtaudio) Destroy() {
  193. C.rtaudio_destroy(audio.audio)
  194. }
  195. func (audio *rtaudio) CurrentAPI() API {
  196. return API(C.rtaudio_current_api(audio.audio))
  197. }
  198. func (audio *rtaudio) DefaultInputDevice() int {
  199. return int(C.rtaudio_get_default_input_device(audio.audio))
  200. }
  201. func (audio *rtaudio) DefaultOutputDevice() int {
  202. return int(C.rtaudio_get_default_output_device(audio.audio))
  203. }
  204. func (audio *rtaudio) Devices() ([]DeviceInfo, error) {
  205. n := C.rtaudio_device_count(audio.audio)
  206. devices := []DeviceInfo{}
  207. for i := C.int(0); i < n; i++ {
  208. cinfo := C.rtaudio_get_device_info(audio.audio, i)
  209. if C.rtaudio_error(audio.audio) != nil {
  210. return nil, errors.New(C.GoString(C.rtaudio_error(audio.audio)))
  211. }
  212. sr := []int{}
  213. for _, r := range cinfo.sample_rates {
  214. if r == 0 {
  215. break
  216. }
  217. sr = append(sr, int(r))
  218. }
  219. devices = append(devices, DeviceInfo{
  220. Name: C.GoString(&cinfo.name[0]),
  221. Probed: cinfo.probed != 0,
  222. NumInputChannels: int(cinfo.input_channels),
  223. NumOutputChannels: int(cinfo.output_channels),
  224. NumDuplexChannels: int(cinfo.duplex_channels),
  225. IsDefaultOutput: cinfo.is_default_output != 0,
  226. IsDefaultInput: cinfo.is_default_input != 0,
  227. PreferredSampleRate: uint(cinfo.preferred_sample_rate),
  228. SampleRates: sr,
  229. })
  230. // TODO: formats
  231. }
  232. return devices, nil
  233. }
  234. // Format defines RtAudio data format type.
  235. type Format int
  236. const (
  237. // FormatInt8 uses 8-bit signed integer.
  238. FormatInt8 Format = C.RTAUDIO_FORMAT_SINT8
  239. // FormatInt16 uses 16-bit signed integer.
  240. FormatInt16 = C.RTAUDIO_FORMAT_SINT16
  241. // FormatInt24 uses 24-bit signed integer.
  242. FormatInt24 = C.RTAUDIO_FORMAT_SINT24
  243. // FormatInt32 uses 32-bit signed integer.
  244. FormatInt32 = C.RTAUDIO_FORMAT_SINT32
  245. // FormatFloat32 uses 32-bit floating point values normalized between (-1..1).
  246. FormatFloat32 = C.RTAUDIO_FORMAT_FLOAT32
  247. // FormatFloat64 uses 64-bit floating point values normalized between (-1..1).
  248. FormatFloat64 = C.RTAUDIO_FORMAT_FLOAT64
  249. )
  250. // Buffer is a common interface for audio buffers of various data format types.
  251. type Buffer interface {
  252. Len() int
  253. Int8() []int8
  254. Int16() []int16
  255. Int24() []Int24
  256. Int32() []int32
  257. Float32() []float32
  258. Float64() []float64
  259. }
  260. // Int24 is a helper type to convert int32 values to int24 and back.
  261. type Int24 [3]byte
  262. // Set Int24 value using the least significant bytes of the given number n.
  263. func (i *Int24) Set(n int32) {
  264. (*i)[0], (*i)[1], (*i)[2] = byte(n&0xff), byte((n&0xff00)>>8), byte((n&0xff0000)>>16)
  265. }
  266. // Get Int24 value as int32.
  267. func (i Int24) Get() int32 {
  268. n := int32(i[0]) | int32(i[1])<<8 | int32(i[2])<<16
  269. if n&0x800000 != 0 {
  270. n |= ^0xffffff
  271. }
  272. return n
  273. }
  274. type buffer struct {
  275. format Format
  276. length int
  277. numChannels int
  278. ptr unsafe.Pointer
  279. }
  280. func (b *buffer) Len() int {
  281. if b.ptr == nil {
  282. return 0
  283. }
  284. return b.length
  285. }
  286. func (b *buffer) Int8() []int8 {
  287. if b.format != FormatInt8 {
  288. return nil
  289. }
  290. if b.ptr == nil {
  291. return nil
  292. }
  293. return (*[1 << 30]int8)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
  294. }
  295. func (b *buffer) Int16() []int16 {
  296. if b.format != FormatInt16 {
  297. return nil
  298. }
  299. if b.ptr == nil {
  300. return nil
  301. }
  302. return (*[1 << 30]int16)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
  303. }
  304. func (b *buffer) Int24() []Int24 {
  305. if b.format != FormatInt24 {
  306. return nil
  307. }
  308. if b.ptr == nil {
  309. return nil
  310. }
  311. return (*[1 << 30]Int24)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
  312. }
  313. func (b *buffer) Int32() []int32 {
  314. if b.format != FormatInt32 {
  315. return nil
  316. }
  317. if b.ptr == nil {
  318. return nil
  319. }
  320. return (*[1 << 30]int32)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
  321. }
  322. func (b *buffer) Float32() []float32 {
  323. if b.format != FormatFloat32 {
  324. return nil
  325. }
  326. if b.ptr == nil {
  327. return nil
  328. }
  329. return (*[1 << 30]float32)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
  330. }
  331. func (b *buffer) Float64() []float64 {
  332. if b.format != FormatFloat64 {
  333. return nil
  334. }
  335. if b.ptr == nil {
  336. return nil
  337. }
  338. return (*[1 << 30]float64)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
  339. }
  340. // Callback is a client-defined function that will be invoked when input data
  341. // is available and/or output data is needed.
  342. type Callback func(out Buffer, in Buffer, dur time.Duration, status StreamStatus) int
  343. var (
  344. mu sync.Mutex
  345. audios = map[int]*rtaudio{}
  346. )
  347. func registerAudio(a *rtaudio) int {
  348. mu.Lock()
  349. defer mu.Unlock()
  350. for i := 0; ; i++ {
  351. if _, ok := audios[i]; !ok {
  352. audios[i] = a
  353. return i
  354. }
  355. }
  356. }
  357. func unregisterAudio(a *rtaudio) {
  358. mu.Lock()
  359. defer mu.Unlock()
  360. for i := 0; i < len(audios); i++ {
  361. if audios[i] == a {
  362. delete(audios, i)
  363. return
  364. }
  365. }
  366. }
  367. func findAudio(k int) *rtaudio {
  368. mu.Lock()
  369. defer mu.Unlock()
  370. return audios[k]
  371. }
  372. //export goCallback
  373. func goCallback(out, in unsafe.Pointer, frames C.uint, sec C.double,
  374. status C.rtaudio_stream_status_t, userdata unsafe.Pointer) C.int {
  375. k := int(uintptr(userdata))
  376. audio := findAudio(k)
  377. dur := time.Duration(time.Microsecond * time.Duration(sec*1000000.0))
  378. inbuf := &buffer{audio.format, int(frames), audio.inputChannels, in}
  379. outbuf := &buffer{audio.format, int(frames), audio.outputChannels, out}
  380. return C.int(audio.cb(outbuf, inbuf, dur, StreamStatus(status)))
  381. }
  382. func (audio *rtaudio) Open(out, in *StreamParams, format Format, sampleRate uint,
  383. frames uint, cb Callback, opts *StreamOptions) error {
  384. var (
  385. cInPtr *C.rtaudio_stream_parameters_t
  386. cOutPtr *C.rtaudio_stream_parameters_t
  387. cOptsPtr *C.rtaudio_stream_options_t
  388. cIn C.rtaudio_stream_parameters_t
  389. cOut C.rtaudio_stream_parameters_t
  390. cOpts C.rtaudio_stream_options_t
  391. )
  392. audio.inputChannels = 0
  393. audio.outputChannels = 0
  394. if out != nil {
  395. audio.outputChannels = int(out.NumChannels)
  396. cOut.device_id = C.uint(out.DeviceID)
  397. cOut.num_channels = C.uint(out.NumChannels)
  398. cOut.first_channel = C.uint(out.FirstChannel)
  399. cOutPtr = &cOut
  400. }
  401. if in != nil {
  402. audio.inputChannels = int(in.NumChannels)
  403. cIn.device_id = C.uint(in.DeviceID)
  404. cIn.num_channels = C.uint(in.NumChannels)
  405. cIn.first_channel = C.uint(in.FirstChannel)
  406. cInPtr = &cIn
  407. }
  408. if opts != nil {
  409. cOpts.flags = C.rtaudio_stream_flags_t(opts.Flags)
  410. cOpts.num_buffers = C.uint(opts.NumBuffers)
  411. cOpts.priority = C.int(opts.Priotity)
  412. cOptsPtr = &cOpts
  413. }
  414. framesCount := C.uint(frames)
  415. audio.format = format
  416. audio.cb = cb
  417. k := registerAudio(audio)
  418. C.cgoRtAudioOpenStream(audio.audio, cOutPtr, cInPtr,
  419. C.rtaudio_format_t(format), C.uint(sampleRate), &framesCount, C.int(k), cOptsPtr)
  420. if C.rtaudio_error(audio.audio) != nil {
  421. return errors.New(C.GoString(C.rtaudio_error(audio.audio)))
  422. }
  423. return nil
  424. }
  425. func (audio *rtaudio) Close() {
  426. unregisterAudio(audio)
  427. C.rtaudio_close_stream(audio.audio)
  428. }
  429. func (audio *rtaudio) Start() error {
  430. C.rtaudio_start_stream(audio.audio)
  431. if C.rtaudio_error(audio.audio) != nil {
  432. return errors.New(C.GoString(C.rtaudio_error(audio.audio)))
  433. }
  434. return nil
  435. }
  436. func (audio *rtaudio) Stop() error {
  437. C.rtaudio_stop_stream(audio.audio)
  438. if C.rtaudio_error(audio.audio) != nil {
  439. return errors.New(C.GoString(C.rtaudio_error(audio.audio)))
  440. }
  441. return nil
  442. }
  443. func (audio *rtaudio) Abort() error {
  444. C.rtaudio_abort_stream(audio.audio)
  445. if C.rtaudio_error(audio.audio) != nil {
  446. return errors.New(C.GoString(C.rtaudio_error(audio.audio)))
  447. }
  448. return nil
  449. }
  450. func (audio *rtaudio) IsOpen() bool {
  451. return C.rtaudio_is_stream_open(audio.audio) != 0
  452. }
  453. func (audio *rtaudio) IsRunning() bool {
  454. return C.rtaudio_is_stream_running(audio.audio) != 0
  455. }
  456. func (audio *rtaudio) Latency() (int, error) {
  457. latency := C.rtaudio_get_stream_latency(audio.audio)
  458. if C.rtaudio_error(audio.audio) != nil {
  459. return 0, errors.New(C.GoString(C.rtaudio_error(audio.audio)))
  460. }
  461. return int(latency), nil
  462. }
  463. func (audio *rtaudio) SampleRate() (uint, error) {
  464. sampleRate := C.rtaudio_get_stream_sample_rate(audio.audio)
  465. if C.rtaudio_error(audio.audio) != nil {
  466. return 0, errors.New(C.GoString(C.rtaudio_error(audio.audio)))
  467. }
  468. return uint(sampleRate), nil
  469. }
  470. func (audio *rtaudio) Time() (time.Duration, error) {
  471. sec := C.rtaudio_get_stream_time(audio.audio)
  472. if C.rtaudio_error(audio.audio) != nil {
  473. return 0, errors.New(C.GoString(C.rtaudio_error(audio.audio)))
  474. }
  475. return time.Duration(time.Microsecond * time.Duration(sec*1000000.0)), nil
  476. }
  477. func (audio *rtaudio) SetTime(t time.Duration) error {
  478. sec := float64(t) * 1000000.0 / float64(time.Microsecond)
  479. C.rtaudio_set_stream_time(audio.audio, C.double(sec))
  480. if C.rtaudio_error(audio.audio) != nil {
  481. return errors.New(C.GoString(C.rtaudio_error(audio.audio)))
  482. }
  483. return nil
  484. }
  485. func (audio *rtaudio) ShowWarnings(show bool) {
  486. if show {
  487. C.rtaudio_show_warnings(audio.audio, 1)
  488. } else {
  489. C.rtaudio_show_warnings(audio.audio, 0)
  490. }
  491. }