flipper-zero-tutorials/js/flipboard/modules/js_speaker.c
2024-04-19 18:00:58 -05:00

210 lines
6.4 KiB
C

#include "../js_modules.h"
#include <furi_hal.h>
typedef struct {
bool acquired;
} JsSpeakerInst;
static void js_speaker_acquire(struct mjs* mjs) {
mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0);
JsSpeakerInst* speaker = mjs_get_ptr(mjs, obj_inst);
furi_assert(speaker);
if(mjs_nargs(mjs) != 1) {
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Invalid args (timeoutMs)");
mjs_return(mjs, MJS_UNDEFINED);
return;
}
if(!mjs_is_number(mjs_arg(mjs, 0))) {
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Invalid numeric arg (timeoutMs)");
mjs_return(mjs, MJS_UNDEFINED);
return;
}
uint32_t timeout = mjs_get_int(mjs, mjs_arg(mjs, 0));
if(!speaker->acquired) {
speaker->acquired = furi_hal_speaker_acquire(timeout);
}
mjs_return(mjs, mjs_mk_boolean(mjs, speaker->acquired));
}
static void js_speaker_release(struct mjs* mjs) {
mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0);
JsSpeakerInst* speaker = mjs_get_ptr(mjs, obj_inst);
furi_assert(speaker);
if(mjs_nargs(mjs) != 0) {
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "No arguments expected");
mjs_return(mjs, MJS_UNDEFINED);
return;
}
if(speaker->acquired) {
furi_hal_speaker_stop();
furi_hal_speaker_release();
speaker->acquired = false;
}
mjs_return(mjs, mjs_mk_boolean(mjs, true));
}
static void js_speaker_start(struct mjs* mjs) {
mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0);
JsSpeakerInst* speaker = mjs_get_ptr(mjs, obj_inst);
furi_assert(speaker);
size_t num_args = mjs_nargs(mjs);
float frequency;
float volume;
if(num_args == 1) {
if(!mjs_is_number(mjs_arg(mjs, 0))) {
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Invalid numeric arg (freq [, volume])");
mjs_return(mjs, MJS_UNDEFINED);
return;
}
volume = 1.0;
} else if(num_args == 2) {
if(!mjs_is_number(mjs_arg(mjs, 0)) || !mjs_is_number(mjs_arg(mjs, 1))) {
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Invalid numeric arg (freq [, volume])");
mjs_return(mjs, MJS_UNDEFINED);
return;
}
volume = mjs_get_double(mjs, mjs_arg(mjs, 1));
if(volume < 0 || volume > 1) {
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Invalid volume (0 <= volume <= 1)");
mjs_return(mjs, MJS_UNDEFINED);
return;
}
} else {
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Invalid args (freq [, volume])");
mjs_return(mjs, MJS_UNDEFINED);
return;
}
if(!speaker->acquired) {
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Speaker must be acquired first");
mjs_return(mjs, MJS_UNDEFINED);
return;
}
frequency = mjs_get_double(mjs, mjs_arg(mjs, 0));
furi_hal_speaker_start(frequency, volume);
mjs_return(mjs, mjs_mk_boolean(mjs, true));
}
static void js_speaker_stop(struct mjs* mjs) {
mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0);
JsSpeakerInst* speaker = mjs_get_ptr(mjs, obj_inst);
furi_assert(speaker);
if(mjs_nargs(mjs) != 0) {
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "No arguments expected");
mjs_return(mjs, MJS_UNDEFINED);
return;
}
if(!speaker->acquired) {
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Speaker must be acquired first");
mjs_return(mjs, MJS_UNDEFINED);
return;
}
furi_hal_speaker_stop();
mjs_return(mjs, mjs_mk_boolean(mjs, true));
}
static void js_speaker_play(struct mjs* mjs) {
mjs_val_t obj_inst = mjs_get(mjs, mjs_get_this(mjs), INST_PROP_NAME, ~0);
JsSpeakerInst* speaker = mjs_get_ptr(mjs, obj_inst);
furi_assert(speaker);
size_t num_args = mjs_nargs(mjs);
float frequency;
float volume;
uint32_t duration;
uint32_t timeout = 1000;
bool acquired_in_play = false;
if(num_args != 3) {
mjs_prepend_errorf(mjs, MJS_BAD_ARGS_ERROR, "Invalid args (freq, volume, duration)");
mjs_return(mjs, MJS_UNDEFINED);
return;
}
if(!mjs_is_number(mjs_arg(mjs, 0)) || !mjs_is_number(mjs_arg(mjs, 1)) ||
!mjs_is_number(mjs_arg(mjs, 2))) {
mjs_prepend_errorf(
mjs, MJS_BAD_ARGS_ERROR, "Invalid numeric arg (freq, volume, duration)");
mjs_return(mjs, MJS_UNDEFINED);
return;
}
frequency = mjs_get_double(mjs, mjs_arg(mjs, 0));
volume = mjs_get_double(mjs, mjs_arg(mjs, 1));
duration = mjs_get_int(mjs, mjs_arg(mjs, 2));
if(!speaker->acquired) {
acquired_in_play = true;
speaker->acquired = furi_hal_speaker_acquire(timeout);
}
if(speaker->acquired) {
furi_hal_speaker_start(frequency, volume);
furi_delay_ms(duration);
furi_hal_speaker_stop();
if(acquired_in_play) {
furi_hal_speaker_release();
speaker->acquired = false;
}
mjs_return(mjs, mjs_mk_boolean(mjs, true));
} else {
mjs_return(mjs, mjs_mk_boolean(mjs, false));
}
}
static void* js_speaker_create(struct mjs* mjs, mjs_val_t* object) {
JsSpeakerInst* speaker = malloc(sizeof(JsSpeakerInst));
speaker->acquired = false;
mjs_val_t speaker_obj = mjs_mk_object(mjs);
mjs_set(mjs, speaker_obj, INST_PROP_NAME, ~0, mjs_mk_foreign(mjs, speaker));
mjs_set(mjs, speaker_obj, "acquire", ~0, MJS_MK_FN(js_speaker_acquire));
mjs_set(mjs, speaker_obj, "release", ~0, MJS_MK_FN(js_speaker_release));
mjs_set(mjs, speaker_obj, "start", ~0, MJS_MK_FN(js_speaker_start));
mjs_set(mjs, speaker_obj, "stop", ~0, MJS_MK_FN(js_speaker_stop));
mjs_set(mjs, speaker_obj, "play", ~0, MJS_MK_FN(js_speaker_play));
*object = speaker_obj;
return speaker;
}
static void js_speaker_destroy(void* inst) {
JsSpeakerInst* speaker = (JsSpeakerInst*)inst;
if(speaker->acquired) {
furi_hal_speaker_stop();
furi_hal_speaker_release();
speaker->acquired = false;
}
free(speaker);
}
static const JsModuleDescriptor js_speaker_desc = {
"speaker",
js_speaker_create,
js_speaker_destroy,
};
static const FlipperAppPluginDescriptor plugin_descriptor = {
.appid = PLUGIN_APP_ID,
.ep_api_version = PLUGIN_API_VERSION,
.entry_point = &js_speaker_desc,
};
const FlipperAppPluginDescriptor* js_speaker_ep(void) {
return &plugin_descriptor;
}