how to play mp3 sound from server on swift4? - audio

I have test this func, the error is like below :
playSound(soundUrl: "httpwebxxxxxxxx/sound2.mp3")
func playSound(soundUrl: String) {
let sound = URL(fileURLWithPath: soundUrl)
do {
let audioPlayer = try AVAudioPlayer(contentsOf: sound)
audioPlayer.prepareToPlay()
audioPlayer.play()
}catch let error {
print(soundUrl)
print("Error: \(error.localizedDescription)")
//Error: The operation couldn’t be completed. (OSStatus error 2003334207.)
}
}
I have tested on realy device iphone 5 ios 10.3 and on simulator too

The initializer fileURLWithPath of URL is only for URLs in the local file system, for a remote URL you have to use the API
let sound = URL(string: soundUrl)
Basically don't load data synchronously from a remote URL. Use URLSession / URLSessionDataTask.

Related

How could I change the audio output device of node module "say"

I'm making a program that will output text to speech, the user will need to be able to change the output device (for example to virtual audio cable). At the moment I'm using https://www.npmjs.com/package/say to produce the speech
e.g.
const say = require("say");
say.speak("Hello World");
but I've no clue on how I could go about choosing the audio output.
What I've found so far has been pretty useless, I'm guessing largely because I don't know the proper terminology to search for answers, regardless this is it:
I first found out about navigator.MediaDevices, then I found how I could make an audio element and change the audio device of that element via setSinkId, then I realized these things are probably(?) irrelevant since the say module seems to play sounds using powershell commands. I've even gone as far as trying to change powershell's output device in app volume device preferences(img), but that seems to do nothing.
I'm pretty much stumped right now, so I'd appreciate any help please. I'm not set on using Say as a module, it just seemed easy to use at first.
Edit:
A workaround I've settled with is making my own TTS class and using SpVoice.
I have something similar to this:
const childProcess = require('child_process');
class TTS {
constructor(channel, speed) {
this.speed = speed;
this.channel = channel;
this.baseCommand = "$speak = New-Object -ComObject SAPI.SPVoice;"
}
speak(text){
var command = this.baseCommand +
`$speak.AudioOutput = foreach ($o in $speak.GetAudioOutputs()) {if ($o.getDescription() -eq '${this.channel}') {$o; break;}}; `
+ "$speak.Speak([Console]::In.ReadToEnd());"
this.child = childProcess.spawn('powershell', [command], {shell: true})
this.child.stdin.setEncoding('ascii')
this.child.stdin.end(text);
this.child.addListener('exit', (code, signal) => {
if (code === null || signal !== null) {
console.log(new Error(`error [code: ${code}] [signal: ${signal}]`))
}
this.child = null
})
}
}
Then I can pass in an audio channel like
tts = new TTS("CABLE Input (VB-Audio Virtual Cable)", 0);
tts.speak("Hello there");
and it will output TTS in my desired channel
Some of the browsers support the built in speechSynthesis API.
Save the following code in 'test.html' file and open the file in chrome web browser for testing the speech api.
<script>
//---------------- SpeechAPI Start ------------------------
function speak(message) {
try {
var utterance= new SpeechSynthesisUtterance("");
utterance.lang='en-GB';
utterance.text=message;
window.speechSynthesis.speak(utterance);
}catch(e){
console.log('Exception in speak : ' + e)
}
}
//---------------- SpeechAPI End ------------------------
</script>
<button onclick="speak('Hello, how are you doing?');">Press to speak</button>
Is this what you are looking for ?

Reading data from StreamSocket only works on desktop, not on phone (Universal Windows App)

Having a weird problem with an UWP app I'm trying to create when creating a socket and reading back data from it. Here's the basic scenario:
_commandSocket = new StreamSocket();
await _commandSocket.ConnectAsync(new HostName("192.168.1.1"), "15740", SocketProtectionLevel.PlainSocket);
_commandOutput = _commandSocket.OutputStream;
_commandInput = _commandSocket.InputStream;
await _commandOutput.WriteAsync(initCommandBuffer);
var lengthBytes = new byte[4].AsBuffer();
await input.ReadAsync(lengthBytes, 4, InputStreamOptions.None);
etc..etc...etc...
I'm basically opening a socket and sending an initialization command to my device. The idea is that it'll reply by first sending me the length of the reply as an uint.
This all works perfectly well when I debug/run the app on my desktop, but if I try to run this on my Window 10 Mobile device (Nokia 930) it seems not a single byte is being read (I've tried reading 1 byte instead of 4). Since app development should be 'Universal' and it's all working perfectly on my desktop I have no idea where to start fixing this.
Opening the connection on the mobile device works, I'm also not getting any errors when sending the initialization command, it just keeps blocking on the await ReadAsync command (as if nothing is being sent back).
I don't have any influence on the device that I'm connecting to, but again since this is all working flawlessly on the desktop and the device doesn't know who's asking I'm pretty clueless.
Cannot confirm my answer for sure, becasue I only tested in on an emulator, but I used stream socket listener.
private async void StartServer()
{
int Port = 80;
try
{
//Bound to port 80
await listener.BindServiceNameAsync(Port.ToString());
}
catch (System.Runtime.InteropServices.COMException)
{
//Port 80 for communication is blocked.
}
listener.ConnectionReceived += async (s, e) =>
{
using (IInputStream input = e.Socket.InputStream)
{
var buffer = new Windows.Storage.Streams.Buffer(200);
await input.ReadAsync(buffer, buffer.Capacity, InputStreamOptions.Partial);
//reads incoming stream
string data = Encoding.ASCII.GetString(buffer.ToArray(), 0, (int) buffer.Length);
}
using (IOutputStream output = e.Socket.OutputStream)
{
using (Stream response = output.AsStreamForWrite())
{
response.Write(Encoding.ASCII.GetBytes("Response."), 0, 1);
}
}
};
}

Threading + multiple windows causing strange errors

I have 2 windows in swift, one is like a login dialog which sends an NSURLConnection.sendAsynchronousRequest to a server to get authenticated. Once it gets the response, the window is supposed to close.
When I close the Window (either from the login window class or main window clasS) I get these errors:
This application is modifying the autolayout engine from a background thread, which can lead to engine corruption and weird crashes. This will cause an exception in a future release.
I have tried all manner of background threads etc. But I think the issue is that I am closing the window why the asynch NSURLConnection request is still hanging.
My code to send the async request from the login window:
dispatch_async(dispatch_get_main_queue(), {
let queue:NSOperationQueue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{ (response:NSURLResponse!, data: NSData!, error: NSError!) -> Void in
var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil
let jsonResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers, error: error) as? NSDictionary
let result: NSString = NSString(data: data, encoding: NSUTF8StringEncoding)!
let expectedString = "special auth string"!
if(result == expectedString) {
self.callback.loginOK()
} else {
self.output.stringValue = result
}
return
})
})
The callback member of the class is the parent view contoller that spawns it, I then close the login window using loginVC.view.window?.close() from the main application window. That causes the error.
The problem is that NSURLConnection.sendAsynchronousRequest will always run in a secondary thread and thus its callback will be called from that secondary thread despite you calling it explicitly from main thread.
You don't need to wrap NSURLConnection.sendAsynchronousRequest in the main thread, instead wrap your ' self.callback.loginOK()' to run in main thread using the dispatch_async to ensure no UI related operations take place in secondary thread. Something like this-
let queue:NSOperationQueue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{ (response:NSURLResponse!, data: NSData!, error: NSError!) -> Void in
var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil
let jsonResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers, error: error) as? NSDictionary
let result: NSString = NSString(data: data, encoding: NSUTF8StringEncoding)!
dispatch_async(dispatch_get_main_queue() {
let expectedString = "special auth string"!
if(result == expectedString) {
self.callback.loginOK()
} else {
self.output.stringValue = result
}
})
return
})

Network request in threads is crashing my application

Currently I have a code that is crashing (SEGFAULT) on me.
I am trying to compare a big amount of images that are in my drive to their counter parts in a server.
To speed up the process I get the image from the server and compare the images on a different thread.
From what I already tried and debugged, the issue is in getting the image from the server (that is why the other calls are commented out).
Also if I run without the QtConcurrent::run it does not crash, but if I put semaphore concurrentComparisons with only one resorce, it will crash.
Finally I also get the following errors
QObject::connect: Cannot connect (null)::configurationAdded(QNetworkConfiguration) to QNetworkConfigurationManager::configurationAdded(QNetworkConfiguration)
QObject::connect: Cannot connect (null)::configurationRemoved(QNetworkConfiguration) to QNetworkConfigurationManager::configurationRemoved(QNetworkConfiguration)
QObject::connect: Cannot connect (null)::configurationChanged(QNetworkConfiguration) to QNetworkConfigurationManager::configurationChanged(QNetworkConfiguration)
QObject::connect: Cannot connect (null)::onlineStateChanged(bool) to QNetworkConfigurationManager::onlineStateChanged(bool)
QObject::connect: Cannot connect (null)::configurationUpdateComplete() to QNetworkConfigurationManager::updateCompleted()
Any help would be very appreciated.....
Relevant code:
QSemaphore FileComparisonInfo::concurrentComparisons(1);
QtConcurrent::run( [this, localPath, imageURL]()
{
ImageComparer cmp;
FileComparisonInfo::concurrentComparisons.acquire();
//cmp.setImageLeftPath(localPath);
cmp.setImageRightPath(imageURL);
//cmp.createDifferenceImage();
FileComparisonInfo::concurrentComparisons.release();
});
void ImageComparer::setImageRightPath(QString path)
{
this->rightImagePath = path;
this->imageRight = getImage(path);
}
QImage* ImageComparer::getImage(QString path)
{
QUrl url(path);
QFile file(path);
if(file.exists())
{
return new QImage(path);
}
else if(url.isValid())
{
return getImageFromURL(path);
}
}
QImage* ImageComparer::getImageFromURL(QString url)
{
QNetworkAccessManager * tempNAM = new QNetworkAccessManager();
QNetworkReply *imageConnection = tempNAM->get( QNetworkRequest( QUrl( url ) ));
QEventLoop loop;
connect(imageConnection, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
QImage * downloadedImage;
if(imageConnection->error() != QNetworkReply::NoError)
{
qDebug() << imageConnection->errorString();
downloadedImage = new QImage();
}
else
{
QByteArray data = imageConnection->readAll();
downloadedImage = new QImage(QImage::fromData(data));
}
tempNAM->deleteLater();
imageConnection->deleteLater();
return downloadedImage;
}
Unfortunately this had nothing to do with the code.
One of the images was corrupted and was segfaulting in the comparison.

play file wav j2me - IllegalArgumentException at Manager.createPlayer()

I got problem about play wav file in my application.
This is my error:
java.lang.IllegalArgumentException
at javax.microedition.media.Manager.createPlayer(), bci=8
at Tajwid.Tajwid.run(Tajwid.java:649)
at Tajwid.Tajwid.actionPerformed(Tajwid.java:186)
at com.sun.lwuit.util.EventDispatcher.fireActionSync(), bci=19
at com.sun.lwuit.util.EventDispatcher.fireActionEvent(EventDispatcher.java:257)
This is my code:
public void run() {
try {
InputStream is = getClass().getResourceAsStream("/tes.wav");
player = Manager.createPlayer(is, "audio/x-wav");
player.realize();
// get volume control for player and set volume to max
vc = (VolumeControl) player.getControl("VolumeControl");
if (vc != null) {
vc.setLevel(100);
}
player.prefetch();
player.start();
} catch (Exception e) {
e.printStackTrace();
}
Device Configuration : CLDC-1.1
Device Profile MIDP 2.0
Error message you've got has sufficient information to figure what went wrong in the code.
Look at it a bit closer:
java.lang.IllegalArgumentException
at javax.microedition.media.Manager.createPlayer()...
It says something went wrong in Manager.createPlayer(). From your code, it is apparent that you use method Manager.createPlayer(java.io.InputStream stream, java.lang.String type).
If you look into API documentation for the method you use (available online), you'll find the explanation when this exception occurs:
Throws:
java.lang.IllegalArgumentException - Thrown if stream is null.
Above means that stream parameter (is in your code) passed to the method is null.
You could add some logging right after initialization of the is to debug this issue easier:
InputStream is = getClass().getResourceAsStream("/tes.wav");
// add some logging to see if initialization was OK or not:
System.out.println("input stream is null: [" + (is == null) + "]");
That way, when running your MIDlet in emulator, you will see whether is was initialized as expected or not.
Actually, looking at the code I would guess that you made a typo in file name passed to getResourceAsStream: "/tes.wav" looks like a mis-typed "/test.wav".

Resources