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.

552 lines
14KB

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