Help with sound API? trying to make a basic radio plugin to learn lua

Hey guys, I’ve been trying to make a simple radio sort of addon to learn lua and get used to the syntax, I’ve had some success, but I was trying to implement a stop pause resume and volume command, while doing this it basically crashes the client, likley because of the loop I used
The code I had is below



AddCSLuaFile()
local receiving_side = CLIENT
local NetworkStreamName = "RadioStreamName"
local playing = false
function string.starts(String,Start)
   return string.sub(String,1,string.len(Start))==Start
end

function string.ends(String,End)
   return End=='' or string.sub(String,-string.len(End))==End
end

function broadcast(message)
	for count, ply in pairs( player.GetAll()) do
		 ply:ChatPrint(message)
	end
end

function string.split(s, split)
	list = {}
	index = 1
		for value in string.gmatch(s, split) do
			list [index] = value
			index = index + 1	 
		end
	return list
end

function trim(s)
  return (s:gsub("^%s*(.-)%s*$", "%1"))
end

if(receiving_side) then
	net.(NetworkStreamName, function (len)
		local command = net.ReadString()
		local args = string.split(command, "%S+")
		local volume = 50
		local stop = false
		local resume = false
		local pause = false
		local play = true
		if string.start(command, "setvolume") then
			volume = args[1]
		end
		if string.start(command, "pause") then
			pause = true
		end
		if string.start(command, "resume") then
			resume = true
		end		
		if string.start(command, "play") then
			local url = args[2]
			sound.PlayURL(URL, "play", function (channel)
				print("Playing " .. URL .. "!")
				playing = true
				while channel:IsValid() and play do
				channel:SetVolume(volume)
					if stop then
						channel:Stop()
						play = false
					end
					if pause then
						channel:Pause()
					end
					if resume then
						channel:Play()
					end
				end
				playing = false
				broadcast("Song over!")	
			end)
		end
	end)
else
	util.AddNetworkString(NetworkStreamName)
	function process(player, strText, bTeamOnly, bPlayerIsDead)
		if string.starts(string.lower(strText), "!say") then
			local args = string.split(strText, "%S+")
			local message = "";
			for i=2,#args do
				message = message .. args* .. " "
			end
			broadcast(trim(message))
			return false
		end
		if string.starts(string.lower(strText), "!music_play") then
			local args = string.split(strText, "%S+");
			if(#args == 2) then
				local stream = args[2]
				net.Start(NetworkStreamName)
				net.WriteString("play " .. args[2])
				net.Broadcast()
			end
		end
		if string.starts(string.lower(strText), "!music_volume") then
			local args = string.split(strText, "%S+");
			if(#args == 2) then
				local volume = args[2]
				net.Start(NetworkStreamName)
				net.WriteString("setvolume " .. args[2])
				net.Broadcast()
			end
		end
		if string.starts(string.lower(strText), "!music_resume") then
			local args = string.split(strText, "%S+");
			if(#args == 2) then
				local volume = args[2]
				net.Start(NetworkStreamName)
				net.WriteString("resume " .. args[2])
				net.Broadcast()
			end
		end
		if string.starts(string.lower(strText), "!music_pause") then
			local args = string.split(strText, "%S+");
			if(#args == 2) then
				local volume = args[2]
				net.Start(NetworkStreamName)
				net.WriteString("pause " .. args[2])
				net.Broadcast()
			end
		end
		return true
	end
	hook.Add("PlayerSay", "TestHook", process) 
end


Ive been attempting to re-write it and what i currently have is this:



AddCSLuaFile()
local receiving_side = CLIENT
local NetworkStreamName = "RadioStreamName"
local NetworkStreamNameVolume = NetworkStreamName .. "volume"
local NetworkStreamNamePause = NetworkStreamName .. "pause"
local NetworkStreamNameStop = NetworkStreamName .. "stop"
local NetworkStreamNameResume = NetworkStreamName .. "resume"
local playing = false
function string.starts(String,Start)
   return string.sub(String,1,string.len(Start))==Start
end

function string.ends(String,End)
   return End=='' or string.sub(String,-string.len(End))==End
end

function broadcast(message)
	for count, ply in pairs( player.GetAll()) do
		 ply:ChatPrint(message)
	end
end

function string.split(s, split)
	list = {}
	index = 1
		for value in string.gmatch(s, split) do
			list [index] = value
			index = index + 1	 
		end
	return list
end

function trim(s)
  return (s:gsub("^%s*(.-)%s*$", "%1"))
end

if(receiving_side) then
	local volume = 50
	local stop = false
	local resume = false
	local pause = false
	local play = true
	local chan 
	net.Receive(NetworkStreamName, function (len)
	local command = net.ReadString()
	local args = string.split(command, "%S+")	
		if string.starts(command, "play") then
			local URL = args[2]
			sound.PlayURL(URL, "play", function (channel)
				print("Playing " .. URL .. "!")
				chan = channel
				playing = true
				
				playing = false
				broadcast("Song over!")	
			end)
		end
	end)
	net.Receive(NetworkStreamNameResume, function (len)
		chan:Play()
	end)
	net.Receive(NetworkStreamNameStop, function (len)
		chan:Stop()
	end)
	net.Receive(NetworkStreamNamePause, function (len)
		chan:Pause()
	end)
	net.Receive(NetworkStreamNameVolume, function (len)
		chan:Pause()
	end)

else
	util.AddNetworkString(NetworkStreamName)
	util.AddNetworkString(NetworkStreamNameResume)
	util.AddNetworkString(NetworkStreamNameStop)
	util.AddNetworkString(NetworkStreamNamePause)
	util.AddNetworkString(NetworkStreamNameVolume)
	function process(player, strText, bTeamOnly, bPlayerIsDead)
		if string.starts(string.lower(strText), "!say") then
			local args = string.split(strText, "%S+")
			local message = "";
			for i=2,#args do
				message = message .. args* .. " "
			end
			broadcast(trim(message))
			return false
		end
		if string.starts(string.lower(strText), "!music_play") then
			local args = string.split(strText, "%S+");
			if(#args == 2) then
				local stream = args[2]
				net.Start(NetworkStreamName)
				net.WriteString("play " .. args[2])
				net.Broadcast()
			end
		end
		if string.starts(string.lower(strText), "!music_volume") then
			local args = string.split(strText, "%S+");
			if(#args == 2) then
				local volume = args[2]
				net.Start(NetworkStreamNameVolume)
				net.WriteString(args[2])
				net.Broadcast()
			end
		end
		if string.starts(string.lower(strText), "!music_resume") then
			local args = string.split(strText, "%S+");
			local volume = args[2]
			net.Start(NetworkStreamNameResume)
			net.WriteString("resume")
			net.Broadcast()
		end
		if string.starts(string.lower(strText), "!music_pause") then
			local args = string.split(strText, "%S+")
			local volume = args[2]
			net.Start(NetworkStreamNamePause)
			net.WriteString("pause")
			net.Broadcast()
		end
		if string.starts(string.lower(strText), "!music_stop") then
			local args = string.split(strText, "%S+");
			local volume = args[2]
			net.Start(NetworkStreamNameStop)
			net.WriteString("stop")
			net.Broadcast()
		end
		return true
	end
	hook.Add("PlayerSay", "TestHook", process) 
end


My current issue is i cant think of any way to see when the song is over, nor can i think of a way to check if its over or not without a while loop, any suggestions would be* greatly* appreciated

Bump

What is so bad about a loop? Other than that you could use a proper timer, that is.

The goal isnt to repeat the same song, as for a timer, i would use that if i had any idea how to tell how long the song is

Oh, my mistake i thought you meant that i should use a timer for seeing if the song was over, that may work for me, thanks for pointing me in the right direction!

Right, i’ve switched to timers but am having some difficulties.

[lua]
AddCSLuaFile()
local receiving_side = CLIENT
local NetworkStreamName = “RadioStreamName”
local playing = false
function string.starts(String,Start)
return string.sub(String,1,string.len(Start))==Start
end

function string.ends(String,End)
return End==’’ or string.sub(String,-string.len(End))==End
end

function broadcast(message)
for count, ply in pairs( player.GetAll()) do
ply:ChatPrint(message)
end
end

function string.split(s, split)
list = {}
index = 1
for value in string.gmatch(s, split) do
list [index] = value
index = index + 1
end
return list
end

function trim(s)
return (s:gsub("^%s*(.-)%s*$", “%1”))
end
if( receiving_side) then
local stop = false
local volume = 100
net.Receive(NetworkStreamName, function (len)
local command = net.ReadString()
local args = string.split(command, “%S+”)
local volume = 50
local stop = false
local resume = false
local pause = false
local play = true
if string.starts(command, “setvolume”) then
volume = args[1]
MsgAll("Volume command recived
")
end
if string.starts(command, “pause”) then
pause = true
MsgAll("Pause command recived
")
end
if string.starts(command, “resume”) then
MsgAll("Resume command recived
")
resume = true
end
if string.starts(command, “play”) then
local URL = args[2]
sound.PlayURL(URL, “play”, function (channel)
print("Playing " … URL … “!”)
playing = true
timer.Create( “UniqueName”, 1, 0, function()
print(“Tick”)
channel:SetVolume(volume)
print("Set volume to " … volume)
if stop then
print("Stopping channel!
")
channel:Stop()
play = false
end
if pause then
print("Pausing channel!
")
channel:Pause()
end
if resume then
print("Resuming channel!
")
channel:Play()
end
if not channel:IsValid() then
print("Soung over!
")
broadcast(“Song over!”)
playing = false
end
end )
timer.Start(“UniqueName”)
end)
end
end)
else
util.AddNetworkString(NetworkStreamName)
function process(player, strText, bTeamOnly, bPlayerIsDead)
if string.starts(string.lower(strText), “!say”) then
local args = string.split(strText, “%S+”)
local message = “”;
for i=2,#args do
message = message … args* … " "
end
broadcast(trim(message))
return false
end
if string.starts(string.lower(strText), “!music_play”) then
local args = string.split(strText, “%S+”);
if(#args == 2) then
local stream = args[2]
net.Start(NetworkStreamName)
net.WriteString("play " … args[2])
net.Broadcast()
end
end
if string.starts(string.lower(strText), “!music_volume”) then
local args = string.split(strText, “%S+”);
if(#args == 2) then
local volume = args[2]
net.Start(NetworkStreamName)
net.WriteString("setvolume " … args[2])
net.Broadcast()
end
end
if string.starts(string.lower(strText), “!music_resume”) then
local args = string.split(strText, “%S+”);
net.Start(NetworkStreamName)
net.WriteString("resume " … args[2])
net.Broadcast()
end
if string.starts(string.lower(strText), “!music_pause”) then
net.Start(NetworkStreamName)
net.WriteString("pause ")
net.Broadcast()
end
return true
end
hook.Add(“PlayerSay”, “TestHook”, process)
end
[/lua]

Basically, the client revives the pause command the volume command etc, however it doesnt act on them, for example, i can do !music_play <some url> and it does play a song.
!music volume 0 results in the client printing “Setting volume to 50” so it would seem it isnt seeing the variables being changed or something, any ideas?

The whole of the setting volume function was nested inside the “play” function which in turn would never get run since setting the volume would call a different part of the script, The volume however should have been applied when the next song was played.

While I was doing quick tests pausing and resuming didn’t appear to be working as intended. (stream was returning as non existant when resuming which it shouldn’t)

To access the channel outside of the play function ( and thus allow setting volumes on it without restarting it ) You need to localise the channel, for example at the start of the client section localise a variable “chan” to nil, and within the play function set “chan” to the channel, this will allow you to access the channel from any part of the script thus allowing you to instantly set the volume when the “volume” is sent down but simply calling chan:SetVolume().

On a side note noticed you are using MsgAll() clientside which has no real effect, since it only act different to Msg() when run on the server

Since you are trying to learn hopefully that explained it to help you give it a shot, http://pastebin.com/aZNy7iTK is the pastebin with the quick changes I made to it ( far from complete or tidy ) , annotated where I have made changes.

Not included in above but is everyone meant to be hearing it at the same volume and such? If not I would suggest replacing net.Broadcast() with net.Send() so only the client makes changes / starts playing can hear or adjust their settings

The objective is for everyone to hear the same volume, yes , thank you SO much for fixing this for me, i tried assigning channels like you did a while back but i suppose code was also broken back then and that’s why it didnt work. but it works like a charm now!