-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdevice.go
151 lines (129 loc) · 3.94 KB
/
device.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// This file is subject to a BSD license.
// Its contents can be found in the enclosed LICENSE file.
package ao
// #include <ao/ao.h>
import "C"
import (
"errors"
"io"
"unsafe"
)
// Device holds an opaque type defining output device data.
type Device struct {
ptr *C.ao_device
}
// PlayU16 is the same as Play() but accepts a slice of 16 bit PCM sample data.
// This function assumes the sample format byte order is set to EndianNative.
func (d *Device) PlayU16(data []uint16) error {
sz := len(data)
if sz == 0 {
return nil
}
return d.Play((*(*[1<<31 - 1]byte)(unsafe.Pointer(&data[0])))[:sz*2])
}
// Write writes at most len(p) bytes to the underlying device.
// Samples are interleaved by channels (Time 1, Channel 1; Time 2, Channel 2;
// Time 1, Channel 1; etc.) in the memory buffer.
//
// Returns an error if playback failed. In which case, the device should
// be closed.
func (d *Device) Write(p []byte) (n int, err error) {
if len(p) == 0 {
return 0, io.EOF
}
if d.ptr == nil {
return 0, errors.New("device is closed")
}
if C.ao_play(
d.ptr,
(*C.char)(unsafe.Pointer(&p[0])),
C.uint_32(len(p)),
) <= 0 {
return 0, errors.New("playback failed; device should be closed")
}
return len(p), nil
}
// Play is an alias for Device.Write(). Refer to its documentation for details.
func (d *Device) Play(p []byte) error {
_, err := d.Write(p)
return err
}
// Close closes the audio device and frees the memory allocated
// by the device structure.
//
// An error is returned if closing of the device failed.
// If this device was writing to a file, the file may be corrupted.
func (d *Device) Close() error {
var err error
if d.ptr != nil {
if C.ao_close(d.ptr) <= 0 {
err = errors.New("failed to close device correctly")
}
d.ptr = nil
}
return err
}
// OpenFile open a file for audio output. The file format is determined by
// the audio driver used.
//
// The driver id can be retrieved by either DriverId() or DefaultDriver().
// Live output drivers cannot be used with this function. Use OpenLive instead.
// Some file formats (notably .WAV) cannot be correctly written to non-seekable
// files (like stdout).
//
// The sample format defines the format of the output stream.
//
// If overwrite is true, the file is automatically overwritten.
// Otherwise a preexisting file will cause the function to report a failure.
//
// The optional map defines device configuration settings.
// Refer to https://xiph.org/ao/doc/drivers.html for a list of options
// supported by the current driver.
//
// Returns an error if the device could not be opened.
// Be sure to call Device.Close() once you are done with it.
func OpenFile(driver int, filename string, overwrite bool, fmt *SampleFormat, options map[string]string) (*Device, error) {
coptions := makeOptions(options)
cfilename := C.CString(filename)
defer func() {
freeOptions(coptions)
C.free(unsafe.Pointer(cfilename))
}()
var coverwrite C.int
if overwrite {
coverwrite = 1
}
dev, err := C.ao_open_file(
C.int(driver),
cfilename,
coverwrite,
fmt.toC(),
coptions,
)
if err != nil {
return nil, err
}
return &Device{dev}, nil
}
// OpenLive opens a live playback audio device for output.
//
// The driver id can be retrieved by either DriverId() or DefaultDriver().
// File output drivers cannot be used with this function. Use OpenFile() instead.
//
// The sample format defines the format of the output stream.
//
// The optional map defines device configuration settings.
// Refer to https://xiph.org/ao/doc/drivers.html for a list of options
// supported by the current driver.
//
// Returns an error if the device could not be opened.
// Be sure to call Device.Close() once you are done with it.
func OpenLive(driver int, fmt *SampleFormat, options map[string]string) (*Device, error) {
coptions := makeOptions(options)
defer freeOptions(coptions)
dev, err := C.ao_open_live(C.int(driver), fmt.toC(), coptions)
if dev == nil {
return nil, err
}
return &Device{dev}, nil
}