Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(643)

Side by Side Diff: third_party/go/src/golang.org/x/mobile/audio/audio.go

Issue 1275153002: Remove third_party/golang.org/x/mobile as it is no longer used with Go 1.5. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Remove golang.org/x/mobile Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // +build darwin
6
7 // Package audio provides a basic audio player.
8 package audio
9
10 import (
11 "fmt"
12 "io"
13 "sync"
14 "time"
15
16 "golang.org/x/mobile/audio/al"
17 "golang.org/x/mobile/audio/alc"
18 )
19
20 // Format represents an audio file format.
21 type Format string
22
23 const (
24 Mono8 = Format("mono8")
25 Mono16 = Format("mono16")
26 Stereo8 = Format("stereo8")
27 Stereo16 = Format("stereo16")
28 )
29
30 var formatToCode = map[Format]int32{
31 Mono8: 0x1100,
32 Mono16: 0x1101,
33 Stereo8: 0x1102,
34 Stereo16: 0x1103,
35 }
36
37 // State indicates the current playing state of the player.
38 type State string
39
40 const (
41 Unknown = State("unknown")
42 Initial = State("initial")
43 Playing = State("playing")
44 Paused = State("paused")
45 Stopped = State("stopped")
46 )
47
48 var codeToState = map[int32]State{
49 0: Unknown,
50 0x1011: Initial,
51 0x1012: Playing,
52 0x1013: Paused,
53 0x1014: Stopped,
54 }
55
56 var device struct {
57 sync.Mutex
58 d *alc.Device
59 }
60
61 type track struct {
62 format Format
63 rate int64 // sample rate
64 src io.ReadSeeker
65 }
66
67 // Player is a basic audio player that plays PCM data.
68 // Operations on a nil *Player are no-op, a nil *Player can
69 // be used for testing purposes.
70 type Player struct {
71 t *track
72 source al.Source
73
74 muPrep sync.Mutex // guards prep and bufs
75 prep bool
76 bufs []al.Buffer
77 size int64 // size of the audio source
78 }
79
80 // NewPlayer returns a new Player.
81 // It initializes the underlying audio devices and the related resources.
82 func NewPlayer(src io.ReadSeeker, format Format, sampleRate int64) (*Player, err or) {
83 device.Lock()
84 defer device.Unlock()
85
86 if device.d == nil {
87 device.d = alc.Open("")
88 c := device.d.CreateContext(nil)
89 if !alc.MakeContextCurrent(c) {
90 return nil, fmt.Errorf("player: cannot initiate a new pl ayer")
91 }
92 }
93 s := al.GenSources(1)
94 if code := al.Error(); code != 0 {
95 return nil, fmt.Errorf("player: cannot generate an audio source [err=%x]", code)
96 }
97 bufs := al.GenBuffers(2)
98 if err := lastErr(); err != nil {
99 return nil, err
100 }
101 return &Player{
102 t: &track{format: format, src: src, rate: sampleRate},
103 source: s[0],
104 bufs: bufs,
105 }, nil
106 }
107
108 func (p *Player) prepare(offset int64, force bool) error {
109 p.muPrep.Lock()
110 defer p.muPrep.Unlock()
111 if !force && p.prep {
112 return nil
113 }
114 if len(p.bufs) > 0 {
115 p.source.UnqueueBuffers(p.bufs)
116 al.DeleteBuffers(p.bufs)
117 }
118 if _, err := p.t.src.Seek(offset, 0); err != nil {
119 return err
120 }
121 p.bufs = []al.Buffer{}
122 // TODO(jbd): Limit the number of buffers in use, unqueue and reuse
123 // the existing buffers as buffers are processed.
124 buf := make([]byte, 128*1024)
125 size := offset
126 for {
127 n, err := p.t.src.Read(buf)
128 if n > 0 {
129 size += int64(n)
130 b := al.GenBuffers(1)
131 b[0].BufferData(uint32(formatToCode[p.t.format]), buf[:n ], int32(p.t.rate))
132 p.bufs = append(p.bufs, b[0])
133 }
134 if err == io.EOF {
135 break
136 }
137 if err != nil {
138 return err
139 }
140 }
141 p.size = size
142 if len(p.bufs) > 0 {
143 p.source.QueueBuffers(p.bufs)
144 }
145 p.prep = true
146 return nil
147 }
148
149 // Play buffers the source audio to the audio device and starts
150 // to play the source.
151 // If the player paused or stopped, it reuses the previously buffered
152 // resources to keep playing from the time it has paused or stopped.
153 func (p *Player) Play() error {
154 if p == nil {
155 return nil
156 }
157 // Prepares if the track hasn't been buffered before.
158 if err := p.prepare(0, false); err != nil {
159 return err
160 }
161 al.PlaySources(p.source)
162 return lastErr()
163 }
164
165 // Pause pauses the player.
166 func (p *Player) Pause() error {
167 if p == nil {
168 return nil
169 }
170 al.PauseSources(p.source)
171 return lastErr()
172 }
173
174 // Stop stops the player.
175 func (p *Player) Stop() error {
176 if p == nil {
177 return nil
178 }
179 al.StopSources(p.source)
180 return lastErr()
181 }
182
183 // Seek moves the play head to the given offset relative to the start of the sou rce.
184 func (p *Player) Seek(offset time.Duration) error {
185 if p == nil {
186 return nil
187 }
188 if err := p.Stop(); err != nil {
189 return err
190 }
191 size := durToByteOffset(p.t, offset)
192 if err := p.prepare(size, true); err != nil {
193 return err
194 }
195 al.PlaySources(p.source)
196 return lastErr()
197 }
198
199 // Current returns the current playback position of the audio that is being play ed.
200 func (p *Player) Current() time.Duration {
201 if p == nil {
202 return time.Duration(0)
203 }
204 // TODO(jbd): Current never returns the Total when the playing is finish ed.
205 // OpenAL may be returning the last buffer's start point as an OffsetByt e.
206 return byteOffsetToDur(p.t, int64(p.source.OffsetByte()))
207 }
208
209 // Total returns the total duration of the audio source.
210 func (p *Player) Total() time.Duration {
211 if p == nil {
212 return 0
213 }
214 // Prepare is required to determine the length of the source.
215 // We need to read the entire source to calculate the length.
216 p.prepare(0, false)
217 return byteOffsetToDur(p.t, p.size)
218 }
219
220 // Volume returns the current player volume. The range of the volume is [0, 1].
221 func (p *Player) Volume() float64 {
222 if p == nil {
223 return 0
224 }
225 return float64(p.source.Gain())
226 }
227
228 // SetVolume sets the volume of the player. The range of the volume is [0, 1].
229 func (p *Player) SetVolume(vol float64) {
230 if p == nil {
231 return
232 }
233 p.source.SetGain(float32(vol))
234 }
235
236 // State returns the player's current state.
237 func (p *Player) State() State {
238 if p == nil {
239 return Unknown
240 }
241 return codeToState[p.source.State()]
242 }
243
244 // Destroy frees the underlying resources used by the player.
245 // It should be called as soon as the player is not in-use anymore.
246 func (p *Player) Destroy() {
247 if p == nil {
248 return
249 }
250 if p.source != 0 {
251 al.DeleteSources(p.source)
252 }
253 p.muPrep.Lock()
254 if len(p.bufs) > 0 {
255 al.DeleteBuffers(p.bufs)
256 }
257 p.muPrep.Unlock()
258 }
259
260 func byteOffsetToDur(t *track, offset int64) time.Duration {
261 size := float64(offset)
262 if t.format == Mono16 || t.format == Stereo16 {
263 size /= 2
264 }
265 if t.format == Stereo8 || t.format == Stereo16 {
266 size /= 2
267 }
268 size /= float64(t.rate)
269 // Casting size back to int64. Work in milliseconds,
270 // so that size doesn't get rounded excessively.
271 return time.Duration(size*1000) * time.Duration(time.Millisecond)
272 }
273
274 func durToByteOffset(t *track, dur time.Duration) int64 {
275 size := int64(dur/time.Second) * t.rate
276 // Each sample is represented by 16-bits. Move twice further.
277 if t.format == Mono16 || t.format == Stereo16 {
278 size *= 2
279 }
280 if t.format == Stereo8 || t.format == Stereo16 {
281 size *= 2
282 }
283 return size
284 }
285
286 // lastErr returns the last error or nil if the last operation
287 // has been succesful.
288 func lastErr() error {
289 if code := al.Error(); code != 0 {
290 return fmt.Errorf("audio: openal failed with %x", code)
291 }
292 return nil
293 }
294
295 // TODO(jbd): Destroy context, close the device.
OLDNEW
« no previous file with comments | « third_party/go/src/golang.org/x/mobile/audio/alc/alc.go ('k') | third_party/go/src/golang.org/x/mobile/audio/audio_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698