Page 1 of 1

[Solved] Microphone won't start on Android

Posted: Sat Jan 25, 2020 4:23 pm
by qwdqwqwffqw
Hello. I've been recently testing out new 11.3 features and having problem with using recording device on an android phone.

(Attachment below)

It's just a simple code that records and plays sound data, and this works just fine on desktop(windows). However on Android, it gets recording device normally yet recordingDevice:start() won't start.

On Windows, "Success!" , "recording : true" are printed, and rate goes up. Recorded sound is successfully played.
On Android, num goes up(which means mouse input and other things are working fine) , but device won't start recording.

* I'm using LOVE-for-Android app, and I made it sure to remove previous version, and installed 11.3 version with apk file on love2d.org front page, instead of one on Playstore as instructed. I also tried with a file on bitbuckets (https://bitbucket.org/rude/love/downloads/). I'm not sure they are different apks, but both of them didn't work anyway.

* I gave the permission to use the mircrophone, by two methods.
1) After installing love-for android, manually giving permission of microphone and storage for LOVE, on Setting - App info - Permission menu.
2) Adding "t.audio.mic = true" in conf.lua, which led app to ask permission with message box when app was ran.
Both did basically same, and neither worked out.

* I've also tried different values for parameters, but it always failed on android.

Am I missing something different on Android environment? ( I'm a layman and ignorant of elementary knowledges.)
Or maybe should I try making apk file with .love, instead of putting main.lua in sdcard/lovegame dir?

Thanks!

Re: Microphone won't start on Android

Posted: Tue Jan 28, 2020 12:24 pm
by AuahDark
You have to try all possible combinations that works. This is the code exactly I used for testing while writing mic support for Android.

Code: Select all

local love = require("love")
local recDev = nil
local isRecording = -1
local soundDataTable = {}
local soundDataLen = 0
local audioSource = nil
local devicesString
local recordingFreq, recordingChan, recordingBitDepth

-- Possible combination testing
local sampleFmts = {48000, 44100, 32000, 22050, 16000, 8000}
local chanStereo = {2, 1}
local bitDepths = {16, 8}

function love.load()
	local devices = love.audio.getRecordingDevices()
	assert(#devices > 0, "no recording devices found")

	recDev = devices[1]

	local devStr = {}
	for i, v in ipairs(devices) do
		devStr[#devStr + 1] = string.format("%d. %s", i, v:getName())
	end
	devicesString = table.concat(devStr, "\n")
end

function love.update(dt)
	if isRecording > 0 then
		isRecording = isRecording - dt
		local data = recDev:getData()
		if data then
			soundDataLen = soundDataLen + data:getSampleCount()
			soundDataTable[#soundDataTable + 1] = data
		end

		if isRecording <= 0 then
			-- Stop recording
			isRecording = -math.huge
			recDev:stop()

			-- assemble soundData
			local soundData = love.sound.newSoundData(soundDataLen, recordingFreq, recordingBitDepth, recordingChan)
			local soundDataIdx = 0
			for _, v in ipairs(soundDataTable) do
				for i = 0, v:getSampleCount() - 1 do
					for j = 1, recordingChan do
						soundData:setSample(soundDataIdx, j, v:getSample(i, j))
					end
					soundDataIdx = soundDataIdx + 1
				end
				v:release()
			end

			audioSource = love.audio.newSource(soundData)
		end
	end
end

function love.mousereleased()
	if isRecording == -1 then
		-- start recording
		local success = false
		-- Test all possible combination
		for _, sampleFmt in ipairs(sampleFmts) do
			for _, bitDepth in ipairs(bitDepths) do
				for _, stereo in ipairs(chanStereo) do
					success = recDev:start(16384, sampleFmt, bitDepth, stereo)

					if success then
						recordingFreq = sampleFmt
						recordingBitDepth = bitDepth
						recordingChan = stereo
						isRecording = 5
						print("Recording", sampleFmt, bitDepth, stereo)
						return
					end

					print("Record parameter failed", sampleFmt, bitDepth, stereo)
				end
			end
		end

		assert(success, "cannot start capture")
	elseif isRecording == -math.huge and audioSource then
		if audioSource:isPlaying() then
			audioSource:pause()
		else
			audioSource:play()
		end
	end
end

function love.keyreleased(k)
	if k == "escape" then
		love.event.quit()
	end
end

function love.draw()
	if isRecording == -1 then
		love.graphics.print("Recording ready", 2, 2)
	elseif isRecording == -math.huge then
		love.graphics.print("Replay "..audioSource:tell(), 2, 2)
	else
		love.graphics.print("Recording at "..recordingFreq..", "..recordingBitDepth..", "..recordingChan..": "..isRecording, 2, 2)
	end

	love.graphics.print(devicesString, 2, 16)
end
In my phone (Mi A1, Android 9) it shows "Recording at 48000, 16, 2". I also noticed in your code that your buffer is too high. In my code above, I used 16384 as buffer size which is good enough to be able to record with such parameters. If I set the buffer size to 100000 as per your code, I can't record with 48000Hz but I can record in 32000Hz, possibly due to memory limitations.

Re: Microphone won't start on Android

Posted: Tue Jan 28, 2020 3:23 pm
by qwdqwqwffqw
Your test code worked perfectly. While other sample rates didn't work at all, both 48000Hz and 22050Hz worked fine regardless of bit depth and channels(on Android 7.0) among suggested combinations.
So, like you said, it seems that setting buffer value too high was the problem.

Thanks for your kind reply!!

Re: Microphone won't start on Android

Posted: Fri May 13, 2022 12:48 am
by n0bleman
AuahDark wrote: Tue Jan 28, 2020 12:24 pm You have to try all possible combinations that works. This is the code exactly I used for testing while writing mic support for Android.

Code: Select all

local love = require("love")
local recDev = nil
local isRecording = -1
local soundDataTable = {}
local soundDataLen = 0
local audioSource = nil
local devicesString
local recordingFreq, recordingChan, recordingBitDepth

-- Possible combination testing
local sampleFmts = {48000, 44100, 32000, 22050, 16000, 8000}
local chanStereo = {2, 1}
local bitDepths = {16, 8}

function love.load()
	local devices = love.audio.getRecordingDevices()
	assert(#devices > 0, "no recording devices found")

	recDev = devices[1]

	local devStr = {}
	for i, v in ipairs(devices) do
		devStr[#devStr + 1] = string.format("%d. %s", i, v:getName())
	end
	devicesString = table.concat(devStr, "\n")
end

function love.update(dt)
	if isRecording > 0 then
		isRecording = isRecording - dt
		local data = recDev:getData()
		if data then
			soundDataLen = soundDataLen + data:getSampleCount()
			soundDataTable[#soundDataTable + 1] = data
		end

		if isRecording <= 0 then
			-- Stop recording
			isRecording = -math.huge
			recDev:stop()

			-- assemble soundData
			local soundData = love.sound.newSoundData(soundDataLen, recordingFreq, recordingBitDepth, recordingChan)
			local soundDataIdx = 0
			for _, v in ipairs(soundDataTable) do
				for i = 0, v:getSampleCount() - 1 do
					for j = 1, recordingChan do
						soundData:setSample(soundDataIdx, j, v:getSample(i, j))
					end
					soundDataIdx = soundDataIdx + 1
				end
				v:release()
			end

			audioSource = love.audio.newSource(soundData)
		end
	end
end

function love.mousereleased()
	if isRecording == -1 then
		-- start recording
		local success = false
		-- Test all possible combination
		for _, sampleFmt in ipairs(sampleFmts) do
			for _, bitDepth in ipairs(bitDepths) do
				for _, stereo in ipairs(chanStereo) do
					success = recDev:start(16384, sampleFmt, bitDepth, stereo)

					if success then
						recordingFreq = sampleFmt
						recordingBitDepth = bitDepth
						recordingChan = stereo
						isRecording = 5
						print("Recording", sampleFmt, bitDepth, stereo)
						return
					end

					print("Record parameter failed", sampleFmt, bitDepth, stereo)
				end
			end
		end

		assert(success, "cannot start capture")
	elseif isRecording == -math.huge and audioSource then
		if audioSource:isPlaying() then
			audioSource:pause()
		else
			audioSource:play()
		end
	end
end

function love.keyreleased(k)
	if k == "escape" then
		love.event.quit()
	end
end

function love.draw()
	if isRecording == -1 then
		love.graphics.print("Recording ready", 2, 2)
	elseif isRecording == -math.huge then
		love.graphics.print("Replay "..audioSource:tell(), 2, 2)
	else
		love.graphics.print("Recording at "..recordingFreq..", "..recordingBitDepth..", "..recordingChan..": "..isRecording, 2, 2)
	end

	love.graphics.print(devicesString, 2, 16)
end
In my phone (Mi A1, Android 9) it shows "Recording at 48000, 16, 2". I also noticed in your code that your buffer is too high. In my code above, I used 16384 as buffer size which is good enough to be able to record with such parameters. If I set the buffer size to 100000 as per your code, I can't record with 48000Hz but I can record in 32000Hz, possibly due to memory limitations.
How I can play recorded file in realtime ??? And dont stop recording! I want to make multiplayer voice chat ? where data to send ? and