()
| 117 | } |
| 118 | |
| 119 | func (p *Player) readLoop() { |
| 120 | defer func() { |
| 121 | // Note: the error is ignored |
| 122 | p.src.Close() |
| 123 | // Receiving from a closed channel returns quickly |
| 124 | // i.e. `case <-p.readLoopEndedCh:` can check if this loops is ended. |
| 125 | close(p.readLoopEndedCh) |
| 126 | }() |
| 127 | |
| 128 | t := time.After(0) |
| 129 | var readErr error |
| 130 | for { |
| 131 | select { |
| 132 | case <-p.closeCh: |
| 133 | p.closedCh <- struct{}{} |
| 134 | return |
| 135 | |
| 136 | case s := <-p.seekCh: |
| 137 | pos, err := p.src.Seek(s.offset, s.whence) |
| 138 | p.buf = nil |
| 139 | p.pos = pos |
| 140 | p.srcEOF = false |
| 141 | p.seekedCh <- err |
| 142 | t = time.After(time.Millisecond) |
| 143 | break |
| 144 | |
| 145 | case <-t: |
| 146 | // If the buffer has 1 second, that's enough. |
| 147 | if len(p.buf) >= p.sampleRate*bytesPerSample*channelNum { |
| 148 | t = time.After(100 * time.Millisecond) |
| 149 | break |
| 150 | } |
| 151 | |
| 152 | // Try to read the buffer for 1/60[s]. |
| 153 | s := 60 |
| 154 | if engo.CurrentBackEnd == engo.BackEndWeb { |
| 155 | s = 20 |
| 156 | if engo.IsAndroidChrome() { |
| 157 | s = 10 |
| 158 | } |
| 159 | } |
| 160 | l := p.sampleRate * bytesPerSample * channelNum / s |
| 161 | l &= mask |
| 162 | buf := make([]byte, l) |
| 163 | n, err := p.src.Read(buf) |
| 164 | |
| 165 | p.buf = append(p.buf, buf[:n]...) |
| 166 | if err == io.EOF { |
| 167 | p.srcEOF = true |
| 168 | } |
| 169 | if p.srcEOF && len(p.buf) == 0 { |
| 170 | t = nil |
| 171 | break |
| 172 | } |
| 173 | if err != nil && err != io.EOF { |
| 174 | readErr = err |
| 175 | t = nil |
| 176 | break |
no test coverage detected