How to seek to a position in a song Discord.js? - ffmpeg

I am facing some difficulty with seeking to a specified timestamp in the current song. I have separate files for all my commands. I want to create a seek.js file which takes input a specified time and then passes it to the play.js file(it plays the current song in the queue) but the problem is I cant seem to find a way to how do this.
This is my play command.
const { Collector } = require("discord.js");
const ytdlDiscord = require("ytdl-core-discord");
//const play = require("../commands/play");
module.exports = {
async play(song, message){
const queue = message.client.queue.get(message.guild.id);
if(!song){
setTimeout(function(){
if(!queue.connection.dispatcher && message.guild.me.voice.channel){
queue.channel.leave();
queue.textChannel.send(`**Cadenza** left successfully`).catch(console.error);
}
else return;
},120000);
message.client.queue.delete(message.guild.id);
return queue.textChannel.send(`**Music Queue Ended**`);
}
let stream = await ytdlDiscord(song.url,{filter: 'audioonly', quality: 'highestaudio', highWaterMark: 1<<25});
let streamType = song.url.includes("youtube.com") ? "opus" : "ogg/opus";
queue.connection.on("disconnect", () => message.client.queue.delete(message.guild.id));
const dispatcher = queue.connection
.play(stream, {type: streamType, highWaterMark: 1})
.on("finish", () => {
if(queue.loop){
let last = queue.songs.shift();
queue.songs.push(last);
module.exports.play(queue.songs[0], message);
}else{
queue.songs.shift();
module.exports.play(queue.songs[0], message);
}
})
.on("error", (err) => {
console.error(err);
queue.songs.shift();
module.exports.play(queue.songs[0], message);
});
dispatcher.setVolumeLogarithmic(queue.volume / 100);
queue.textChannel.send(`Started Playing **${song.title}**`);
}
};
seek command
const { play } = require("../include/play");
function timeConvert(str){
const t = str.split(':');
let s = 0, m = 1;
while(t.length > 0){
s = +m * parseInt(t.pop(),10);
m = m * 60;
}
return s;
}
module.exports = {
name: 'seek',
description: 'Seeks to a certain point in the current track.',
execute(message,args){
const queue = message.client.queue.get(message.guild.id);
if(!queue) return message.channel.send("There is no song playing.").catch(console.error);
queue.playing = true;
let time = timeConvert(args[0]);
if( time > queue.songs[0].duration)
return message.channel.send(`**Input a valid time**`);
else{
let time = timeConvert(args[0]) * 1000;
#main code here
}
}
}
How can I pass the time variable to play() so that the current song seeks to that amount?

Related

Streaming audio from FFMPEG to browser via WebSocket and WebAudioApi

My project has 2 parts:
a web interface that the user accesses
and a standalone app installed on the computer, that acts as a websocket server.
From the web UI, the user has to hear his computer's microphone.
At this moment, I have a working solution that listens to microphone and sends the raw PCM audio chunks back to web-UI which is able to play them. But some serious lag gets added in time, despite it all runs on the same computer, so there's no internet latency/etc. That is why I am testing FFMPEG now.
So, here's the FFMPEG command for streaming microphone data:
ffmpeg.exe -re -f dshow -i audio="Microphone (HD Pro Webcam C920)" -ar 44100 -ac 1 -f f32le pipe:1
Data gets sent successfully via websocket, but playing it using WebAudioApi is not working, i mean i don't hear anything.
Can anyone point me to what am I doing wrong?
Here's the web javascript:
let ipOfAudioServer = 'localhost';
let wsClient = null;
var audioCtx = null;
var subcounter = 0;
var audiobuffer = [];
var source = null;
// must match the values in the audio-server. Thought despite audio-server could send 2channels.. we resume to only one, to save bandwidth
var sampleRate = 44100;
var channels = 1;
var microphone = 'Microphone (HD Pro Webcam C920)';
// this method reads current position from the audiobuffer and plays the audio
// the method will re-call itself, in order to play the next item in queue
this.play = function(soundName) {
var ffs = audiobuffer[subcounter];
if (ffs) {
var frameCount = ffs.byteLength;
console.log(frameCount, audiobuffer.length);
var myAudioBuffer = audioCtx.createBuffer(channels, frameCount, sampleRate);
myAudioBuffer.getChannelData(0).set(ffs)
if (myAudioBuffer != null)
{
subcounter += 1;
source = audioCtx.createBufferSource();
source.buffer = myAudioBuffer;
source.connect(audioCtx.destination);
source.onended = () => { console.log("finished, continuing to seek buffer!"); play(soundName); }
source.start();
}
}
// just in case the counter got to be bigger than the actual amount of items in the list, set it back to last one
if (subcounter > audiobuffer.length)
subcounter = audiobuffer.length;
};
// the method to initialize WS client
this.initWebsocketClient = function ()
{
if (wsClient == null)
{
wsClient = new WebSocket(`ws://${ipOfAudioServer}:23233`, "protocol");
wsClient.binaryType = "arraybuffer";
wsClient.onmessage = function (event)
{
if (typeof event.data === 'object') {
console.log(event.data, event.data.size);
// clear memory in case buffer is already too big
if (subcounter > 50) {
console.log('cleared memory');
audiobuffer = [];
subcounter = 0;
}
audiobuffer.push(event.data);
if (audiobuffer.length == 1) {
play('sinewave');
}
}
else {
if (event.data == 'stopMicrophone=ok') {
wsClient.close();
wsClient = null;
audiobuffer = [];
subcounter = 0;
}
console.log(event.data);
}
}
}
};
// method used in send() which will actually send the message only after connection has been established successfully.
this.waitForConnection = function (callback, interval) {
if (wsClient.readyState === 1) {
callback();
} else {
var that = this;
// optional: implement backoff for interval here
setTimeout(function () {
that.waitForConnection(callback, interval);
}, interval);
}
};
// using this method to send WS messages to the audio-server
this.send = function (message, callback)
{
this.initWebsocketClient();
this.waitForConnection(function () {
wsClient.send(message);
if (typeof callback !== 'undefined') {
callback();
}
}, 1000);
};
// called by clicking the start button
function startCapture() {
if (audioCtx == null)
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
audiobuffer = [];
subcounter = 0;
this.send(`startMicrophone?device=${microphone}`);
}
// called by clicking the stop button
function stopCapture() {
this.send('stopMicrophone');
}

I am trying to use flutter Isolate with database data. But it's throwing an error. I don't know why is it happening?

I'm using the hive database. My code is:
HiveStocktaking? stocktaking =
_database.getStocktakingById(_stocktakingId);
StocktakingStats stocktakingStats =
_database.getStocktakingStats(_stocktakingId, true);
List<HiveStocktakingItem> stocktakingItemShortage = _database
.getStocktakingAllItem(_stocktakingId, 'shortage', '',
getAll: withProducts)
.values
.first;
List<HiveStocktakingItem> stocktakingItemSurplus = _database
.getStocktakingAllItem(_stocktakingId, 'surplus', '',
getAll: withProducts)
.values
.first;
int shortageLength = withProducts ? stocktakingItemShortage.length : 0;
int surplusLength = withProducts ? stocktakingItemSurplus.length : 0;
if (type == 'excel') {
createIsolate(
stocktaking,
stocktakingStats,
stocktakingItemShortage,
stocktakingItemSurplus,
shortageLength,
surplusLength,
);
}
Future createIsolate(
HiveStocktaking? stocktaking,
StocktakingStats stocktakingStats,
List<HiveStocktakingItem> stocktakingItemShortage,
List<HiveStocktakingItem> stocktakingItemSurplus,
int shortageLength,
int surplusLength) async {
ReceivePort receivePort = ReceivePort();
Isolate.spawn(isolateFunction, receivePort.sendPort);
SendPort childSendPort = await receivePort.first;
ReceivePort responsePort = ReceivePort();
childSendPort.send([
stocktaking,
stocktakingStats,
stocktakingItemShortage,
stocktakingItemSurplus,
shortageLength,
surplusLength,
responsePort.sendPort
]);
var sum = await responsePort.first;
print('sum: $sum');
}
void isolateFunction(SendPort mainSendPort) async {
ReceivePort childReceivePort = ReceivePort();
mainSendPort.send(childReceivePort.sendPort);
await for (var message in childReceivePort) {
HiveStocktaking? stocktaking = message[0];
StocktakingStats stocktakingStats = message[1];
List<HiveStocktakingItem> stocktakingItemShortage = message[2];
List<HiveStocktakingItem> stocktakingItemSurplus = message[3];
int shortageLength = message[4];
int surplusLength = message[5];
SendPort replyPort = message[6];
//heavy task
sync.Workbook workbook = sync.Workbook();
var sheet = workbook.worksheets[0];
sheet.getRangeByIndex(1, 1)
..setText('Отчет по инвентаризации')
..columnWidth = 40
..cellStyle.bold = true
..rowHeight = 30
..cellStyle.fontSize = 20;
sheet.getRangeByIndex(2, 1).setText('Магазин: ${stocktaking?.shopName}');
sheet
.getRangeByIndex(3, 1)
.setText('Дата начала: ${stocktaking?.createdAt}');
sheet
.getRangeByIndex(4, 1)
.setText('Дата завершения: ${stocktaking?.finishedAt}');
sheet.getRangeByIndex(2, 3)
..setText(
'Отсканировано товаров: ${BaseFunctions.numberRound(stocktakingStats.totalScannedMeasurementValue)}')
..columnWidth = 30;
sheet.getRangeByIndex(3, 3).setText(
'Недостач: ${BaseFunctions.numberRound(stocktakingStats.totalMeasurementValue)}');
sheet.getRangeByIndex(4, 3).setText(
'Излишков: ${BaseFunctions.numberRound(stocktakingStats.surplus)}');
// etc generating codes
List<int> bytes = workbook.saveAsStream();
workbook.dispose();
var uint8list = Uint8List.fromList(bytes);
if (Platform.isMacOS) {
String fileName = 'stocktaking_report_' +
DateFormat('dd-MM-yyyy_HH-mm-ss').format(DateTime.now()) +
'.pdf';
String? path =
await PathProviderPlatform.instance.getApplicationSupportPath();
final File file =
File(Platform.isWindows ? '$path\\$fileName' : '$path/$fileName');
await file.writeAsBytes(bytes, flush: true);
await Process.run('open', <String>['$path/$fileName'], runInShell: true);
} else {
await FileSaver.instance.saveFile(
'stocktaking_report_' +
DateFormat('dd-MM-yyyy_HH-mm-ss').format(DateTime.now()),
uint8list,
'xlsx',
mimeType: MimeType.MICROSOFTEXCEL,
);
}
replyPort.send(1);
}
}
But it is throwing this error:
[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: Invalid argument(s): Illegal argument in isolate message: (object extends NativeWrapper - Library:'dart:io' Class: _RandomAccessFileOpsImpl#13069316)
if I give the createIsolate fake data it works perfectly.
if (type == 'excel') {
ProjectFiles.createIsolate(
HiveStocktaking(),
StocktakingStats(),
[],
[],
0,
0,
);
}
I found a way to solve this issue. If you want to use the hive database in an isolate function note that you must init your database in the isolate function and close the boxes (which you want to use in the isolate) in the main thread. Register the boxes' adapter in the isolate. After your doing close the boxes which opened in isolate. To initiate the database in isolate, you have to set the database path to Hive.init(path). You can send this path through isolate's port. If you want to use closed boxes in the main thread you have to reopen it. Here some codes for example:
static Future<bool> myFunc() async {
ReceivePort receivePort = ReceivePort();
Isolate.spawn(isolateFunc, receivePort.sendPort);
SendPort childSendPort = await receivePort.first;
await Hive.box<YourBox>('boxName').close();
// database path
Directory appDocumentDir = await getApplicationDocumentsDirectory();
ReceivePort responsePort = ReceivePort();
childSendPort.send([appDocumentDir, responsePort.sendPort]);
var sum = await responsePort.first;
var box = await Hive.openBox<YourBox>('boxName');
HiveDatabase.setInstanceYourBox(box);
return sum == 1;
}
static void isolateDownloadStocktaking(SendPort mainSendPort) async {
ReceivePort childReceivePort = ReceivePort();
mainSendPort.send(childReceivePort.sendPort);
await for (var message in childReceivePort) {
Directory appDocumentDir = message[0];
Hive.init(appDocumentDir.path);
Hive.registerAdapter(YourBoxAdapter());
await HiveDatabase.getInstanceYourBox();
// you can use your box
SendPort replyPort = message[1];
await Hive.box<YourBox>('boxName').close();
replyPort.send(1);
}
}
HiveDatabase class is here:
class HiveDatabase {
static Box<YourBox>? _yourBox;
static HiveDatabase instance = HiveDatabase._();
HiveDatabase._();
static Future<HiveDatabase> getInstanceYourBox() async {
_yourBox ??= await Hive.openBox<YourBox>('boxName');
return instance;
}
static Future<HiveDatabase> setInstanceYourBox(Box<YourBox> box) async {
_yourBox = box;
return instance;
}
List<YourBox> elements() {
return (_yourBox?.values ?? []).toList();
}
Future<void> updateElement(YourBox value) async {
await _yourBox?.put(value.id, value);
}
Future<void> addElement(YourBox value) async {
await _yourBox?.put(value.id, value);
}
Future<void> deleteElement(int index) async {
await _yourBox?.deleteAt(index);
}
Future<void> clearYourBox() async {
await _yourBox?.clear();
}
}

Epson js SDK unable to use multiple printers

Intro
We're developing this javascript based web application that is supposed to print receipts using the epson javascript sdk.
Right now we've got this poc where multiple printers can be added to the app and where receipts can be printed per individual printer.
The problem is that the receipt will ONLY be printer from the last added printer.
Further investigating tells us that the sdk just uses the last added (connected) printer. This can be seen at the following images.
In the first image there are 2 printers setup. Notice the different ip addresses.
In the second image we log what EpsonPrinter instance is being used while printing. Notice the ip address is clearly the first printer.
In the third image we trace the network. Notice the ip address that is actually used (ignore the error).
We created our own EpsonPrinter class that can be found here or here below.
EpsonPrinter
export default class EpsonPrinter {
name = null
ipAddress = null
port = null
deviceId = null
crypto = false
buffer = false
eposdev = null
printer = null
intervalID = null
restry = 0
constructor (props) {
const {
name = 'Epson printer',
ipAddress,
port = 8008,
deviceId = 'local_printer',
crypto = false,
buffer = false
} = props
this.name = name
this.ipAddress = ipAddress
this.port = port
this.deviceId = deviceId
this.crypto = crypto
this.buffer = buffer
this.eposdev = new window.epson.ePOSDevice()
this.eposdev.onreconnecting = this.onReconnecting
this.eposdev.onreconnect = this.onReconnect
this.eposdev.ondisconnect = this.onDisconnect
this.connect()
}
onReconnecting = () => {
this.consoleLog('reconnecting')
}
onReconnect = () => {
this.consoleLog('reconnect')
}
onDisconnect = () => {
this.consoleLog('disconnect')
if (this.intervalID === null ){
this.intervalID = setInterval(() => this.reconnect(), 5000)
}
}
connect = () => {
this.consoleLog('connect')
this.eposdev.ondisconnect = null
this.eposdev.disconnect()
this.eposdev.connect(this.ipAddress, this.port, this.connectCallback)
}
reconnect = () => {
this.consoleLog('(Re)connect')
this.eposdev.connect(this.ipAddress, this.port, this.connectCallback)
}
connectCallback = (data) => {
clearInterval(this.intervalID)
this.intervalID = null
this.eposdev.ondisconnect = this.onDisconnect
if (data === 'OK' || data === 'SSL_CONNECT_OK') {
this.createDevice()
} else {
setTimeout(() => this.reconnect(), 5000)
}
}
createDevice = () => {
console.log('create device, try: ' + this.restry)
const options = {
crypto: this.crypto,
buffer: this.buffer
}
this.eposdev.createDevice(this.deviceId, this.eposdev.DEVICE_TYPE_PRINTER, options, this.createDeviceCallback)
}
createDeviceCallback = (deviceObj, code) => {
this.restry++
if (code === 'OK') {
this.printer = deviceObj
this.printer.onreceive = this.onReceive
} else if (code === 'DEVICE_IN_USE') {
if (this.restry < 5) {
setTimeout(() => this.createDevice(), 3000)
}
}
}
onReceive = (response) => {
this.consoleLog('on receive: ', response)
let message = `Print ${this.name} ${response.success ? 'success' : 'failute'}\n`
message += `Code: ${response.code}\n`
message += `Status: \n`
if (response.status === this.printer.ASB_NO_RESPONSE) { message += ' No printer response\n' }
if (response.status === this.printer.ASB_PRINT_SUCCESS) { message += ' Print complete\n' }
if (response.status === this.printer.ASB_DRAWER_KICK) { message += ' Status of the drawer kick number 3 connector pin = "H"\n' }
if (response.status === this.printer.ASB_OFF_LINE) { message += ' Offline status\n' }
if (response.status === this.printer.ASB_COVER_OPEN) { message += ' Cover is open\n' }
if (response.status === this.printer.ASB_PAPER_FEED) { message += ' Paper feed switch is feeding paper\n' }
if (response.status === this.printer.ASB_WAIT_ON_LINE) { message += ' Waiting for online recovery\n' }
if (response.status === this.printer.ASB_PANEL_SWITCH) { message += ' Panel switch is ON\n' }
if (response.status === this.printer.ASB_MECHANICAL_ERR) { message += ' Mechanical error generated\n' }
if (response.status === this.printer.ASB_AUTOCUTTER_ERR) { message += ' Auto cutter error generated\n' }
if (response.status === this.printer.ASB_UNRECOVER_ERR) { message += ' Unrecoverable error generated\n' }
if (response.status === this.printer.ASB_AUTORECOVER_ERR) { message += ' Auto recovery error generated\n' }
if (response.status === this.printer.ASB_RECEIPT_NEAR_END) { message += ' No paper in the roll paper near end detector\n' }
if (response.status === this.printer.ASB_RECEIPT_END) { message += ' No paper in the roll paper end detector\n' }
if (response.status === this.printer.ASB_SPOOLER_IS_STOPPED) { message += ' Stop the spooler\n' }
if (!response.success) {
alert(message)
// TODO: error message?
} else {
// TODO: success -> remove from queue
}
}
printReceipt = () => {
this.consoleLog(`Print receipt, `, this)
try {
if (!this.printer) {
throw `No printer created for ${this.name}`
}
this.printer.addPulse(this.printer.DRAWER_1, this.printer.PULSE_100)
this.printer.addText(`Printed from: ${this.name}\n`)
this.printer.send()
} catch (err) {
let message = `Print ${this.name} failure\n`
message += `Error: ${err}`
alert(message)
}
}
consoleLog = (...rest) => {
console.log(`${this.name}: `, ...rest)
}
}
Poc
The full working poc can be found here.
Epson javascript sdk
2.9.0
Does anyone have any experience with the epson sdk? It it supposed to be able to support multiple connections on the same time? Please let use know.
For the ones looking for a way to handle multiple printers using this SDK. We came up with the following work around:
We created a separated 'printer app' that is responsible for handling ONE printer connection and hosted it online. We then 'load' this printer app into our app that needs multiple connections using Iframes. Communication between app and printer app is done by means of window.PostMessage API to, for example, initialise the printer with the correct printer connection and providing data that has to be printed.
It takes some effort but was the most stable solution we could come up with handling multiple connections.
If anyone else comes up with a better approach please let me know!
You can checkout our printer app here for inspiration (inspect the app because it doesn't show much visiting it just like that).
For use your class EpsonPrinter, i add also myPrinters class after your class:
class myPrinters {
printers = null;
cantidad = 0;
constructor() {
console.log("Creo la coleccion de printers");
this.printers = [];
}
inicializarConeccionImpresora(idImpresora, ip, puerto, _deviceId) {
let ipAddress = ip;
let port = puerto;
let deviceId = _deviceId;
console.log("Agrego una impresora");
let myPrinter = new EpsonPrinter(ipAddress);
myPrinter.port = port;
myPrinter.deviceId = deviceId;
myPrinter.id = idImpresora;
console.log('Id impresora antes de connect es: ' + idImpresora);
myPrinter.connect();
this.printers[this.cantidad] = myPrinter;
this.cantidad ++;
}
imprimirPruebaJS(idImpresora) {
let printer = null;
let printerTemp = null
for(var i = 0; i < this.printers.length; i++) {
printerTemp = this.printers[i];
if (printerTemp.id == idImpresora) {
printer = printerTemp.printer;
}
}
if (printer == null) {
console.log("La impresora no esta iniciada en clase myPrinters");
return;
}
printer.addText('Hola mundo texto normal\n');
printer.addFeed();
printer.addCut(printer.CUT_FEED);
}
}
call myPrinters class in this way :
myEpsonPrinters = new myPrinters();
myEpsonPrinters.inicializarConeccionImpresora(1, '192.168.0.51', 8008, 'local_printer');
myEpsonPrinters.inicializarConeccionImpresora(2, '192.168.0.52', 8008, 'local_printer');
myEpsonPrinters.imprimirPruebaJS(1)
or
myEpsonPrinters.imprimirPruebaJS(2)
Test it and tell me.
Juan
Just create multiple objects for printing simple as this
this.eposdev = [];
let printersCnt = 3;
let self = this;
for(let i=1 ; i <= printersCnt ; i++){
this.eposdev[i] = new window.epson.ePOSDevice()
this.eposdev[i].onreconnecting = function (){
this.consoleLog('reConnecting')
}
this.eposdev[i].onreconnect = function (){
this.consoleLog('onReconnect')
}
this.eposdev[i].ondisconnect = function (){
this.consoleLog('onDisconnect')
}
}
function connect(printerKey) => {
this.consoleLog('connect')
this.eposdev.ondisconnect = null
this.eposdev.disconnect()
this.eposdev.connect(self.ipAddress[printerKey], self.port[printerKey], function(){
clearInterval(self.intervalID)
self.intervalID = null
self.eposdev[i].ondisconnect = self.ondisconnect
if (data === 'OK' || data === 'SSL_CONNECT_OK') {
console.log('create device, try: ' + self.restry)
const options = {
crypto: self.crypto,
buffer: self.buffer
}
self.eposdev[printerKey].createDevice(self.deviceId, self.eposdev[printerKey].DEVICE_TYPE_PRINTER, options, function(deviceObj, code){
this.restry++
if (code === 'OK') {
self.printer[printerKey] = deviceObj
self.printer.onreceive = function(){
console.log("onreceive");
}
} else if (code === 'DEVICE_IN_USE') {
if (self.restry < 5) {
setTimeout(() => self.createDevice(printerKey), 3000)
}
})
}
} else {
setTimeout(() => self.reconnect(printerKey), 5000)
}
})
}
Epson says that with version 2.12.0 you can add more than one printer.

JS: java.lang.Exception: Failed resolving method read on class android.media.AudioRecord

I'm trying to use android.media.AudioRecord to save audio, initialization is OK, startRecording() is also called without error, but when I start reading audio from the buffer I got error Failed resolving method read on class android.media.AudioRecord.
Here is the code:
const SAMPLE_RATE = 44100;
const RECORD_AUDIO = android.Manifest.permission.RECORD_AUDIO;
const AudioRecord = android.media.AudioRecord;
const AudioFormat = android.media.AudioFormat;
const MediaRecorder = android.media.MediaRecorder;
ngOnInit(): void {
this.bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
if (this.bufferSize == AudioRecord.ERROR || this.bufferSize == AudioRecord.ERROR_BAD_VALUE) {
this.bufferSize = SAMPLE_RATE * 2;
}
this.bufferSize = this.bufferSize * 10;
this.audioBuffer = new Array(this.bufferSize / 2);
if (!permissions.hasPermission(RECORD_AUDIO)) {
permissions.requestPermission(RECORD_AUDIO).then(() => {
this.createRecorder();
}, (err) => {
console.log('[BrowseComponent] ngOnInit, ', 'permissions error:', err);
});
}
else {
this.createRecorder();
}
}
createRecorder() {
this.record = new AudioRecord.Builder()
.setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION)
.setAudioFormat(new AudioFormat.Builder()
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setSampleRate(SAMPLE_RATE)
.setChannelMask(AudioFormat.CHANNEL_IN_MONO)
.build())
.setBufferSizeInBytes(this.bufferSize)
.build();
this.recordState = this.record && this.record.getState();
if (this.recordState != AudioRecord.STATE_INITIALIZED) {
console.error('[BrowseComponent] createRecorder, ', 'AudioRecord can\'t initialize, state:', this.recordState);
return;
}
console.log('[BrowseComponent] createRecorder, ', 'AudioRecord:', this.record);
}
startRecord() {
this.recording = true;
this.record.startRecording();
this.shortsRead = 0;
while (this.recording) {
const numberOfShort = this.record.read(this.audioBuffer, 0, this.bufferSize);
this.shortsRead += numberOfShort;
// Do something with the audioBuffer
}
}
startRecord() is called from (tap) button handler.
Any ideas what may be wrong?
I guess the problem is that you are passing JavaScript Array instead of the Java Primitive (short) typed Array, so the runtime is unable to identify a method that matches the given parameters.
Use Array.create method to typecast, refer the docs here for more details.

General solution for ajax request in Protractor

I want to wait until ajax call complete. Below I wrote general method. But It seems that is not work.
When I ran call function every afterajax request , isLoaded always to be true.
In protractor, Is there any solution? Or where have I made mistake?
Thank you
module.waitUntilJqueryLoad = async function (timeout) {
var isDone = false;
timeout = timeout || 60;
await browser.sleep(1000);
//Wait for jQuery to load
var isLoaded = await browser.driver.executeScript("return jQuery.active == 0;");
if(isLoaded) {
console.log("JQuery is Ready!");
return await browser;
}
//This loop will rotate for 60 times to check If page Is ready after every 1 second.
//You can replace your value with 60 If you wants to Increase or decrease wait time.
for (var i = 0; i < timeout; i++) {
try {
await browser.sleep(1000);
} catch (err) {}
//To check page ready state.
var isLoaded = await browser.driver.executeScript("return jQuery.active == 0;");
console.log(isLoaded);
if(isLoaded) {
console.log("JQuery is Ready");
isDone = true;
} else {
console.log("JQuery is NOT Ready !!");
}
if(isDone)
break;
}
return browser;
};
I have a work around for that. If your loading popup added display style, it will work.
This is not a general solution but other posted solution has not worked even below code.
await browser.wait(until.invisibilityOf(element(by.id('loadingPanel'))), 60000);
Example Usage :
element(by.id('selectPerson')).waitForInvisibilityOf(10000); // wait 10 seconds
Here is my solution;
protractor.ElementFinder.prototype.waitForInvisibilityOf = async function (timeout) {
var _debug = true;
var isDone = false;
timeout = timeout || 60000;
var seconds = timeout / 1000;
if(await !this.isPresent())
return this;
//This loop will rotate for 60 times to check If page Is ready after every 1 second.
//You can replace your value with 60 If you wants to Increase or decrease wait time.
for (var i = 1; i <= seconds; i++) {
await browser.sleep(1000);
var style = await this.getAttribute('style');
var insibilityOf = await style.includes('display: none;');
var visibilityOf = await style.includes('display: block;');
if(insibilityOf) {
if(_debug)
console.log(i + " second: Element invisible!");
isDone = true;
}
else {
if(_debug)
console.log(i + " second: Element NOT invisible!");
}
if(seconds === i)
throw "Element invisibility timed out after "+ timeout +" milliseconds";
if(!insibilityOf && !visibilityOf && i > 10) // break for paging is loaded
break;
if(isDone) // If element is invisible
break;
}
return await this; };

Resources