C++ sp_会话_进程_事件在调用sp_会话_登录后导致访问冲突

C++ sp_会话_进程_事件在调用sp_会话_登录后导致访问冲突,c++,windows,spotify,libspotify,C++,Windows,Spotify,Libspotify,这是一个非常奇怪的问题,我已经尝试了好几天了。奇怪的是,它只对某些用户帐户执行此操作。这是一个Windows应用程序,我使用自动存储塔示例作为起点 我调用sp_session_login() 我得到了登录()的回调 我看到notify_主线程回调 sp_session_process_events()处理一系列事件,然后处理访问冲突 我已经对此进行了多次跟踪,在导致崩溃的帐户上,我得到了大约8次userinfo_updated()回调。没有崩溃的帐户我只看到一两次。我没有在回叫中做任何事。我

这是一个非常奇怪的问题,我已经尝试了好几天了。奇怪的是,它只对某些用户帐户执行此操作。这是一个Windows应用程序,我使用自动存储塔示例作为起点

  • 我调用sp_session_login()
  • 我得到了登录()的回调
  • 我看到notify_主线程回调
  • sp_session_process_events()处理一系列事件,然后处理访问冲突
我已经对此进行了多次跟踪,在导致崩溃的帐户上,我得到了大约8次userinfo_updated()回调。没有崩溃的帐户我只看到一两次。我没有在回叫中做任何事。我想看看它是否需要我没有提供的回调

有一种方法可以防止它崩溃。如果我在logged_in()回调中(如Jukebox示例中)立即加载一首曲目并播放它,它不会崩溃

在调试这个过程中,任何帮助都将不胜感激

-汤米

更新日期:2016年4月7日 下面是日志文件输出。希望有人能帮我理解这一点。另外,我认为它与播放列表有关。我确实设置了播放列表回调

14:57:47.735 sp_会话_登录登录用户tgsource

14:57:47.788 sp_会话\u登录会话返回:sp_错误\u确定

14:57:47.859日志_消息21:57:47.859 I[user_cache:135]UserCache::initiateGetUsers()将查询1个用户

14:57:47.906日志信息21:57:47.906 I[ap:1752]连接到ap.gslb.spotify.com:4070

14:57:47.937已登录用户为:tgsource

14:57:47.937日志_消息21:57:47.937 I[脱机管理器:2084]存储已清理

14:57:47.984日志_消息21:57:47.984 I[ap:1226]已连接到ap:194.68.29.165:4070

14:57:48.405凭证\u blob\u更新凭证\u blob\u更新

14:57:48.405用户信息\已调用更新的用户信息

14:57:48.452用户信息\已调用更新的用户信息

14:57:48.452用户信息\已调用更新的用户信息

14:57:48.920播放列表容器加载的播放列表数:8

14:57:49.107日志消息21:57:49.107 E[ap:4172]频道错误(3,1,播放列表)

14:57:49.139日志_消息21:57:49.139 W[core/playlist/playlist.h:45]在更新时添加观察者

14:57:49.139日志_消息21:57:49.139 W[core/playlist/playlist.h:45]在更新时添加观察者

14:57:49.154日志\消息21:57:49.154 W[核心/播放列表/播放列表.h:45]在更新时添加观察者

14:57:49.154日志\消息21:57:49.154 W[核心/播放列表/播放列表.h:45]在更新时添加观察者

14:57:49.295日志_消息21:57:49.295 I[user_cache:135]UserCache::initiateGetUsers()将查询1个用户

14:57:49.295日志消息21:57:49.295 W[core/playlist/playlist.h:45]在更新时添加观察者

14:57:49.295日志消息21:57:49.295 W[core/playlist/playlist.h:45]在更新时添加观察者

14:57:49.327用户信息\已调用更新的用户信息

14:57:49.467用户信息\已调用更新的用户信息

**撞车**

更新日期:2016年11月4日 下面是重现问题的源代码。它是光盘机示例中playtrack.c文件的一个端口。我删除了轨道加载,它导致了相同的问题

    /**
 * Copyright (c) 2006-2010 Spotify Ltd
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 *
 * This example application is the most minimal way to just play a spotify URI.
 *
 * This file is part of the libspotify examples suite. Jukebox - playtrack.c
 */
#include <errno.h>
#include "stdint.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "../libspotify/api.h"
#include "audio.h"
#include <windows.h>

/* --- Data --- */
extern const uint8_t g_appkey[];
extern const size_t g_appkey_size;
static audio_fifo_t g_audiofifo;
static HANDLE g_notify_mutex;
static HANDLE g_notify_cond;
static int g_notify_do;
int    g_playback_done;
sp_session *g_sess;
static sp_track *g_currenttrack;
const  char *g_trackurl; 
static bool is_logged_out = FALSE;
static HANDLE events;



/* ---------------------------  PLAYLIST CALLBACKS  ------------------------- */
/**
 * Playlist container callbacks.
 * If some callbacks should not be of interest, set them to NULL.
 *
 */
static void SP_CALLCONV PlaylistContainerLoaded(sp_playlistcontainer* pc, void* userdata) 
{
    int numPlaylists = sp_playlistcontainer_num_playlists(pc);
    printf("Number of playlists: %d", numPlaylists);                
}

static sp_playlistcontainer_callbacks pc_callbacks = 
{
    NULL,
    NULL,
    NULL,
    &PlaylistContainerLoaded
};

/* ---------------------------  SESSION CALLBACKS  ------------------------- */
/**
 * This callback is called when an attempt to login has succeeded or failed.
 *
 * @sa sp_session_callbacks#logged_in
 */
static void SP_CALLCONV logged_in(sp_session *sess, sp_error error)
{
    sp_link *link;

    if (SP_ERROR_OK != error) {
        fprintf(stderr, "Login failed: %s\n",
            sp_error_message(error));
        exit(2);
    }

    sp_playlistcontainer *pc = sp_session_playlistcontainer(sess);
    sp_playlistcontainer_add_callbacks(pc, &pc_callbacks, NULL);


// Note:  Removing the track start will cause this to crash 
#if 0

    printf("Loading track\n");


    link = sp_link_create_from_string("spotify:track:0W4Kpfp1w2xkY3PrV714B7");

    sp_track_add_ref(g_currenttrack = sp_link_as_track(link));
    sp_link_release(link);

    if (sp_track_error(g_currenttrack) == SP_ERROR_OK) {
        printf("Now playing \"%s\"...\n", sp_track_name(g_currenttrack));


        printf("Duration: %d\n", sp_track_duration(g_currenttrack));
        fflush(stdout);

        sp_session_player_load(g_sess, g_currenttrack);
        sp_session_player_play(g_sess, 1);
        }
#endif

    /* Track not loaded? Then we need to wait for the metadata to
           load before we can start playback (see metadata_updated below) */
}

/**
 * Callback called when libspotify has new metadata available
 *
 * @sa sp_session_callbacks#metadata_updated
 */
static void SP_CALLCONV metadata_updated(sp_session *sess)
{
    puts("Metadata updated, trying to start playback");

    if (sp_track_error(g_currenttrack) != SP_ERROR_OK)
        return;

    sp_session_player_load(g_sess, g_currenttrack);
    sp_session_player_play(g_sess, 1);
}

/**
 * This callback is called from an internal libspotify thread to ask
 * us to reiterate the main loop.
 *
 * We notify the main thread using a condition variable and a protected variable.
 *
 * @sa sp_session_callbacks#notify_main_thread
 */
static void SP_CALLCONV notify_main_thread(sp_session *sess)
{
    g_notify_do = 1;
    SetEvent(events);
}

/**
 * This callback is used from libspotify whenever there is PCM data available.
 *
 * @sa sp_session_callbacks#music_delivery
 */
static int SP_CALLCONV music_delivery(sp_session *sess, const sp_audioformat *format,
                          const void *frames, int num_frames)
{
    audio_fifo_t *af = &g_audiofifo;
    audio_fifo_data_t *afd;
    size_t s;

    if (num_frames == 0)
        return 0; // Audio discontinuity, do nothing

    WaitForSingleObject(af->mutex, INFINITE);

    /* Buffer one second of audio */
    if (af->qlen > format->sample_rate) {
        ReleaseMutex(af->mutex);

        return 0;
    }

    s = num_frames * sizeof(int16_t) * format->channels;

    afd = malloc(sizeof(audio_fifo_data_t) + s);
    memcpy(afd->samples, frames, s);

    afd->nsamples = num_frames;

    afd->rate = format->sample_rate;
    afd->channels = format->channels;

    TAILQ_INSERT_TAIL(&af->q, afd, link);
    af->qlen += num_frames;

    PulseEvent(af->cond);   
    ReleaseMutex(af->mutex);

    return num_frames;
}


/**
 * This callback is used from libspotify when the current track has ended
 *
 * @sa sp_session_callbacks#end_of_track
 */
static void SP_CALLCONV end_of_track(sp_session *sess)
{
    printf("end_of_track\n");
    g_playback_done = 1;
}

/**
 * Notification that some other connection has started playing on this account.
 * Playback has been stopped.
 *
 * @sa sp_session_callbacks#play_token_lost
 */
static void SP_CALLCONV play_token_lost(sp_session *sess)
{
    printf("play_token_lost\n");
    audio_fifo_flush(&g_audiofifo);

    if (g_currenttrack != NULL) {
        sp_session_player_unload(g_sess);
        g_currenttrack = NULL;
    }
}

static void SP_CALLCONV log_message(sp_session *session, const char *msg)
{
    puts(msg);
}

static void SP_CALLCONV userinfo_updated(sp_session *session)
{
    printf("Userinfo called.\n");

}

static void SP_CALLCONV offline_status_updated(sp_session *sess)
{
    sp_offline_sync_status status;
    sp_offline_sync_get_status(sess, &status);
    if(status.syncing) {
        printf("Offline status: queued:%d:%zd done:%d:%zd copied:%d:%zd nocopy:%d err:%d\n",
            status.queued_tracks,
            (size_t)status.queued_bytes,
            status.done_tracks,
            (size_t)status.done_bytes,
            status.copied_tracks,
            (size_t)status.copied_bytes,
            status.willnotcopy_tracks,
            status.error_tracks);
    } else {
        printf("Offline status: Idle\n");
    }
}

/**
 * The session callbacks
 */
static sp_session_callbacks session_callbacks = {
    &logged_in,
    NULL,
    &metadata_updated,
    NULL,
    NULL,
    &notify_main_thread,
    &music_delivery,
    &play_token_lost,
    &log_message,
    &end_of_track,
    NULL,
    &userinfo_updated,
    NULL,
    NULL,
    NULL,
    &offline_status_updated,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
};


/**
 * The session configuration. Note that application_key_size is an
 * external, so we set it in main() instead.
 */
static sp_session_config spconfig = {
    SPOTIFY_API_VERSION,
    "tmp",
    "tmp",
    g_appkey,
    0, // Set in main()
    "spotify-jukebox-playtrack",
    &session_callbacks,
    NULL,
};
/* -------------------------  END SESSION CALLBACKS  ----------------------- */


/**
 * A track has ended. Remove it from the playlist.
 *
 * Called from the main loop when the music_delivery() callback has set g_playback_done.
 */
static void SP_CALLCONV track_ended(void)
{
    printf("track_ended\n");

    if (g_currenttrack) {
        sp_track_release(g_currenttrack);
        g_currenttrack = NULL;
        sp_session_player_unload(g_sess);
        exit(0);
    }
}

/**
 * Show usage information
 *
 * @param  progname  The program name
 */
static void usage(const char *progname)
{
    fprintf(stderr, "usage: %s <username> <password> <trackurl>\n", progname);
}


/*************************************************
 *  app main
 *
 *************************************************/
int main(int argc, char **argv)
{
    sp_session *sp;
    sp_error err;
    int next_timeout = 0;
    DWORD ev;

    const char* username_default = "username";
    const char* password_default = "login";

    const char *username = argc > 1 ? argv[1] : NULL;
    const char *password = argc > 2 ? argv[2] : NULL;
    g_trackurl = argc > 3 ? argv[3] : NULL;


    if (!username || !password) {
        username = username_default;
        password = password_default;
    }

    events = CreateEvent(NULL, FALSE, FALSE, NULL);
    audio_init(&g_audiofifo);

    /* Create session */
    spconfig.application_key_size = g_appkey_size;


    err = sp_session_create(&spconfig, &sp);

    if (SP_ERROR_OK != err) {
        fprintf(stderr, "Unable to create session: %s\n",
            sp_error_message(err));
        exit(1);
    }

    g_sess = sp;

//  Q: Why a mutex and cond here???

//  pthread_mutex_init(&g_notify_mutex, NULL);
//  pthread_cond_init(&g_notify_cond, NULL);

    err = sp_session_login(sp, username, password, 0, NULL);
//  pthread_mutex_lock(&g_notify_mutex);

    if (SP_ERROR_OK != err) {
        fprintf(stderr, "Unable to create session: %s\n",
            sp_error_message(err));
        exit(1);
    }

    while(!is_logged_out) 
    {
        ev = WaitForSingleObject( events, next_timeout > 0 ? next_timeout : INFINITE);

        switch (ev) 
        {
            case WAIT_OBJECT_0:
            case WAIT_TIMEOUT:
                do {
                    sp_session_process_events(g_sess, &next_timeout);
                } while (next_timeout == 0);
                break;
        }

        if( g_playback_done )
        {
            track_ended();
            break;
        }
    }

    audio_free(&g_audiofifo);

    printf("Logged out\n");
    sp_session_release(g_sess);
    printf("Exiting...\n");

    return 0;
}
/**
*版权所有(c)2006-2010 Spotify有限公司
*
*特此向任何获得副本的人免费授予许可
*本软件和相关文档文件(“软件”)的
*在软件中不受限制,包括但不限于权利
*使用、复制、修改、合并、发布、分发、再许可和/或销售
*软件的副本,并允许向其提供软件的人员
*按照以下条件提供:
*
*上述版权声明和本许可声明应包含在
*软件的所有副本或主要部分。
*
*本软件按“原样”提供,无任何形式的明示或明示担保
*默示,包括但不限于适销性保证,
*适用于特定目的和非侵权。在任何情况下
*作者或版权持有人应承担任何索赔、损害或其他责任
*无论是在合同诉讼、侵权诉讼或其他诉讼中,由以下原因引起的责任:,
*与本软件有关或与本软件的使用或其他交易有关
*软件。
*
*
*这个示例应用程序是播放SpotifyURI的最简单的方式。
*
*此文件是libspotify示例套件的一部分。自动存储塔-playtrack.c
*/
#包括
#包括“stdint.h”
#包括
#包括
#包括
#包括
#包括“./libspotify/api.h”
#包括“audio.h”
#包括
/*---数据--*/
外部施工单位8_t g_appkey[];
外部const size\u t g\u appkey\u size;
静态音频fifo;
静态句柄g_notify_互斥体;
静态句柄g_notify_cond;
静态int g___do;
int g_播放完成;
sp_会话*g_sess;
静态sp_轨迹*g_当前轨迹;
const char*g_trackurl;
静态布尔值已记录\u退出=错误;
静态处理事件;
/*------------------------------------播放列表回调-----------------*/
/**
*播放列表容器回调。
*如果对某些回调不感兴趣,请将它们设置为NULL。
*
*/
静态void SP_CALLCONV playlicannerloader(SP_playlicanner*pc,void*userdata)
{
int numPlaylists=sp_playlistcontainer_num_playlists(pc);
printf(“播放列表的数量:%d”,numPlaylists);
}
静态sp\U播放列表容器\U回调pc\U回调=
{
无效的
无效的
无效的
&播放列表已加载
};
/*------------------------------------会话回调------------------*/
/**
*此回调称为