3

Since Spotify is unlikely to provide a successor to libspotify anytime soon, I'm trying to wrap it into a thin Rust library that I can use for other projects. I'm using Bindings generated from the header file by rust-bindgen. Since they are quite long (~1100 lines) and not that easy to shrink down to only the important bits, I created a pastebin containing the code.

Calling sp_build_id works just fine, invoking sp_session_create on the other hand, causes a segfault at address 0x000001C0. Searching for libspotify and that memory address yielded this post. It suggests that something is wrong with the string marshalling, I just cannot figure out what it could be or if it indeed is the string marshalling.

This is how I call the method:

fn main() {
    let app_key = include_bytes!(env!("SP_APP_KEY_PATH"));
    let cache_path = ::std::ffi::CString::new(env!("SP_CACHE_PATH")).unwrap();

    let config = sp_session_config {
        api_version: 12,
        cache_location: cache_path.as_ptr(),
        settings_location: cache_path.as_ptr(),
        application_key: &app_key[..] as *const _ as *const ::std::os::raw::c_void,
        application_key_size: app_key.len() as u64,
        ..Default::default()
    };

    let mut ptr = ::std::ptr::null_mut();
    match unsafe { sp_session_create(&config, &mut ptr) } {
        Enum_sp_error::SP_ERROR_OK => println!("Session creation succeeded!"),
        err => println!("Session creation failed! {:?}", err)
    }
}

SP_CACHE_PATH points to a folder in my PC in which libspotify can store its assets and SP_APP_KEY_PATH points to the binary file with the application key. This all works fine (I have checked the generated code after the macros).

sp_session_create looks like this:

#[link(name = "libspotify")]
extern "system" {
    pub fn sp_session_create(config: *const sp_session_config, sess: *mut *mut sp_session) -> sp_error;
}

The system-callconv expands to stdcall on 32-bit and cdecl on 64-bit, so it should just work for libspotify.

I'm running Windows 10, Rust nightly 1.10 32-bit MSVC and I'm using libspotify 12.1.51. I currently do not have a Linux machine at my disposal, so it's kinda hard to test the code on other operating systems. I'd be glad if somebody else could try to test out the code and see if it works for them or not. I'd also gladly appreciate any ideas on how I might improve the FFI code.

Moritz Gunz
  • 702
  • 6
  • 15
  • *I currently do not have a Linux machine at my disposal* — Docker and various VM solutions are free to use and downloading and installing something like Ubuntu is very straight-forward. Not that you have to do this, but don't think you need a whole machine. – Shepmaster May 09 '16 at 19:26
  • I just tried running my code on a VM, and it segfaults too! So there might be something wrong with the interop code. – Moritz Gunz May 10 '16 at 07:34
  • Can you try `app_key.as_ptr() as *const c_void` instead? My guess is that you are casting the slice to a void pointer, not the data contained within the slice. `0x1C0` is 448 in decimal, which could *conceivably* be the length of the slice. – Shepmaster May 10 '16 at 12:45
  • `.as_ptr()`returns a `*const c_char`, so I'm not sure that casting it to a const void would help. It probably won't even compile since Spotify requests a const char. – Moritz Gunz May 10 '16 at 14:33
  • The important part is `as_ptr`. The void cast was just keeping what you already had; remove it if unneeded. – Shepmaster May 10 '16 at 14:38
  • Ah, I misread your post (was on mobile). Thought you were referring to the strings. Sill no luck, though. – Moritz Gunz May 10 '16 at 17:53

0 Answers0