-- **************************************************************************** -- Network streaming example -- -- stream = require("play_network") -- stream.init(pin) -- stream.play(pcm.RATE_8K, ip, port, "/jump_8k.u8", function () print("stream finished") end) -- -- Playback can be stopped with stream.stop(). -- And resources are free'd with stream.close(). -- local M, module = {}, ... _G[module] = M local _conn local _drv local _buf local _lower_thresh = 2 local _upper_thresh = 5 local _play_cb -- **************************************************************************** -- PCM local function stop_stream(cb) _drv:stop() if _conn then _conn:close() _conn = nil end _buf = nil if cb then cb() elseif _play_cb then _play_cb() end _play_cb = nil end local function cb_drained() print("drained "..node.heap()) stop_stream() end local function cb_data() if #_buf > 0 then local data = table.remove(_buf, 1) if #_buf <= _lower_thresh then -- unthrottle server to get further data into the buffer _conn:unhold() end return data end end local _rate local function start_play() print("starting playback") -- start playback _drv:play(_rate) end -- **************************************************************************** -- Networking functions -- local _skip_headers local _chunk local _buffering local function data_received(c, data) if _skip_headers then -- simple logic to filter the HTTP headers _chunk = _chunk..data local i, j = string.find(_chunk, '\r\n\r\n') if i then _skip_headers = false data = string.sub(_chunk, j+1, -1) _chunk = nil end end if not _skip_headers then _buf[#_buf+1] = data if #_buf > _upper_thresh then -- throttle server to avoid buffer overrun c:hold() if _buffering then -- buffer got filled, start playback start_play() _buffering = false end end end end local function cb_disconnected() if _buffering then -- trigger playback when disconnected but we're still buffering start_play() _buffering = false end end local _path local function cb_connected(c) c:send("GET ".._path.." HTTP/1.0\r\nHost: iot.nix.nix\r\n".."Connection: close\r\nAccept: /\r\n\r\n") _path = nil end function M.play(rate, ip, port, path, cb) _skip_headers = true _chunk = "" _buffering = true _buf = {} _rate = rate _path = path _play_cb = cb _conn = net.createConnection(net.TCP, false) _conn:on("receive", data_received) _conn:on("disconnection", cb_disconnected) _conn:connect(port, ip, cb_connected) end function M.stop(cb) stop_stream(cb) end function M.init(pin) _drv = pcm.new(pcm.SD, pin) -- get called back when all samples were read from stream _drv:on("drained", cb_drained) _drv:on("data", cb_data) --_drv:on("stopped", cb_stopped) end function M.vu(cb, freq) _drv:on("vu", cb, freq) end function M.close() stop_stream() _drv:close() _drv = nil end return M