Over-disposing of the same audio data

Hello!
I have a scene that plays a number of sounds. This scene has a button that goes to another scene:

local composer = require( "composer" )

local scene = composer.newScene()

local widget = require( "widget" )


-- -----------------------------------------------------------------------------------
-- Code outside of the scene event functions below will only be executed ONCE unless
-- the scene is removed entirely (not recycled) via "composer.removeScene()"
-- -----------------------------------------------------------------------------------





voiceAlef=audio.loadSound("audio/alefba/letters/1.mp3",{channel=1})
index=1


local function playAlef()
	audio.play(voiceAlef)

end

--------------------------------------
local function gotoAlefPorsesh1( event )
	  local options={
        effect="fade",
        time=0,
        
    }
    composer.gotoScene("parts.alefba.alefporsesh1",options)
    return true
end
---------------------------------------
local function nextLetter()
		index=index+1
		print("index:" .. index)
		if index>32 then
		 	index=1
		 	--gotoAlefPorsesh1()
		 end

		ball:setFrame( index )
		example:setFrame(index)


		ball.width=100
		ball.height=100

		ball.x = display.contentCenterX
		ball.y = display.contentCenterY +20

		--sceneGroup:insert(ball)

		example.width=100
		example.height=100

		example.x=438
		example.y=260

		--sceneGroup:insert(example)
		

		voice=audio.loadSound("audio/alefba/letters/" .. index .. ".mp3",{channel=2})
		audio.play(voice)
		
end





-- -----------------------------------------------------------------------------------
-- Scene event functions
-- -----------------------------------------------------------------------------------

-- create()
function scene:create( event )

	local sceneGroup = self.view
	-- Code here runs when the scene is first created but has not yet appeared on screen
	background=display.newImageRect("images/alefba/background.jpg",570,360)
	sceneGroup:insert(background)
	background.x=display.contentWidth/2
	background.y=display.contentHeight/2

	local arrow=display.newImageRect("images/game.png",60,60)
	sceneGroup:insert( arrow )
	arrow.x=display.screenOriginX+530
	arrow.y=display.safeScreenOriginY+30

	arrow:addEventListener( "tap", gotoAlefPorsesh1 )

		index=1

		display.setDefault( "background",0.26,0.77,0.84)

	local sheetOptions = {
	    width = 150,
	    height = 150,
	    numFrames = 32,
	    sheetContentWidth = 600,
	    sheetContentHeight = 1200}

	ballSheet = graphics.newImageSheet( "images/alefba/sheet22.png", sheetOptions )
	ball = display.newSprite( ballSheet, { name="balls", start=1, count=sheetOptions.numFrames } )
	sceneGroup:insert(ball)

	ball.x = display.contentCenterX
	ball.y = display.contentCenterY+20

	ball.width=100
	ball.height=100


	sheetOptions2={
		width = 150,
	    height = 150,
	    numFrames = 32,
	    sheetContentWidth = 600,
	    sheetContentHeight = 1200}


	exampleSheet=graphics.newImageSheet("images/alefba/sheet33.png",sheetOptions2)
	example=display.newSprite(exampleSheet,{name="examples", start=1, count=sheetOptions2.numFrames})
	sceneGroup:insert(example)

	example.x=430
	example.y=260
	example.width=100
	example.height=100





	ball:addEventListener( "tap", nextLetter )
	--example:addEventListener( "tap", playSound )


	



end


-- show()
function scene:show( event )

	local sceneGroup = self.view
	local phase = event.phase

	if ( phase == "will" ) then
		-- Code here runs when the scene is still off screen (but is about to come on screen)
	



	elseif ( phase == "did" ) then
		-- Code here runs when the scene is entirely on screen
		--playAlef()

	end

	
end


-- hide()
function scene:hide( event )

	local sceneGroup = self.view
	local phase = event.phase

	if ( phase == "will" ) then
		-- Code here runs when the scene is on screen (but is about to go off screen)


	elseif ( phase == "did" ) then
		-- Code here runs immediately after the scene goes entirely off screen
		audio.stop(1)
		audio.stop(2)
		audio.dispose( voiceAlef )
		audio.dispose(voice)
		index=0

		composer.removeScene("parts.alefba.alef")


	end
end


-- destroy()
function scene:destroy( event )

	local sceneGroup = self.view
	-- Code here runs prior to the removal of scene's view

			

end


-- -----------------------------------------------------------------------------------
-- Scene event function listeners
-- -----------------------------------------------------------------------------------
scene:addEventListener( "create", scene )
scene:addEventListener( "show", scene )
scene:addEventListener( "hide", scene )
scene:addEventListener( "destroy", scene )
-- -----------------------------------------------------------------------------------

return scene

The problem is that when I enter another scene and try to return to the previous scene via the physical back button, I get “Over-disposing of the same audio data” error.

However, if I return to the previous scene with an icon that I put on the screen (non physical), there is no problem.

This is the code I wrote in the second scene for the physical back button ( outside of the scene event):

local function onKeyEvent( event )

	-- Output which key was pressed down/up to the console
	print( '"' .. event.keyName .. '" : ' .. event.phase )

	-- Display the key event information on screen
	

	-- If the Android "back" key was pressed, prevent it from backing out of the app
	-- This is done by returning true, telling the operating system to override the key
	if ( event.keyName == "back" ) then
		-- gotoHome()
		return true
	end

	-- Return false to indicate that this app is NOT overriding the received key
	-- This lets the operating system execute its default handling of the key
	return false
end

And this is the listener that i put in create() of second scene.

Runtime:addEventListener( "key", onKeyEvent )

Does anyone know where the problem comes from?

I’m not sure about this, but I guess the return button is being called twice, so you are also disposing the audio handlers twice which causes the issue.

Try this:

local function onKeyEvent( event )

	-- Output which key was pressed down/up to the console
	print( '"' .. event.keyName .. '" : ' .. event.phase )

	-- Display the key event information on screen
	

	-- If the Android "back" key was pressed, prevent it from backing out of the app
	-- This is done by returning true, telling the operating system to override the key
    if  event.keyName == "back" and event.phase == "down" then
		-- gotoHome()
		return true
	end

	-- Return false to indicate that this app is NOT overriding the received key
	-- This lets the operating system execute its default handling of the key
	return false
end

The only difference is this line if event.keyName == "back" and event.phase == "down" then

You should also verify if the handlers are not nil when you are trying to dispose them and nil them after you do.

1 Like

thanks for your help. But this code causes the application to close completely after hitting the physical back button.

Could you try it again? I noticed that I added the new line but forgot to delete the old one. Now I fixed it.

Unfortunately, it still comes out of the application completely.

Sorry if this is not helpful to your problem or in the context of your app but for many years now we just load all audio at the beginning and dont dispose between scenes. If we need to stop an audio stream, we will usually just call stop on that particular channel but we completely did away with disposal between scenes.

It’s less of a mess because AL libraries are not particularly optimum on some systems and besides, we’ve never faced memory issues by preloading all sound clips— even with games that have a lot of audio, we faced no issues on low end hardware so it seems quite safe to do

Do you mean that audio.dispose( ) is unnecessary? And audio.stop() is enough?

What i like to do is keep a separate script where i load all the sounds and have functions in that script for playing whichever sound i need. Then I never dispose anything— i just call thr play function for the sound i need. It may increase your initial loading time by 1-2s, but it’s really much cleaner unless you have a massive library of audio for your app.

We never call dispose at all

1 Like

Thanks a lot. I have to read about scripts.