A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 152 lines 5.8 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2010 Thomas Martitz 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21 22#include <jni.h> 23#include <stdio.h> 24#include <sys/mman.h> 25#include "notification.h" 26#include "appevents.h" 27#include "metadata.h" 28#include "albumart.h" 29#include "misc.h" 30#include "thread.h" 31#include "debug.h" 32#include "audio.h" 33 34extern JNIEnv *env_ptr; 35extern jclass RockboxService_class; 36extern jobject RockboxService_instance; 37 38static jmethodID updateNotification, finishNotification; 39static jobject NotificationManager_instance; 40static jstring title, artist, album, albumart; 41 42/* completely arbitrary dimensions. neded for find_albumart() */ 43static const struct dim dim = { .width = 200, .height = 200 }; 44#define NZV(a) (a && a[0]) 45 46/* 47 * notify about track change, and show track info */ 48static void track_changed_callback(unsigned short id, void *param) 49{ 50 (void)id; 51 struct mp3entry* id3 = ((struct track_event *)param)->id3; 52 JNIEnv e = *env_ptr; 53 if (id3) 54 { 55 /* passing NULL to DeleteLocalRef() is OK */ 56 e->DeleteLocalRef(env_ptr, title); 57 e->DeleteLocalRef(env_ptr, artist); 58 e->DeleteLocalRef(env_ptr, album); 59 e->DeleteLocalRef(env_ptr, albumart); 60 61 char buf[200]; 62 const char * ptitle = id3->title; 63 if (!ptitle && *id3->path) 64 { /* pass the filename as title if id3 info isn't available */ 65 ptitle = strip_extension(buf, sizeof(buf), strrchr(id3->path,'/') + 1); 66 } 67 68 title = e->NewStringUTF(env_ptr, ptitle ?: ""); 69 artist = e->NewStringUTF(env_ptr, id3->artist ?: ""); 70 album = e->NewStringUTF(env_ptr, id3->album ?: ""); 71 72 albumart = NULL; 73 if (id3->has_embedded_albumart && id3->albumart.type == AA_TYPE_JPG) 74 { /* extract albumart to a temporary file using mmap() */ 75 snprintf(buf, sizeof(buf), "/sdcard/rockbox/.temp_albumart_%d.jpg", 76 thread_self()); 77 int dst_fd = creat(buf, 0666); 78 if (dst_fd >= 0) 79 { 80 int src_fd = open(id3->path, O_RDONLY); 81 off_t o_pos = id3->albumart.pos; 82 off_t pa_pos = o_pos & ~(sysconf(_SC_PAGE_SIZE) - 1); 83 if (src_fd >= 0) 84 { /* align to page boundary */ 85 int pos_diff = o_pos - pa_pos; 86 unsigned char* p = mmap(NULL, id3->albumart.size + pos_diff, 87 PROT_READ, MAP_SHARED, src_fd, pa_pos); 88 if (p != MAP_FAILED) 89 { 90 write(dst_fd, p + pos_diff, id3->albumart.size); 91 munmap(p, id3->albumart.size + pos_diff); 92 albumart = e->NewStringUTF(env_ptr, buf); 93 } 94 close(src_fd); 95 } 96 close(dst_fd); 97 } 98 } 99 else if (find_albumart(id3, buf, sizeof(buf), &dim)) 100 { 101 albumart = e->NewStringUTF(env_ptr, buf); 102 } 103 104 e->CallVoidMethod(env_ptr, NotificationManager_instance, 105 updateNotification, title, artist, album, albumart); 106 } 107} 108 109/* 110 * notify about track finishing */ 111static void track_finished_callback(unsigned short id, void *param) 112{ 113 (void)id; 114 if (((struct track_event *)param)->flags & TEF_REWIND) 115 return; /* Not a true track end */ 116 117 JNIEnv e = *env_ptr; 118 e->CallVoidMethod(env_ptr, NotificationManager_instance, 119 finishNotification); 120 121 /* delete temporary albumart file */ 122 char buf[MAX_PATH]; 123 snprintf(buf, sizeof(buf), "/sdcard/rockbox/.temp_albumart_%d.jpg", 124 thread_self()); 125 unlink(buf); 126} 127 128void notification_init(void) 129{ 130 JNIEnv e = *env_ptr; 131 jfieldID nNM = e->GetFieldID(env_ptr, RockboxService_class, 132 "mFgRunner", "Lorg/rockbox/Helper/RunForegroundManager;"); 133 NotificationManager_instance = e->GetObjectField(env_ptr, 134 RockboxService_instance, nNM); 135 if (NotificationManager_instance == NULL) 136 { 137 DEBUGF("Failed to get RunForegroundManager instance. Performance will be bad"); 138 return; 139 } 140 141 jclass class = e->GetObjectClass(env_ptr, NotificationManager_instance); 142 updateNotification = e->GetMethodID(env_ptr, class, "updateNotification", 143 "(Ljava/lang/String;" 144 "Ljava/lang/String;" 145 "Ljava/lang/String;" 146 "Ljava/lang/String;)V"); 147 finishNotification = e->GetMethodID(env_ptr, class, "finishNotification", 148 "()V"); 149 150 add_event(PLAYBACK_EVENT_TRACK_CHANGE, track_changed_callback); 151 add_event(PLAYBACK_EVENT_TRACK_FINISH, track_finished_callback); 152}