libspotify: logging out or releasing session causes crash - spotify

This is in response to dan's (dan^spotify on IRC) offer to take a look at my testcase, but I post it here in case anyone has encountered similar issues.
I'm experiencing a problem with libspotify where the application crashes (memory access violation) in both of these two scenarios:
the first sp_session_process_events (triggered by notify main thread callback) that's called after the sp_session_logout() function is called crashes the application
skipping logout and calling sp_session_release() crashes the application
I've applied sufficient synchronization from the session callbacks, and I'm otherwise operating on a single thread.
I've made a small testcase that does the following:
Creates session
Logs in
Waits 10 seconds
Attempts to logout, upon which it crashes (when calling sp_session_process_events())
If it were successful in logging out (which it isn't), would call sp_session_release()
I made a Gist for the testcase. It can be found here: https://gist.github.com/4496396
The test case is made using Qt (which is what I'm using for my project), so you'd need Qt 5 to compile it. I've also only written it with Windows and Linux in mind (don't have Mac). Assuming you have Qt 5 and Qt Creator installed, the instructions are as follows:
Download the gist
Copy the libspotify folder into the same folder as the .pro file
Copy your appkey.c file into the same folder
Edit main.cpp to login with your username and password
Edit line 38-39 in sessiontest.cpp and set the cache and settings path to your liking
Open up the .pro file and run from Qt Creator
I'd be very grateful if someone could tell me what I'm doing wrong, as I've spent so many hours trying anything I could think of or just staring at it, and I fear I've gone blind to my own mistakes by now.
I've tested it on both Windows 7 and Linux Ubuntu 12.10, and I've found some difference in behavior:
On Windows, the testcase crashes invariably regardless of settings and cache paths.
On Linux, if setting settings and cache to "" (empty string), logging out and releasing the session works fine.
On Linux, if paths are anything else, the first run (when folder does not already exist) logs out and releases session as it should, but on the next run (when folder already exists), it crashes in the exact same way as it does on Windows.
Also, I can report that sp_session_flush_caches() does not cause a crash.
EDIT: Also, hugo___ on IRC was kind enough to test it on OSX for me. He reported no crashes despite running the application several times in a row.

While you very well may be looking at a bug in libspotify, I'd like to point out a possibly redundant call to sp_session_process_events(), from what I gathered from looking at your code.
void SessionTest::processSpotifyEvents()
{
if (m_session == 0)
{
qDebug() << "Process: No session.";
return;
}
int interval = 0;
sp_session_process_events(m_session, &interval);
qDebug() << interval;
m_timerId = startTimer(interval);
}
It seems this code will pickup the interval value and start a timer on that to trigger a subsequent call to event(). However, this code will also call startTimer when interval is 0, which is strictly not necessary, or rather means that the app can go about doing other stuff until it gets a notify_main_thread callback. The docs on startTimer says "If interval is 0, then the timer event occurs once every time there are no more window system events to process.". I'm not sure what that means exactly but it seems like it can produce at least one redundant call to sp_session_process_events().
http://qt-project.org/doc/qt-4.8/qobject.html#startTimer

I notice that you will get a crash on sp_session_release if you have a track playing when you call it.

I have been chasing this issue today. Login/logout works just fine on Mac, but the issue was 100% repeatable as you described on Windows.
By registering empty callbacks for offline_status_updated and credentials_blob_updated, the crash went away. That was a pretty unsatisfying fix, and I wonder if any libspotify developers want to comment on it.
Callbacks registered in my app are:
logged_in
logged_out
notify_main_thread
log_message
offline_status_updated
credentials_blob_updated
I should explicitly point out that I did not try this on the code you supplied. It would be interesting to know if adding those two extra callbacks works for you. Note that the functions I supply do absolutely nothing. They just have to be there and be registered when you create the session.

Adding the following call in your "logged in" libspotify callback seems to fix this crash as detailed in this SO post:
sp_session_playlistcontainer(session);

Related

Bukkit/Spigot - How to wait until BukkitRunnable is finished

In my onDisbale() method in my Main class I have a loop which creates and starts new BukkitRunnables.
I'm getting a error in console: org.bukkit.plugin.IllegalPluginAccessException: Plugin attempted to register task while disabled I need to somehow wait in my onDisable() method until all the BukkitRunnables I create in the loop are finished. How to do that?
My code looks like this:
#Override
public void onDisable() {
for (Player p : Bukkit.getOnlinePlayers()) {
new PlayerDataSaverRunnable().runTaskAsynchronously(this);
}
}
The onDisable method is the very last thing that gets called before your plugin is disabled and the server shuts down. So, as the error message says, you unfortunately can't schedule any new tasks in the onDisable function.
You mentioned in a comment that you were trying to write to a file in the plugins folder, and under normal circumstances you'd want to do that asynchronously. But, because onDisable only ever gets called when the server is shut down (or when the entire server is reloaded with /reload), it's perfectly fine to run code here that blocks the main thread and could potentially take a few seconds to run — in the case of a shutdown, by the time this method gets called, all the players will have already been kicked off the server, and so there's no "lag" to complain about. If your plugin is super advanced and has to save a bunch of stuff, I don't think any server owners would complain even if it took 10 or so seconds to disable.
Of course, you would have to be saving something crazy for it to take a whole 10 seconds to save. More than likely, most files will save in just a few milliseconds.
If you're really dead-set on disabling the plugin as fast as possible, you might consider having some async task that runs every 5 minutes or so and auto-saves the files. Then, in onDisable, you could only save files that changed since the auto-saver was last run. That's a good practice anyways, just incase the server crashes or the power goes out and the onDisable method doesn't get a chance to run. But, then again, I would still recommend that you save everything in the onDisable method (that's what I do for all of my plugins, as well), even if it will take a few seconds and block the main thread, just so you can be 100% sure that everything gets saved correctly.

Why doesn't ElectronJS simply exit when given a blank index.js file?

I'm trying to understand the Electron Main process. I'm confused about something.
Try this:
% touch blank.js
% electron blank.js
You will notice that electron does not exit. Since no 'app' has been created, it isn't clear to me why the process is sticking around, and why I need to call process.exit from blank.js to terminate. The documentation is a bit thin in describing main/browser extensions to process.
Say I have a typical electron app:
await app.whenReady();
const win = new BrowserWindow();
await win.loadUrl("https://google.com");
The window is created and the main method exits. Nothing else is awaiting anything. Electron doesn't exit in this case, because it doesn't make sense to since we're now just waiting on the user to interact with the window.
The things that should trigger an exit are the remaining window closing (window-all-closed event), or an explicit app.quit() type of command.
Now I guess you might say that this is different since a window actually got created, but how would Electron know that this will happen? For how long must it wait until it can be sure that no window will be created?
Establishing a rule like "the main method must await the window creation" seems overly-restrictive to me, so Electron just assumes that it might happen later or it might not, but until it's told to exit, it'll wait.
Ultimately, someone on the Electron team could give a more accurate answer, but this is my best guess.

hunchentoot-based app in a lisp image (from buildapp) immediately returns

So I have an application using restas, based on hunchentoot.
At some point, I have the following function:
(defun main (args)
(declare (ignore args))
(set-config)
(restas:start '#:spa :port 8080))
(set-config) sets a few values related to database.
Anyway, I then use buildapp in the following way:
buildapp --output dist/spa --load-system spa --asdf-tree ~/quicklisp/ --entry spa::main --compress-core
Which works perfectly. The (set-config) function requires a config.json file to be present, and it indeed doesn't work when the file doesn't exist, so I know for sure that the application is correctly compiled.
When I run the generated binary however, the application immediately returns. Which means the HTTP server doesn't stay up.
I guess it's related to the fact that hunchentoot spawns a new thread, but it shouldn't stop the process, should it?
Also, I don't want to not use threads, i.e. I want the fact that each request is a separate thread.
So... I'm not sure exactly why it immediately returns. Why? And how to fix it?
I guess that you have to enter a main loop to keep the program running. The example at http://www.xach.com/lisp/buildapp/ uses the SBCL-specific (sb-impl::toplevel-repl nil).

Possible causes of "EOSError 1400 - Invalid window handle"

I have a problem.
I have a VCL application using a thread. This thread does some calculations and calls a MainForm's method through Synchronize(). It all works just fine, I have a "Start" button, which creates and runs the thread and a "Stop" button which stops and frees it. No errors, no nothing.
But for some reason when I close the application and I've run the thread I get a EOSError 1400 - Invalid window handle. I've breakpointed the OnClose procedure and the only thing I do there is saving an ini file, no error in that, when I trace further (using F7), I get to the very end (Application.Run; end.), after "calling" the end. I get the error, so there is no specific line of code raising it.
I hope the question is somewhat clear and I hope it's solvable, because just ignoring the error seems a bit unclean.
Thanks inb4
ANSWER
This error occured to me when the Execute method of a thread was called, it looked like this:
procedure TRunThread.Execute;
var (...)
begin
while not Terminated do begin
(...)
MainForm.Memo1.Lines.Add('Some text'); // Even though this call worked fine during
//the application running, it caused errors on shutting the app down.
// For acccessing GUI elements, it's necessary to use Synchronize()
(...)
end;
end;
A possible reason is some unsynchronized access to GUI from the thread. You said that the thread does not do it, but without seeing the TRunThread.Execute source code that looks like the best guess.
I had the same problem, error code 5 Access is denied. This turned out to related to a thread started to test an internet connection on an embedded panel (using BeginThread). If the user exits the form (which is testing the internet connection) immediately after displaying the form, the AV occurs.
On my development PC, the internet connection test was successful...and so fast I never saw the problem! After struggling for several hours, I finally tracked it down to this thread and reproduced it by disconnecting my network cable.
The solution was straightforward: When exiting the form (eg. in the FormDestroy event) ensure the thread is definitely not running before continuing.

AudioQueueStart fail -12985

I made a streaming music player and it works fine in the foreground.
But in the background iOS4, it doesn't play the next song automatically. ( remote control works )
The reason is AudioQueueStart return -12985.
I already check the audio session. it just fine. I use AudioQueueStart when it start to play the music.
How can you remove AudioQueueStart?
- (void)play
{
[self setupAudioQueueBuffers]; // calcluate the size to use for each audio queue buffer, and calculate the // number of packets to read into each buffer
OSStatus status = AudioQueueStart(self.queueObject, NULL);
}
I read the answer in the web about the AudioQueueStart fail subject.
One thing to check is that the AudioSession is active first.
In my case, I had previously set the session to inactive between song changes before starting a new song:AudioSessionSetActive(false);
Once I removed this AudioQueueStart works just fine from the background.
In my experience, the -12985 message occurs because another app already has an audio session active when you try to start playback in your app. Options are to 1) instruct the user to close the other app, or 2) set mix mode (see kAudioSessionProperty_OverrideCategoryMixWithOthers).
The disadvantage of mix mode is if you depend on lock screen art or remote controls, they won't work with mix mode set.
I also faced with such problem week ago. I've spent two days to find solution and I found it. May be this link will help (it is official answer): http://developer.apple.com/library/ios/#qa/qa1668/_index.html
Make sure that you activate session from applicationDidEnterBackground task handler. Now my application can play sound in background.
See this.
You probably need to include the following:
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
Towards the bottom there is a reiteration of the how important that line is. As it is not mentioned in any of the three main audio audio guides (AVFoundation, AudioSession, or AudioQueue) it can easily be missed.
I have the same problem.
I registry the AudioSessionInterruptionListener, pause the audio when phone call, resume it after the call end. but get -12985 error code when call AudioQueueStart to resume.
My solution is that I try to call AudioQueueStart after 0.02s.
I don't know the reason.
On iOS7, AudioQueueStart was returning '!int' ('tni!'), though i'm sure no one would be surprised to find that it's not documented in the docs or headers. It was the same issue, though, and the same fix (setting the audio session to active in the background task handler) worked for me.

Resources