Foreign code not working

Hi, I am trying to write a foreign code to allow audio recording. But i am facing a problem.
Hee is the code:
using Uno;
using Uno.UX;
using Uno.Collections;
using Fuse;
using Uno.Threading;
using Fuse.Scripting;
using Uno.Compiler.ExportTargetInterop;
using Uno.Permissions;

[UXGlobalModule]
[ForeignInclude(Language.Java,
“android.media.MediaPlayer”,
“android.media.MediaRecorder”,
“android.os.Bundle”,
“android.widget.Toast”,
“android.os.Environment”,
“java.io.IOException”)]
public class Audio: NativeModule{

public Audio(){
	AddMember( new NativeFunction("RecordAudio", (NativeCallback)RecordAudio) );
	AddMember( new NativeFunction("StopAudio", (NativeCallback)StopAudio) );
	/*AddMember( new NativeFunction("playAudio", (NativeCallback)PlayAudio) );*/
}

object RecordAudio(Context c, object[] args){
	string nomFichier="recordTest";
	string outputFile = AudioRecordImplement.Record(nomFichier);
	return outputFile;
}

object StopAudio(Context c, object[] args){
	AudioRecordImplement.Stop();
}

/*object PlayAudio(string nomFichier){

}*/


public extern(Android) class AudioRecordImplement{
	
	
	[Foreign(Language.Java)]
	private MediaRecorder myAudioRecorder;
	static extern(Android) string Record(string nomFichier)
	@{
		private String outputFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pyeple/Pyeple Audio/".nomFichier.".opus";
		Activity a = com.fuse.Activity.getRootActivity();

		try {
			myAudioRecorder = new MediaRecorder();
			myAudioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
			myAudioRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
			myAudioRecorder.setAudioEncoder(MediaRecorder.OutputFormat.DEFAULT);
			myAudioRecorder.setOutputFile(outputFile);
			myAudioRecorder.prepare();
			myAudioRecorder.start();
			} catch (IllegalStateException ise) {
				// make something ...
			} catch (IOException ioe) {
				// make something
			}
		Toast.makeText(a, "Recording started", Toast.LENGTH_LONG).show();
		return outputFile;
	@}

	[Foreign(Language.Java)]
	static extern(Android) string Stop()
	@{
		myAudioRecorder.stop();
		myAudioRecorder.release();
		myAudioRecorder = null;
		Toast.makeText(getApplicationContext(), "Audio Recorder successfully", Toast.LENGTH_LONG).show();
	@}

	[Foreign(Language.Java)]
	static extern(Android) string play()
	@{
		MediaPlayer mediaPlayer = new MediaPlayer();
		try {
			mediaPlayer.setDataSource(outputFile);
			mediaPlayer.prepare();
			mediaPlayer.start();
			Toast.makeText(getApplicationContext(), "Playing Audio", Toast.LENGTH_LONG).show();
		} catch (Exception e) {
				// make something
		}
	@}
}

}

here the error:
C:\Users\User\Documents\Fuse\Pyeple\Audio.uno(29.23): E3102: There is nothing named ‘AudioRecordImplement’ accessible in this scope. Are you missing a package reference?
C:\Users\User\Documents\Fuse\Pyeple\Audio.uno(29,24): Error E3102: There is nothing named ‘AudioRecordImplement’ accessible in this scope. Are you missing a package reference?C:\Users\User\Documents\Fuse\Pyeple\Audio.uno(34.3): E3102: There is nothing named ‘AudioRecordImplement’ accessible in this scope. Are you missing a package reference?
C:\Users\User\Documents\Fuse\Pyeple\Audio.uno(34,4): Error E3102: There is nothing named ‘AudioRecordImplement’ accessible in this scope. Are you missing a package reference?1,54 s

Are you running this code from Fuse Studio or command line (uno build -t=android)? I used got similar errors until I realized I had to build and run native code from the command line. Don’t know if this applies to you?

I think because class AudioRecordImplement is only specified for android only, but not for desktop or iOS platform with the inclusion of extern(Android) in the class definition.

You have either to make all definitions and implementations of your classes in the other platform ( desktop / dotnet and iOS ) or make a conditional macro (if defined(Android)) when you call/instantiate your class just for the specific platform.

as example like this :

object RecordAudio(Context c, object[] args)
{
	string nomFichier="recordTest";
	string outputFile = "";
	if defined(Android)
		outputFile = AudioRecordImplement.Record(nomFichier);
	return outputFile;
}

object StopAudio(Context c, object[] args)
{
	if defined(Android)
		AudioRecordImplement.Stop();
	return null;
}

I tried it but it return th same errors.

Sorry, it worked. It seems to be fuse studio bugging. I restart my computer and it worked. But now i have a new problem: when i try to use it with "var Audio

I have slightly modified your code. I think it will works even though it still rough

File AudioModule.uno

using Uno;
using Uno.UX;
using Uno.Collections;
using Fuse;
using Uno.Threading;
using Fuse.Scripting;
using Uno.Compiler.ExportTargetInterop;
using Uno.Permissions;

namespace Test.Audio
{
	[UXGlobalModule]
	public class Audio: NativeModule
	{
		static readonly Audio _instance;
		public Audio(){
			if (_instance != null) return;
			_instance = this;
			Resource.SetGlobalKey(_instance, "AudioRecorder");
			AddMember( new NativeFunction("recordAudio", (NativeCallback)RecordAudio) );
			AddMember( new NativeFunction("isRecording", (NativeCallback)IsRecording) );
			AddMember( new NativeFunction("stopAudio", (NativeCallback)StopAudio) );
			AddMember( new NativeFunction("playAudio", (NativeCallback)PlayAudio) );
		}

		object RecordAudio(Context c, object[] args)
		{
			if defined(Android)
			{
				AudioRecordImplement.getInstance().Record();
			}
			return null;
		}

		object IsRecording(Context c, object[] args)
		{
			if defined(Android)
				return AudioRecordImplement.getInstance().IsRecording();
			return false;
		}

		object StopAudio(Context c, object[] args)
		{
			if defined(Android)
				return AudioRecordImplement.getInstance().Stop();
			return null;
		}

		object PlayAudio(Context c, object[] args)
		{
			if defined(Android)
				return AudioRecordImplement.getInstance().Play();
			return null;
		}
	}

	[ForeignInclude(Language.Java,"android.media.MediaPlayer","android.media.MediaRecorder","android.os.Bundle","android.widget.Toast","android.os.Environment","java.io.IOException")]
	extern(Android) class AudioRecordImplement
	{

		Java.Object _handle;
		string _outputFile;
		bool _started;
		static AudioRecordImplement _instance;

		private AudioRecordImplement()
		{
			_handle = InitMediaRecorder();
		}

		public static AudioRecordImplement getInstance() {
			if (_instance == null)
				_instance = new AudioRecordImplement();
			return _instance;
		}

		[Foreign(Language.Java)]
		public Java.Object InitMediaRecorder()
		@{
			MediaRecorder myAudioRecorder = new MediaRecorder();
			return myAudioRecorder;
		@}

		public void Record()
		{
			var permissions = new PlatformPermission[]
			{
				Permissions.Android.RECORD_AUDIO,
				Permissions.Android.WRITE_EXTERNAL_STORAGE,
				Permissions.Android.READ_EXTERNAL_STORAGE
			};

			Permissions.Request(permissions).Then(OnPermitted, OnRejected);
		}

		public bool IsRecording() {
			return _started;
		}

		void OnPermitted(PlatformPermission[] permissions)
	    {
	    	if (permissions.Length == 3)
	        	_outputFile = Record(_handle);
	    }

	    void OnRejected(Exception e)
	    {
	        debug_log "Error: " + e.Message;
	    }

		[Foreign(Language.Java)]
		extern(Android) string Record(Java.Object handle)
		@{
			String outputFile = com.fuse.Activity.getRootActivity().getExternalCacheDir().getAbsolutePath();
			outputFile += "/testAudio.3gp";
			try {
				MediaRecorder myAudioRecorder = (MediaRecorder)handle;
				myAudioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
				myAudioRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
				myAudioRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
				myAudioRecorder.setOutputFile(outputFile);
				myAudioRecorder.prepare();
				myAudioRecorder.start();
				@{AudioRecordImplement:Of(_this)._started:Set(true)};
				com.fuse.Activity.getRootActivity().runOnUiThread(new Runnable() {
					@Override
			        public void run() {
			            Toast.makeText(com.fuse.Activity.getRootActivity(), "Audio Recorder start", Toast.LENGTH_LONG).show();
			        }
				});
			} catch (IllegalStateException ise) {
				outputFile = null;
				android.util.Log.d("FuseTest", ise.getMessage());
			} catch (IOException ioe) {
				outputFile = null;
				android.util.Log.d("FuseTest", ioe.getMessage());
			} catch (Exception e) {
				outputFile = null;
				android.util.Log.d("FuseTest", e.getMessage());
			}
			return outputFile;
		@}

		public bool Stop()
		{
			if (_started)
				return Stop(_handle);
			return false;
		}

		[Foreign(Language.Java)]
		extern(Android) bool Stop(Java.Object handle)
		@{
			MediaRecorder myAudioRecorder = (MediaRecorder)handle;
			myAudioRecorder.stop();
			myAudioRecorder.release();
			myAudioRecorder = null;
			@{AudioRecordImplement:Of(_this)._started:Set(false)};
			com.fuse.Activity.getRootActivity().runOnUiThread(new Runnable() {
				@Override
		        public void run() {
		            Toast.makeText(com.fuse.Activity.getRootActivity(), "Audio Recorder stop", Toast.LENGTH_LONG).show();
		        }
			});
			return true;
		@}

		public bool Play()
		{
			if (_outputFile != null)
				return Play(_outputFile);
			return false;
		}

		[Foreign(Language.Java)]
		static extern(Android) bool Play(string outputFile)
		@{
			MediaPlayer mediaPlayer = new MediaPlayer();
			try {
				mediaPlayer.setDataSource(outputFile);
				mediaPlayer.prepare();
				mediaPlayer.start();
				com.fuse.Activity.getRootActivity().runOnUiThread(new Runnable() {
					@Override
			        public void run() {
			            Toast.makeText(com.fuse.Activity.getRootActivity(), "Playing Audio", Toast.LENGTH_LONG).show();
			        }
				});
			} catch (Exception e) {
					// make something
				return false;
			}
			return true;
		@}
	}
}

File Project.unoproj

{
  "RootNamespace":"",
  "Packages": [
    "Fuse",
    "FuseJS",
    "Uno.Permissions"
  ],
  "Includes": [
    "*",
    "**.js:FuseJS"
  ]
}

and in MainView.ux

<App>
	<JavaScript>
		var AudioRecorder = require("AudioRecorder");

		module.exports = {
			recordAudio: function () {
				AudioRecorder.recordAudio();
			},
			stopRecording: function() {
				AudioRecorder.stopAudio();
			},
			startPlayback: function() {
				AudioRecorder.playAudio();
			}
		};
	</JavaScript>
	<ClientPanel>
		<Panel Height="60" Alignment="Top">
			<Grid ColumnCount="3" RowCount="1" Alignment="HorizontalCenter" CellSpacing="5">
				<Button Text="Record Audio" Clicked="{recordAudio}" />
				<Button Text="Stop Recording" Clicked="{stopRecording}" />
				<Button Text="Playback Record" Clicked="{startPlayback}" />
			</Grid>
		</Panel>
	</ClientPanel>
</App>

Hope it helps…

1 Like

Thanks a lot. It work.