play_network.lua 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. -- ****************************************************************************
  2. -- Network streaming example
  3. --
  4. -- stream = require("play_network")
  5. -- stream.init(pin)
  6. -- stream.play(pcm.RATE_8K, ip, port, "/jump_8k.u8", function () print("stream finished") end)
  7. --
  8. -- Playback can be stopped with stream.stop().
  9. -- And resources are free'd with stream.close().
  10. --
  11. local M, module = {}, ...
  12. _G[module] = M
  13. local _conn
  14. local _drv
  15. local _buf
  16. local _lower_thresh = 2
  17. local _upper_thresh = 5
  18. local _play_cb
  19. -- ****************************************************************************
  20. -- PCM
  21. local function stop_stream(cb)
  22. _drv:stop()
  23. if _conn then
  24. _conn:close()
  25. _conn = nil
  26. end
  27. _buf = nil
  28. if cb then cb()
  29. elseif _play_cb then _play_cb()
  30. end
  31. _play_cb = nil
  32. end
  33. local function cb_drained()
  34. print("drained "..node.heap())
  35. stop_stream()
  36. end
  37. local function cb_data()
  38. if #_buf > 0 then
  39. local data = table.remove(_buf, 1)
  40. if #_buf <= _lower_thresh then
  41. -- unthrottle server to get further data into the buffer
  42. _conn:unhold()
  43. end
  44. return data
  45. end
  46. end
  47. local _rate
  48. local function start_play()
  49. print("starting playback")
  50. -- start playback
  51. _drv:play(_rate)
  52. end
  53. -- ****************************************************************************
  54. -- Networking functions
  55. --
  56. local _skip_headers
  57. local _chunk
  58. local _buffering
  59. local function data_received(c, data)
  60. if _skip_headers then
  61. -- simple logic to filter the HTTP headers
  62. _chunk = _chunk..data
  63. local i, j = string.find(_chunk, '\r\n\r\n')
  64. if i then
  65. _skip_headers = false
  66. data = string.sub(_chunk, j+1, -1)
  67. _chunk = nil
  68. end
  69. end
  70. if not _skip_headers then
  71. _buf[#_buf+1] = data
  72. if #_buf > _upper_thresh then
  73. -- throttle server to avoid buffer overrun
  74. c:hold()
  75. if _buffering then
  76. -- buffer got filled, start playback
  77. start_play()
  78. _buffering = false
  79. end
  80. end
  81. end
  82. end
  83. local function cb_disconnected()
  84. if _buffering then
  85. -- trigger playback when disconnected but we're still buffering
  86. start_play()
  87. _buffering = false
  88. end
  89. end
  90. local _path
  91. local function cb_connected(c)
  92. c:send("GET ".._path.." HTTP/1.0\r\nHost: iot.nix.nix\r\n".."Connection: close\r\nAccept: /\r\n\r\n")
  93. _path = nil
  94. end
  95. function M.play(rate, ip, port, path, cb)
  96. _skip_headers = true
  97. _chunk = ""
  98. _buffering = true
  99. _buf = {}
  100. _rate = rate
  101. _path = path
  102. _play_cb = cb
  103. _conn = net.createConnection(net.TCP, 0)
  104. _conn:on("receive", data_received)
  105. _conn:on("disconnection", cb_disconnected)
  106. _conn:connect(port, ip, cb_connected)
  107. end
  108. function M.stop(cb)
  109. stop_stream(cb)
  110. end
  111. function M.init(pin)
  112. _drv = pcm.new(pcm.SD, pin)
  113. -- get called back when all samples were read from stream
  114. _drv:on("drained", cb_drained)
  115. _drv:on("data", cb_data)
  116. --_drv:on("stopped", cb_stopped)
  117. end
  118. function M.vu(cb, freq)
  119. _drv:on("vu", cb, freq)
  120. end
  121. function M.close()
  122. stop_stream()
  123. _drv:close()
  124. _drv = nil
  125. end
  126. return M